Sunteți pe pagina 1din 4494

Contents

SharePoint development
SharePoint Framework
Getting started
Set up Office 365 tenant
Set up development environment
Web parts
Getting started
Build your first web part
Connect your web part to SharePoint
Deploy your web part to a SharePoint page
Host your web part from Office 365 CDN
Add jQueryUI Accordion to your web part
Use Office UI Fabric React components in your web part
Provision assets from your web part
Deploy your web part to an Azure CDN
Basics
Integrate properties with SharePoint
Configure custom properties
Configure web part icon
Using full-width column
Hide from the toolbox
Preconfigure web parts
Validate properties
Share data between web parts
Tutorial
Extend property pane
Build custom controls
Use cascading dropdowns
Migrate existing customizations
Script Editor web part
jQuery and DataTables
jQuery and FullCalendar
AngularJS applications
Work with __REQUESTDIGEST
Use JSOM
Extensions
Getting started
Build your first extension
Use page placeholders
Deploy your extension to SharePoint
Host extension from CDN
Build Field Customizer
Build ListView Command Set
Configure extension icon
Migrate existing customizations
Client Side Rendering (JSLink)
JavaScript embedding (UserCustomAction)
Edit Control Block (ECB) menu item tutorial
Client Side Rendering (JSLink) tutorial
JavaScript embedding (UserCustomAction) tutorial
Guidance
Enterprise guidance
Team-based development
Governance considerations
Connecting components
External libraries
Add external libraries
JavaScript libraries
CSS styles
SP PnP JS
AngularJS
Connect to APIs
Connect to APIs secured with Azure AD
Call the Microsoft Graph API using OAuth
Connect to APIs secured with Azure AD using the AadHttpClient
Consume enterprise APIs (tutorial)
Consume multi-tenant enterprise APIs (tutorial)
Microsoft Graph
Consume Microsoft Graph (tutorial)
Microsoft GraphHttpClient (Deprecated)
Tutorial (Deprecated)
Setup and deployment
Package solution
Custom build tasks
Extend Webpack
Update packages
Tenant-scoped solution deployment
Tenant properties
Provision SharePoint assets
Optimize builds for production
Localize web parts
SharePoint 2016 support
Use preview capabilities
Design
Design a web part
Reactive and nonreactive web parts
Responsive design
Titles and descriptions
Commanding within a web part
UI text
Placeholders and fallbacks
Empty state of a web part
Accessibility
Key web part examples
Web part showcase
Authoring pages
Design considerations
Custom dialogs
Work with CSS
Themes and colors
Use themes
Office UI Fabric integration
Tools and libraries
Toolchain
Yeoman generator
Debugging
Debug in Visual Studio Code
Debug on modern pages
Roadmap
Known issues and FAQ
Features
Connect to Office 365 group
CSOM development
Hub sites
Create hub sites with PowerShell
PowerShell cmdlets for hub sites
REST API
SP.HubSites.CanCreate
GetById
HubSiteData
HubSites
JoinHubSite
RegisterHubSite
SyncHubSiteTheme
UnRegisterHubSite
SPHubSite type
SPHubSiteData type
SharePoint APIs
SharePoint .NET Server, CSOM, JSOM, and REST API index
Complete basic operations using SharePoint client library code
Complete basic operations using JavaScript library code in SharePoint
Get to know the SharePoint REST service
Complete basic operations
Work with lists and list items
Work with folders and files
Determine endpoint URIs
Use OData query operations
Navigate data structure
Synchronize items
Upload a file
Set custom permissions
Make batch requests
Migration API
Azure container and queue
Encryption
Throttling
Sharing
Site design
Get started
Set scope
Customize default design
JSON schema reference
PowerShell cmdlets
REST API
PnP provisioning engine
Site theming
JSON schema reference
PowerShell cmdlets
CSOM API
REST API
Webhooks
Get started
Reference implementation
Use Azure Functions
List webhooks
Create subscription
Update subscription
Delete subscription
Get subscription
Application Lifecycle Management (ALM) APIs
Column formatting
Communication site
Shorter share links
SharePoint development overview
What's new for developers in SharePoint 2019
SharePoint glossary
Protocol handler error in SharePoint 2016
Programming models
SharePoint Add-ins compared with SharePoint solutions
Build farm solutions
Customize a field type using client-side rendering
URLs and tokens
Virtual directories in solutions
Access SharePoint from mobile and native device apps
Build Windows Phone apps that access SharePoint
Set up an environment for developing mobile apps
Application templates in Visual Studio
List Application template
Create a list app
Store and retrieve list items
Implement business logic and data validation
Support and convert field types
Customize list item queries and filter data
Customize the user interface of a list app
Use multiple lists
Configure and use push notifications
Create a mobile app that contains data from an external data source
Integrate maps with Windows Phone apps and lists
Build search-driven mobile apps with the Navigation and Event Logging REST
interfaces
SharePoint mobile object model
SharePoint mobile client authentication object model
Export the Name field in a Document Library list to a mobile app
Build localized applications based on SharePoint templates
Language support
Build mobile apps for other platforms
Build reusable components
Build sites for SharePoint
What's new with site development
Develop the site design
Design Manager
SharePoint page model
Master pages, the Master Page Gallery, and page layouts
Map a network drive to the Master Page Gallery
Apply a master page to a site
Create a page layout
Customize page layouts for a catalog-based site
Apply styles to page fields
Resolve errors and warnings when previewing a page
Convert an HTML file into a master page
Create a minimal master page
Change the preview page in Design Manager
SharePoint Online Suite Navigation control
Retrieve the URL of a Pages library
Branding and design capabilities
Design packages
Device channels
Display templates
Image renditions
Snippets
Themes
Managed metadata and navigation in SharePoint
Managed navigation
Content Search web part
Use code to pin terms to navigation term sets
Publish SharePoint sites
Cross-site publishing in SharePoint
User segmentation in SharePoint
Minimal Download Strategy overview
Modify SharePoint components for MDS
Optimize page performance
Optimize site accessibility
Add SharePoint capabilities
Workflows
Get started with workflows
Workflow fundamentals
What's new in workflows
Set up a workflow development environment
Configure MSMQ for workflows
Workflow initiation and configuration properties
Workflow development best practices
Debugging workflows
Using the pairing cmdlet Register-SPWorkflowService
Workflow samples
Develop SharePoint workflows using Visual Studio
Create a workflow app
Create workflows
SharePoint Workflow Services CSOM
Web Services in workflows
Tasks in workflows
Create custom SharePoint workflow forms
Build and deploy workflow custom actions
Use workflow interop for SharePoint
Common error messages in workflow development
SharePoint workflow object model
Develop workflows in SharePoint Designer and Visio
What's changed in SharePoint Designer
Create a workflow by using SharePoint Designer and the SharePoint Workflow
platform
Shapes in the SharePoint Server workflow template in Visio
Troubleshoot SharePoint Server workflow validation errors in Visio
Dictionary actions in SharePoint Designer
Coordination actions in SharePoint Designer
Task Actions in SharePoint Designer
Eventing Actions in SharePoint Designer
Visual Designer for workflow in SharePoint Designer
Web Services in SharePoint workflows using SharePoint Designer
Package and deploy workflow in SharePoint
Create a workflow with elevated permissions
Match the SharePoint Designer version with the farm version
Transfer a workflow between SharePoint Designer and Visio Professional
Workflow actions and activities reference
Workflow activity classes
Workflow actions quick reference
Workflow actions available using the workflow interop bridge
Workflow conditions quick reference (SharePoint 2010)
Workflow actions quick reference (SharePoint 2010)
Visio shapes in SharePoint Designer (SharePoint 2010)
Validation issues in Visio (SharePoint 2010)
Social and collaboration
What's new for developers
Get started developing with social features
Read and write to the social feed by using the .NET client object model
Read and write to the social feed by using the REST service
Social feed REST API reference
Following people and content REST API reference
Work with social feeds
Create and delete posts using the .NET client object model
Create and delete posts using the JavaScript object model
Include mentions, tags, and links to sites and documents
Embed images, videos, and documents
Reference threads and digest threads in feeds
Follow people
Follow people using the .NET client object model
Follow people using the JavaScript object model
Follow content
Follow documents and sites using the .NET client object model
Follow documents, sites, and tags using the REST service
Work with user profiles
Retrieve user profile properties using the .NET client object model
Retrieve user profile properties using the JavaScript object model
Work with user profiles using the server object model
Location and map functionality
Add a Geolocation column to a list programmatically
Create a map view for the Geolocation field
Set the Bing Maps key at the web and farm level
Extend the Geolocation field type by using client-side rendering
Search in SharePoint
What's new in SharePoint search for developers
Search new content
Search connector framework
Enhance the BDC model file for Search
Crawl associated external content types
Crawl binary large objects (BLOBs)
Configure item-level security
Configure search
Custom word breakers
Custom content processing with the Content Enrichment web service callout
Use the web service callout
Trigger expression syntax
Build search queries
Keyword Query Language (KQL) syntax reference
FAST Query Language (FQL) syntax reference
Using the SharePoint search Query APIs
Search REST API
Retrieve query suggestions using the Search REST service
Search add-ins
Customize search results
Sort search results
Customize ranking models
Custom security trimming
Use a custom security trimmer for search results
Export and import search configuration settings programmatically
Refine queries
Business Connectivity Services (BCS)
What's new in BCS
Get started with BCS
Set up a development environment for BCS
External content types
Create external content types for SQL Server
Create associations in SharePoint
Add-in-scoped external content types
Create an add-in-scoped external content type
Convert an add-in-scoped external content type to tenant-scoped
Access external data by using REST
Use OData sources with BCS
Create an external content type
Create an OData data service for use as a BCS external system
Create an external list
External events and alerts
Create external event receivers
Get started using the client object model with external data
Use the client code library to access external data
BCS programmers reference
BCS REST API reference
BCS client object model reference
Changes in the BDC model schema
BDC model schema reference
Create hybrid connectivity apps for SharePoint
Develop with Duet Enterprise 2.0
Use SAP workflow
Use SAP reporting
Office and SharePoint application services
Excel Services
Getting started
Overview
Architecture
Development roadmap
Features
Blogs, forums, and resources
Excel Web Services
What's new
Access the SOAP API
Loop-back SOAP calls and direct linking
Develop a custom application
Error codes
Get values from ranges
Set values of ranges
Specify a range address and sheet name
Get an entire workbook or a snapshot
Use the CloseWorkbook method call asynchronously
Set various credentials
Refresh data
Use the SubCode property to capture error codes
User-defined functions (UDFs)
Understand UDFs
Develop a managed-code UDF
FAQ about UDFs
Enable UDFs
Create a UDF that calls a web service
Access an external data source from a UDF
Deploy UDFs using SharePoint Foundation solutions
Restrict UDF code access security permissions
Excel Web Access
Programmatically add a web part to a page
Locate and copy required SharePoint DLLs
ECMAScript
Develop using the Content Editor web part
ECMAScript overview
JavaScript UDFs overview
JavaScript object model
Create a mashup that uses an embedded workbook and Bing Maps
Excel Services REST API
REST API overview
Basic URI structure and path
Discovery
Resources URI
Getting ranges using Atom feed and HTML fragment
Sample URI
Access a schema
Unsupported features
Advanced scenarios and additional samples
Use OData with REST in SharePoint
Request Excel workbook data from SharePoint Server using OData
General guidelines
Alerts
Known issues and tips
Best practices
Trust a location
Save from Excel client to the server
Save to the server to prepare for programmatic access
Catch exceptions
Remove Excel Interactive View from a webpage
Machine Translation Service
PerformancePoint Services
Create report renderers
Create report editors
Create filter data providers
Create filter editors
Create tabular data source providers
Create tabular data source editors
Create scorecard transforms
PowerPoint Automation Services
Access web apps
What's new in Access
Visio Services
Word Automation Services
Extend the fixed-format export feature
Authentication, authorization, and security
Authorization, users, groups, and the object model
Role, inheritance, elevation of privilege, and password changes
Claims-based identity
Sign in to SharePoint
Claims provider overview
Create a claims provider
Deploy a claims provider
Claims-based identity and concepts
Sample delegation, federation, and authentication scenario
Claims-based identity term definitions
Configuration, administration, and resources
eDiscovery
What's new in eDiscovery and compliance
CMIS
XLIFF interchange file format
Create no-code solutions
SharePoint Composites
Save a site as a template
Upgrade site customizations
Upgrade web templates
Use Feature upgrade to apply new master pages
Set up a development environment for SharePoint
How-tos for SharePoint
Code samples for SharePoint
Choose the right API set
Use the Office 365 content delivery network (CDN)
Use the site collection app catalog
Maintenance mode for client-side web parts
SharePoint Workflow Manager
SharePoint Application Lifecycle Management
Accessibility
Detect the installed SKU
Avoid getting throttled or blocked in SharePoint Online
Volume Shadow Copy Service (VSS)
VSS Writer
VSS requestors
Create a VSS requestor
Back up and restore SharePoint
Back up and restore a search service application
SharePoint Add-ins
Get started creating SharePoint-hosted add-ins
1. Deploy and install add-ins
2. Add custom columns
3. Add a custom content type
4. Add a web part to a page
5. Add a workflow
6. Add a custom page and style
7. Add custom client-side rendering
8. Create a custom ribbon button in the host web
9. Use the SharePoint JavaScript APIs to work with SharePoint data
10. Work with host web data from JavaScript in the add-in web
Get started creating provider-hosted add-ins
1. Give your add-in the SharePoint look-and-feel
2. Include a custom button
3. Get an overview of the SharePoint object model
4. Add write operations
5. Include an add-in part
6. Handle add-in events
7. Add first-run logic
8. Programmatically deploy a custom button
9. Handle list item events
Design
Design options for add-ins
Add-in architecture and development landscape
Patterns for developing and hosting an add-in
Host webs, add-in webs, and SharePoint components
Secure data access and client object models for add-ins
UX design for add-ins
SharePoint Add-ins UX design guidelines
Develop
Explore the app manifest structure and the package of an add-in
URL strings and tokens in add-ins
Create UX components in SharePoint
Use a SharePoint website's style sheet in add-ins
Use the client chrome control in add-ins
Create add-in parts to install with your add-in
Create custom actions to deploy with add-ins
Customize a list view in add-ins using client-side rendering
Use the client-side People Picker control in SharePoint-hosted add-ins
Highlight content and enhance the functionality of SharePoint-hosted add-ins with
the callout control
Include a web part in a webpage on the add-in web
Office Web Widgets - Experimental overview
Use the experimental People Picker widget in add-ins
Use the experimental Desktop List View widget in add-ins
Office Web Widgets - Experimental License Terms
Work with external data in SharePoint
Create a custom proxy page for the cross-domain library
Query a remote service using the web proxy
Handle events in add-ins
Create a remote event receiver
Create an add-in event receiver
Debug and troubleshoot a remote event receiver
Create a provider-hosted add-in that includes a custom SharePoint list and content
type
Get user identity and properties in SharePoint
Localize SharePoint Add-ins
Authorization and authentication of add-ins
Add-in permissions in SharePoint
Register add-ins
Add-in authorization policy types in SharePoint
Three authorization systems for add-ins
Creating add-ins that use low-trust authorization
Context Token OAuth flow for add-ins
Authorization Code OAuth flow for add-ins
Handle security tokens in provider-hosted low-trust add-ins
Use an Office 365 SharePoint site to authorize provider-hosted add-ins on an
on-premises SharePoint site
Replace an expiring client secret in an add-in
Creating add-ins that use high-trust authorization
Create high-trust add-ins
Create and use access tokens in provider-hosted high-trust add-ins
Troubleshooting high-trust add-ins
Package and publish high-trust add-ins
Creating add-ins that use the cross-domain library
Access SharePoint data from add-ins using the cross-domain library
Work with the cross-domain library across different Internet Explorer security
zones in SharePoint Add-ins
Create add-ins that can be used by anonymous users
Convert an autohosted add-in to a provider-hosted add-in
Create add-ins for the SAP Gateway for Microsoft
Create an add-in that contains a document template and a task pane add-in
Publish
Deploy and install add-ins
Tenancies and deployment scopes for add-ins
SharePoint Add-ins update process
Update add-ins
Update add-in web components in SharePoint
Update host web components in SharePoint
Update remote components in add-ins
Create a handler for the update event in add-ins
Publish add-ins by using Visual Studio
Tools
Set up a development environment for add-ins on Office 365
Create a developer site on an existing Office 365 subscription
Set up an on-premises development environment for add-ins
Create add-ins in Visual Studio
Solution guidance
Modernizing your classic SharePoint sites
Modernize the user interface
Maximize use of modern lists and libraries
Analyze and use the scanner data
Rollout approaches
Transform classic pages to modern client-side pages
Page transformation model
Page layout mapping
Page transformation API
Modernize customizations
Modernize site branding
Connect to an Office 365 group
Analyze and use the scanner data
Site permissions after Office 365 group connection
Branding and site provisioning solutions
Page model
Development and design tools and practices
Metadata, site navigation, and publishing site features
Site branding
Use composed looks to brand sites
Use remote provisioning to brand pages
Use CSS to brand pages
Customize elements of a page
Update the branding of existing sites and regions
Customize OneDrive for Business sites
Site provisioning
Implement a site classification solution
Modify host web lists at creation time
Create content types by using CSOM
Modify site permissions and get external sharing status
Manage users and groups
UX components
Customize the UX
Create UX controls
Improve performance
Customizing the "modern" experiences in SharePoint Online
Provision "modern" team sites programmatically
Customize "modern" team sites
Customize "modern" lists and libraries
Customize "modern" site pages
SharePoint "modern" sites classification
OneDrive and SharePoint Online Multi-Geo
Permissions model
Discover your tenant configuration
Access OneDrive for Business
Work with sites
Provision classic team sites
Manage apps/add-ins
Work with user profiles
Search in a tenant
Manage metadata
Define and publish content types
Connect to external data using BCS and Secure Store Service
Set up a sample application
Building SharePoint Online portals
Performance
Information architecture
Navigation
Content aggregation
Branding
Deployment
Composite business add-ins
Migrate InfoPath forms
Data storage options
Corporate event add-in integration
Call web services from workflows
ECM solutions
Document library templates
Auto-tagging
Information management
Records management extensions
Taxonomy operations
Bulk upload documents
Upload large files
Synchronize term groups
Support % and # in files and folders with ResourcePath API
Localization solutions
Use localization features
Localize UI elements
Search solutions
Search customizations
Security and performance
Authorization considerations for tenants hosted in Germany, China, or US
Handle SharePoint Online throttling
Set up app-only access to SharePoint
Grant access using Azure AD app-only
Grant access using SharePoint app-only
Implement a web app policy alternative
Migrate from permissive to strict tenant setting
Authorize provider-hosted add-in users at run time
Cross-domain images in provider-hosted add-ins
Elevated privileges in SharePoint Add-ins
Provide add-in app-only tenant administrative permissions in SharePoint Online
Develop using tenant permissions with app-only
Set external sharing in Office 365
JavaScript patterns and performance
SharePoint Add-in recipes
App-only and elevated privileges
Branding sites
Custom actions
Custom field type
Custom ribbons
Customize your site UI using JavaScript embedding
Delegate controls
Document ID provider
Event receivers and list event receivers
Feature stapling
Information management policy
JavaScript customizations
List definition/list template
List instance
Localization
Master pages
MMS manipulation
Modules
OneDrive for Business customization
Performance considerations
Remote timer jobs
Remote event receivers
Search API usage
Search configuration
SharePoint change log
Site columns and content types
Site provisioning
Asynchronous operations in SharePoint Add-ins
User controls and web controls
User profile manipulation
Variations
Web part
Upload web parts
Connect SharePoint Add-in parts
Workflows, actions (activities), events, and forms
Yammer integration
Transforming farm solutions
Replace content types and site columns
Replace files
Replace lists
Replace web parts
Transforming sandbox solutions
Replace web parts
Replace event receivers
Replace feature receivers
Fix code-based InfoPath forms
User profile solutions
Read or update user profile properties
Bulk update custom user profile properties
Migrate user profile properties
Personalize search results
Upload user profile pictures
Deploying your SharePoint Add-ins
Deploy sites to Azure
Use Azure WebJobs with Office 365
Configure provider-hosted add-ins for distribution
Configure Office 365 projects for distribution
PnP remote provisioning
PnP provisioning engine
PnP provisioning framework
PnP provisioning engine and the Core library
PnP provisioning schema
Provisioning console application sample
PnP remote timer job framework
PnP timer job framework
Create remote timer jobs
Get started with WebJobs
PnP Office 365 CLI
PnP PowerShell reference
PnP Sites Core API reference
PnP Sites Core API reference - Extension methods
SharePoint schema reference
SharePoint Add-in schemas
Schema reference for manifests of SharePoint Add-ins
Schema map (SharePoint Add-in Manifest)
Elements (SharePoint Add-in Manifest)
App element
AppPermissionRequest element
AppPermissionRequests element
AppPrerequisite element
AppPrerequisites element
AppPrincipal element
AutoDeployedWebApplication element
DebugInfo element
InstalledEventEndpoint element
Internal element
Properties element
Property element
RemoteEndpoint element
RemoteEndpoints element
RemoteWebApplication element
SettingsPage element
StartPage element
SupportedLanguages element
SupportedLocale element
SupportedLocales element
Title element
UninstallingEventEndpoint element
UpgradedEventEndpoint element
WebTemplate element
Types (SharePoint Add-in Manifest)
AppDefinition complexType
AppPermissionPropertyDefinition complexType
AppPermissionRequestDefinition complexType
AppPermissionRequestsDefinition complexType
AppPrerequisite complexType
AppPrerequisiteCollection complexType
AppPrincipalDefinition complexType
AutoDeployedWebApplicationDebugInfoDefinition complexType
PropertiesDefinition complexType
RemoteEndpointDefinition complexType
RemoteEndpointsDefinition complexType
SupportedLocaleDefinition complexType
SupportedLocalesDefinition complexType
UrlElementDefinition complexType
WebTemplateDefinition complexType
AppPermissionAppPrincipalDefinition simpleType
AppPermissionRightDefinition simpleType
AppPrerequisiteTypeDefinition simpleType
AppPrincipalTypeDefinition simpleType
AutoDeployedWebApplicationDebugInfoAppUrlDefinition simpleType
CultureNameDefinition simpleType
DescriptionDefinition simpleType
GUID simpleType
ManifestUri simpleType
NameDefinition simpleType
RestrictedInt simpleType
SupportedLanguagesDefinition simpleType
TitleDefinition simpleType
TypeDefinition simpleType
VersionDefinition simpleType
WebTemplateIdDefinition simpleType
AppHostWebFeatures schema reference
Schema map (AppHostWebFeatures)
Elements (AppHostWebFeatures)
ActivationDependencies element
ActivationDependency element
ApplyElementManifests element
Button element
CheckBox element
ClientWebPart element
ColorPicker element
ComboBox element
CommandUIDefinition element
CommandUIDefinitions element
CommandUIExtension element
CommandUIHandler element
CommandUIHandlers element
Content element
ContextualGroup element
ContextualTabs element
Controls element
CustomAction element (CustomActionDefinitions)
CustomAction element (ElementDefinitionCollection)
DropDown element
ElementFile element
ElementManifest element
ElementManifests element
Elements element
EnumItem element
EnumItems element
Feature element
Feature element (FeatureTemplateReferences)
FlyoutAnchor element
Gallery element
GalleryButton element
Group element
Groups element
GroupTemplate element
InsertTable element
Label element
MaxSize element
Menu element
MenuSection element
MRUSplitButton element
Properties element (FeatureDefinition)
Properties element (FeatureTemplateReference)
Properties element (ClientWebPartDefinition)
Property element (FeaturePropertyDefinitions)
Property element (PropertyBagDefinition)
Property element (ClientWebPartProperties)
QAT element
Ribbon element
Scale element
Scaling element
Spinner element
SplitButton element
Tab element
Tabs element
TextBox element
ToggleButton element
UpgradeActions element
UrlAction element
VersionRange element
Types (AppHostWebFeatures)
ClientWebPartDefinition complexType
ClientWebPartDefinitionContent complexType
ClientWebPartEnumItem complexType
ClientWebPartEnumItems complexType
ClientWebPartProperties complexType
ClientWebPartProperty complexType
CommandUIDefinitionsType complexType
CommandUIDefinitionType complexType
CommandUIExtensionType complexType
CommandUIHandlersType complexType
CommandUIHandlerType complexType
CustomActionDefinition complexType
CustomActionDefinitions complexType
ElementDefinitionCollection complexType
ElementManifestReference complexType
ElementManifestReferences complexType
FeatureActivationDependencyDefinition complexType
FeatureActivationDependencyDefinitions complexType
FeatureDefinition complexType
FeaturePropertyDefinition complexType
FeaturePropertyDefinitions complexType
FeatureTemplateReference complexType
FeatureTemplateReferences complexType
PropertyBagDefinition complexType
PropertyValueAttributeDefinition complexType
SimplePropertyDefinition complexType
UpgradeActionsDefinition complexType
UrlActionDefinition complexType
VersionRangeDefinition complexType
ClientWebPartDefinitionContentType simpleType
ClientWebPartPropertyType simpleType
CustomActionLocations simpleType
CustomActionRegistrationType simpleType
FeatureScope simpleType
FeatureVersion simpleType
PropertyBagParentTypeDefinition simpleType
PropertyBagType simpleType
UIVersion simpleType
WebPartPersonalizationScope simpleType
AppPartConfigDefinition schema reference
Schema map (AppPartConfigDefinition)
Elements (AppPartConfigDefinition)
AppPartConfig element
Id element
Types (AppPartConfigDefinition)
AppPartConfigDefinition complexType
GUID simpleType
Business connectivity services (BCS) schemas
SolutionManifestDefinitions schema
ContextDefinition element
ContextDefinitionGroup element
ContextDefinitionGroups element
Entities element
Entity element
OfficeItemCustomizations element
PromotedProperty element
SolutionDefinition element
SolutionSettings element
View element
OutlookItemCustomizations element
OfficeItemProperties element
OfficeItemProperty element
FormRegions element
FormRegion element
Picture element
OutlookFolder element
Associations element
Association element
Views element
FolderViewDefinition element
SolutionManifestDeclarativeExtensions schema
Actions element
CodeMethodAction element
ConstantParameter element
ContextActivated element
ContextDeactivated element
ContextEventHandlers element
DeclarativeAssociation element
DeclarativeContextDefinition element
DeclarativeContextDefinitionGroup element
DeclarativeFormRegion element
DeclarativeFormRegions element
DeclarativeSolutionSettings element
ExpressionParameter element
Layout element
Layouts element
Parameters element
Picture element
UrlAction element
LayoutDefinitions schema
ActionName element
ActionNames element
Children element
Container element
CustomProperties element
CustomProperty element
OBPart element
TitleBar element
Subscription schema
Association element
Associations element
FilterValue element
FilterValues element
FilterValues element
Identities element
Identity element
LocalizedDisplayName element
LocalizedDisplayNames element
Properties element
Property element
Queries element
Query element
Subscription element
BDCMetadata schema
AccessControlEntry element
AccessControlList element
Action element
ActionParameter element
ActionParameters element
Actions element
Association element
AssociationGroup element
AssociationGroups element
AssociationReference element
ConvertType element
DefaultValue element
DefaultValues element
DestinationEntity element
Entities element
Entity element
FilterDescriptor element
FilterDescriptors element
Identifier element
Identifiers element
Interpretation element
LobSystem element
LobSystemInstance element
LobSystemInstances element
LobSystems element
LocalizedDisplayName element
LocalizedDisplayNames element
Method element
MethodInstance element
MethodInstances element
Methods element
Model element
NormalizeDateTime element
Parameter element
Parameters element
Properties element
Property element
Proxy element
Right element
SourceEntity element
TypeDescriptor element
TypeDescriptors element
BDCMetadataResource schema
AccessControlEntry element
AccessControlList element
Action element
ActionParameter element
ActionParameters element
Actions element
Association element
AssociationGroup element
AssociationGroups element
Entities element
Entity element
FilterDescriptor element
FilterDescriptors element
Identifier element
Identifiers element
LobSystem element
LobSystemInstance element
LobSystemInstances element
LobSystems element
LocalizedDisplayName element
LocalizedDisplayNames element
Method element
MethodInstance element
MethodInstances element
Methods element
Model element
Parameter element
Parameters element
Properties element
Property element
Right element
TypeDescriptor element
TypeDescriptor element
TypeDescriptors element
Workflow schemas
WorkflowActions4 schema reference
Schema map (Workflow actions)
Elements (Workflow actions)
Action element
ActionBody element
ActionConditions element
Actions element
ActionVariables element
ActivityBody element
ActivitySource element
AssemblyRedirect element
AssemblyRedirects element
Block element
Blocks element
Coercion element
Coercions element
CompositeStep element
CompositeSteps element
Condition element
Conditions element
ContentType element
DataSource element
DataSourceRef element
DataSources element (Action element)
DataSources element (CompositeStep element)
Default element (Conditions element)
Default element (Actions element)
Dictionary element
Evaluation element
Event element
Events element
Field element
FieldBind element
Fields element
Flow element
Flows element
HashtableSource element
Modification element
Modifications element
NestedInitiationFieldNodes element
Option element
Parameter element (parametersType)
Parameter element (coercionParametersType)
Parameters element (Condition element)
Parameters element (Action element)
Parameters element (Coercion element)
Parameters element (Flow element)
Property element
RuleDesigner element (Default element)
RuleDesigner element (Condition element)
RuleDesigner element (Action element)
RuleDesigner element (Flow element)
RuleDesigner element (defaultElementType)
SchemaSource element
VariableType element
VariableTypes element
WorkflowInfo element
Types (Workflow actions)
appliesToTypes simpleType
coercionParametersType complexType
dataSourcesType complexType
dataSourceType complexType
defaultElementType complexType
parametersType complexType
propertiesType complexType
ruleDesignerType complexType
WorkflowActions3 schema reference
Action element
ActionBody element
ActionConditions element
ActionVariables element
ActivitySource element
ContentType element
DataSources element
DataSource element
DataSourceRef element
Default element
Dictionary element
Evaluation element
Field element
FieldBind element
Fields element
HashtableSource element
Modifications element
Modification element
NestedInitiationFieldNodes element
Option element
Parameter element
Parameters element
RuleDesigner element
SchemaSource element
WorkflowActions element
Workflow configuration schema reference
WorkflowConfig element
Template element
Association element
ContentTypes element
ContentType element
Initiation element
Fields element
Parameters element
Parameter element
WorkflowInfo schema reference
.ACTIONS File Example
Action element
ActionBody element
ActionConditions element
ActionVariables element
Actions element
Actions schema reference
ActivitySource element
AssemblyRedirect element
AssemblyRedirects element
Coercion element
Coercions element
Condition element
Conditions element
CompositeSteps element
CompositeStep element
ContentType element
DataSource element
DataSourceRef element
DataSources element
Default element
Default Workflow Actions
Default Workflow Conditions
Dictionary element
Evaluation element
Field element
FieldBind element
Fields element
HashtableSource element
Modification element
Modifications element
NestedInitiationFieldNodes element
Option element
Parameter element
Parameters element
RuleDesigner element
SchemaSource element
VariableType element
VariableTypes element
WorkflowInfo element
SharePoint Features schemas
Client Web Part Definition schema
Content Type Bindings
ContentTypeBinding element
Elements element
Content Type Definitions
ContentType element
DocumentTemplate element
Elements element
FieldRef element
FieldRefs element
Folder element
RemoveFieldRef element
XmlDocument element
XmlDocuments element
Custom Action Definition schema
CommandUIDefinitions element
CommandUIDefinition element
CommandUIExtension element
CommandUIHandlers element
CommandUIHandler element
CustomAction element
CustomActionGroup element
Elements element
HideCustomAction element
UrlAction element
Default Custom Action Locations and IDs
Delegate Controls
Control element
Elements element
Property element
Document Converter
DocumentConverter element
Elements element
Event Registrations
Assembly element
Class element
Data element
Elements element
Filter element
Name element
Receiver element
Receivers element
SequenceNumber element
SolutionId element
Synchronization element
Type element
SourceId element
SourceType element
Feature.xml Files
ActivationDependencies element
ActivationDependency element
AddContentTypeField element
ApplyElementManifests element
CustomUpgradeAction element
ElementFile element
ElementManifest element
ElementManifests element
Feature element
MapFile element
Parameter element
Parameters element
Properties element
Property element
UpgradeActions element
VersionRange element
Feature/Site Template Associations
Elements element
FeatureSiteTemplateAssociation element
Property element
Field Definitions
Elements element
Field element
List Instances
Data element
Elements element
Field element
ListInstance element
Row element
Rows element
DataSource element
Property element
List Template Files
Elements element
ListTemplate element
List Definition (Schema.xml) Files
Modules
AllUsersWebPart element
BinarySerializedWebPart element
Elements element
File element
GUID element
GUIDMap element
Module element
NavBarPage element
Property element
View element
WebPart element
WebPartConnection element
WebPartTransformer element
Property Bag schema
Elements element
PropertyBag element
Property element
Site Definition (Onet.xml) Files
Web Template XML
WebTemplate element
Elements
Workflow Definitions
AssociationCategories element
AssociationData element
Categories element
Elements element
ExtendedStatusColumnValues element
InitiationCategories element
InitiationType element
MetaData element
Modification_GUID_Name element
StatusColumnValue element
StatusPageUrl element
Workflow element (Elements)
Content migration schemas
DeploymentManifest schema
Selected Type Definitions
AnonymousState Simple Type
DefaultItemOpen Simple Type
DraftVisibilityType Simple Type
Guid Simple Type
ListItemDocType Simple Type
SecurityModificationType Simple Type
SPBaseType Simple Type
SPDictionaryEntryAccess Simple Type
SPDictionaryEntryValueType Simple Type
SPEventHostType Simple Type
SPEventReceiverType Simple Type
SPListTemplateType Simple Type
SPModerationStatusType Simple Type
SPObjectType Simple Type
SPViewScope Simple Type
TRUEFALSE Simple Type
Aggregations element (SPView)
Aggregations element (SPWebPart)
Assignment element
Attachment element
Attachments element
CalendarViewStyles element (SPView)
CalendarViewStyles element (SPWebPart)
ContentType element
ContentTypes element
DeletedField element
DeletedFields element
DocumentLibrary element
DocumentTemplate element
EventReceiver element
EventReceivers element (SPFile)
EventReceivers element (SPList)
EventReceivers element (SPListItem)
EventReceivers element (SPWeb)
Feature element
Field element (SPFieldCollection)
Field element (FieldDataCollection)
Field element (DeploymentFieldTemplate)
FieldRef element (SPFieldCollection)
FieldRef element (SPFieldLinkCollection)
Fields element (SPList)
Fields element (SPListItem)
FieldTemplate element
File element (SPGenericObject)
File element (SPFileVersionCollection)
Folder element
Form element
Formats element (SPView)
Formats element (SPWebPart)
Forms element
GroupByFooter element (SPView)
GroupByFooter element (SPWebPart)
GroupByHeader (SPView)
GroupByHeader (SPWebPart)
GroupX element
Link element
Links element (SPFile)
Links element (SPListItem)
List element
ListFormBody element (SPView)
ListFormBody element (SPWebPart)
ListItem element (SPGenericObject)
ListItem element (SPListItemVersionCollection)
ListTemplate element
Module element
PagedClientCallbackRowset element (SPView)
PagedClientCallbackRowset element (SPWebPart)
PagedRecurrenceRowset element (SPView)
PagedRecurrenceRowset element (SPWebPart)
PagedRowset element (SPView)
PagedRowset element (SPWebPart)
Personalization element
Personalizations element
PictureLibrary element
Properties element (SPAttachment)
Properties element (SPFile)
Properties element (SPFolder)
Properties element (SPModule)
Properties element (SPWeb)
Property element
Query element (SPView)
Query element (SPWebPart)
Role element
RoleAssignment element
RoleAssignments element
RoleAssignmentX element
Roles element
RoleX element
RowLimit element (SPView)
RowLimit element (SPWebPart)
RowLimitExceeded element (SPView)
RowLimitExceeded element (SPWebPart)
Script element (SPView)
Script element (SPWebPart)
Site element
SPObject element
SPObjects element
Toolbar element (SPView)
Toolbar element (SPWebPart)
UserX element
Versions element (SPFile)
Versions element (SPListItem)
View element
ViewBidiHeader element (SPView)
ViewBidiHeader element (SPWebPart)
View Body element (SPView)
View Body element (SPWebPart)
ViewData element (SPView)
ViewData element (SPWebPart)
ViewEmpty element (SPView)
ViewEmpty element (SPWebPart)
ViewFields element (SPView)
ViewFields element (SPWebPart)
ViewFooter element (SPView)
ViewFooter element (SPWebPart)
ViewHeader element (SPView)
ViewHeader element (SPWebPart)
Views element
ViewStyle element (SPView)
ViewStyle element (SPWebPart)
Web element
WebPart element
WebParts element
WebStructure element
WebTemplate element
DeploymentExportSettings schema
DeploymentObject element
ExportObjects element
ExportSettings element
Guid Simple Type
SPDeploymentObjectType Simple Type
SPExportMethodType Simple Type
SPIncludeDescendents Simple Type
SPIncludeSecurity Simple Type
SPIncludeVersions Simple Type
DeploymentLookupListMap schema
Guid Simple Type
LookupItem element
LookupItems element
LookupList element
LookupLists element
DeploymentRequirements schema
Requirement element
Requirements element
SPRequirementObjectType Simple Type
DeploymentRootObjectMap schema
Guid Simple Type
RootObject element
RootObjects element
SPDeploymentObjectType Simple Type
DeploymentSystemData schema
Guid Simple Type
ManifestFile element
ManifestFiles element
SchemaVersion element
SPDeploymentObjectType Simple Type
SystemData element
SystemObject element
SystemObjects element
DeploymentUserGroupMap schema
Group element
Groups element
Member element
User element
Users element
UserGroupMap element
DeploymentViewFormsList schema
ViewForm element
ViewFormsList element
Collaborative Application Markup Language (CAML) schemas
Introduction to Collaborative Application Markup Language (CAML)
Major CAML Files
Data-defining elements
HTML-rendering elements
Deprecated CAML elements
Query schema
And element
BeginsWith element
Contains element
DateRangesOverlap element
Eq element
FieldRef element
Geq element
GroupBy element
Gt element
In element
Includes element
IsNotNull element
IsNull element
Leq element
ListProperty element
Lt element
Membership element
Month element
Neq element
NotIncludes element
Now element
Or element
OrderBy element
Today element
UserID element
Value element
Values element
Where element
XML element
View schema
Global attributes for HTML-rendering elements
A- F
Batch element
Case element
Column element
Column2 element
ContentTypes element
Counter element
CurrentRights element
Default element
Else element
Expr element
Expr1 element
Expr2 element
Field element
FieldPrefix element
FieldProperty element
Fields element
FieldSortParams element
FieldSwitch element
FilterLink element
ForEach element
G- L
GetFileExtension element
GetVar element
HTML element
HttpHost element
HttpPath element
HttpVDir element
ID element
Identity element
IfEqual element
IfHasRights element
IfNeg element
IfNew element
IfSubString element
Join element
Joins element
Length element
Limit element
List element
ListProperty element
ListUrl element
ListUrlDir element
LookupColumn element
M-Z
MapToAll element
MapToContentType element
MapToControl element
MapToIcon element
MeetingProperty element
Method element
More element
PageUrl element
ProjectProperty element
ProjectedFields element
Property element
RightsChoices element
RightsGroup element
ScriptQuote element
SelectionOptions element
ServerProperty element
SetList element
SetVar element
Switch element
Text element
Then element
ThreadStamp element
URL element
UrlBaseName element
UrlDirName element
UserID element
WebQueryInfo element
List schema
A- K
Aggregations element
AllUsersWebPart element
ArrayOfProperty element
CHOICE element
CHOICES element
ContentTypeRef element
ContentTypes element
Customization element
Default element (Field)
Default element (Form)
DefaultDescription element
DefaultFormula element
DefaultFormulaValue element
DisplayBidiPattern element
DisplayPattern element
DocumentLibraryTemplate element
Field element
FieldRef element
FieldRefs element
Fields element
Filter element
Folder element
Form element
Forms element
Formula element
FormulaDisplayNames element
GroupByFooter element
GroupByHeader element
L- Z
List element
ListFormBody element
ListFormButtons element
ListFormClosing element
ListFormOpening element
MAPPING element
MAPPINGS element
MetaData element
Method element
PagedClientCallbackRowset element
PagedRecurrenceRowset element
PagedRowset element
ParameterBinding element
ParameterBindings element
Property element
Query element
RowLimit element
RowLimitExceeded element
Toolbar element
Validation element
View element
ViewBidiHeader element
ViewBody element
ViewData element
ViewEmpty element
ViewFields element
ViewFooter element
ViewHeader element
Views element
ViewStyle element
WebParts element
XslLink element
Site schema
A- L
AllUsersWebPart element
BaseType element
BaseTypes element
BinarySerializedWebPart element
Components element
Configuration element
Configurations element
Data element
DocumentTemplate element
DocumentTemplateFile element
DocumentTemplateFiles element
DocumentTemplates element
ExecuteUrl element
ExternalSecurityProvider element
Feature element
Field element
File element
FileDialogPostProcessor element
GUID element
GUIDMap element
List element
Lists element
ListTemplate element
ListTemplates element
M-Z
MetaData element
Module element
Modules element
NavBar element
NavBarLink element
NavBarPage element (Module)
NavBarPage element (NavBar)
NavBars element
Project element
Properties element
Property element (Feature)
Property element (Module)
Row element
Rows element
ServerEmailFooter element
SiteFeatures element
Template element
Templates element
View element
WebFeatures element
WebPart element
WebPartConnection element
WebPartTransformer element
Site Deletion Confirmation schema
AutoDeleteBody element
AutoDeleteSubject element
AutoDeleteWarning element
Confirmation element
ConfirmationBody element
ConfirmationSubject element
Email element
Regional Settings schema
Bias element
Currencies element
Currency element
Date element
Day element
DaylightTime element
DayOfWeek element
History element
Hour element
Language element
Languages element
Locale element
Locales element
Month element
RegionalSettings element
StandardTime element
TimeZone element
TimeZones element
Document Icons schema
ByExtension element
ByProgID element
DocIcons element
Mapping element
General schema
A- H
Attachments element
CategoryBot element
CrossProjectLink element
DataFormatLCID element
Discussions element
Escape element
FieldFilterImageURL element
FieldFilterOptions element
FieldSortImageURL element
Format element
FormatDef element
Formats element
GetProgID element
GlobalLists element
GUID element
HTMLBase element
HtmlTrInfo element
I -Z
IfOld element
ImagesPath element
InForm element
IsPrivilegedUser element
ListForm element
LocaleInfo element
Mapping element
MapToText element
OkToVote element
PresenceEnabled element
QuotedXML element
ReadSecurity element
Recurrence element
SchemaSecurity element
Script element
Security element
Site element
TodayISO element
UserEmail element
ViewStyles element
Week element
WriteSecurity element
SharePoint search settings portability schemas
SPS15XSDSearchSet1
Schema map (SPS15XSDSearchSet1)
Elements (SPS15XSDSearchSet1)
Active element
ArrayOfSource element
AuthInfo element
BuiltIn element
ConnectionTimeout element
ConnectionUrlTemplate element
CreatedDate element
Description element
HasPermissionToReadAuthInfo element
Id element
IndexOffset element
LastModifiedDate element
MaximumResponseLength element
Name element
Owner element
ProviderId element
QueryTransform element
Source element (ArrayOfSource)
Source element
Types (SPS15XSDSearchSet1)
ArrayOfSource complexType
Source complexType
SPS15XSDSearchSet2
Schema map (SPS15XSDSearchSet2)
Elements (SPS15XSDSearchSet2)
_AuthSchemeName element
_AuthSubmissionMethod element
_AuthSubmissionPath element
_Cookies element
_ErrorPageUrl element (CookieAuthData)
_ErrorPageUrl element (FormsAuthCredentials)
_nameValuePairs element
_NameValuePairs element
_SecurableNameValuePairs element
_SsoAppId element
_UserName element
AccountAuthCredentials element
Aliases element
AliasesOverridden element
AliasInfo element
AliasInfoCollection element
Anchoring element
ArrayOfCrawledPropertyInfo element
ArrayOfManagedPropertyInfo element
ArrayOfPropertyRule element
ArrayOfResultItemType element
AuthenticationData element
AuthenticationInformation element
AuthenticationType element
BaseInfo element
BaseInfoCollectionOfAliasInfoTzWWwPjw element
BaseInfoCollectionOfCrawledPropertyInfoTzWWwPjw element
BaseInfoCollectionOfManagedPropertyInfoTzWWwPjw element
BaseInfoCollectionOfMappingInfoTzWWwPjw element
BaseInfoCollectionOfOverrideInfoTzWWwPjw element
BuiltIn element
CategoryName element
CompleteMatching element
Context element
CookieAuthData element
CrawledPropertyInfo element
CrawledPropertyInfo element (ArrayOfCrawledPropertyInfo)
CrawledPropertyInfoCollection element
CrawledPropertyName element
CrawledPropset element
CutoffMaxBuckets element
Data element
DatabaseId element
DeleteDisallowed element
Description element
DescriptionLSID element
Dictionary element (AliasInfo)
Dictionary element (CrawledPropertyInfo)
Dictionary element (ManagedPropertyInfo)
Dictionary element (MappingInfo)
Dictionary element (OverrideInfo)
DisableInheritance element
DisplayProperties element
DisplayTemplateUrl element
Divisor element
EnabledForScoping element
EntityExtractorBitMap element
ExtraProperties element
FederationAuthType element
FormsAuthCredentials element
FullTextIndex element
HasMultipleValues element
ID element
IndexOptions element
InternalID element
Intervals element
IsDeleted element
IsFunction element
IsMappedToContents element
IsNameEnum element
IsQuoted element
IsReadOnly element
JoinedByOr element
LastItemName element (AliasInfo)
LastItemName element (CrawledProperty)
LastItemName element (ManagedPropertyInfo)
LastItemName element (MappingInfo)
LastItemName element (OverrideInfo)
LastModifiedDate element
ManagedDataType element
ManagedPid element (AliasInfo)
ManagedPid element (MappingInfo)
ManagedPid element (OverrideInfo)
ManagedPropertyInfo element (ArrayOfManagedPropertyInfo)
ManagedPropertyInfo element
ManagedPropertyInfoCollection element
ManagedType element
MappedCrawledProperties element
MappedManagedProperties element
MappingDisallowed element
MappingInfo element
MappingInfoCollection element
MappingOrder element
MappingsOverridden element
Name element (ResultItemType)
Name element (PropertyRuleOperator)
Name element (BaseInfo)
NameLSID element
OptimizeForFrequentUse element
OverrideInfo element
OverrideInfoCollection element
Owner element
Password element
Pid element
PropertyName element
PropertyOperator element
PropertyRule element (ArrayOfPropertyRule)
PropertyRule element
PropertyRuleCollection element
PropertyRuleOperator element
PropertyRules element
PropertyValues element
Propset element
Queryable element
Refinable element
RefinerAnchoring element
RefinerConfiguration element (ManagedPropertyInfo)
RefinerConfiguration element
RefinerType element
RemoveDuplicates element
Representation element
Resolution element
RespectPriority element
ResultItemType element (ArrayOfResultItemType)
ResultItemType element
Retrievable element
RuleNameLSID element
RulePriority element
Rules element
SafeForAnonymous element
Samples element
SchemaID element (AliasInfo)
SchemaID element (CrawledPropertyInfo)
SchemaID element (MappingInfo)
SchemaID element (OverrideInfo)
Searchable element
SearchObjectOwner element
SecurableAuthData element
SerializableSecurableNameValuePairs element
Sortable element
SortableType element (ManagedPropertyInfo)
SortableType element
SourceID element
SPFarmId element
SPSiteId element
SPSiteSubscriptionId element
SPWebId element
SsoAuthData element
TokenNormalization element (ManagedPropertyInfo)
TokenNormalization element (OverrideInfo)
TotalCount element
Type element
UpdateGroup element
Types (SPS15XSDSearchSet2)
AccountAuthCredentials complexType
AliasInfo complexType
AliasInfoCollection complexType
ArrayOfCrawledPropertyInfo complexType
ArrayOfManagedPropertyInfo complexType
ArrayOfPropertyRule complexType
ArrayOfResultItemType complexType
AuthenticationData complexType
AuthenticationInformation complexType
BaseInfo complexType
BaseInfoCollectionOfAliasInfoTzWWwPjw complexType
BaseInfoCollectionOfCrawledPropertyInfoTzWWwPjw complexType
BaseInfoCollectionOfManagedPropertyInfoTzWWwPjw complexType
BaseInfoCollectionOfMappingInfoTzWWwPjw complexType
BaseInfoCollectionOfOverrideInfoTzWWwPjw complexType
CookieAuthData complexType
CrawledPropertyInfo complexType
CrawledPropertyInfoCollection complexType
FormsAuthCredentials complexType
ManagedPropertyInfo complexType
ManagedPropertyInfoCollection complexType
MappingInfo complexType
MappingInfoCollection complexType
OverrideInfo complexType
OverrideInfoCollection complexType
PropertyRule complexType
PropertyRuleCollection complexType
PropertyRuleOperator complexType
RefinerConfiguration complexType
ResultItemType complexType
SearchObjectOwner complexType
SecurableAuthData complexType
SsoAuthData complexType
FederationAuthType simpleType
ManagedDataType simpleType
RefinerAnchoring simpleType
RefinerType simpleType
SortableType simpleType
SPS15XSDSearchSet3
Schema map (SPS15XSDSearchSet3)
Elements (SPS15XSDSearchSet3)
Aliases element
ArrayOfSearchQueryConfigurationSettings element
BestBets element
CategoriesAndCrawledProperties element
CrawledProperties element
DefaultSourceId element
DefaultSourceIdSet element
DeployToParent element
DisableInheritanceOnImport element
ManagedProperties element
Mappings element
Overrides element
QueryRuleGroups element
QueryRules element
RankingModels element
ResultTypes element
SearchConfigurationSettings element
SearchQueryConfigurationSettings element (SearchConfigurationSettings)
SearchQueryConfigurationSettings element
(ArrayOfSearchQueryConfigurationSettings)
SearchQueryConfigurationSettings element
SearchRankingModelConfigurationSettings element
(SearchConfigurationSettings)
SearchRankingModelConfigurationSettings element
SearchSchemaConfigurationSettings element (SearchConfigurationSettings)
SearchSchemaConfigurationSettings element
Sources element
UserSegments element
Types (SPS15XSDSearchSet3)
ArrayOfSearchQueryConfigurationSettings complexType
SearchConfigurationSettings complexType
SearchQueryConfigurationSettings complexType
SearchRankingModelConfigurationSettings complexType
SearchSchemaConfigurationSettings complexType
SPS15XSDSearchSet4
Schema map (SPS15XSDSearchSet4)
Elements (SPS15XSDSearchSet4)
BoundVariableOrigin element
GroupProcessingDirective element
LicenseType element
MatchingOptions element
QueryActionEnableOnClickThroughOptions element
QueryTransformParentType element
Types (SPS15XSDSearchSet4)
BoundVariableOrigin simpleType
GroupProcessingDirective simpleType
LicenseType simpleType
MatchingOptions simpleType
QueryActionEnableOnClickThroughOptions simpleType
QueryTransformParentType simpleType
SPS15XSDSearchSet5
Schema map (SPS15XSDSearchSet5)
Elements (SPS15XSDSearchSet5)
AlertChangeType element
ArrayOfReorderingRule element
Boost element
KeywordInclusion element
MatchType element
MatchValue element
QueryAuthenticationType element
QueryHint element
ReorderingRule element (ArrayOfReorderingRule)
ReorderingRule element
ReorderingRuleMatchType element
ResubmitFlag element
ResultType element
SearchProvider element
SimilarType element
SortDirection element
SpellcheckMode element
Types (SPS15XSDSearchSet5)
AlertChangeType simpleType
KeywordInclusion simpleType
QueryAuthenticationType simpleType
QueryHint simpleType
ReorderingRuleMatchType simpleType
ResubmitFlag simpleType
ResultType simpleType
SearchProvider simpleType
SimilarType simpleType
SortDirection simpleType
SpellcheckMode simpleType
ArrayOfReorderingRule complexType
ReorderingRule complexType
SPS15XSDSearchSet6
Schema map (SPS15XSDSearchSet6)
Elements (SPS15XSDSearchSet6)
LocStringId element
Types (SPS15XSDSearchSet6)
LocStringId simpleType
Other SharePoint schemas
Field Types schema
FieldTypes element
FieldType element
Field element
PropertySchema element
Fields element
Field element
Default element
RenderPattern element
AlertTemplates schema
AlertTemplate element
AlertTemplates element
Digest element
DigestNotificationExcludedFields element
EventTypes element
Fields element
FilterDefinition element
Filters element
Footer element
Format element
FriendlyName element
Header element
HeaderFields element
HeaderFieldsFooter element
HeaderFieldsHeader element
Immediate element
ImmediateNotificationExcludedFields element
NotificationHandlerAssembly element
NotificationHandlerClassName element
Properties element
Query element
RowFields element
RowFooter element
RowHeader element
ShortName element
Subject element
UpdateHandlerAssembly element
UpdateHandlerClassName element
Mobile Document Viewer schema
MobileDocViewers element
MobileDocViewer element
BrowserCondition element
Override element
Server Ribbon schema
Button element
CheckBox element
ColorPicker element
Colors element
Color element
ComboBox element
CommandUI element
ContextualGroup element
ContextualTabs element
ControlRef element
Controls element (CommandUIDefinition)
Controls element (Group)
Controls element (MenuSection)
DropDown element
FlyoutAnchor element
Gallery element
GalleryButton element (Gallery)
GalleryButton element (Group)
Groups element
Group element
GroupTemplate element
InsertTable element
Jewel element
Label element
Layout element
MaxSize element
Menu element
MenuSection element
MRUSplitButton element
OverflowSection element
OverflowArea element
QAT element
Ribbon element
RibbonTemplates element
Row element
Scale element
Scaling element
Section element
Spinner element
SplitButton element
Strip element
Tabs element
Tab element
Templates element
TextBox element
ToggleButton element
Unit element
UnitAbbreviation element
Solution schema
ActivationDependencies element
ActivationDependency element
App_GlobalResourceFile element
ApplicationResourceFile element
ApplicationResourceFiles element
Assemblies element (Assemblies)
Assemblies element (CodeAccessSecurity)
Assembly element (Assemblies)
Assembly element (CodeAccessSecurity)
BindingRedirect element
BindingRedirects element
ClassResource element
ClassResources element
CodeAccessSecurity element
DwpFile element
DwpFiles element
FeatureManifest element
FeatureManifests element
IPermission element
PermissionSet element
PolicyItem element
Resource element
Resources element
RootFile element
RootFiles element
SafeControl element
SafeControls element
SiteDefinitionManifest element
SiteDefinitionManifests element
Solution element
TemplateFile element
TemplateFiles element
WebTempFile element
SPMetal Parameters schema
Column element
ContentType element
ExcludeColumn element
ExcludeContentType element
ExcludeList element
ExcludeOtherColumns element
ExcludeOtherContentTypes element
ExcludeOtherLists element
IncludeHiddenColumns element
IncludeHiddenContentTypes element
IncludeHiddenLists element
List element
Web element
Upgrade Definition schema
AppliedSiteFeatures element
AppliedWebFeatures element
Config element
Feature element
File element
Files element
List element
Lists element
WebTemplate element
dsQueryResponse schema
dsQueryResponse element
Rows element
Row element
Community
Contribute
Contribute
Open source projects
GitHub repositories
Submit issues
Submit feature requests
SharePoint developer videos on YouTube
Office development on Twitter
SharePoint developer forum
Tutorials
Build SharePoint Framework solutions, apps, add-ins, and solutions for SharePoint for your enterprise or customer needs.

Setup

Get started

Community

SharePoint Dev Blog

Videos

Samples

Ideas

Issues

Forum

SharePoint Framework
Overview of the SharePoint Framework
Set up your development environment
Build your first client-side web part

SharePoint REST service


Get to know the SharePoint REST service
Complete basic operations
SharePoint in Microsoft Graph

SharePoint webhooks
Overview of SharePoint webhooks
Get started with SharePoint webhooks
SharePoint list webhooks

SharePoint Add-ins
Overview of SharePoint Add-ins
Provider-hosted add-ins
SharePoint-hosted add-ins

SharePoint development overview


Programming models for SharePoint
Use the Office 365 content delivery network
Use the site collection app catalog
Refer to the SharePoint glossary

Solution guidance
Modernize your classic SharePoint sites
Customizing modern experiences
Building SharePoint Online portals

"Sharing is caring!"
Overview of the SharePoint Framework
4/20/2018 • 5 minutes to read Edit Online

The SharePoint Framework (SPFx) is a page and web part model that provides full support for client-side SharePoint development, easy integration with SharePoint data, and support for
open source tooling. With the SharePoint Framework, you can use modern web technologies and tools in your preferred development environment to build productive experiences and apps
that are responsive and mobile-ready from day one. The SharePoint Framework works for SharePoint Online and soon also for on-premises (SharePoint 2016 Feature Pack 2).
Key features of the SharePoint Framework include the following:
It runs in the context of the current user and connection in the browser. There are no iFrames for the customization (JavaScript is embedded directly to the page).
The controls are rendered in the normal page DOM.
The controls are responsive and accessible by nature.
It enables the developer to access the lifecycle in addition to render, load, serialize and deserialize, configuration changes, and more.
It is framework-agnostic. You can use any JavaScript framework that you like: React, Handlebars, Knockout, Angular, and more.
The toolchain is based on common open source client development tools such as npm, TypeScript, Yeoman, webpack, and gulp.
Performance is reliable.
End users can use SPFx client-side solutions that are approved by the tenant administrators (or their delegates) on all sites, including self-service team, group, or personal sites.
SPFx web parts can be added to both classic and modern pages.
The runtime model improves on the Script Editor web part. It includes a robust client API, an HttpClient object that handles authentication to SharePoint and Office 365, contextual
information, easy property definition and configuration, and more.
If you work primarily with C#, you want to learn more about client-side JavaScript development. Most of your existing JavaScript knowledge related to SharePoint, however, is completely
transferable, as the data models have not changed, and you’ll use the same REST services or JavaScript Object Model (JSOM), depending on your requirements. If you are a C# developer,
TypeScript is a nice transition into the JavaScript world. The choice of IDE is up to you. Many developers like to use the cross-platform IDE Visual Studio Code. Many developers also use
products like Sublime and ATOM. Use what works best for you.

Why the SharePoint Framework?


SharePoint was launched as an on-premises product in 2001. Over time, a large developer community has extended and shaped it in many ways. For the most part, the developer
community followed the same patterns and practices that the SharePoint product development team used, including web parts, SharePoint feature XML, and more. Many features were
written in C#, compiled to DLLs, and deployed to on-premises farms.
That architecture worked well in environments with only one enterprise, but it didn’t scale to the cloud, where multiple tenants run side-by-side. As a result, we introduced two alternative
models: client-side JavaScript injection, and SharePoint Add-ins. Both of these solutions have pros and cons.

JavaScript injection
One of the most popular web parts in SharePoint Online is the Script Editor. You can paste JavaScript into the Script Editor web part and have that JavaScript execute when the page renders.
It’s simple and rudimentary, but effective. It runs in the same browser context as the page, and is in the same DOM, so it can interact with other controls on the page. It is also relatively
performant, and simple to use.
There are a few downsides to this approach, however. First, while you can package your solution so that end users can drop the control onto the page, you can't easily provide configuration
options. Also, the end user can edit the page and modify the script, which can break the web part. Another big problem is that the Script Editor web part is not marked as "Safe For
Scripting". Most self-service site collections (my-sites, team sites, group sites) have a feature known as "NoScript" enabled. Technically, it is the removal of the Add/Customize Pages (ACP)
permission in SharePoint. This means that the Script Editor web part will be blocked from executing on these sites.

SharePoint Add-in model


The current option for solutions that run in NoScript sites is the add-in/app-part model. This implementation creates an iFrame where the actual experience resides and executes. The
advantage is that because it's external to the system and has no access to the current DOM/connection, it's easier for information workers to trust and deploy. End users can install add-ins on
NoScript sites.
There are some downsides to this approach as well. First, they run in an iFrame. iFrames are slower than the Script Editor web part, because it requires a new request to another page. The
page has to go through authentication and authorization, make its own calls to get SharePoint data, load various JavaScript libraries, and more. A Script Editor web part might typically take,
for example, 100 milliseconds to load and render, while an app part might take 2 seconds or more. Additionally, the iFrame boundary makes it more difficult to create responsive designs
and inherit CSS and theming information. iFrames do have stronger security, which can be useful for you (your page is inaccessible by other controls on the page) and for the end user (the
control has no access to their connection to Office 365).

SharePoint Framework
Historically, we created web parts as full trust C# assemblies that were installed on the cloud servers. However, current development models for the most part involve JavaScript running in a
browser making REST API calls to the SharePoint and Office 365 back-end workloads. C# assemblies don’t work in this world. We needed a new development model. The SharePoint
Framework is the next evolution in SharePoint development.

What's next?
SharePoint Framework web parts and extensions have now reached General Availability (GA). We continue to provide updates and refinements over time based on your feedback and
experiences. For any additional SharePoint Framework capabilities that are first launched in preview mode, you might experience occasional breaking changes around API names, flows, and
more. Future updates to the SharePoint Framework will be backward-compatible so that your solutions continue to work.

SharePoint Framework License


The SharePoint Framework components are licensed under this Microsoft EUL A.

Questions?
If you have any questions, post them on SharePoint StackExchange. Tag your questions and comments with #spfx, #spfx-webparts, and #spfx-tooling.
You can also post issues, questions, or feedback about the docs or the SharePoint Framework in our GitHub repo.

See also
Overview of SharePoint client-side web parts
Overview of SharePoint Framework Extensions
SharePoint development
SharePoint glossary
Set up your Office 365 tenant
3/26/2018 • 2 minutes to read Edit Online

To build and deploy client-side web parts using the SharePoint Framework, you need an Office 365 tenant.
If you already have an Office 365 tenant, see the section Create app catalog site.
If you don't have one, you can get an Office 365 developer subscription when you join the Office 365 Developer Program. See the Office 365 Developer Program documentation for step-
by-step instructions about how to join the Office 365 Developer Program and sign up and configure your subscription.
NOTE

Make sure that you are signed out of any existing Office 365 tenants before you sign up.

Create app catalog site


You need an app catalog to upload and deploy web parts. If you've already set up an app catalog, see create a new developer site collection.

To create an app catalog site


1. Go to the SharePoint Admin Center by entering the following URL in your browser. Replace yourtenantprefix with your Office 365 tenant prefix.

https://yourtenantprefix-admin.sharepoint.com

2. In the left sidebar, select the apps menu item, and then select app catalog.
3. Select OK to create a new app catalog site.
4. On the next page, enter the following details:
Title: Enter app catalog.
Web Site Address suffix: Enter your preferred suffix for the app catalog; for example: apps.
Administrator: Enter your username, and then select the resolve button to resolve the username.
5. Select OK to create the app catalog site.
SharePoint creates the app catalog site, and you are able to see its progress in the SharePoint admin center.

Create a new developer site collection


You also need a site collection and a site for your testing. You can create a new site collection by using any of the available templates. You may choose to use developer site collection, but
that does not really add additional value because workbench and basic testing can be performed under any site.

To create a new developer site collection


1. Go to the SharePoint Admin Center by entering the following URL in your browser. Replace yourtenantprefix with your Office 365 tenant prefix.

https://yourtenantprefix-admin.sharepoint.com

2. On the SharePoint ribbon, select New > Private Site Collection.


3. In the dialog box, enter the following details:
Title: Enter a title for your developer site collection; for example: Developer Site.
Web Site Address suffix: Enter a suffix for your developer site collection; for example: dev.
Template Selection: Select Developer Site as the site collection template.
Administrator: Enter your username, and then select the resolve button to resolve the username.
4. Select OK to create the site collection.
SharePoint creates the developer site and you are able to see its progress in the SharePoint admin center. After the site is created, you can browse to your developer site collection.

SharePoint Workbench
SharePoint Workbench is a developer design surface that enables you to quickly preview and test web parts without deploying them in SharePoint. SharePoint Framework developer
toolchain contains a version of the Workbench that works locally and helps you quickly test and validate solutions that you are building. It is also hosted in your tenancy to preview and test
your local web parts in development. You can access the SharePoint Workbench from any SharePoint site in your tenancy by browsing to the following URL:

https://your-sharepoint-site/_layouts/workbench.aspx

Next steps
Now that you have configured your SharePoint tenant, set up your development environment to build client-side web parts.
Set up your Office 365 tenant
3/26/2018 • 2 minutes to read Edit Online

To build and deploy client-side web parts using the SharePoint Framework, you need an Office 365 tenant.
If you already have an Office 365 tenant, see the section Create app catalog site.
If you don't have one, you can get an Office 365 developer subscription when you join the Office 365 Developer Program. See the Office 365 Developer Program documentation for step-
by-step instructions about how to join the Office 365 Developer Program and sign up and configure your subscription.
NOTE

Make sure that you are signed out of any existing Office 365 tenants before you sign up.

Create app catalog site


You need an app catalog to upload and deploy web parts. If you've already set up an app catalog, see create a new developer site collection.

To create an app catalog site


1. Go to the SharePoint Admin Center by entering the following URL in your browser. Replace yourtenantprefix with your Office 365 tenant prefix.

https://yourtenantprefix-admin.sharepoint.com

2. In the left sidebar, select the apps menu item, and then select app catalog.
3. Select OK to create a new app catalog site.
4. On the next page, enter the following details:
Title: Enter app catalog.
Web Site Address suffix: Enter your preferred suffix for the app catalog; for example: apps.
Administrator: Enter your username, and then select the resolve button to resolve the username.
5. Select OK to create the app catalog site.
SharePoint creates the app catalog site, and you are able to see its progress in the SharePoint admin center.

Create a new developer site collection


You also need a site collection and a site for your testing. You can create a new site collection by using any of the available templates. You may choose to use developer site collection, but
that does not really add additional value because workbench and basic testing can be performed under any site.

To create a new developer site collection


1. Go to the SharePoint Admin Center by entering the following URL in your browser. Replace yourtenantprefix with your Office 365 tenant prefix.

https://yourtenantprefix-admin.sharepoint.com

2. On the SharePoint ribbon, select New > Private Site Collection.


3. In the dialog box, enter the following details:
Title: Enter a title for your developer site collection; for example: Developer Site.
Web Site Address suffix: Enter a suffix for your developer site collection; for example: dev.
Template Selection: Select Developer Site as the site collection template.
Administrator: Enter your username, and then select the resolve button to resolve the username.
4. Select OK to create the site collection.
SharePoint creates the developer site and you are able to see its progress in the SharePoint admin center. After the site is created, you can browse to your developer site collection.

SharePoint Workbench
SharePoint Workbench is a developer design surface that enables you to quickly preview and test web parts without deploying them in SharePoint. SharePoint Framework developer
toolchain contains a version of the Workbench that works locally and helps you quickly test and validate solutions that you are building. It is also hosted in your tenancy to preview and test
your local web parts in development. You can access the SharePoint Workbench from any SharePoint site in your tenancy by browsing to the following URL:

https://your-sharepoint-site/_layouts/workbench.aspx

Next steps
Now that you have configured your SharePoint tenant, set up your development environment to build client-side web parts.
Set up your SharePoint Framework development environment
6/18/2018 • 2 minutes to read Edit Online

You can use Visual Studio or your own custom development environment to build SharePoint Framework solutions. You can use a Mac, PC, or Linux.
NOTE

Before following the steps in this article, be sure to Set up your Office 365 tenant.
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/-tXf8gxjmOI

Install developer tools


Install NodeJS
Install NodeJS LTS version.
If you are in Windows, you can use the msi installers in this link for the easiest way to set up NodeJS.
If you have NodeJS already installed, check that you have the latest version by using node -v . It should return the current LTS version.
If you are using a Mac, we recommend that you use homebrew to install and manage NodeJS.
NOTE

Current LTS version of NodeJS is 8.11.3. Notice that 9.x versions are currently not supported with SharePoint Framework development.

Install a code editor


You can use any code editor or IDE that supports client-side development to build your web part, such as:
Visual Studio Code
Atom
Webstorm
The steps and examples in this documentation use Visual Studio Code, but you can use any editor of your choice.

If you are using Ubuntu


You need to install compiler tools by using the following command:

sudo apt-get install build-essential

If you are using fedora


You need to install compiler tools by using the following command:

sudo yum install make automake gcc gcc-c++ kernel-devel

Install Yeoman and gulp


Yeoman helps you kick-start new projects, and prescribes best practices and tools to help you stay productive. SharePoint client-side development tools include a Yeoman generator for
creating new web parts. The generator provides common build tools, common boilerplate code, and a common playground website to host web parts for testing.
Enter the following command to install Yeoman and gulp:

npm install -g yo gulp

Install Yeoman SharePoint generator


The Yeoman SharePoint web part generator helps you quickly create a SharePoint client-side solution project with the right toolchain and project structure.
To install the SharePoint Framework Yeoman generator globally, enter the following command:

npm install -g @microsoft/generator-sharepoint

If you need to switch between the different projects created by using different versions of the SharePoint Framework Yeoman generator, you can install the generator locally as a
development dependency in the project folder by executing the following command:

npm install @microsoft/generator-sharepoint --save-dev

For more information about the Yeoman SharePoint generator, see Scaffold projects by using Yeoman SharePoint generator.

Optional tools
Following are some tools that might come in handy as well:
Fiddler
Postman plug-in for Chrome
Cmder for Windows
Oh My Zsh for Mac
Git source control tools

Next steps
You are now ready to build your first client-side web part!
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at sp-dev-docs repository. Thanks for your input in
advance.
Overview of SharePoint client-side web parts
3/26/2018 • 2 minutes to read Edit Online

SharePoint client-side web parts are controls that appear inside a SharePoint page but run locally in the browser. They're the building blocks of pages that appear on a SharePoint site.
You can build client-side web parts using modern script development tools and the SharePoint workbench (a development test surface), and you can deploy your client-side web parts to
modern pages and classic web part pages in Office 365 tenants.
In addition to plain JavaScript projects, you can build web parts alongside common scripting frameworks, such as AngularJS and React. For example, you can use React along with
components from Office UI Fabric React to quickly create experiences based on the same components used in Office 365.
For more information, see the Getting started, Basics, and Concepts sections (in the TOC).

See also
Overview of the SharePoint Framework
SharePoint Framework development tools and libraries
Build your first SharePoint client-side web part (Hello World part 1)
6/18/2018 • 11 minutes to read Edit Online

Client-side web parts are client-side components that run inside the context of a SharePoint page. Client-side web parts can be deployed to SharePoint Online, and you can also use modern
JavaScript tools and libraries to build them.
Client-side web parts support:
Building with HTML and JavaScript.
Both SharePoint Online and on-premises environments.
NOTE

Before following the steps in this article, be sure to Set up your development environment.
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/YqUIX2pMUzg

Create a new web part project


To create a new web part project
1. Create a new project directory in your favorite location.

md helloworld-webpart

2. Go to the project directory.

cd helloworld-webpart

3. Create a new HelloWorld web part by running the Yeoman SharePoint Generator.

yo @microsoft/sharepoint

4. When prompted:
Accept the default helloworld-webpart as your solution name, and then select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder for where to place the files.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Accept the default HelloWorld as your web part name, and then select Enter.
Accept the default HelloWorld description as your web part description, and then select Enter.
Accept the default No javascript web framework as the framework you would like to use, and then select Enter.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld web part. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold.

For information about troubleshooting any errors, see Known issues.

Using your favorite Code Editor


Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your web part, such as:
Visual Studio Code
Atom
Webstorm
SharePoint Framework documentation uses Visual Studio code in the steps and examples. Visual Studio Code is a lightweight but powerful source code editor from Microsoft that runs on
your desktop and is available for Windows, Mac, and Linux. It comes with built-in support for JavaScript, TypeScript, and Node.js, and has a rich ecosystem of extensions for other languages
(such as C++, C#, Python, PHP) and runtimes.

Preview the web part


To preview your web part, build and run it on a local web server. The client-side toolchain uses HTTPS endpoint by default. However, because a default certificate is not configured for the
local dev environment, your browser reports a certificate error. The SPFx toolchain comes with a developer certificate that you can install for building web parts.

To install the developer certificate and preview your web part


1. Switch to your console, ensure that you are still in the helloworld-webpart directory, and then enter the following command:

gulp trust-dev-cert

2. Now that we have installed the developer certificate, enter the following command in the console to build and preview your web part:

gulp serve

This command executes a series of gulp tasks to create a local, node-based HTTPS server on localhost:4321 and launches your default browser to preview web parts from your local dev
environment.
SharePoint client-side development tools use gulp as the task runner to handle build process tasks such as:
Bundling and minifying JavaScript and CSS files.
Running tools to call the bundling and minification tasks before each build.
Compiling SASS files to CSS.
Compiling TypeScript files to JavaScript.
Visual Studio Code provides built-in support for gulp and other task runners. Select Ctrl+Shift+B on Windows or Cmd+Shift+B on Mac to debug and preview your web part.
SharePoint Workbench is a developer design surface that enables you to quickly preview and test web parts without deploying them in SharePoint. SharePoint Workbench includes the
client-side page and the client-side canvas in which you can add, delete, and test your web parts in development.

To use SharePoint Workbench to preview and test your web part


1. To add the HelloWorld web part, select the add icon (this icon appears when you mouse hovers over a section as shown in the previous image). This opens the toolbox where you can
see a list of web parts available for you to add. The list includes the HelloWorld web part as well other web parts available locally in your development environment.

2. Select HelloWorld to add the web part to the page.


Congratulations! You have just added your first client-side web part to a client-side page.
3. Select the pencil icon on the far left of the web part to reveal the web part property pane.

The property pane is where you can define properties to customize your web part. The property pane is client-side driven and provides a consistent design across SharePoint.
4. Modify the text in the Description text box to Client-side web parts are awesome!
Notice how the text in the web part also changes as you type.
One of the new capabilities available to the property pane is to configure its update behavior, which can be set to reactive or non-reactive. By default, the update behavior is reactive and
enables you to see the changes as you edit the properties. The changes are saved instantly when the behavior is reactive.

Web part project structure


To use Visual Studio Code to explore the web part project structure
1. In the console, break the processing by selecting Ctrl+C (in Windows).
2. Enter the following command to open the web part project in Visual Studio Code (or use your favorite editor):

code .

If you get an error, you might need to install the code command in PATH.
TypeScript is the primary language for building SharePoint client-side web parts. TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. SharePoint client-side
development tools are built using TypeScript classes, modules, and interfaces to help developers build robust client-side web parts.
The following are some key files in the project.

Web part class


HelloWorldWebPart.ts in the src\webparts\helloworld folder defines the main entry point for the web part. The web part class HelloWorldWebPart extends the
BaseClientSideWebPart. Any client-side web part should extend the BaseClientSideWebPart class to be defined as a valid web part.
BaseClientSideWebPart implements the minimal functionality that is required to build a web part. This class also provides many parameters to validate and access read-only properties
such as displayMode, web part properties, web part context, web part instanceId, the web part domElement, and much more.
Notice that the web part class is defined to accept a property type IHelloWorldWebPartProps.
The property type is defined as an interface before the HelloWorldWebPart class in the HelloWorldWebPart.ts file.

export interface IHelloWorldWebPartProps {


description: string;
}

This property definition is used to define custom property types for your web part, which is described in the property pane section later.
Web part render method
The DOM element where the web part should be rendered is available in the render method. This method is used to render the web part inside that DOM element. In the HelloWorld web
part, the DOM element is set to a DIV. The method parameters include the display mode (either Read or Edit) and the configured web part properties if any:

public render(): void {


this.domElement.innerHTML = `
<div class="${ styles.helloWorld }">
<div class="${ styles.container }">
<div class="${ styles.row }">
<div class="${ styles.column }">
<span class="${ styles.title }">Welcome to SharePoint!</span>
<p class="${ styles.subTitle }">Customize SharePoint experiences using web parts.</p>
<p class="${ styles.description }">${escape(this.properties.description)}</p>
<a href="https://aka.ms/spfx" class="${ styles.button }">
<span class="${ styles.label }">Learn more</span>
</a>
</div>
</div>
</div>
</div>`;
}

This model is flexible enough so that web parts can be built in any JavaScript framework and loaded into the DOM element.
Configure the Web part property pane
The property pane is defined in the HelloWorldWebPart class. The propertyPaneSettings property is where you need to define the property pane.
When the properties are defined, you can access them in your web part by using this.properties.<property-value> , as shown in the render method:

<p class="${styles.description}">${escape(this.properties.description)}</p>

Notice that we are performing an HTML escape on the property's value to ensure a valid string. To learn more about how to work with the property pane and property pane field types, see
Make your SharePoint client-side web part configurable.
Let's now add a few more properties to the property pane: a check box, a drop-down list, and a toggle. We first start by importing the respective property pane fields from the framework.
1. Scroll to the top of the file and add the following to the import section from @microsoft/sp-webpart-base :

PropertyPaneCheckbox,
PropertyPaneDropdown,
PropertyPaneToggle

The complete import section looks like the following:

import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
PropertyPaneCheckbox,
PropertyPaneDropdown,
PropertyPaneToggle
} from '@microsoft/sp-webpart-base';

2. Update the web part properties to include the new properties. This maps the fields to typed objects.
3. Replace the IHelloWorldWebPartProps interface with the following code.

export interface IHelloWorldWebPartProps {


description: string;
test: string;
test1: boolean;
test2: string;
test3: boolean;
}

4. Save the file.


5. Replace the getPropertyPaneConfiguration method with the following code, which adds the new property pane fields and maps them to their respective typed objects.
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: 'Description'
}),
PropertyPaneTextField('test', {
label: 'Multi-line Text Field',
multiline: true
}),
PropertyPaneCheckbox('test1', {
text: 'Checkbox'
}),
PropertyPaneDropdown('test2', {
label: 'Dropdown',
options: [
{ key: '1', text: 'One' },
{ key: '2', text: 'Two' },
{ key: '3', text: 'Three' },
{ key: '4', text: 'Four' }
]}),
PropertyPaneToggle('test3', {
label: 'Toggle',
onText: 'On',
offText: 'Off'
})
]
}
]
}
]
};
}

6. After you add your properties to the web part properties, you can now access the properties in the same way you accessed the description property earlier:

<p class="${ styles.description }">${escape(this.properties.test)}</p>

To set the default value for the properties, you need to update the web part manifest's properties property bag.
7. Open HelloWorldWebPart.manifest.json and modify the properties to:

"properties": {
"description": "HelloWorld",
"test": "Multi-line text field",
"test1": true,
"test2": "2",
"test3": true
}

The web part property pane now has these default values for those properties.

Web part manifest


The HelloWorldWebPart.manifest.json file defines the web part metadata such as version, id, display name, icon, and description. Every web part must contain this manifest.

{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "7d5437ee-afc2-4e66-914b-80be5ace4056",
"alias": "HelloWorldWebPart",
"componentType": "WebPart",

// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,

// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,

"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "HelloWorld" },
"description": { "default": "HelloWorld description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "HelloWorld",
"test": "Multi-line text field",
"test1": true,
"test2": "2",
"test3": true
}
}]
}

Now that we have introduced new properties, ensure that you are again hosting the web part from the local development environment by executing the following command. This also
ensures that the previous changes were correctly applied.

gulp serve

Preview the web part in SharePoint


SharePoint Workbench is also hosted in SharePoint to preview and test your local web parts in development. The key advantage is that now you are running in SharePoint context and you
are able to interact with SharePoint data.
1. Go to the following URL: https://your-sharepoint-tenant.sharepoint.com/_layouts/workbench.aspx

NOTE

If you do not have the SPFx developer certificate installed, Workbench notifies you that it is configured not to load scripts from localhost. Stop the currently running process in the
console window, and execute the gulp trust-dev-cert command in your project directory console to install the developer certificate before running the gulp serve command again.

2. Notice that the SharePoint Workbench now has the Office 365 Suite navigation bar.
3. Select the add icon in the canvas to reveal the toolbox. The toolbox now shows the web parts available on the site where the SharePoint Workbench is hosted along with your
HelloWorldWebPart.

4. Add HelloWorld from the toolbox. Now you're running your web part in a page hosted in SharePoint!

NOTE

The color of the web part depends on the colors of the site. By default, web parts inherit the core colors from the site by dynamically referencing Office UI Fabric Core styles used in the site
where the web part is hosted.
Because you are still developing and testing your web part, there is no need to package and deploy your web part to SharePoint.
Next steps
Congratulations on getting your first Hello World web part running!
Now that your web part is running, you can continue building out your Hello World web part in the next topic, Connect your web part to SharePoint. You will use the same Hello World web
part project and add the ability to interact with SharePoint List REST APIs. Notice that the gulp serve command is still running in your console window (or in Visual Studio Code if you are
using that as editor). You can continue to let it run while you go to the next article.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, please report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your
input in advance.
Build your first SharePoint client-side web part (Hello World part 1)
6/18/2018 • 11 minutes to read Edit Online

Client-side web parts are client-side components that run inside the context of a SharePoint page. Client-side web parts can be deployed to SharePoint Online, and you can also use modern
JavaScript tools and libraries to build them.
Client-side web parts support:
Building with HTML and JavaScript.
Both SharePoint Online and on-premises environments.
NOTE

Before following the steps in this article, be sure to Set up your development environment.
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/YqUIX2pMUzg

Create a new web part project


To create a new web part project
1. Create a new project directory in your favorite location.

md helloworld-webpart

2. Go to the project directory.

cd helloworld-webpart

3. Create a new HelloWorld web part by running the Yeoman SharePoint Generator.

yo @microsoft/sharepoint

4. When prompted:
Accept the default helloworld-webpart as your solution name, and then select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder for where to place the files.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Accept the default HelloWorld as your web part name, and then select Enter.
Accept the default HelloWorld description as your web part description, and then select Enter.
Accept the default No javascript web framework as the framework you would like to use, and then select Enter.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld web part. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold.

For information about troubleshooting any errors, see Known issues.

Using your favorite Code Editor


Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your web part, such as:
Visual Studio Code
Atom
Webstorm
SharePoint Framework documentation uses Visual Studio code in the steps and examples. Visual Studio Code is a lightweight but powerful source code editor from Microsoft that runs on
your desktop and is available for Windows, Mac, and Linux. It comes with built-in support for JavaScript, TypeScript, and Node.js, and has a rich ecosystem of extensions for other languages
(such as C++, C#, Python, PHP) and runtimes.

Preview the web part


To preview your web part, build and run it on a local web server. The client-side toolchain uses HTTPS endpoint by default. However, because a default certificate is not configured for the
local dev environment, your browser reports a certificate error. The SPFx toolchain comes with a developer certificate that you can install for building web parts.

To install the developer certificate and preview your web part


1. Switch to your console, ensure that you are still in the helloworld-webpart directory, and then enter the following command:

gulp trust-dev-cert

2. Now that we have installed the developer certificate, enter the following command in the console to build and preview your web part:

gulp serve

This command executes a series of gulp tasks to create a local, node-based HTTPS server on localhost:4321 and launches your default browser to preview web parts from your local dev
environment.
SharePoint client-side development tools use gulp as the task runner to handle build process tasks such as:
Bundling and minifying JavaScript and CSS files.
Running tools to call the bundling and minification tasks before each build.
Compiling SASS files to CSS.
Compiling TypeScript files to JavaScript.
Visual Studio Code provides built-in support for gulp and other task runners. Select Ctrl+Shift+B on Windows or Cmd+Shift+B on Mac to debug and preview your web part.
SharePoint Workbench is a developer design surface that enables you to quickly preview and test web parts without deploying them in SharePoint. SharePoint Workbench includes the
client-side page and the client-side canvas in which you can add, delete, and test your web parts in development.

To use SharePoint Workbench to preview and test your web part


1. To add the HelloWorld web part, select the add icon (this icon appears when you mouse hovers over a section as shown in the previous image). This opens the toolbox where you can
see a list of web parts available for you to add. The list includes the HelloWorld web part as well other web parts available locally in your development environment.

2. Select HelloWorld to add the web part to the page.


Congratulations! You have just added your first client-side web part to a client-side page.
3. Select the pencil icon on the far left of the web part to reveal the web part property pane.

The property pane is where you can define properties to customize your web part. The property pane is client-side driven and provides a consistent design across SharePoint.
4. Modify the text in the Description text box to Client-side web parts are awesome!
Notice how the text in the web part also changes as you type.
One of the new capabilities available to the property pane is to configure its update behavior, which can be set to reactive or non-reactive. By default, the update behavior is reactive and
enables you to see the changes as you edit the properties. The changes are saved instantly when the behavior is reactive.

Web part project structure


To use Visual Studio Code to explore the web part project structure
1. In the console, break the processing by selecting Ctrl+C (in Windows).
2. Enter the following command to open the web part project in Visual Studio Code (or use your favorite editor):

code .

If you get an error, you might need to install the code command in PATH.
TypeScript is the primary language for building SharePoint client-side web parts. TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. SharePoint client-side
development tools are built using TypeScript classes, modules, and interfaces to help developers build robust client-side web parts.
The following are some key files in the project.

Web part class


HelloWorldWebPart.ts in the src\webparts\helloworld folder defines the main entry point for the web part. The web part class HelloWorldWebPart extends the
BaseClientSideWebPart. Any client-side web part should extend the BaseClientSideWebPart class to be defined as a valid web part.
BaseClientSideWebPart implements the minimal functionality that is required to build a web part. This class also provides many parameters to validate and access read-only properties
such as displayMode, web part properties, web part context, web part instanceId, the web part domElement, and much more.
Notice that the web part class is defined to accept a property type IHelloWorldWebPartProps.
The property type is defined as an interface before the HelloWorldWebPart class in the HelloWorldWebPart.ts file.

export interface IHelloWorldWebPartProps {


description: string;
}

This property definition is used to define custom property types for your web part, which is described in the property pane section later.
Web part render method
The DOM element where the web part should be rendered is available in the render method. This method is used to render the web part inside that DOM element. In the HelloWorld web
part, the DOM element is set to a DIV. The method parameters include the display mode (either Read or Edit) and the configured web part properties if any:

public render(): void {


this.domElement.innerHTML = `
<div class="${ styles.helloWorld }">
<div class="${ styles.container }">
<div class="${ styles.row }">
<div class="${ styles.column }">
<span class="${ styles.title }">Welcome to SharePoint!</span>
<p class="${ styles.subTitle }">Customize SharePoint experiences using web parts.</p>
<p class="${ styles.description }">${escape(this.properties.description)}</p>
<a href="https://aka.ms/spfx" class="${ styles.button }">
<span class="${ styles.label }">Learn more</span>
</a>
</div>
</div>
</div>
</div>`;
}

This model is flexible enough so that web parts can be built in any JavaScript framework and loaded into the DOM element.
Configure the Web part property pane
The property pane is defined in the HelloWorldWebPart class. The propertyPaneSettings property is where you need to define the property pane.
When the properties are defined, you can access them in your web part by using this.properties.<property-value> , as shown in the render method:

<p class="${styles.description}">${escape(this.properties.description)}</p>

Notice that we are performing an HTML escape on the property's value to ensure a valid string. To learn more about how to work with the property pane and property pane field types, see
Make your SharePoint client-side web part configurable.
Let's now add a few more properties to the property pane: a check box, a drop-down list, and a toggle. We first start by importing the respective property pane fields from the framework.
1. Scroll to the top of the file and add the following to the import section from @microsoft/sp-webpart-base :

PropertyPaneCheckbox,
PropertyPaneDropdown,
PropertyPaneToggle

The complete import section looks like the following:

import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
PropertyPaneCheckbox,
PropertyPaneDropdown,
PropertyPaneToggle
} from '@microsoft/sp-webpart-base';

2. Update the web part properties to include the new properties. This maps the fields to typed objects.
3. Replace the IHelloWorldWebPartProps interface with the following code.

export interface IHelloWorldWebPartProps {


description: string;
test: string;
test1: boolean;
test2: string;
test3: boolean;
}

4. Save the file.


5. Replace the getPropertyPaneConfiguration method with the following code, which adds the new property pane fields and maps them to their respective typed objects.
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: 'Description'
}),
PropertyPaneTextField('test', {
label: 'Multi-line Text Field',
multiline: true
}),
PropertyPaneCheckbox('test1', {
text: 'Checkbox'
}),
PropertyPaneDropdown('test2', {
label: 'Dropdown',
options: [
{ key: '1', text: 'One' },
{ key: '2', text: 'Two' },
{ key: '3', text: 'Three' },
{ key: '4', text: 'Four' }
]}),
PropertyPaneToggle('test3', {
label: 'Toggle',
onText: 'On',
offText: 'Off'
})
]
}
]
}
]
};
}

6. After you add your properties to the web part properties, you can now access the properties in the same way you accessed the description property earlier:

<p class="${ styles.description }">${escape(this.properties.test)}</p>

To set the default value for the properties, you need to update the web part manifest's properties property bag.
7. Open HelloWorldWebPart.manifest.json and modify the properties to:

"properties": {
"description": "HelloWorld",
"test": "Multi-line text field",
"test1": true,
"test2": "2",
"test3": true
}

The web part property pane now has these default values for those properties.

Web part manifest


The HelloWorldWebPart.manifest.json file defines the web part metadata such as version, id, display name, icon, and description. Every web part must contain this manifest.

{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "7d5437ee-afc2-4e66-914b-80be5ace4056",
"alias": "HelloWorldWebPart",
"componentType": "WebPart",

// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,

// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,

"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "HelloWorld" },
"description": { "default": "HelloWorld description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "HelloWorld",
"test": "Multi-line text field",
"test1": true,
"test2": "2",
"test3": true
}
}]
}

Now that we have introduced new properties, ensure that you are again hosting the web part from the local development environment by executing the following command. This also
ensures that the previous changes were correctly applied.

gulp serve

Preview the web part in SharePoint


SharePoint Workbench is also hosted in SharePoint to preview and test your local web parts in development. The key advantage is that now you are running in SharePoint context and you
are able to interact with SharePoint data.
1. Go to the following URL: https://your-sharepoint-tenant.sharepoint.com/_layouts/workbench.aspx

NOTE

If you do not have the SPFx developer certificate installed, Workbench notifies you that it is configured not to load scripts from localhost. Stop the currently running process in the
console window, and execute the gulp trust-dev-cert command in your project directory console to install the developer certificate before running the gulp serve command again.

2. Notice that the SharePoint Workbench now has the Office 365 Suite navigation bar.
3. Select the add icon in the canvas to reveal the toolbox. The toolbox now shows the web parts available on the site where the SharePoint Workbench is hosted along with your
HelloWorldWebPart.

4. Add HelloWorld from the toolbox. Now you're running your web part in a page hosted in SharePoint!

NOTE

The color of the web part depends on the colors of the site. By default, web parts inherit the core colors from the site by dynamically referencing Office UI Fabric Core styles used in the site
where the web part is hosted.
Because you are still developing and testing your web part, there is no need to package and deploy your web part to SharePoint.
Next steps
Congratulations on getting your first Hello World web part running!
Now that your web part is running, you can continue building out your Hello World web part in the next topic, Connect your web part to SharePoint. You will use the same Hello World web
part project and add the ability to interact with SharePoint List REST APIs. Notice that the gulp serve command is still running in your console window (or in Visual Studio Code if you are
using that as editor). You can continue to let it run while you go to the next article.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, please report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your
input in advance.
Connect your client-side web part to SharePoint (Hello World part 2)
5/3/2018 • 9 minutes to read Edit Online

Connect your web part to SharePoint to access functionality and data in SharePoint and provide a more integrated experience for end users. This article continues building the Hello World
web part built in the previous article Build your first web part.
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/hYrP6D4FaaU

Run gulp serve


Ensure that you have the gulp serve command running. If it is not already running, go to the helloworld-webpart project directory and run it by using the following commands.

cd helloworld-webpart
gulp serve

Get access to page context


When the Workbench is hosted locally, you do not have the SharePoint page context. You can still test your web part in many different ways. For example, you can concentrate on building
the web part's UX and use mock data to simulate SharePoint interaction when you don't have the SharePoint context.
However, when the Workbench is hosted in SharePoint, you get access to the page context, which provides various key properties such as:
Web title
Web absolute URL
Web server-relative URL
User sign-in name

To get access to the page context


1. Use the following variable in your web part class:

this.context.pageContext

2. Switch to Visual Studio code (or your preferred IDE) and open src\webparts\helloWorld\HelloWorldWebPart.ts.
3. Inside the render method, replace the innerHTML code block with the following code:
this.domElement.innerHTML = `
<div class="${ styles.helloWorld }">
<div class="${ styles.container }">
<div class="${ styles.row }">
<div class="${ styles.column }">
<span class="${ styles.title }">Welcome to SharePoint!</span>
<p class="${ styles.subTitle }">Customize SharePoint experiences using web parts.</p>
<p class="${ styles.description }">${escape(this.properties.description)}</p>
<p class="${ styles.description }">${escape(this.properties.test)}</p>
<p class="${ styles.description }">Loading from ${escape(this.context.pageContext.web.title)}</p>
<a href="https://aka.ms/spfx" class="${ styles.button }">
<span class="${ styles.label }">Learn more</span>
</a>
</div>
</div>
</div>
</div>`;

4. Notice how ${ } is used to output the variable's value in the HTML block. An extra HTML p is used to display this.context.pageContext.web.title . Because this web part loads
from the local environment, the title is Local Workbench.
5. Save the file. The gulp serve running in your console detects this save operation and:
Builds and bundles the updated code automatically.
Refreshes your local Workbench page (as the web part code needs to be reloaded).
NOTE

Keep the console window and Visual Studio Code side-by-side to see gulp automatically compile as you save changes in Visual Studio Code.
6. In your browser, switch to the local SharePoint Workbench tab. If you have already closed the tab, the URL is https://localhost:4321/temp/workbench.html .
You should see the following in the web part:

7. Navigate to the SharePoint Workbench hosted in SharePoint. The full URL is https://your-sharepoint-site-url/_layouts/workbench.aspx . Notice that on the SharePoint Online side,
you need to refresh the page to see the changes.
NOTE

If you do not have the SPFx developer certificate installed, Workbench notifies you that it is configured not to load scripts from localhost. Execute gulp trust-dev-cert command in
your project directory console to install the developer certificate.
You should now see your SharePoint site title in the web part now that page context is available to the web part.
Define list model
You need a list model to start working with SharePoint list data. To retrieve the lists, you need two models.
1. Switch to Visual Studio Code and go to src\webparts\helloWorld\HelloWorldWebPart.ts.
2. Define the following interface models just above the HelloWorldWebPart class:

export interface ISPLists {


value: ISPList[];
}

export interface ISPList {


Title: string;
Id: string;
}

The ISPList interface holds the SharePoint list information that we are connecting to.

Retrieve lists from mock store


To test in the local Workbench, you need a mock store that returns mock data.

To create a mock store


1. Create a new file inside the src\webparts\helloWorld folder named MockHttpClient.ts.
2. Copy the following code into MockHttpClient.ts:

import { ISPList } from './HelloWorldWebPart';

export default class MockHttpClient {

private static _items: ISPList[] = [{ Title: 'Mock List', Id: '1' },


{ Title: 'Mock List 2', Id: '2' },
{ Title: 'Mock List 3', Id: '3' }];

public static get(): Promise<ISPList[]> {


return new Promise<ISPList[]>((resolve) => {
resolve(MockHttpClient._items);
});
}
}

Things to note about the code:


Because there are multiple exports in HelloWorldWebPart.ts, the specific one to import is specified by using { } . In this case, only the data model ISPList is required.
You do not need to type the file extension when importing from the default module, which in this case is HelloWorldWebPart.
It exports the MockHttpClient class as a default module so that it can be imported in other files.
It builds the initial ISPList mock array and returns.
3. Save the file.
You can now use the MockHttpClient class in the HelloWorldWebPart class. You first need to import the MockHttpClient module.

To import the MockHttpClient module


1. Open the HelloWorldWebPart.ts file.
2. Copy and paste the following code just under import * as strings from 'HelloWorldWebPartStrings'; .

import MockHttpClient from './MockHttpClient';

3. Add the following private method that mocks the list retrieval inside the HelloWorldWebPart class.
private _getMockListData(): Promise<ISPLists> {
return MockHttpClient.get()
.then((data: ISPList[]) => {
var listData: ISPLists = { value: data };
return listData;
}) as Promise<ISPLists>;
}

4. Save the file.

Retrieve lists from SharePoint site


Next you need to retrieve lists from the current site. You will use SharePoint REST APIs to retrieve the lists from the site, which are located at
https://yourtenantprefix.sharepoint.com/_api/web/lists .

SharePoint Framework includes a helper class spHttpClient to execute REST API requests against SharePoint. It adds default headers, manages the digest needed for writes, and collects
telemetry that helps the service to monitor the performance of an application.

To use this helper class, import them from the @microsoft/sp-http module
1. Scroll to the top of the HelloWorldWebPart.ts file.
2. Copy and paste the following code just under import MockHttpClient from './MockHttpClient'; :

import {
SPHttpClient,
SPHttpClientResponse
} from '@microsoft/sp-http';

3. Add the following private method to retrieve lists from SharePoint inside the HelloWorldWebPart class.

private _getListData(): Promise<ISPLists> {


return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + `/_api/web/lists?$filter=Hidden eq false`, SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
return response.json();
});
}

The method uses the spHttpClient helper class and issues a get request. It uses the ISPLists model and also applies a filter to not retrieve hidden lists.
4. Save the file.
5. Switch to the console window that is running gulp serve and check if there are any errors. If there are errors, gulp reports them in the console, and you need to fix them before
proceeding.

Add new styles


The SharePoint Framework uses Sass as the CSS pre-processor, and specifically uses the SCSS syntax, which is fully compliant with normal CSS syntax. Sass extends the CSS language and
allows you to use features such as variables, nested rules, and inline imports to organize and create efficient style sheets for your web parts. The SharePoint Framework already comes with a
SCSS compiler that converts your Sass files to normal CSS files, and also provides a typed version to use during development.

To add new styles


1. Open HelloWorld.module.scss. This is the SCSS file where you define your styles.
By default, the styles are scoped to your web part. You can see that as the styles are defined under .helloWorld.
2. Add the following styles after the .button style, but still inside the main .helloWorld style section:

.list {
color: #333333;
font-family: 'Segoe UI Regular WestEuropean', 'Segoe UI', Tahoma, Arial, sans-serif;
font-size: 14px;
font-weight: normal;
box-sizing: border-box;
margin: 10;
padding: 10;
line-height: 50px;
list-style-type: none;
box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}

.listItem {
color: #333333;
vertical-align: center;
font-family: 'Segoe UI Regular WestEuropean', 'Segoe UI', Tahoma, Arial, sans-serif;
font-size: 14px;
font-weight: normal;
box-sizing: border-box;
margin: 0;
padding: 0;
box-shadow: none;
*zoom: 1;
padding: 9px 28px 3px;
position: relative;
}

3. Save the file.


Gulp rebuilds the code in the console as soon as you save the file. This generates the corresponding typings in the HelloWorld.module.scss.ts file. After compiled to TypeScript, you
can then import and reference these styles in your web part code.
You can see that in the render method of the web part:
<div class="${styles.row}">

Render lists information


Open the HelloWorldWebPart class.
SharePoint Workbench gives you the flexibility to test web parts in your local environment and from a SharePoint site. SharePoint Framework aids this capability by helping you understand
which environment your web part is running from by using the EnvironmentType module.

To use the EnvironmentType module


1. Import the Environment and the EnvironmentType modules from the @microsoft/sp-core-library bundle. Add it to the import section at the top as shown in the following code:

import {
Environment,
EnvironmentType
} from '@microsoft/sp-core-library';

2. Add the following private method inside the HelloWorldWebPart class to call the respective methods to retrieve list data:

private _renderListAsync(): void {


// Local environment
if (Environment.type === EnvironmentType.Local) {
this._getMockListData().then((response) => {
this._renderList(response.value);
});
}
else if (Environment.type == EnvironmentType.SharePoint ||
Environment.type == EnvironmentType.ClassicSharePoint) {
this._getListData()
.then((response) => {
this._renderList(response.value);
});
}
}

Things to note about hostType in the _renderListAsync method:


The Environment.type property helps you check if you are in a local or SharePoint environment.
The correct method is called depending on where your Workbench is hosted.
3. Save the file.
Now you need to render the list data with the value fetched from the REST API.
4. Add the following private method inside the HelloWorldWebPart class:

private _renderList(items: ISPList[]): void {


let html: string = '';
items.forEach((item: ISPList) => {
html += `
<ul class="${styles.list}">
<li class="${styles.listItem}">
<span class="ms-font-l">${item.Title}</span>
</li>
</ul>`;
});

const listContainer: Element = this.domElement.querySelector('#spListContainer');


listContainer.innerHTML = html;
}

The previous method references the new CSS styles added earlier by using the styles variable.
5. Save the file.

Retrieve list data


1. Navigate to the render method, and replace the code inside the method with the following code:

this.domElement.innerHTML = `
<div class="${ styles.helloWorld }">
<div class="${ styles.container }">
<div class="${ styles.row }">
<div class="${ styles.column }">
<span class="${ styles.title }">Welcome to SharePoint!</span>
<p class="${ styles.subTitle }">Customize SharePoint experiences using web parts.</p>
<p class="${ styles.description }">${escape(this.properties.description)}</p>
<p class="${ styles.description }">${escape(this.properties.test)}</p>
<p class="${ styles.description }">Loading from ${escape(this.context.pageContext.web.title)}</p>
<a href="https://aka.ms/spfx" class="${ styles.button }">
<span class="${ styles.label }">Learn more</span>
</a>
</div>
</div>
<div id="spListContainer" />
</div>
</div>`;

this._renderListAsync();

2. Save the file.


Notice in the gulp serve console window that it rebuilds the code. Make sure you don't see any errors.
3. Switch to your local Workbench and add the HelloWorld web part.
You should see the mock data returned.

4. Switch to the Workbench hosted in SharePoint. Refresh the page and add the HelloWorld web part.
You should see lists returned from the current site.

5. Now you can stop the server from running. Switch to the console and stop gulp serve . Select Ctrl+C to terminate the gulp task.

Next steps
Congratulations on connecting your web part to SharePoint list data!
You can continue building out your Hello World web part in the next topic Deploy your web part to a SharePoint page. You will learn how to deploy and preview the Hello World web part in
a SharePoint page.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Deploy your client-side web part to a SharePoint page (Hello World part 3)
5/3/2018 • 4 minutes to read Edit Online

Ensure that you have completed the procedures in the following articles before you start:
Build your first SharePoint client-side web part
Connect your client-side web part to SharePoint
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/BpJ01ahxbiY

Package the HelloWorld web part


1. In the console window, go to the web part project directory created in Build your first SharePoint client-side web part.

cd helloworld-webpart

2. If gulp serve is still running, stop it from running by selecting Ctrl+C.


Unlike in the Workbench, to use client-side web parts on modern SharePoint server-side pages, you need to deploy and register the web part with SharePoint. First you need to
package the web part.
3. Open the HelloWorldWebPart web part project in Visual Studio Code, or your preferred IDE.
4. Open package-solution.json from the config folder.
The package-solution.json file defines the package metadata as shown in the following code:

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "helloworld-webpart-client-side-solution",
"id": "4432f33b-5845-4ca0-827e-a8ae68c7b945",
"version": "1.0.0.0",
"includeClientSideAssets": true
},
"paths": {
"zippedPackage": "solution/helloworld-webpart.sppkg"
}
}

5. In the console window, enter the following command to package your client-side solution that contains the web part:

gulp package-solution

The command creates the package in the sharepoint/solution folder:

helloworld-webpart.sppkg
Package contents
The package uses SharePoint Feature to package your web part. By default, the gulp task creates a feature for your web part.
You can view the raw package contents in the sharepoint/debug folder.
The contents are then packaged into an .sppkg file. The package format is very similar to a SharePoint Add-ins package and uses Microsoft Open Packaging Conventions to package your
solution.
The JavaScript files, CSS, and other assets are packaged inside of the package when the --ship option is used. In this case, however, we will first test deployment and capabilities by hosting
JavaScript files from localhost. This deployment option is explained in the next tutorial.
NOTE

Starting from the SharePoint Framework v1.4, static assets are by default packaged inside of the sppkg package. When a package is deployed in the app catalog, the assets are automatically
hosted either from Office 365 CDN (if enabled) or from an app catalog URL. You can control this behavior with the includeClientSideAssets setting in the package-solution.json file.

Deploy the HelloWorld package to app catalog


Next, you need to deploy the package that was generated to the app catalog.
NOTE

If you do not have an app catalog, a SharePoint Online Admin can create one by following the instructions in this guide: Use the App Catalog to make custom business apps available for
your SharePoint Online environment.
1. Go to your site's app catalog.
2. Upload or drag and drop the helloworld-webpart.sppkg to the app catalog.

This deploys the client-side solution package. Because this is a full trust client-side solution, SharePoint displays a dialog and asks you to trust the client-side solution to deploy.

3. Select Deploy.

Install the client-side solution on your site


1. Go to your developer site collection.
2. Select the gears icon on the top nav bar on the right, and then select Add an app to go to your Apps page.
3. In the Search box, enter helloworld, and select Enter to filter your apps.
4. Select the helloworld-webpart-client-side-solution app to install the app on the site.

The client-side solution and the web part are installed on your developer site.
The Site Contents page shows you the installation status of your client-side solution. Make sure the installation is complete before going to the next step.

Preview the web part on a SharePoint page


Now that you have deployed and installed the client-side solution, add the web part to a SharePoint page. Remember that resources such as JavaScript and CSS are available from the local
computer.
1. Open the <your-webpart-guid>.manifest.json from the \dist folder.
Notice that the internalModuleBaseUrls property in the loaderConfig entry still refers to your local computer:

"internalModuleBaseUrls": [
"https://`your-local-machine-name`:4321/"
]

2. Before adding the web part to a SharePoint server-side page, run the local server.
3. In the console window that has the helloworld-webpart project directory, run the gulp task to start serving from localhost:

gulp serve --nobrowser

NOTE

--nobrowser will not automatically launch the SharePoint Workbench.

Add the HelloWorld web part to modern page


1. In your browser, go to your site where the solution was just installed.
2. Select the gears icon in the top nav bar on the right, and then select Add a page.
3. Edit the page.
4. Open the web part picker and select your HelloWorld web part.
The web part assets are loaded from the local environment. To load the scripts hosted on your local computer, you need to enable the browser to load unsafe scripts. Depending on the
browser you are using, make sure you enable loading unsafe scripts for this session.
You should see the HelloWorld web part you built in the previous article that retrieves lists from the current site.

Edit web part properties


1. Select the Configure element icon (pen) in the web part to open the property pane for the web part.

This is the same property pane you built and previewed in the Workbench.
2. Edit the Description property, and enter Client-side web parts are awesome!
3. Notice that you still have the same behaviors such as a reactive pane where the web part is updated as you type.
4. Select the x icon to close the client-side property pane.
5. On the toolbar, select Save and close to save the page.

Next steps
Congratulations! You have deployed a client-side web part to a modern SharePoint page.
You can continue building out your Hello World web part in the next topic Hosting client-side web part from Office 365 CDN, where you will learn how to deploy and load the web part
assets from an Office 365 CDN instead of localhost.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Host your client-side web part from Office 365 CDN (Hello World part 4)
4/20/2018 • 6 minutes to read Edit Online

Office 365 Content Delivery Network (CDN) provides you an easy solution to host your assets directly from your own Office 365 tenant. It can be used for hosting any static assets that are
used in SharePoint Online.
NOTE

There are multiple different hosting options for your web part assets. This tutorial concentrates on showing the Office 365 CDN option, but you could also use the Azure CDN or simply host
your assets from SharePoint library from your tenant. In the latter case, you would not benefit from the CDN performance improvements, but that would also work from the functionality
perspective. Any location that end users can access using HTTP(S) would be technically suitable for hosting the assets for end users.
IM P O R T A N T

This article uses the includeClientSideAssets attribute, which was introduced in the SPFx v1.4. This version is not supported with SharePoint 2016 Feature Pack 2. If you are using an on-
premises setup, you need to decide the CDN hosting location separately. You can also simply host the JavaScript files from a centralized library in your on-premises SharePoint to which
your users have access. Please see additional considerations in the SharePoint 2016 specific guidance.
Make sure that you have completed the following tasks before you begin:
Build your first client-side web part
Connect your client-side web part to SharePoint
Deploy your client-side web part to a SharePoint page
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/MEZMs8VMVQ0

Enable CDN in your Office 365 tenant


1. Ensure that you have the latest version of the SharePoint Online Management Shell by downloading it from the Microsoft Download site.
 T IP

If you are using a non-Windows machine, you cannot use the SharePoint Online Management Shell. You can, however, manage these settings by using Office 365 CLI.
2. Connect to your SharePoint Online tenant with a PowerShell session.

Connect-SPOService -Url https://contoso-admin.sharepoint.com

3. Get the current status of public CDN settings from the tenant level by executing the following commands one-by-one.

Get-SPOTenantCdnEnabled -CdnType Public


Get-SPOTenantCdnOrigins -CdnType Public
Get-SPOTenantCdnPolicies -CdnType Public

SharePoint Framework solutions can automatically benefit from the Office 365 Public CDN as long as it's enabled in your tenant. When CDN is enabled, */CLIENTSIDEASSETS origin is
automatically added as a valid origin.
1. Enable public CDN in the tenant.

Set-SPOTenantCdnEnabled -CdnType Public


2. Confirm settings by selecting Y and then Enter.

Now public CDN has been enabled in the tenant by using the default file type configuration allowed. This means that the following file type extensions are supported: CSS, EOT, GIF,
ICO, JPEG, JPG, JS, MAP, PNG, SVG, TTF, and WOFF.
SharePoint Framework solutions can automatically benefit from the Office 365 Public CDN as long as it's enabled in your tenant. When CDN is enabled, the */CLIENTSIDEASSETS
origin is automatically added as a valid origin.
NOTE

If you have previously enabled Office 365 CDN, you should re-enable the public CDN so that you have the */CLIENTSIDEASSETS entry added as a valid CDN origin for public CDN. If
this entry is not present and the public CDN is enabled in your tenant, bundle requests will contain the token hostname spclientsideassetlibrary in their URL, causing the requests to
fail.
3. You can double-check the current setup of your end-points. Execute the following command to get the list of CDN origins from your tenant:

Get-SPOTenantCdnOrigins -CdnType Public

Notice that your newly added origin is listed as a valid CDN origin. Final configuration of the origin takes a while (approximately 15 minutes), so we can continue by creating your test
web part, which will be hosted from the origin when the deployment is completed.

NOTE

When the origin is listed without the (configuration pending) text, it is ready to be used in your tenant. This is the indication of an on-going configuration between SharePoint Online
and the CDN system.

End task in project directory


1. Switch to the console and make sure you are still in the project directory that you used to set up your web part project.
2. End the possible gulp serve task by selecting Ctrl+C, and ensure that you are in your project directory:

cd helloworld-webpart

Review solution settings


1. Open the HelloWorldWebPart web part project in Visual Studio Code or your preferred IDE.
2. Open package-solution.json from the config folder.
The package-solution.json file defines the package metadata as shown in the following code:

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "helloworld-webpart-client-side-solution",
"id": "4432f33b-5845-4ca0-827e-a8ae68c7b945",
"version": "1.0.0.0",
"includeClientSideAssets": true
},
"paths": {
"zippedPackage": "solution/helloworld-webpart.sppkg"
}
}

The default value for the includeClientSideAssets is true , which means that static assets are packaged automatically inside of the .sppkg files, and you do not need to separately host your
assets from an external system.
If Office 365 CDN is enabled, it is used automatically with default settings. If Office 365 CDN is not enabled, assets are served from the app catalog site collection.
NOTE

Starting from the SharePoint Framework v1.4, static assets are by default packaged inside of the sppkg package. When a package is deployed in the app catalog, they are automatically
hosted either from Office 365 CDN (if enabled) or from an app catalog URL. You can control this behavior with the includeClientSideAssets setting in the package-solution.json file.

Prepare web part assets to deploy


1. Execute the following task to bundle your solution. This executes a release build of your project by using a dynamic label as the host URL for your assets. This URL is automatically
updated based on your tenant CDN settings.

gulp bundle --ship

2. Execute the following task to package your solution. This creates an updated helloworld-webpart.sppkg package on the sharepoint/solution folder.

gulp package-solution --ship

NOTE

If you are interested in what actually got packaged inside of the sppkg file, you can look in the content of the sharepoint/solution/debug folder.
3. Upload or drag and drop the newly created client-side solution package to the app catalog in your tenant.
4. Because you already deployed the package, you are prompted as to whether to replace the existing package. Select Replace It.

5. Notice how the domain list in the prompt says SharePoint Online. This is because the content is either served from the Office 365 CDN or from the app catalog, depending on the
tenant settings. Select Deploy.

6. Open the site where you previously installed the helloworld-webpart-client-side-solution or install the solution to a new site.
7. After the solution has been installed, select Add a page from the gear menu, and select HelloWorld from the modern page web part picker to add your custom web part to page.

8. Notice how the web part is rendered even though you are not running the node.js service locally.
9. Save changes on the page with the web part.
10. Select F12 to open up developer tools.
11. Extend publiccdn.sharepointonline.com under the source and notice how the hello-world-web-part file is loaded from the Public CDN URL pointing dynamically to a library
located under the app catalog site collection.

NOTE

If you would not have CDN enabled in your tenant, and the includeClientSideAssets setting would be true in the package-solution.json, the loading URL for the assets would be
dynamically updated and pointing directly to the ClientSideAssets folder located in the app catalog site collection. In this example case, the URL would be
https://sppnp.microsoft.com/sites/apps/ClientSideAssets/ .

Now you have deployed your custom web part to SharePoint Online and it's being hosted automatically from the Office 365 CDN.

Next steps
You can load jQuery and jQuery UI and build a jQuery Accordion web part. To continue, see Add jQueryUI Accordion to your client-side web part.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Add jQueryUI Accordion to your SharePoint client-side web part
4/20/2018 • 7 minutes to read Edit Online

Adding the jQueryUI Accordion to your web part project involves creating a new web part, as shown in the following image.

Ensure that you've completed the following steps before you start:
Build your first web part
Connect your web part to SharePoint
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/7UOxTbMMPrQ

The developer toolchain uses Webpack, SystemJS, and CommonJS to bundle your web parts. This includes loading any external dependencies such as jQuery or jQueryUI. To load external
dependencies, at a high level, you need to:
Acquire the external library, either via npm or download from the vendor.
If available, install the respective framework's TypeScript type definitions.
If required, update your solution config to not include the external dependency in your web part bundle by default.

Create a new web part project


1. Create a new project directory in your favorite location:
md jquery-webpart

W A R N IN G

Make sure to create this directory in a new folder, not as a subdirectory of helloworld-webpart .
2. Go to the project directory:

cd jquery-webpart

3. Create a new jQuery web part by running the Yeoman SharePoint Generator:

yo @microsoft/sharepoint

4. When prompted:
Accept the default jquery-webpart as your solution name. and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder for where to place the files.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Enter jQuery for the web part name, and select Enter.
Enter jQuery Web Part as the description of the web part, and select Enter.
Accept the default No JavaScript framework option for the framework, and select Enter to continue.
At this point, Yeoman installs the required dependencies and scaffolds the solution files. This might take a few minutes. Yeoman scaffolds the project to include your jQueryWebPart
as well.
6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

7. Enter the following to open the web part project in Visual Studio Code:

code .

Install jQuery and jQuery UI NPM Packages


1. In the console, enter the following to install the jQuery npm package:

npm install --save jquery@2

2. Now enter the following to install the jQueryUI npm package:

npm install --save jqueryui

Next, we need to install the typings for our project. Starting from TypeScript 2.0, we can use npm to install needed typings.
3. Open your console and install the needed types:

npm install --save @types/jquery@2


npm install --save @types/jqueryui

To unbundle external dependencies from web part bundle


By default, any dependencies you add are bundled into the web part bundle. In some cases, this is not ideal. You can choose to unbundle these dependencies from the web part bundle.
1. In Visual Studio Code, open the file config\config.json.
This file contains information about your bundle(s) and any external dependencies.
The bundles region contains the default bundle information; in this case, the jQuery web part bundle. When you add more web parts to your solution, you see one entry per web
part.

"bundles": {
"j-query-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/jQuery/JQueryWebPart.js",
"manifest": "./src/webparts/jQuery/JQueryWebPart.manifest.json"
}
]
}
},

2. The externals section contains the libraries that are not bundled with the default bundle.

"externals": {},

3. To exclude jQuery and jQueryUI from the default bundle, add the modules to the externals section:
"jquery":"node_modules/jquery/dist/jquery.min.js",
"jqueryui":"node_modules/jqueryui/jquery-ui.min.js"

Now when you build your project, jQuery and jQueryUI are not bundled into your default web part bundle.
The full content of the config.json file is currently as follows:

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"j-query-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/jQuery/JQueryWebPart.js",
"manifest": "./src/webparts/jQuery/JQueryWebPart.manifest.json"
}
]
}
},
"externals": {
"jquery":"node_modules/jquery/dist/jquery.min.js",
"jqueryui":"node_modules/jqueryui/jquery-ui.min.js"
},
"localizedResources": {
"JQueryWebPartStrings": "lib/webparts/jQuery/loc/{locale}.js"
}
}

Build the Accordion


Open the project folder jquery-webpart in Visual Studio Code. Your project should have the jQuery web part that you added earlier under the /src/webparts/jQuery folder.

To add the Accordion HTML


1. Add a new file in the src/webparts/jQuery folder called MyAccordionTemplate.ts.
2. Create and export (as a module) a class MyAccordionTemplate that holds the HTML code for the accordion.

export default class MyAccordionTemplate {


public static templateHtml: string = `
<div class="accordion">
<h3>Section 1</h3>
<div>
<p>
Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer
ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit
amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut
odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.
</p>
</div>
<h3>Section 2</h3>
<div>
<p>
Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet
purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor
velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In
suscipit faucibus urna.
</p>
</div>
<h3>Section 3</h3>
<div>
<p>
Nam enim risus, molestie et, porta ac, aliquam ac, risus. Quisque lobortis.
Phasellus pellentesque purus in massa. Aenean in pede. Phasellus ac libero
ac tellus pellentesque semper. Sed ac felis. Sed commodo, magna quis
lacinia ornare, quam ante aliquam nisi, eu iaculis leo purus venenatis dui.
</p>
<ul>
<li>List item one</li>
<li>List item two</li>
<li>List item three</li>
</ul>
</div>
<h3>Section 4</h3>
<div>
<p>
Cras dictum. Pellentesque habitant morbi tristique senectus et netus
et malesuada fames ac turpis egestas. Vestibulum ante ipsum primis in
faucibus orci luctus et ultrices posuere cubilia Curae; Aenean lacinia
mauris vel est.
</p>
<p>
Suspendisse eu nisl. Nullam ut libero. Integer dignissim consequat lectus.
Class aptent taciti sociosqu ad litora torquent per conubia nostra, per
inceptos himenaeos.
</p>
</div>
</div>`;
}

3. Save the file.

To import the Accordion HTML


1. In Visual Studio Code, open src\webparts\jQuery\JQueryWebPart.ts.
2. At the top of the file, where you can find other imports, add the following import:
import MyAccordionTemplate from './MyAccordionTemplate';

To import jQuery and jQueryUI


1. You can import jQuery to your web part in the same way that you imported MyAccordionTemplate. At the top of the file, where you can find other imports, add the following imports:

import * as jQuery from 'jquery';


import 'jqueryui';

2. Load some external CSS files by using the module loader. Add the following import:

import { SPComponentLoader } from '@microsoft/sp-loader';

3. Load the jQueryUI styles in the JQueryWebPart web part class by adding a constructor and using the newly imported SPComponentLoader. Add the following constructor to your web
part:

public constructor() {
super();

SPComponentLoader.loadCss('//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css');
}

This code does the following:


Calls the parent constructor with the context to initialize the web part.
Loads the accordion styles from a CDN asynchronously.

To render Accordion
1. In the jQueryWebPart.ts , go to the render method.
2. Set the web part's inner HTML to render the accordion HTML:

this.domElement.innerHTML = MyAccordionTemplate.templateHtml;

3. jQueryUI Accordion has a few options that you can set to customize the accordion. Define a few options for your accordion just under
this.domElement.innerHTML = MyAccordionTemplate.templateHtml; :

const accordionOptions: JQueryUI.AccordionOptions = {


animate: true,
collapsible: false,
icons: {
header: 'ui-icon-circle-arrow-e',
activeHeader: 'ui-icon-circle-arrow-s'
}
};

As you can see, the jQueryUI typed definition allows you to create a typed variable called JQueryUI.AccordionOptions and specify the supported properties.
If you play around with the IntelliSense, you notice that you get full support for available methods under JQueryUI. as well as the method parameters.
4. Finally, initialize the accordion:

jQuery('.accordion', this.domElement).accordion(accordionOptions);

As you can see, you use the variable jQuery that you used to import the jquery module. You then initialize the accordion.
The complete render method looks like this:

public render(): void {


this.domElement.innerHTML = MyAccordionTemplate.templateHtml;

const accordionOptions: JQueryUI.AccordionOptions = {


animate: true,
collapsible: false,
icons: {
header: 'ui-icon-circle-arrow-e',
activeHeader: 'ui-icon-circle-arrow-s'
}
};

jQuery('.accordion', this.domElement).accordion(accordionOptions);
}

5. Save the file.

Preview the web part


1. In your console, ensure that you are still in the jquery-webpart folder, and enter the following to build and preview your web part:

gulp serve

NOTE

Visual Studio Code provides built-in support for gulp and other task runners. You can select Ctrl+Shift+B in Windows or Cmd+Shift+B on a Mac to debug and preview your web
part.
Gulp executes the tasks and opens the local SharePoint web part Workbench.
2. In the page canvas, select the + (plus sign) to show the list of web parts, and add the jQuery web part. You should now see the jQueryUI Accordion!

3. In the console where you have gulp serve running, select Ctrl+C to terminate the task.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Use Office UI Fabric React components in your SharePoint client-side web part
5/3/2018 • 5 minutes to read Edit Online

This article describes how to build a simple web part that uses the DocumentCard component of Office UI Fabric React. Office UI Fabric React is the front-end framework for building
experiences for Office and Office 365. Fabric React includes a robust collection of responsive, mobile-first components that make it easy for you to create web experiences by using the Office
Design Language.
The following image shows a DocumentCard component created with Office UI Fabric React.

You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/1YRu4-nZot4

Create a new web part project


1. Create a new project directory in your favorite location:

md documentcardexample-webpart

2. Go to the project directory:

cd documentcardexample-webpart

3. Make sure you have the latest version of @microsoft/generator-sharepoint installed and create a new web part by running the Yeoman SharePoint generator:
yo @microsoft/sharepoint

4. When prompted:
Accept the default documentcardexample-webpart as your solution name, and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder for where to place the files.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Use DocumentCardExample for your web part name, and select Enter.
Accept the default DocumentCardExample description, and select Enter.
Select React as the framework, and select Enter.
At this point, Yeoman installs the required dependencies and scaffolds the solution files. This might take a few minutes. Yeoman scaffolds the project to include your
DocumentCardExample web part as well.
6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

7. Next, enter the following to open the web part project in Visual Studio Code:

code .

You now have a web part project with the React framework.
8. Open DocumentCardExampleWebPart.ts from the src\webparts\documentCardExample folder.
As you can see, the render method creates a react element and renders it in the web part DOM.

public render(): void {


const element: React.ReactElement<IDocumentCardExampleProps > = React.createElement(
DocumentCardExample,
{
description: this.properties.description
}
);

9. Open DocumentCardExample.tsx from the src\webparts\documentCardExample\components folder.


This is the main react component that Yeoman added to your project that renders in the web part DOM.

export default class DocumentCardExample extends React.Component<IDocumentCardExampleProps, {}> {


public render(): React.ReactElement<IDocumentCardExampleProps> {
return (
<div className={ styles.documentCardExample }>
<div className={ styles.container }>
<div className={ styles.row }>
<div className={ styles.column }>
<span className={ styles.title }>Welcome to SharePoint!</span>
<p className={ styles.subTitle }>Customize SharePoint experiences using web parts.</p>
<p className={ styles.description }>{escape(this.props.description)}</p>
<a href="https://aka.ms/spfx" className={ styles.button }>
<span className={ styles.label }>Learn more</span>
</a>
</div>
</div>
</div>
</div>
);
}
}

Add an Office UI Fabric component


The new modern experiences in SharePoint use Office UI Fabric and Office UI Fabric React as the default front-end framework for building the new experiences. As a result, SharePoint
Framework ships with a default version of Office UI Fabric and Fabric React that matches the version available in SharePoint. This ensures that the web part you are building uses the right
version of the Fabric styles and components when deployed to SharePoint.
Because we chose React as our framework when creating the solution, the generator installed the right version of Office UI Fabric React as well. You can directly import the Fabric
components in your react components without any additional work.
NOTE

With the current release of the SharePoint Framework, we recommend that you use the Office UI Fabric and Fabric React that ships with the generator. We don't recommend that you update
the Office UI Fabric and Fabric React packages independently because that might conflict with the already available version in SharePoint, and as a result, your web part may fail to function
as expected.

To add an Office UI Fabric component


1. Open DocumentCardExample.tsx from the src\webparts\documentCardExample\components folder.
2. Add the following import statement to the top of the file to import Fabric React components that we want to use.
import {
DocumentCard,
DocumentCardPreview,
DocumentCardTitle,
DocumentCardActivity,
IDocumentCardPreviewProps
} from 'office-ui-fabric-react/lib/DocumentCard';

3. Delete the current render method, and add the following updated render method:

public render(): JSX.Element {


const previewProps: IDocumentCardPreviewProps = {
previewImages: [
{
previewImageSrc: String(require('./document-preview.png')),
iconSrc: String(require('./icon-ppt.png')),
width: 318,
height: 196,
accentColor: '#ce4b1f'
}
],
};

return (
<DocumentCard onClickHref='http://bing.com'>
<DocumentCardPreview { ...previewProps } />
<DocumentCardTitle title='Revenue stream proposal fiscal year 2016 version02.pptx' />
<DocumentCardActivity
activity='Created Feb 23, 2016'
people={
[
{ name: 'Kat Larrson', profileImageSrc: String(require('./avatar-kat.png')) }
]
}
/>
</DocumentCard>
);
}

4. Save the file.


In this code, the DocumentCard component includes some extra sections:
DocumentCardPreview
DocumentCardTitle
DocumentCardActivity
The previewProps property includes some properties of the DocumentCardPreview.
5. Notice the use of the relative path with a require statement to load images. Currently, you need to perform a small configuration in the gulpfile.js to enable these images to get
processed properly by webpack.
6. Open gulpfile.js from the root folder.
7. Add the following code just above the build.initialize(gulp); code line.

build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
if (build.getConfig().production) {
var basePath = build.writeManifests.taskConfig.cdnBasePath;
if (!basePath.endsWith('/')) {
basePath += '/';
}
generatedConfiguration.output.publicPath = basePath;
}
else {
generatedConfiguration.output.publicPath = "/dist/";
}
return generatedConfiguration;
}
});

8. Save the file.


Your full gulpfile.js file should look as follows.
'use strict';

const gulp = require('gulp');


const build = require('@microsoft/sp-build-web');
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);

build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
if (build.getConfig().production) {
var basePath = build.writeManifests.taskConfig.cdnBasePath;
if (!basePath.endsWith('/')) {
basePath += '/';
}
generatedConfiguration.output.publicPath = basePath;
}
else {
generatedConfiguration.output.publicPath = "/dist/";
}
return generatedConfiguration;
}
});

build.initialize(gulp);

Copy the image assets


Copy the following images to your src\webparts\documentCardExample\components folder:
avatar-kat.png
icon-ppt.png
document-preview.png

Preview the web part in Workbench


1. In the console, enter the following to preview your web part in Workbench:

gulp serve

2. In the toolbox, select your DocumentCardExample web part to add:

NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.

See also
Build your first SharePoint client-side web part
Provision SharePoint assets from your SharePoint client-side web part
7/9/2018 • 12 minutes to read Edit Online

SharePoint assets can be provisioned as part of the SharePoint Framework solution, and are deployed to SharePoint sites when the solution is installed on it.
Before you start, complete the procedures in the following articles to ensure that you understand the basic flow of creating a custom client-side web part:
Build your first web part
Connect your web part to SharePoint
You can also follow these steps by watching this video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/qAqNk_X82QM

Create a new web part project


1. Create a new project directory in your favorite location:

md asset-deployment-webpart

2. Go to the project directory:

cd asset-deployment-webpart

3. Create a new client-side web part solution by running the Yeoman SharePoint Generator:

yo @microsoft/sharepoint

4. When prompted:
Accept the default asset-deployment-webpart as your solution name, and then select Enter.
Select SharePoint Online only (latest), and then select Enter.
Select Use the current folder as the location for the files.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Enter AssetDeployment for the web part name, and then select Enter.
Enter AssetDeployment Web Part as the description of the web part, and then select Enter.
Accept the default No JavaScipt web framework option for the framework, and then select Enter to continue.
At this point, Yeoman installs the required dependencies and scaffolds the solution files. This might take a few minutes. Yeoman scaffolds the project to include your
AssetDeployment web part as well.
6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

7. Next, enter the following to open the web part project in Visual Studio Code:

code .

Create folder structure for your SharePoint assets


We first need to create an assets folder where we place all feature framework assets used to provision SharePoint structures when a package is installed.
1. Create a folder called sharepoint to the root of the solution.
2. Create a folder called assets as a sub-folder for the just created sharepoint folder.
Your solution structure should look like the following picture:

Create feature framework files for initial deployment


To be able to provision SharePoint assets to sites with feature framework elements, we need to create needed XML files to the asset folder. Supported elements for the SharePoint
Framework solution packages are following:
Fields / site columns
Content types
List instances
List instances with custom schema
In the following steps, we define the needed structure to be provisioned.

To add an element.xml file for SharePoint definitions


1. Create a new file inside the sharepoint\assets folder named elements.xml.
2. Copy the following XML structure into elements.xml.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<Field ID="{060E50AC-E9C1-4D3C-B1F9-DE0BCAC300F6}"
Name="SPFxAmount"
DisplayName="Amount"
Type="Currency"
Decimals="2"
Min="0"
Required="FALSE"
Group="SPFx Columns" />

<Field ID="{943E7530-5E2B-4C02-8259-CCD93A9ECB18}"
Name="SPFxCostCenter"
DisplayName="Cost Center"
Type="Choice"
Required="FALSE"
Group="SPFx Columns">
<CHOICES>
<CHOICE>Administration</CHOICE>
<CHOICE>Information</CHOICE>
<CHOICE>Facilities</CHOICE>
<CHOICE>Operations</CHOICE>
<CHOICE>Sales</CHOICE>
<CHOICE>Marketing</CHOICE>
</CHOICES>
</Field>

<ContentType ID="0x010042D0C1C200A14B6887742B6344675C8B"
Name="Cost Center"
Group="SPFx Content Types"
Description="Sample content types from web part solution">
<FieldRefs>
<FieldRef ID="{060E50AC-E9C1-4D3C-B1F9-DE0BCAC300F6}" />
<FieldRef ID="{943E7530-5E2B-4C02-8259-CCD93A9ECB18}" />
</FieldRefs>
</ContentType>

<ListInstance
CustomSchema="schema.xml"
FeatureId="00bfea71-de22-43b2-a848-c05709900100"
Title="SPFx List"
Description="SPFx List"
TemplateType="100"
Url="Lists/SPFxList">
</ListInstance>

</Elements>

Note the following about the pasted XML structure:


We are provisioning two fields to the site, a content type and a list instance with custom schema.
Definitions use standard Feature Framework schema, which is well known to SharePoint developers.
Custom fields are being referenced in the introduced content type.
We use the CustomSchema attribute in the ListInstance element to define a provisioning time schema.xml file for the list. This way the list is still based on the out-of-the-box list
template (normal custom list '100' in this case), but we can define an alternative provisioning definition during initial provisioning.
When provisioning list instances using Features you must provide the ID of the Feature associated with the particular list definition. Using the FeatureId attribute you are supposed
to provide the ID of the Feature which contains the List Definition. As an example: if you’re provisioning an instance of a custom list the FeatureId attribute should be set to
{00bfea71-de22-43b2-a848-c05709900100}.
More details about the used schema structures can be found at Using Features in SharePoint Foundation on MSDN.

To add a schema.xml file for defining list structure


In the previous step, we referenced the schema.xml file in the CustomSchema attribute of the ListInstance element, so we need to include that in our package.
1. Create a new file inside the sharepoint\assets folder named schema.xml.
2. Copy the following XML structure into schema.xml.
<List xmlns:ows="Microsoft SharePoint" Title="Basic List" EnableContentTypes="TRUE" FolderCreation="FALSE" Direction="$Resources:Direction;" Url="Lists/Basic List" BaseType="0" xmlns="http://
<MetaData>
<ContentTypes>
<ContentTypeRef ID="0x010042D0C1C200A14B6887742B6344675C8B" />
</ContentTypes>
<Fields></Fields>
<Views>
<View BaseViewID="1" Type="HTML" WebPartZoneID="Main" DisplayName="$Resources:core,objectiv_schema_mwsidcamlidC24;" DefaultView="TRUE" MobileView="TRUE" MobileDefaultView="TRUE" SetupPat
<XslLink Default="TRUE">main.xsl</XslLink>
<JSLink>clienttemplates.js</JSLink>
<RowLimit Paged="TRUE">30</RowLimit>
<Toolbar Type="Standard" />
<ViewFields>
<FieldRef Name="LinkTitle"></FieldRef>
<FieldRef Name="SPFxAmount"></FieldRef>
<FieldRef Name="SPFxCostCenter"></FieldRef>
</ViewFields>
<Query>
<OrderBy>
<FieldRef Name="ID" />
</OrderBy>
</Query>
</View>
</Views>
<Forms>
<Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
</Forms>
</MetaData>
</List>

Note the following about the included XML structure:


The custom content type deployed by using the elements.xml file is referenced in the ContentTypeRef element.
Custom fields called SPFxAmount and SPFxCostCenter are referenced in the FieldRef element.
More details about the used schema structures can be found at Understanding Schema.xml Files article at MSDN.

Ensure that definitions are taken into use in build pipeline


Now we have created the needed structures for provisioning SharePoint assets automatically from the solution when it's deployed. The next step is to ensure that we package these XML files
as part of the solution file.
1. Open package-solution.json from the config folder.
The package-solution.json file defines the package metadata as shown in the following code:

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "asset-deployment-webpart-client-side-solution",
"id": "6690f11b-012f-4268-bc33-3086eb2dd287",
"version": "1.0.0.0",
"includeClientSideAssets": true
},
"paths": {
"zippedPackage": "solution/asset-deployment-webpart.sppkg"
}
}

2. To ensure that our newly added Feature Framework files are taken into account while the solution is being packaged, we need to include a Feature Framework feature definition for
the solution package. Let's include a JSON definition for the needed feature inside of the solution structure as demonstrated in the following code.

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "asset-deployment-webpart-client-side-solution",
"id": "6690f11b-012f-4268-bc33-3086eb2dd287",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"features": [{
"title": "asset-deployment-webpart-client-side-solution",
"description": "asset-deployment-webpart-client-side-solution",
"id": "523fe887-ced5-4036-b564-8dad5c6c6e24", // <-- Update 'id' with a new GUID
"version": "1.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
],
"elementFiles":[
"schema.xml"
]
}
}]
},
"paths": {
"zippedPackage": "solution/asset-deployment-webpart.sppkg"
}
}

Note the following about the added json definitions:


Make sure you define a unique GUID for the id property inside the feature section
You can technically have multiple features in the package because features is a collection; however, this is not recommended.
elements.xml is referenced under elementManifests so that it's packaged properly for the actual feature XML structure as an element manifest file.
You can have multiple element.xml files in the definition, and they would be executed in the order they are mentioned in the JSON definition. Typically, you should avoid using multiple
element.xml files because this adds unnecessary complexity. You can define all needed assets in a single element.xml file.

Deploy and test asset provisioning


Now you are ready to deploy the solution to SharePoint. Because we are provisioning assets directly to the SharePoint sites when the solution is installed, you cannot test the capability in a
local or online Workbench.
1. In the console window, enter the following command to package your client-side solution that contains the web part so that we get the basic structure ready for packaging:

gulp bundle

2. Execute the following command to create the solution package:

gulp package-solution

The command creates the package in the sharepoint/solution folder:

asset-deployment-webpart.sppkg

3. Before testing the package in SharePoint, let's quickly have a look on the default structures created for the package around the defined feature framework elements. Move back to the
Visual Studio Code side and expand the sharepoint/solution/debug folder, which contains the raw XML structures to be included in the actual sppkg package.

4. Deploy the package that was generated to the app catalog. Go to your tenant's app catalog.
5. Upload or drag and drop the asset-deployment-webpart.sppkg located in the sharepoint/solution folder to the app catalog. SharePoint displays a dialog and asks you to trust the
client-side solution to deploy.

NOTE

SharePoint validates the published package when it's deployed and you only see the trust dialog if the package is valid for deployment. You can also see the status around this
validation from the 'Valid App Package' column in the app catalog.
6. Go to the site where you want to test the SharePoint asset provisioning. This could be any site collection in the tenant where you deployed this solution package.
7. Select the gears icon on the top nav bar on the right, and then select Add an app to go to your Apps page.
8. In the Search box, enter deployment, and then select Enter to filter your apps.
9. Select the asset-deployment-webpart-client-side-solution app to install the app on the site. When installation is completed, refresh the page by selecting F5. Notice how the
custom SPFx List has been provisioned to site as part of the solution package deployment.

10. Select SPFx List to move to the list. Notice how the custom fields Amount and Cost Center are visible automatically in the default view of the list.

Define upgrade actions for new version


Whenever you build a new version of your SharePoint Framework solution, you might have some required changes on the provisioned SharePoint assets. You can take advantage of the
Feature Framework upgrade action support when a new version of the package is being deployed.
SharePoint Framework solutions do support the following Feature Framework upgrade action definitions:
ApplyElementManifest
AddContentTypeField
 T IP

You can read more details around the Feature Framework upgrade action definitions at SharePoint Add-ins update process.

To add a new element.xml file for the new version


1. Go back to your solution in Visual Studio Code.
2. Create a new file inside the sharepoint\assets folder named elements-v2.xml.
3. Copy the following XML structure into elements-v2.xml, which defines a new SharePoint list to be provisioned with a title of New List.

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<ListInstance
FeatureId="00bfea71-de22-43b2-a848-c05709900100"
Title="New List"
Description="New list provisioned from v2"
TemplateType="100"
Url="Lists/NewList">
</ListInstance>

</Elements>

4. We also need a definition for actual Feature Framework upgrade actions, so create a new file inside the sharepoint\assets folder named upgrade-actions-v2.xml.
5. Copy the following XML structure into upgrade-actions-v2.xml. Notice that the feature GUID reference in the path refers to the automatically created folder under the
sharepoint/solution/debug folder and has to be updated based on your solution. This GUID also matches the GUID of the feature, which we defined in the package-solution.json
file.

<ApplyElementManifests>
<ElementManifest Location="523fe887-ced5-4036-b564-8dad5c6c6e24\elements-v2.xml" />
</ApplyElementManifests>

To deploy the new version to SharePoint


Next we need to update both the solution version and the feature version responsible for the asset provisioning.
IM P O R T A N T

The solution version indicates for SharePoint that there's a new version of the SharePoint Framework solution available. The feature version ensures that the upgrade actions are executed
accordingly when the solution package is upgraded in the existing site(s).
1. Open package-solution.json from the config folder and update the version values for both the solution and the feature to "2.0.0.0".
2. We also need to include elements-v2.xml under the elementManifest section, and need to include the upgradeActions element with a pointer to the just created upgrade-actions-
v2.xml file.
Here's a complete package-solution.json file with needed changes. Notice that identifiers for your solution could be slightly different, so concentrate on adding only the missing
pieces.

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "asset-deployment-webpart-client-side-solution",
"id": "6690f11b-012f-4268-bc33-3086eb2dd287",
"version": "2.0.0.0",
"includeClientSideAssets": true,
"features": [{
"title": "asset-deployment-webpart-client-side-solution",
"description": "asset-deployment-webpart-client-side-solution",
"id": "523fe887-ced5-4036-b564-8dad5c6c6e24",
"version": "2.0.0.0",
"assets": {
"elementManifests": [
"elements.xml",
"elements-v2.xml"
],
"elementFiles":[
"schema.xml"
],
"upgradeActions":[
"upgrade-actions-v2.xml"
]
}
}]
},
"paths": {
"zippedPackage": "solution/asset-deployment-webpart.sppkg"
}
}

IM P O R T A N T

Notice that we also included the elements-v2.xml under the elementManifest section. This ensures that when you install this package to a clean site as a version 2.0, the end result
will match the upgraded packages.
3. In the console window, enter the following command to re-package your client-side solution that contains the web part so that we get the basic structure ready for packaging:

gulp bundle

4. Execute the following command to create the solution package:

gulp package-solution

The command creates a new version of the solution package in the sharepoint/solution folder. Notice that you can easily confirm from the sharepoint/solution/debug folder that the
updated XML files are included in the solution package.
5. Next you need to deploy the new version that was generated to the app catalog. Go to your tenant's app catalog.
6. Upload or drag and drop the asset-deployment-webpart.sppkg located in the sharepoint/solution folder to the app catalog. SharePoint requests that you confirm overriding the
existing version.

7. Select Replace It to update the latest version to the app catalog.


8. Select Deploy to trust the latest version.
Notice that the App Version column for the asset-deployment-webpart-client-side-solution is now updated to be "2.0.0.0".

To update an existing instance in the site


Now that the package has been updated in the app catalog, we can move to the actual SharePoint content site and perform the upgrade for the existing instance.
1. Go to the site where you deployed the first version of the SharePoint Framework solution.
2. Go to the Site Contents page.
3. Select Details from the context menu of the asset-deployment-webpart-client-side-solution solution.

This presents the current details around the installed SharePoint Framework solution. This page also now shows the text as 'There is a new version of this app. Get it now' to indicate
that there's a new version available.

4. Select the GET IT button to start the update process for the package.

If you move to the classic experience, you can see more details on the actual upgrade action being applied for the SharePoint Framework solution.

NOTE

Because the SharePoint Framework uses the same app infrastructure as SharePoint Add-ins, the status for the upgrade indicates that the update can happen for an add-in or an app.
The update can take a while, but when the solution status changes to normal again, you can select F5 to refresh the site contents page to confirm that a new list called New List has
been successfully provisioned as part of the update process.
Now we have successfully upgraded this instance to the latest version. This Feature Framework option for SharePoint asset provisioning is pretty much the same as it is for the
SharePoint Add-in model. The key difference is that the assets are being provisioned directly to a normal SharePoint site, because there's no concept called app or add-in web with
SharePoint Framework solutions.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.

See also
Provision SharePoint assets with your solution package
Sample solution - Deployment of SharePoint assets as part of SPFx package
Deploy your SharePoint client-side web part to Azure CDN
3/26/2018 • 7 minutes to read Edit Online

Create a new sample web part and deploy its assets to an Azure Content Delivery Network (CDN) instead of using the default Office 365 CDN as the hosting solution. You'll use an Azure
Storage account integrated with a CDN to deploy your assets. SharePoint Framework build tools provide out-of-the-box support for deploying to an Azure Storage account; however, you
can also manually upload the files to your favorite CDN provider or to SharePoint.
NOTE

There are multiple different hosting options for your web part assets. This tutorial concentrates on showing the Azure CDN option, but you could also use the Office 365 CDN or simply host
your assets from SharePoint library from your tenant. In the latter case, you would not benefit from the CDN performance improvements, but that would also work from the functionality
perspective. Any location that end users can access by using HTTP would be technically suitable for hosting the assets for end users.

Configure an Azure storage account


To configure an Azure storage account and integrate it with the CDN, follow the instructions at Integrate an Azure storage account with Azure CDN, along with the detailed steps in this
article.

Storage account name


This is the name you used to create your storage account, as described in Step 1: Create a storage account.
For example, in the following screenshot, spfxsamples is the storage account name.

This creates a new storage account endpoint spfxsamples.blob.core.windows.net.


NOTE

You need to create a unique storage account name for your own SharePoint Framework projects.

BLOB container name


Create a new Blob service container. This is available in your storage account dashboard.
Select the + Container and create a new container with the following:
Name: azurehosted-webpart
Access type: Container
Storage account access key
In the storage account dashboard, select Access Key in the dashboard, and copy one of the access keys.

CDN profile and endpoint


Create a new CDN profile and associate the CDN endpoint with this BLOB container.
1. Create a new CDN profile as described in Step 2: Enable CDN for the storage account (scroll down in Step 2 for To create a new CDN profile).
For example, in the following screenshot, spfxwebparts is the CDN profile name.
2. Create a CDN endpoint as described in Step 2: Enable CDN for the storage account. The CDN endpoint is created with the following URL: http://spfxsamples.azureedge.net

For example, in the following screenshot, spfxsamples is the endpoint name, Storage is the origin type, and spfxsamples.blob.core.windows.net is the storage account.

Because you associated the CDN endpoint with your storage account, you can also access the BLOB container at the following URL: http://spfxsamples.azureedge.net/azurehosted-webpart/

Note, however, that you have not yet deployed the files.

Create a new web part project


1. Create a new project directory in your preferred location:

md azurehosted-webpart

2. Go to the project directory:

cd azurehosted-webpart

3. Create a new SharePoint Framework solution by running Yeoman SharePoint Generator:

yo @microsoft/sharepoint

4. When prompted:
Accept the default azurehosted-webpart as your solution name, and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder for where to place the files.
Select y to use the tenant-scoped deployment option, which makes the web part available across sites immediately when it's deployed.
Select WebPart as the client-side component type to be created.
5. The next set of prompts ask for specific information about your web part:
Use AzureCDN for your web part name, and select Enter.
Accept the default AzureCDN description as your web part description, and select Enter.
Accept the default No javascript web framework as the framework you would like to use, and select Enter.

At this point, Yeoman scaffolds the solution files and installs the required dependencies. This might take a few minutes. Yeoman scaffolds the project to include your custom web part
as well.
6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

7. Enter the following to open the web part project in Visual Studio Code:

code .

Configure the solution not to use default settings


1. Open package-solution.json in the config folder.
This is where we control the solution packaging.
2. Update includeClientSideAssets value as false so that client-side assets are NOT packaged inside of the sppkg file, which is the default behavior. Because we are hosting assets from
an external CDN, we do not want them to be included in the solution package. Your configuration should look somewhat like the following.

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "azurehosted-webpart-client-side-solution",
"id": "a4e95ed1-d096-4573-8a57-d0cc3b52da6a",
"version": "1.0.0.0",
"includeClientSideAssets": false,
"skipFeatureDeployment": true
},
"paths": {
"zippedPackage": "solution/azurehosted-webpart.sppkg"
}
}

NOTE

The skipFeatureDeployment setting is here true because the answer for the tenant-scope deployment option was said to be 'y' in the Yeoman flow. This means that you do NOT need
to explicitly install the solution to the site before the web part is available. Deploying and approving the solution package in the tenant app catalog is sufficient to make the web part
available across all the sites in the given tenant.

Configure Azure Storage account details


1. Open deploy-azure-storage.json in the config folder.
This is the file that contains your Azure Storage account details.
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./temp/deploy/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "azurehosted-webpart",
"accessKey": "<!-- ACCESS KEY -->"
}

2. Replace the account, container, accessKey with your storage account name, BLOB container, and storage account access key respectively.
workingDir is the directory where the web part assets are located.
In this example, with the storage account created earlier, this file will look like:

{
"workingDir": "./temp/deploy/",
"account": "spfxsamples",
"container": "azurehosted-webpart",
"accessKey": "q1UsGWocj+CnlLuv9ZpriOCj46ikgBbDBCaQ0FfE8+qKVbDTVSbRGj41avlG73rynbvKizZpIKK9XpnpA=="
}

3. Save the file.

Configure the web part to load from CDN


For the web part to load from your CDN, you need to tell it your CDN path.
1. Switch to Visual Studio Code and open the write-manifests.json from the config folder.
2. Enter your CDN base path for the cdnBasePath property.

{
"cdnBasePath": "<!-- PATH TO CDN -->"
}

In this example, with the CDN profile created earlier, this file will look like:

{
"cdnBasePath": "https://spfxsamples.azureedge.net/azurehosted-webpart/"
}

NOTE

The CDN base path is the CDN endpoint with the BLOB container.
3. Save the file.

Prepare the web part assets to deploy


Before uploading the assets to CDN, you need to build them.
1. Switch to the console and execute the following gulp task:

gulp bundle --ship

This builds the minified assets required to upload to the CDN provider. The --ship indicates the build tool to build for distribution. You should also notice that the output of the build
tools indicate the Build Target is SHIP.

Build target: SHIP


[21:23:01] Using gulpfile ~/apps/azurehosted-webpart/gulpfile.js
[21:23:01] Starting gulp
[21:23:01] Starting 'default'...

The minified assets can be found under the temp\deploy directory.

Deploy assets to Azure Storage


1. Switch to the console of the azurehosted-webpart project directory.
2. Enter the gulp task to deploy the assets to your storage account:

gulp deploy-azure-storage

This deploys the web part bundle along with other assets such as JavaScript and CSS files to the CDN.

Deploy the updated package


To package the solution
Because you changed the web part bundle, you need to redeploy the package to the app catalog. You used --ship to generate minified assets for distribution.
1. Switch to the console of the azurehosted-webpart project directory.
2. Enter the gulp task to package the client-side solution, this time with the --ship flag set. This forces the task to pick up the CDN base path configured in the previous step:

gulp package-solution --ship

This creates the updated client-side solution package in the sharepoint\solution folder.
To upload to your app catalog
1. Upload or drag and drop the client-side solution package to the app catalog. Notice how the URL is pointing to the Azure CDN URL configured in the previous steps.
2. Select the check box to indicate that the solution can be deployed automatically across all sites in the organization.

3. Select Deploy.
The app catalog now has the client-side solution package where the web part bundle is loaded from the CDN.

Test the HelloWorld web part


1. Go to any SharePoint site in your tenant and select Add a page from the gears menu.
2. Edit the page and select AzureCDN web part from the web part picker to confirm that your deployment has been successful.

3. Notice that you are not running gulp serve, and therefore nothing is served from localhost. Content is served from the Azure CDN. You can also double-check this by selecting F12
in your browser and confirming that you can see the Azure CDN as one of the sources for the page assets.

Deploy to other CDNs


To deploy the assets to your favorite CDN provider, you can copy the files from temp\deploy folder. To generate assets for distribution, run the following gulp command as we did before
with the --ship parameter:

gulp bundle --ship

As long as you are updating the cdnBasePath accordingly, your files are being properly loaded.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.

See also
Build your first SharePoint client-side web part
Integrate web part properties with SharePoint
3/26/2018 • 4 minutes to read Edit Online

When building classic web parts, web part properties were isolated from SharePoint, and their values were managed by end-users. SharePoint Framework offers you a new set of
capabilities that simplify managing web part properties' values and integrate them with SharePoint Search. This article explains how you can use these capabilities when building SharePoint
Framework client-side web parts.
IM P O R T A N T

The following guide applies only to SharePoint Framework client-side web parts placed on modern SharePoint pages. Capabilities described in this article don't apply to classic web parts or
SharePoint Framework client-side web parts placed on classic pages.

Client-side web part properties


When building SharePoint Framework client-side web parts, you can define properties that can be configured by users. By using properties instead of fixed values, web parts are more
flexible and suitable for many different scenarios.
Compared to classic web parts, there are some differences in how the SharePoint Framework handles web part properties. The following schema illustrates how web part property values
flow through the different layers of SharePoint.

Before accepting values for web part properties from end users, you should always validate them. This not only allows you to ensure that your web parts are user-friendly, but also helps you
prevent storing invalid data in the web part's configuration.
Additionally, you should consider that the SharePoint Framework doesn't support personalization, and all users see the same configuration of the particular web part.

Specify web part property value type


In classic SharePoint web parts, web part property values were isolated from SharePoint. If you had a web part property with a URL of a file stored in SharePoint, you had to manually
ensure that this URL was valid and pointing to a correct document in case it was moved or renamed. Also, if you allowed users to enter some text to be displayed in the web part, that text
wouldn't be indexed by SharePoint Search.
When building web parts, SharePoint Framework allows you to specify what kind of value the particular web part property holds. This configuration determines how SharePoint handles the
value. Depending on the specified configuration, SharePoint can include the value of the particular property in the Search index, remove unsafe HTML, and even keep links to documents
stored in SharePoint up to date in case a file gets moved or renamed.
To specify the configuration for your web part properties, in the web part class, override the propertiesMetadata getter:

import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
IWebPartPropertiesMetadata
} from '@microsoft/sp-webpart-base';

// ...

export default class ArticleLinkWebPart extends BaseClientSideWebPart<IArticleLinkWebPartProps> {


// ...
protected get propertiesMetadata(): IWebPartPropertiesMetadata {
return {
'title': { isSearchablePlainText: true },
'intro': { isHtmlString: true },
'image': { isImageSource: true },
'url': { isLink: true }
};
}
// ...
}

The propertiesMetadata method returns an object, where the property is a string and specifies the name of the web part property, and the value is an object specifying how SharePoint
should handle that particular property.
When overriding the propertiesMetadata method, you don't have to list all the web part properties. By default, web part properties' values are not processed by SharePoint, and you
should include only those properties that you want to be processed.
Following is the list of possible values that can be set in the properties metadata and their impact on how the value of the web part property is processed by SharePoint.

ME TAD ATA V ALU E S E AR CHAB LE LINK FIX U P R EMO V E U NS AFE HTML

none (default) no no no

isSearchablePlainText yes no no

isHtmlString yes yes yes

isImageSource yes yes no

isLink yes yes no

IM P O R T A N T

When defining the configuration for your web part properties, you should use only one of the properties mentioned in the table for each web part property. Setting multiple properties will
most likely lead to undesirable results, and you should avoid it.
By default the value of a web part property is not indexed by SharePoint Search and it's not processed by SharePoint in any way. It's passed to the web part exactly how it's been entered by
the user configuring the web part.
If you specify the web part property as isSearchablePlainText , it is included in the full-text Search index. Whenever users search for any keywords included in the value of that property,
SharePoint Search returns the page with the web part in the search results. If the value contains a link to a document stored in SharePoint, that link won't be updated if the referenced
document is moved or renamed. Also, any HTML entered by users, is kept intact. When working with the value of such a property, you should treat it as plain-text and escape HTML that
might be entered by users before rendering it on the page to avoid script injection.
When a web part property is defined as isHtmlString , SharePoint first of all removes any unsafe HTML, such as script tags, from the property value. The HTML that remains can be
considered safe to render on a page. If the value contains any URLs pointing to files stored in SharePoint, as soon as one of these files is renamed or moved, SharePoint automatically
updates the URL stored in the web part property. This significantly simplifies managing URLs across all web parts and pages in your tenant. HTML web part properties are also searchable,
so users can look for any keywords included in the property value.
Property value types isImageSource and isLink are meant to be used for web part properties that include nothing else but a link to an image or a file stored in SharePoint. In both cases,
SharePoint Search includes the content in the full-text index and keeps the specified URL up to date in case the referenced file is renamed or moved. Additionally, image sources may get
additional processing to help images download faster. If the page has a title image, and the image is among the first five images on the page, or the image is in the first two rows on the page,
the image is preloaded.
Make your SharePoint client-side web part configurable
3/26/2018 • 2 minutes to read Edit Online

The property pane allows end users to configure the web part with several properties. The article Build your first web part describes how the property pane is defined in the
HelloWorldWebPart class. The property pane properties are defined in propertyPaneSettings.
A property pane has three key metadata: a page, an optional header, and at least one group.
Pages provide you the flexibility to separate complex interactions and put them into one or more pages. Pages contain a header and groups.
Headers allow you to define the title of the property pane.
Groups allow you to define the various sections or fields for the property pane through which you want to group your field sets.
The following figure shows an example of a property pane in SharePoint.

Configure the property pane


The following code example initializes and configures the property pane in your web part. You override the getPropertyPaneConfiguration method and return a collection of property
pane page(s).

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
})
]
}
]
}
]
};
}

Property pane fields


The following field types are supported:
Button
Checkbox
Choice group
Dropdown
Horizontal rule
Label
Link
Slider
Textbox
Multi-line Textbox
Toggle
Custom
The field types are available as modules in sp-client-platform. They require an import before you can use them in your code:

import {
PropertyPaneTextField,
PropertyPaneCheckbox,
PropertyPaneLabel,
PropertyPaneLink,
PropertyPaneSlider,
PropertyPaneToggle,
PropertyPaneDropdown
} from '@microsoft/sp-webpart-base';

Every field type method is defined as follows, taking PropertyPaneTextField as an example:

PropertyPaneTextField('targetProperty',{
//field properties are defined here
})

The targetProperty defines the associated object for that field type and is also defined in the props interface in your web part.
To assign types to these properties, define an interface in your web part class that includes one or more target properties.

export interface IHelloWorldWebPartProps {


targetProperty: string
}

This is then available in your web part by using this.properties.targetProperty.

<p class="ms-font-l ms-fontColor-white">${this.properties.description}</p>

When the properties are defined, you can access them in your web part by using the this.properties.[property-name]. For more information, see render method of the
HelloWorldWebPart.

Handle field changes


The property pane has two interaction modes:
Reactive
Non-reactive
In reactive mode, on every change, a change event is triggered. Reactive behavior automatically updates the web part with the new values.
While reactive mode is sufficient for many scenarios, at times you need non-reactive behavior. Non-reactive does not update the web part automatically unless the user confirms the changes.
To turn on the non-reactive mode, add the following code in your web part:

protected get disableReactivePropertyChanges(): boolean {


return true;
}

Custom property pane controls


SharePoint Framework contains a set of standard controls for the property pane. But sometimes you need additional functionality beyond the basic controls. SharePoint Framework allows
you to build custom controls to deliver the required functionality. To learn more, read the Build custom controls for the property pane guide.

See also
SharePoint Framework Overview
Configure web part icon
3/26/2018 • 4 minutes to read Edit Online

Selecting an icon that illustrates the purpose of your SharePoint client-side web part makes it easier for users to find your web part among other all web parts available in the toolbox.

Preconfigure web parts


A web part icon is defined in the web part manifest as part of preconfigured entries. If you have a multipurpose web part that can be configured to meet different needs, each configuration
can have a different icon indicating its purpose.
Using a representative icon helps users find the web part they are looking for. For more information about preconfiguring your web parts, see Simplify adding web parts with preconfigured
entries.
SharePoint Framework offers you a number of ways to define the icon for your web part.

Use Office UI Fabric icon font


One way to define the icon for your web part is by using the officeFabricIconFontName property. This property allows you to choose one of the icons offered as a part of Office UI Fabric.
For a list of available Office UI Fabric icons, see Icons.

To use a specific icon


1. On the Office UI Fabric icons overview page, copy its name, and paste it as the value of the officeFabricIconFontName property in the manifest of your web part.
{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "bcae7077-85cb-41a0-b3d3-2084f268a211",
"alias": "WeatherWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"preconfiguredEntries": [
{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": {
"default": "Other"
},
"title": {
"default": "Weather"
},
"description": {
"default": "Shows current weather in the given location"
},
"officeFabricIconFontName": "Sunny",
"properties": {
"location": "Munich"
}
}
]
}

2. When adding your web part to the page, the selected icon is displayed in the toolbox.

The big benefit of this approach is that you don't need to deploy the icon image file along with your web part assets. Additionally, on computers using different DPI or other accessibility
settings, the icon automatically adapts to these settings without losing quality.

Use an external icon image


Although Office UI Fabric offers many images, when building web parts you might want to use something specific to your organization to clearly separate your web parts from other first-
and third-party web parts visible in the toolbox.
In addition to using Office UI Fabric icons, SharePoint Framework also allows you to use images.

To use an image as a web part icon


1. Specify the image's absolute URL in the iconImageUrl property in the web part manifest.
{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "bcae7077-85cb-41a0-b3d3-2084f268a211",
"alias": "WeatherWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"preconfiguredEntries": [
{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": {
"default": "Other"
},
"title": {
"default": "Weather"
},
"description": {
"default": "Shows current weather in the given location"
},
"iconImageUrl": "https://assets.contoso.com/weather.png",
"properties": {
"location": "Munich"
}
}
]
}

2. The web part icon image displayed in the toolbox is 40x28px. If your image is bigger, it is sized proportionally to match these dimensions.

While using custom images gives you more flexibility to choose an icon for your web part, it requires you to deploy them along with your other web part assets. Additionally, your image
might lose quality when displayed in higher DPI or specific accessibility settings. To avoid quality loss, you can use vector-based SVG images, which are also supported by the SharePoint
Framework.

Use a base64-encoded image


When using a custom image, rather than specifying an absolute URL to the image file hosted together with other web part assets, you can have your image base64-encoded and use the
base64 string instead of the URL.
A number of services are available online that you can use to base64-encode your image; for more information, see Convert your images to Base64.

To use a base64-encoded image


1. Encode the image.
2. Copy the base64 string and use it as the value for the iconImageUrl property in the web part manifest.
{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "bcae7077-85cb-41a0-b3d3-2084f268a211",
"alias": "WeatherWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"preconfiguredEntries": [
{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": {
"default": "Other"
},
"title": {
"default": "Weather"
},
"description": {
"default": "Shows current weather in the given location"
},
"iconImageUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTAyMiIgaGVpZ2h0PSI5NzgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1
"properties": {
"location": "Munich"
}
}
]
}

Base64 encoding works for both bitmap images, such as PNG, as well as vector SVG images. The big benefit of using base64-encoded images is that you don't need to deploy the web part
icon image separately.

Additional considerations
Each web part must have an icon. If you specify the web part icon by using both the officeFabricIconFontName and the iconImageUrl properties, the icon specified in the
officeFabricIconFontName is used.
If you choose not to use an Office UI Fabric icon, you have to specify a URL in the iconImageUrl property.

See also
SharePoint Framework Overview
Use web parts with the full-width column
4/10/2018 • 2 minutes to read Edit Online

Modern SharePoint pages support layouts that allow users to organize the information they present on their pages. Users can choose from a number of different section layouts such as two
columns, three columns, or one-third column. Modern pages in communication sites offer an additional section layout named Full-width column. This layout spans the full width of the
page without any horizontal margin or padding. SharePoint Framework web parts can be placed in any layout, but due to extra requirements, web parts must explicitly enable support for the
full-width column.

Layout requirements for the full-width column


One thing that regular layouts in modern SharePoint pages share, is the maximum width. To guarantee the ease of readability and usability, the body of a modern page doesn't expand
beyond a certain width. When building web parts that will be used in regular layouts, you test your web part's width against the known maximum and minimum width constraints to ensure
that they are displayed properly.
When working with the full-width column layout, however, things become a bit more complicated as that layout expands to the full width of the page. When displayed on an ultra-wide
monitor, the full-width column can even become a few thousands pixels wide. This introduces additional testing requirements that you should take into account when building web parts that
can be used in the full-width column.

Enable support for the full-width column


By default, SharePoint Framework client-side web parts cannot be placed in full-width column layouts. To allow users to add your web part to full-width columns, in the web part manifest set
the supportsFullBleed property to true .

{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "34f6d7f2-262f-460a-8b65-152d784127cb",
"alias": "HelloWorldWebPart",
"componentType": "WebPart",

// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,

// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"supportsFullBleed": true,

"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "HelloWorld" },
"description": { "default": "HelloWorld description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "HelloWorld"
}
}]
}

With this setting enabled, when you edit a page with a full-width column layout, your web part will be displayed among the web parts that can be added to the column.
At this time, the SharePoint Workbench doesn't support testing web parts in the full-width column layout. Instead, you will have to deploy your web part to a developer tenant, create a
communication site, and test your web part there.
Hide a web part from the toolbox
6/12/2018 • 2 minutes to read Edit Online

For scenarios where you automatically instantiate a custom web part on a modern page, you might want the web part not to be manually available for end-users. This could for example be a
status web part on a home page.

Configure hiding the web part from the toolbox


By default a SharePoint Framework client-side web part will be displayed in the web part toolbox when a user edit a page. To allow hiding the web part from the toolbox you add set the
hiddenFromToolbox property to true in the web part manifest.

{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "34f6d7f2-262f-460a-8b65-152d784127cb",
"alias": "HelloWorldWebPart",
"componentType": "WebPart",

// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,

// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"hiddenFromToolbox": true,

"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "HelloWorld" },
"description": { "default": "HelloWorld description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "HelloWorld"
}
}]
}

With the hiddenFromToolbox setting enabled, when you edit a page, the web part will not be listed in the toolbox.
Simplify adding web parts with preconfigured entries
5/3/2018 • 14 minutes to read Edit Online

More complex SharePoint Framework client-side web parts likely have many properties that the user must configure. You can help users by adding preconfigured property entries for
specific scenarios. A preconfigured entry initializes the web part with pre-set values.
NOTE

Before following the steps in this article, be sure to set up your SharePoint client-side web part development environment.

Web part preconfigured entries


Each SharePoint Framework client-side web part consists of two pieces:
The manifest that describes the web part
The web part code
One of the properties specified in the web part manifest is the preconfiguredEntries property.

{
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",

"id": "6737645a-4443-4210-a70e-e5e2a219133a",
"alias": "GalleryWebPart",
"componentType": "WebPart",
"version": "0.0.1",
"manifestVersion": 2,

"preconfiguredEntries": [{
"groupId": "1edbd9a8-0bfb-4aa2-9afd-14b8c45dd489", // Discover
"group": { "default": "Under Development" },
"title": { "default": "Gallery" },
"description": { "default": "Shows items from the selected list" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "Gallery"
}
}]
}

The preconfiguredEntries property provides information about your web part for use in the web part toolbox. When users add web parts to the page, the information from the
preconfiguredEntries property is used to display the web part in the toolbox and define its default settings when it's added to the page.
If you've built classic web parts with full-trust solutions, you can think of each entry in the preconfiguredEntries array as corresponding to a .webpart file. Just like a .webpart file, each
entry in the preconfiguredEntries property is linked to the web part code and specifies basic information about the web part, such as its title or description as well as default values for its
properties.

Properties of a preconfiguredEntries array item


Each item in the preconfiguredEntries array consists of several properties. The following table explains the purpose of each property.

PR O PER T Y NAME V ALU E T YPE R EQ U IR ED PU R PO S E S AMPLE V ALU E

title ILocalizedString yes The web part title that is displayed in "title": { "default": "Weather",
the toolbox. "nl-nl": "Weerbericht" }

description ILocalizedString yes The web part description that is "description": { "default":
displayed in the toolbox tooltips. "Shows weather in the given
location", "nl-nl": "Toont
weerbericht voor de opgegeven
locatie" }

officeFabricIconFontName string no The icon for the web part that is "officeFabricIconFontName":
displayed in the toolbox. Its value must "Sunny"
be one of the Office UI Fabric icon
names. If this property has a value, the
iconImageUrl property is ignored.

iconImageUrl string no The icon for the web part that is "iconImageUrl":
displayed in the toolbox and is "https://cdn.contoso.com/weather.png"
represented by an image URL. The
image at the URL must be exactly
40x28 px. If the
officeFabricIconName property does
not have a value, this property must
have a value.

groupId string yes The group ID to determine which "groupId": "1edbd9a8-0bfb-4aa2-


modern group contains the web part 9afd-14b8c45dd489"
in a modern site page. The SharePoint
Framework reserves group IDs for
predefined groups. The developer can
pick one from those groups. If the
developer fills an ID not in the
predefined groups, it falls back to
Other group.
PR O PER T Y NAME V ALU E T YPE R EQ U IR ED PU R PO S E S AMPLE V ALU E

group ILocalizedString no The group name in the web part picker "group": { "default": "Content",
to contain the web part in the classic "nl-nl": "Inhoud" }
page. If no value is provided, the web
part is displayed in the Miscellaneous
group.

dataVersion string no Use this field to specify the data "dataVersion": "1.0"
version of the pre-configured data
provided to the web part. Note that
data version is different from the
version field in the manifest. The
manifest version is used to control the
versioning of the web part code, while
data version is used to control the
versioning of the serialized data of the
web part. Refer to the dataVersion field
of your web part for more information.
Supported values format:
MAJOR.MINOR version

properties TProperties yes A key-value pair object with default "properties": { "location":
values for web part properties. "Redmond", "numberOfDays": 3,
"showIcon": true }

Some web part properties have a value of type ILocalizedString. This type is a key-value pair object that allows developers to specify strings for the different locales. At a minimum, a value
of type ILocalizedString must contain the default value.
Optionally, developers can provide the translations of that value to the different locales that their web part supports. If the web part is placed on a page in a locale that isn't listed in the
localized string, the default value is used instead.
Valid ILocalizedString values:

"title": {
"default": "Weather",
"nl-nl": "Weerbericht"
}

"title": {
"default": "Weather"
}

An ILocalizedString value that is not valid because the default key is missing:

"title": {
"en-us": "Weather"
}

Predefined modern groups


There are 7 out-of-the-box groups as shown in the following table. Use the group ID in the groupId property.

G R O U P NAME ID G R O U P INCLU D ES ...

Text, media, and content cf066440-0614-43d6-98ae-0b31cf14c7c3 Web parts that display text, multi-media, documents, information
from the web, and other rich content.

Discover 1edbd9a8-0bfb-4aa2-9afd-14b8c45dd489 Web parts that organize, group, and filter content to help users
discover information.

Communication and collaboration 75e22ed5-fa14-4829-850a-c890608aca2d Web parts that facilitate information sharing, team work, and social
interactions.

Planning and process 1bc7927e-4a5e-4520-b540-71305c79c20a Web parts that empower team productivity with the use of planning
and process tools.

Business and intelligence 4aca9e90-eff5-4fa1-bac7-728f5f157b66 Web parts for tracking and analyzing data, and for integrating
business flow with pages.

Site tools 070951d7-94da-4db8-b06e-9d581f1f55b1 Web parts for site information and management.

Other 5c03119e-3074-46fd-976b-c60198311f70 Web parts not in other groups.

If the developer fills an ID not in the previous list, the web part falls back to the Other group.
To see how you can use preconfigured entries when building web parts, you will build a sample gallery web part. Using several properties, users can configure this web part to show items
from a selected list in a specific way. For brevity, you will omit the actual implementation of the web part logic and will focus on using the preconfiguredEntries property to provide
preconfigured versions of the gallery web part.
Create a new web part project
1. Start by creating a new folder for your project.

md react-preconfiguredentries

2. Go to the project folder.

cd react-preconfiguredentries

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project.

yo @microsoft/sharepoint

4. When prompted, enter the following values:


react-preconfiguredentries as your solution name
Use the current folder for the location to place the files
Gallery as your web part name
Shows items from the selected list as your web part description
React as the starting point to build the web part
5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor you prefer.

Add web part properties


In the web part manifest, add web part properties so that users can configure the gallery web part.
1. In the code editor, open the ./src/webparts/gallery/GalleryWebPart.manifest.json file.
2. Replace the properties section with the following JSON:
{
//...
"preconfiguredEntries": [{
//...
"properties": {
"listName": "",
"order": "",
"numberOfItems": 10,
"style": ""
}
}]
}

Note the following about this code:


The listName property specifies the name of the list from which list items should be displayed.
The order property specifies the order in which items should be shown, that is chronological, or reverse chronological order.
The numberOfItems property specifies how many items should be displayed.
The style property specifies how the items should be displayed, such as thumbnails, which is useful for showing images, or as a list, which is more suitable for documents.
Web part properties specified in the manifest must also be added to the web part properties interface.
3. In the code editor, open the ./src/webparts/gallery/IGalleryWebPartProps.ts file. Change its code to:

export interface IGalleryWebPartProps {


listName: string;
order: string;
numberOfItems: number;
style: string;
}

When building SharePoint Framework client-side web parts using React, after changing the web part properties interface, you need to update the web part's render method that uses
that interface to create an instance of the main React component.
4. In the code editor, open the ./src/webparts/gallery/GalleryWebPart.ts file. Change the web part render method to:

export default class GalleryWebPart extends BaseClientSideWebPart<IGalleryWebPartProps> {


// ...
public render(): void {
const element: React.ReactElement<IGalleryProps> = React.createElement(Gallery, {
listName: this.properties.listName,
order: this.properties.order,
numberOfItems: this.properties.numberOfItems,
style: this.properties.style
});

ReactDom.render(element, this.domElement);
}
// ...
}

5. Update the main React component to display the values of the properties. If the web part hasn't been configured, show the standard web part placeholder. In the code editor, open the
./src/webparts/gallery/components/Gallery.tsx file, and change its code to:
import * as React from 'react';
import styles from './Gallery.module.scss';
import { IGalleryProps } from './IGalleryProps';

export default class Gallery extends React.Component<IGalleryProps, void> {


public render(): JSX.Element {
if (this.needsConfiguration()) {
return <div className="ms-Grid" style={{ color: "#666", backgroundColor: "#f4f4f4", padding: "80px 0", alignItems: "center", boxAlign: "center" }}>
<div className="ms-Grid-row" style={{ color: "#333" }}>
<div className="ms-Grid-col ms-u-hiddenSm ms-u-md3"></div>
<div className="ms-Grid-col ms-u-sm12 ms-u-md6" style={{ height: "100%", whiteSpace: "nowrap", textAlign: "center" }}>
<i className="ms-fontSize-su ms-Icon ms-Icon--ThumbnailView" style={{ display: "inline-block", verticalAlign: "middle", whiteSpace: "normal" }}></i><span className="ms-fontWeight-l
</div>
<div className="ms-Grid-col ms-u-hiddenSm ms-u-md3"></div>
</div>
<div className="ms-Grid-row" style={{ width: "65%", verticalAlign: "middle", margin: "0 auto", textAlign: "center" }}>
<span style={{ color: "#666", fontSize: "17px", display: "inline-block", margin: "24px 0", fontWeight: 100 }}>Show items from the selected list</span>
</div>
<div className="ms-Grid-row"></div>
</div>;
}
else {
return (
<div className={styles.gallery}>
<div className={styles.container}>
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className='ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1'>
<span className="ms-font-xl ms-fontColor-white">
Welcome to SharePoint!
</span>
<p className='ms-font-l ms-fontColor-white'>
Customize SharePoint experiences using web parts.
</p>
<p className='ms-font-l ms-fontColor-white'>
List: {this.props.listName}<br />
Order: {this.props.order}<br />
Number of items: {this.props.numberOfItems}<br />
Style: {this.props.style}
</p>
<a href="https://aka.ms/spfx" className={styles.button}>
<span className={styles.label}>Learn more</span>
</a>
</div>
</div>
</div>
</div>
);
}
}

private needsConfiguration(): boolean {


return Gallery.isEmpty(this.props.listName) ||
Gallery.isEmpty(this.props.order) ||
Gallery.isEmpty(this.props.style);
}

private static isEmpty(value: string): boolean {


return value === undefined ||
value === null ||
value.length === 0;
}
}

6. Update the main React component interface to match the web part property interface, because we are bypassing all the web part properties to this component. In the code editor,
open the ./src/webparts/gallery/components/IGalleryProps.ts file, and change its code to:

import { IGalleryWebPartProps } from '../IGalleryWebPartProps';

export interface IGalleryProps extends IGalleryWebPartProps {


}

Render web part properties in the property pane


For users to be able to use the newly defined properties to configure the web part, the properties must be displayed in the web part property pane.
1. In the code editor, open the ./src/webparts/gallery/GalleryWebPart.ts file. In the top section of the file, change the @microsoft/sp-webpart-base import statement to:

import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneDropdown,
PropertyPaneSlider,
PropertyPaneChoiceGroup
} from '@microsoft/sp-webpart-base';

2. Change the propertyPaneSettings to:


export default class GalleryWebPart extends BaseClientSideWebPart<IGalleryWebPartProps> {
// ...
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneDropdown('listName', {
label: strings.ListNameFieldLabel,
options: [{
key: 'Documents',
text: 'Documents'
},
{
key: 'Images',
text: 'Images'
}]
}),
PropertyPaneChoiceGroup('order', {
label: strings.OrderFieldLabel,
options: [{
key: 'chronological',
text: strings.OrderFieldChronologicalOptionLabel
},
{
key: 'reversed',
text: strings.OrderFieldReversedOptionLabel
}]
}),
PropertyPaneSlider('numberOfItems', {
label: strings.NumberOfItemsFieldLabel,
min: 1,
max: 10,
step: 1
}),
PropertyPaneChoiceGroup('style', {
label: strings.StyleFieldLabel,
options: [{
key: 'thumbnails',
text: strings.StyleFieldThumbnailsOptionLabel
},
{
key: 'list',
text: strings.StyleFieldListOptionLabel
}]
})
]
}
]
}
]
};
}
}

In a real-life scenario, you would retrieve the list of lists from the current SharePoint site. For brevity, in this example, you use a fixed list instead.

Add localization labels


1. In the code editor, open the ./src/webparts/gallery/loc/mystrings.d.ts file. Change its code to:

declare interface IGalleryStrings {


PropertyPaneDescription: string;
BasicGroupName: string;
ListNameFieldLabel: string;
OrderFieldLabel: string;
OrderFieldChronologicalOptionLabel: string;
OrderFieldReversedOptionLabel: string;
NumberOfItemsFieldLabel: string;
StyleFieldLabel: string;
StyleFieldThumbnailsOptionLabel: string;
StyleFieldListOptionLabel: string;
}

declare module 'galleryStrings' {


const strings: IGalleryStrings;
export = strings;
}

2. Add the missing resource strings by opening the ./src/webparts/gallery/loc/en-us.js file and changing its code to:
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListNameFieldLabel": "List",
"OrderFieldLabel": "Items order",
"OrderFieldChronologicalOptionLabel": "chronological",
"OrderFieldReversedOptionLabel": "reversed chronological",
"NumberOfItemsFieldLabel": "Number of items to show",
"StyleFieldLabel": "Items display style",
"StyleFieldThumbnailsOptionLabel": "thumbnails",
"StyleFieldListOptionLabel": "list"
}
});

3. Confirm that the project is building by running the following command:

gulp serve

4. In the web browser, add the web part to the canvas and open its property pane. You should see all the properties available for users to configure.

Because you didn't specify any default values for the web part, every time users add the web part to the page, they have to configure it first. You can simplify this experience by providing
default values for the most common scenarios.

Specify default values for the web part


Imagine that users often use the gallery web part to show the five most recently added images. Rather than requiring users to configure the web part manually each time, you could provide
them with a preconfigured version that uses the correct settings.
1. In the code editor, open the ./src/webparts/gallery/GalleryWebPart.manifest.json file. Change the existing entry in the preconfiguredEntries property to:

{
// ...
"preconfiguredEntries": [{
"groupId": "6737645a-4443-4210-a70e-e5e2a219133a",
"group": { "default": "Content" },
"title": { "default": "Recent images" },
"description": { "default": "Shows 5 most recent images" },
"officeFabricIconFontName": "Picture",
"properties": {
"listName": "Images",
"order": "reversed",
"numberOfItems": 5,
"style": "thumbnails"
}
}]
}

2. Start debugging the project by running the following command:


gulp serve

NOTE

If you were debugging the project previously, stop debugging and start it again. Changes made to the web part manifest are not automatically reflected in the Workbench while
debugging, and you have to rebuild the project to see them.
3. When you open the web part toolbox to add the web part to the canvas, you see that its name and icon changed to reflect the preconfigured settings.

4. After adding the web part to the page, it works immediately by using the preconfigured settings.

Specify multiple preconfigured web part entries


Imagine that another group of users often uses your gallery web part to show documents recently added to their site. To help them use your web part, you can add another set of presets that
addresses their configuration needs.
1. In the code editor, open the ./src/webparts/gallery/GalleryWebPart.manifest.json file. Change the preconfiguredEntries property to:
{
// ...
"preconfiguredEntries": [{
"groupId": "6737645a-4443-4210-a70e-e5e2a219133a",
"group": { "default": "Content" },
"title": { "default": "Recent images" },
"description": { "default": "Shows 5 most recent images" },
"officeFabricIconFontName": "Picture",
"properties": {
"listName": "Images",
"order": "reversed",
"numberOfItems": 5,
"style": "thumbnails"
}
},
{
"groupId": "6737645a-4443-4210-a70e-e5e2a219133a",
"group": { "default": "Content" },
"title": { "default": "Recent documents" },
"description": { "default": "Shows 10 most recent documents" },
"officeFabricIconFontName": "Documentation",
"properties": {
"listName": "Documents",
"order": "reversed",
"numberOfItems": 10,
"style": "list"
}
}]
}

2. Notice how you keep the previous preconfigured entry intact and add another one next to it by using different values for properties.
3. To see the result, start debugging the project by running the following command:

gulp serve

4. When you open the web part toolbox to add the web part to the canvas, you see that there are two web parts for you to choose from.

5. After adding the Recent documents web part to the page, it works immediately by using its specific preconfigured settings.
Specify an unconfigured instance of the web part
When building web parts, there are often specific scenarios that the web part should support. Providing preconfigured entries for those scenarios makes it easier for users to use the web
part.
Depending on how you build your web part, it could be possible that the web part can support other unforeseen scenarios as well. If you only provide specific preconfigured entries, users
might not realize they can use your web part for a different scenario. It might be a good idea to provide a generic unconfigured variant of your web part as well.
1. In the code editor, open the ./src/webparts/gallery/GalleryWebPart.manifest.json file. Change the preconfiguredEntries property to:

{
// ...
"preconfiguredEntries": [{
"groupId": "6737645a-4443-4210-a70e-e5e2a219133a",
"group": { "default": "Content" },
"title": { "default": "Recent images" },
"description": { "default": "Shows 5 most recent images" },
"officeFabricIconFontName": "Picture",
"properties": {
"listName": "Images",
"order": "reversed",
"numberOfItems": 5,
"style": "thumbnails"
}
},
{
"groupId": "6737645a-4443-4210-a70e-e5e2a219133a",
"group": { "default": "Content" },
"title": { "default": "Recent documents" },
"description": { "default": "Shows 10 most recent documents" },
"officeFabricIconFontName": "Documentation",
"properties": {
"listName": "Documents",
"order": "reversed",
"numberOfItems": 10,
"style": "list"
}
},
{
"groupId": "6737645a-4443-4210-a70e-e5e2a219133a",
"group": { "default": "Content" },
"title": { "default": "Gallery" },
"description": { "default": "Shows items from the selected list" },
"officeFabricIconFontName": "CustomList",
"properties": {
"listName": "",
"order": "",
"numberOfItems": 5,
"style": ""
}
}]
}

2. Notice that the generic unconfigured version of the web part is added next to the configurations that target specific scenarios. This way, if there is no specific configuration addressing
users' needs, they can always use the generic version and configure it according to their requirements.
3. To see the result, start debugging the project by running the following command:

gulp serve

4. When you open the web part toolbox to add the web part to the canvas, you see that there are now three web parts that users can choose from.
Validate web part property values
3/26/2018 • 9 minutes to read Edit Online

When working with SharePoint Framework client-side web parts, users can configure them to meet their needs by using their properties. By validating the provided configuration values, you
can make it easier for users to configure the web part and improve the overall user experience of working with your web part.
NOTE

Before following the steps in this article, be sure to set up your development environment for building SharePoint Framework solutions.

Create a new web part project


1. Start by creating a new folder for your project.

md react-listinfo

2. Go to the project folder.

cd react-listinfo

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project.

yo @microsoft/sharepoint

4. When prompted, enter the following values:


react-listinfo as your solution name
Use the current folder for the location to place the files
React as the starting point to build the web part
List info as your web part name
Shows information about the selected list as your web part description

5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer.
Options for validating web part properties
SharePoint Framework offers developers two ways to validate values of web part properties. You can validate the value directly, inside a web part's code, or you can call an external API to
perform the validation there.
Validating values inline is useful for performing simple validations such as minimal/maximum length, required properties, or simple pattern recognition, like a zip code. Whenever the
validation is based on business logic, such as checking a social security number or a security group membership, calling external APIs is a better approach.
To validate the value of a web part property, you have to implement the event handler for the onGetErrorMessage event of that particular property. For inline validation, the event handler
should return a string with the validation error or an empty string if the provided value is valid.
For validation using remote APIs, the event handler returns a promise of string. If the provided value is invalid, the promise resolves with the error message. If the provided value is valid, the
promise resolves with an empty string.

Validate web part property values inline


In this step you verify that the description web part property is specified and its value is not longer than 40 characters. You do this by using the inline validation process.
1. In the code editor, open the ./src/webparts/listInfo/ListInfoWebPart.ts file. In the ListInfoWebPart class, add the validateDescription method with the following code:

export default class ListInfoWebPart extends BaseClientSideWebPart<IListInfoWebPartProps> {


// ...

private validateDescription(value: string): string {


if (value === null ||
value.trim().length === 0) {
return 'Provide a description';
}

if (value.length > 40) {


return 'Description should not be longer than 40 characters';
}

return '';
}
}

The validateDescription method checks if the description is provided, and if it isn't longer than 40 characters. If the provided description is invalid, the method returns an error
message corresponding to the validation error. If the provided value is correct, it returns an empty string.
2. Associate the validateDescription method with the description web part property. In the ListInfoWebPart class, change the implementation of the
getPropertyPaneConfiguration method to:
export default class ListInfoWebPart extends BaseClientSideWebPart<IListInfoWebPartProps> {
// ...

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel,
onGetErrorMessage: this.validateDescription.bind(this)
})
]
}
]
}
]
};
}

// ...
}

You have extended the definition of the description web part by defining the validateDescription method as the event handler for the onGetErrorMessage event.
3. Run the following command to see the result of the validation:

gulp serve

4. In the Workbench, add the web part to the canvas and open its properties. If you remove the description, you should see the first validation error.

5. Provide a value that's longer than 40 characters. You should see another validation error displayed under the text field.
6. Notice that when providing an invalid value, the web part is rendered showing the last valid value. Additionally, in the non-reactive property pane mode, if one of the web part
properties is invalid, the Apply button is disabled, preventing the user from applying the invalid configuration.

Validate web part property values using remote APIs


In some scenarios, validating web part property values can be more complex and may require specific business logic. In such cases, it might be more efficient for you to validate the value by
using an existing API rather than implementing and maintaining the business logic in the web part.
In this step, you implement validation logic that checks if the list with the name specified in the web part properties exists in the current SharePoint site.

Add the listName web part property


1. In the code editor, open the ./src/webparts/listInfo/ListInfoWebPart.manifest.json file. In the properties property, add a new property named listName with the default value
set to an empty string:
{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "1ec8f92d-ea55-4584-bf50-bac435c916bf",
"alias": "ListInfoWebPart",
"componentType": "WebPart",

// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,

// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,

"preconfiguredEntries": [{
"groupId": "1ec8f92d-ea55-4584-bf50-bac435c916bf",
"group": { "default": "Under Development" },
"title": { "default": "List info" },
"description": { "default": "Shows information about the selected list" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "List info"
}
}]
}

2. In the code editor, open the ./src/webparts/listInfo/IListInfoWebPartProps.ts file, and extend the interface definition with the listName property of type string.

export interface IListInfoWebPartProps {


description: string;
listName: string;
}

3. Finish adding the new web part property by opening the ./src/webparts/listInfo/ListInfoWebPart.ts file in the code editor, and changing the implementation of the
getPropertyPaneConfiguration method to:

export default class ListInfoWebPart extends BaseClientSideWebPart<IListInfoWebPartProps> {


// ...

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel,
onGetErrorMessage: this.validateDescription.bind(this)
}),
PropertyPaneTextField('listName', {
label: strings.ListNameFieldLabel
})
]
}
]
}
]
};
}

// ...
}

4. Add the missing ListNameFieldLabel resource string by changing the code of the ./src/webparts/listInfo/loc/mystrings.d.ts file to:

declare interface IListInfoStrings {


PropertyPaneDescription: string;
BasicGroupName: string;
DescriptionFieldLabel: string;
ListNameFieldLabel: string;
}

declare module 'listInfoStrings' {


const strings: IListInfoStrings;
export = strings;
}

5. Change the code of the ./src/webparts/listInfo/loc/en-us.js file to:

define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"DescriptionFieldLabel": "Description Field",
"ListNameFieldLabel": "List name"
}
});

6. Run the following command to verify that the project is running and that the newly added list name property is displayed in the web part property pane:
gulp serve

Validate the name of the list by using the SharePoint REST API
In this step, you validate the provided list name and check if it corresponds to an existing list on the current SharePoint site.
1. In the code editor, open the ./src/webparts/listInfo/ListInfoWebPart.ts file, and add the following references:

import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';


import { escape } from '@microsoft/sp-lodash-subset';

2. In the ListInfoWebPart class, add the validateListName method with the following code:

export default class ListInfoWebPart extends BaseClientSideWebPart<IListInfoWebPartProps> {


// ...

private validateListName(value: string): Promise<string> {


return new Promise<string>((resolve: (validationErrorMessage: string) => void, reject: (error: any) => void): void => {
if (value === null ||
value.length === 0) {
resolve('Provide the list name');
return;
}

this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + `/_api/web/lists/getByTitle('${escape(value)}')?$select=Id`, SPHttpClient.configurations.v1)


.then((response: SPHttpClientResponse): void => {
if (response.ok) {
resolve('');
return;
}
else if (response.status === 404) {
resolve(`List '${escape(value)}' doesn't exist in the current site`);
return;
}
else {
resolve(`Error: ${response.statusText}. Please try again`);
return;
}
})
.catch((error: any): void => {
resolve(error);
});
});
}
}

First, the validateListName method checks if a list name has been provided. If not, it resolves the promise with a relevant validation error. If the user has provided a list name, the
validateListName method uses the SPHttpClient to call the SharePoint REST API and check if the list with the specified name exists.
If the list with the specified name exists on the current site, the response returns a 200 OK status code, and the validateListName method resolves the promise with an empty string,
confirming that the provided value represents a valid list.
If the list with the specified name doesn't exist, the response returns a different code. Typically, it is a 404 Not Found response, but if the request failed in some other way, a different
status code can be returned. In both cases, the validateListName method displays a relevant error message to the user.
With the list name validation method defined, the next step is to configure it as the validation handler for the listName web part property.
3. In the ListInfoWebPart class, replace the code of the getPropertyPaneConfiguration method with:
export default class ListInfoWebPart extends BaseClientSideWebPart<IListInfoWebPartProps> {
// ...

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel,
onGetErrorMessage: this.validateDescription.bind(this)
}),
PropertyPaneTextField('listName', {
label: strings.ListNameFieldLabel,
onGetErrorMessage: this.validateListName.bind(this)
})
]
}
]
}
]
};
}

// ...
}

4. Run the following command to see the result of the validation:

gulp serve --nobrowser

Because the list name validation method communicates with the SharePoint REST API, you have to test the web part in the hosted version of the SharePoint workbench.
5. Add the web part to the canvas and open its properties. Because you haven't specified a default value for the list name, which is a required property, you see a validation error.

If you provide the name of a list that doesn't exist, the web part displays a validation error stating that the list you specified doesn't exist in the current site.
If you specify the name of an existing list, the validation error disappears.

Optimize validation using remote APIs


When validating web part properties using remote APIs, SharePoint Framework monitors changes in the property pane controls and sends updated values for validation to the specified
validation handler. By default, the SharePoint Framework waits 200 ms before triggering the validation process. If the user hasn't changed the particular value for 200 ms, the SharePoint
Framework starts the validation process. When the validation handler uses a remote API, each time the validation process starts, that method issues a web request to the API to validate the
specified value. If users don't type fast enough, this results in partially completed values being sent over for validation, unnecessarily stressing the network and the API. In such cases, you
should consider increasing the validation delay.
You can configure the validation delay for each property separately, depending on the type of value that users need to provide.
To increase the validation delay for the listName property
1. In the code editor, open the ./src/webparts/listInfo/ListInfoWebPart.ts file. Change the code of the getPropertyPaneConfiguration method to:

export default class ListInfoWebPart extends BaseClientSideWebPart<IListInfoWebPartProps> {


// ...

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel,
onGetErrorMessage: this.validateDescription.bind(this)
}),
PropertyPaneTextField('listName', {
label: strings.ListNameFieldLabel,
onGetErrorMessage: this.validateListName.bind(this),
deferredValidationTime: 500
})
]
}
]
}
]
};
}

// ...
}

2. The deferredValidationTime property specifies the number of milliseconds that the SharePoint Framework waits before starting the validation process.
3. Run the following command to see that the applied delay is working as expected:

gulp serve --nobrowser


Share data between client-side web parts
3/26/2018 • 9 minutes to read Edit Online

When building client-side web parts, loading data once and reusing it across different web parts helps you improve the performance of your pages and decrease the load on your network.
This article describes a number of approaches that you can use to share data across multiple web parts.

Why share data between web parts


Often, when building web parts, a number of them are used together on one page. If you consider each web part as a standalone part of the page, you may end up in a situation where you
are loading a similar or even the same set of data multiple times on the same page. This unnecessarily slows down the loading of the page and increases traffic on your network.

A sample service responsible for loading the data could look like the following:
import { IDocument } from './IDocument';

export class DocumentsService {


public static getRecentDocument(): Promise<IDocument> {
return new Promise<IDocument>((resolve: (document: IDocument) => void, reject: (error: any) => void): void => {
// [...] reach out to a remote API
resolve(recentDocument);
});
}

public static getRecentDocuments(startFrom: number = 0): Promise<IDocument[]> {


return new Promise<IDocument[]>((resolve: (documents: IDocument[]) => void, reject: (error: any) => void): void => {
// [...] reach out to a remote API
resolve(recentDocuments);
});
}
}

SharePoint Framework client-side web parts would consume this service by using the following code:

import { DocumentsService, IDocument } from '../../services';

export default class RecentDocumentsWebPart extends BaseClientSideWebPart<IRecentDocumentsWebPartProps> {

public render(): void {


this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'documents');

DocumentsService.getRecentDocuments(this.properties.startFrom)
.then((documents: IDocument[]): void => {
const element: React.ReactElement<IRecentDocumentsProps> = React.createElement(
RecentDocuments,
{
documents: documents
}
);

this.context.statusRenderer.clearLoadingIndicator(this.domElement);
ReactDom.render(element, this.domElement);
});
}

// ...
}

To improve the loading time of the page and decrease the traffic on your network, you can build your web parts in such a way that they load the data only once. Whenever one of the web
parts on the page requests a specific set of data, it reuses data loaded previously if possible.

Store the retrieved data in a globally-scoped variable


NOTE

Globally-scoped variables are generally a bad idea. However, for illustration and simplicity purposes, we are using them here as "demo code." There are many patterns around this issue,
including importing/exporting modules by using TypeScript concepts.
Web parts built using the SharePoint Framework are isolated into separate modules. This way, one web part cannot directly access data and properties stored by another web part. One way
to overcome this design characteristic and make data loaded by one web part available to other web parts on the page is to assign the retrieved data to a globally-scoped variable.
Using the data access service shown earlier, it could be changed as follows:
import { IDocument } from './IDocument';

export class DocumentsService {


public static getRecentDocument(): Promise<IDocument> {
return new Promise<IDocument>((resolve: (document: IDocument) => void, reject: (error: any) => void): void => {
this.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments[0]);
});
});
}

public static getRecentDocuments(startFrom: number = 0): Promise<IDocument[]> {


return new Promise<IDocument[]>((resolve: (documents: IDocument[]) => void, reject: (error: any) => void): void => {
this.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments.slice(startFrom, startFrom + 3));
});
});
}

private static ensureRecentDocuments(): Promise<IDocument[]> {


return new Promise<IDocument[]>((resolve: (recentDocuments: IDocument[]) => void, reject: (error: any) => void): void => {
if ((window as any).loadedData) {
// data already loaded so reuse
resolve((window as any).loadedData);
return;
}

if ((window as any).loadingData) {
// data is being loaded, wait a moment and try again
window.setTimeout((): void => {
DocumentsService.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments);
});
}, 100);
}
else {
(window as any).loadingData = true;
// data not loaded yet, call the remote API,
// store the data for subsequent requests, and resolve the Promise
(window as any).loadedData = loadedData;
(window as any).loadingData = false;
resolve((window as any).loadedData);
}
});
}
}

Notice how loading the data has been moved from the specific methods to the ensureRecentDocuments method. If the data has been loaded previously, the method resolves the promise
immediately by returning the previously loaded documents. If the data is currently being loaded, the method waits for 100 ms and tries resolving the promise again.
If you look at the log in the developer tools, you notice that the remote API is now called only once.
Looking at the informational messages, you can confirm that when the second web part tries to load the data, it detects that the data is already being loaded. After the data is loaded, it reuses
the existing data rather than loading it itself.
Using a globally-scoped variable is the easiest way to exchange data between different web parts on the page. One downside of using this approach, however, is that the data is exposed not
only to web parts but also to all other elements on the page. This introduces the risk of other elements on the page using the same variable as you to store their data, potentially overwriting
your data.

Store the retrieved data in a cookie


Another approach to exchange data across different web parts is by storing the data in a cookie. The added benefit of using cookies is that you can persist the data for longer periods of time.
So in cases where the data doesn't change often, you can load the data once and reuse it not only across different web parts but also across different pages.
The implementation that uses cookies is very similar to how you store data in a globally-scoped variable. The only difference is that the actual data would be stored in a cookie.
import { IDocument } from './IDocument';
import * as Cookies from 'js-cookie';

export class DocumentsService {


private static cookieName: string = 'recentDocuments';

public static getRecentDocument(): Promise<IDocument> {


return new Promise<IDocument>((resolve: (document: IDocument) => void, reject: (error: any) => void): void => {
this.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments[0]);
});
});
}

public static getRecentDocuments(startFrom: number = 0): Promise<IDocument[]> {


return new Promise<IDocument[]>((resolve: (documents: IDocument[]) => void, reject: (error: any) => void): void => {
this.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments.slice(startFrom, startFrom + 3));
});
});
}

private static ensureRecentDocuments(): Promise<IDocument[]> {


return new Promise<IDocument[]>((resolve: (recentDocuments: IDocument[]) => void, reject: (error: any) => void): void => {
let loadedData: IDocument[] = Cookies.getJSON(DocumentsService.cookieName);
if (loadedData) {
// data already loaded so reuse
resolve(loadedData);
return;
}

if ((window as any).loadingData) {
// data is being loaded, wait a moment and try again
window.setTimeout((): void => {
DocumentsService.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments);
});
}, 100);
}
else {
(window as any).loadingData = true;
// data not loaded yet, call the remote API,
// store the data for subsequent requests, and resolve the Promise
Cookies.set(DocumentsService.cookieName, loadedData, {
expires: 1,
path: '/'
});
(window as any).loadingData = false;
resolve(loadedData);
}
});
}
}

In the previous example, the js-cookie package is used to simplify working with cookies. Using the parameters passed into the Cookies.set() method, you can specify to which pages and for
how long the retrieved data should be available.
When you load the page in Microsoft Edge for the first time, you see that the data is retrieved once and reused by both web parts.
On subsequent requests, a web part can directly reuse the previously loaded data without calling the remote API.
When loading the page in Google Chrome, you see that the data is loaded twice from the remote API and is not being cached at all.
Different web browsers have different limits regarding how much data can be stored in a cookie. In this example, the retrieved data exceeds the maximum length of what can be stored in a
cookie in Google Chrome. As a result, no cookie is being set and the data is loaded twice.
While you could use cookies to share data between web parts, assuming the data that you want to share is not too large, there are some downsides to using cookies. Similar to globally-
scoped variables, cookies are available to all elements on the page, or even across the whole portal, and could be overwritten by them. Additionally, web browsers send cookies with outgoing
requests and retrieve them with incoming responses, which adds overhead to loading information in the portal. Another important thing that you should consider is that cookies are
persisted in the web browser, and you should never store any confidential information in them.

Store the retrieved data in session or local storage


An alternative to using cookies is storing data in session or local storage. Similar to cookies, browser storage allows you to persist data not only for subsequent requests but also across
pages. The benefits of using browser storage over using cookies are that data stored in browser storage is not sent with outgoing requests and you can store more data than in a cookie.
Comparable to cookies, browser storage is capable of storing only string values. So if you need to store more complex objects, you need to serialize them first by using, for example, the
native JSON.stringify() method.
If you want data to be stored only during the current session, you should use session storage. If the data should be persisted for a longer period of time, you should use local storage. Data
stored in local storage doesn't expire and it's up to you to clear it.
The previously used implementation of the data access service based on cookies can easily be adapted to use local storage instead.
import { IDocument } from './IDocument';

export class DocumentsService {


private static storageKey: string = 'recentDocuments';

public static getRecentDocument(): Promise<IDocument> {


return new Promise<IDocument>((resolve: (document: IDocument) => void, reject: (error: any) => void): void => {
this.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments[0]);
});
});
}

public static getRecentDocuments(startFrom: number = 0): Promise<IDocument[]> {


return new Promise<IDocument[]>((resolve: (documents: IDocument[]) => void, reject: (error: any) => void): void => {
this.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments.slice(startFrom, startFrom + 3));
});
});
}

private static ensureRecentDocuments(): Promise<IDocument[]> {


return new Promise<IDocument[]>((resolve: (recentDocuments: IDocument[]) => void, reject: (error: any) => void): void => {
let loadedData: IDocument[] = localStorage ? JSON.parse(localStorage.getItem(DocumentsService.storageKey)) : undefined;
if (loadedData) {
// data already loaded so reuse
resolve(loadedData);
return;
}

if ((window as any).loadingData) {
// data is being loaded, wait a moment and try again
window.setTimeout((): void => {
DocumentsService.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments);
});
}, 100);
}
else {
(window as any).loadingData = true;
// data not loaded yet, call the remote API,
// store the data for subsequent requests, and resolve the Promise
if (localStorage) {
localStorage.setItem(DocumentsService.storageKey, JSON.stringify(loadedData));
}
(window as any).loadingData = false;
resolve(loadedData);
}
});
}
}

The implementation of this service is very similar to when using cookies. One thing that you should keep in mind, however, is that browser storage can be disabled by the user, and you
should always check for its availability before performing operations on it. Just as with cookies, local storage is persisted in the web browser and you should never use it to store any
confidential information.

See also
Tutorial: Share data between web parts by using a global variable
Share data between web parts by using a global variable (tutorial)
5/3/2018 • 18 minutes to read Edit Online

When building client-side web parts, loading data once and reusing it across different web parts helps improve the performance of your pages and decrease the load on your network.
NOTE

Before following the steps in this article, be sure to set up your SharePoint client-side web part development environment.

Create a new project


1. Using a command prompt, create a new folder for your project:

md react-recentdocuments

2. Go into the project folder:

cd react-recentdocuments

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:

yo @microsoft/sharepoint

4. When prompted, use the following values:


WebPart as the type of client-side component to create.
react-recentdocuments as your solution name.
Use the current folder for the location to place the files.
Recent documents as your web part name.
Shows recently modified documents as your web part description.
React as the framework to use.

5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer.
Show the recently modified documents
The Recent Documents web part shows information about the most recently modified documents displayed as cards by using Office UI Fabric.

Remove the standard description property


1. Remove the standard description property from the IRecentDocumentsWebPartProps interface. In the code editor, open the
./src/webparts/recentDocuments/IRecentDocumentsWebPartProps.ts file, and paste the following code:

export interface IRecentDocumentsWebPartProps {


}

2. Remove the standard description property from the web part manifest. Open the ./src/webparts/recentDocuments/RecentDocumentsWebPart.manifest.json file, and from
the properties property, remove the description property:

{
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",

"id": "7a7e3aa9-5d8a-4155-936b-0b0e06e9ca11",
"alias": "RecentDocumentsWebPart",
"componentType": "WebPart",
"version": "0.0.1",
"manifestVersion": 2,

"preconfiguredEntries": [{
"groupId": "7a7e3aa9-5d8a-4155-936b-0b0e06e9ca11",
"group": { "default": "Under Development" },
"title": { "default": "Recent documents" },
"description": { "default": "Shows recently modified documents" },
"officeFabricIconFontName": "Page",
"properties": {
}
}]
}

3. Remove the standard description property from the web part. In the code editor, open the ./src/webparts/recentDocuments/RecentDocumentsWebPart.ts file, and replace its
render method with the following code:

export default class RecentDocumentsWebPart extends BaseClientSideWebPart<IRecentDocumentsWebPartProps> {


// ...
public render(): void {
const element: React.ReactElement<IRecentDocumentsProps > = React.createElement(
RecentDocuments,
{
}
);

ReactDom.render(element, this.domElement);
}
// ...
}

4. Replace its getPropertyPaneConfiguration method with the following code:

export default class RecentDocumentsWebPart extends BaseClientSideWebPart<IRecentDocumentsWebPartProps> {


// ...

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: []
}
]
}
]
};
}
}

Create the IDocumentActivity interface


Use this interface to display the activity information of a particular document on a card.
In the ./src/webparts/recentDocuments folder, create a new file named IDocumentActivity.ts, and paste the following code:

export interface IDocumentActivity {


title: string;
actorName: string;
actorImageUrl: string;
}

Create the IDocument interface


This interface represents a document with all the information necessary to display the document as a card.
In the ./src/webparts/recentDocuments folder, create a new file named IDocument.ts, and paste the following code:
import { IDocumentActivity } from './IDocumentActivity';

export interface IDocument {


title: string;
url: string;
imageUrl: string;
iconUrl: string;
activity: IDocumentActivity;
}

Show recent documents in the RecentDocuments React component


1. Add the documents property to the IRecentDocumentsProps interface. In the code editor, open the
./src/webparts/recentDocuments/components/IRecentDocumentsProps.ts file, and paste the following code:

import { IDocument } from '../IDocument';

export interface IRecentDocumentsProps {


documents: IDocument[];
}

2. In the code editor, open the ./src/webparts/recentDocuments/components/RecentDocuments.tsx file, and paste the following code:

import * as React from 'react';


import {
DocumentCard,
DocumentCardType,
DocumentCardPreview,
DocumentCardTitle,
DocumentCardActivity
} from 'office-ui-fabric-react';
import { IDocument } from '../IDocument';
import styles from './RecentDocuments.module.scss';
import { IRecentDocumentsProps } from './IRecentDocumentsProps';

export default class RecentDocuments extends React.Component<IRecentDocumentsProps, void> {


public render(): React.ReactElement<IRecentDocumentsProps> {
const documents: JSX.Element[] = this.props.documents.map((document: IDocument, index: number, array: IDocument[]): JSX.Element => {
return (
<DocumentCard type={DocumentCardType.compact} onClickHref={document.url} accentColor='#ce4b1f' key={index}>
<DocumentCardPreview previewImages={[{
name: document.title,
url: document.url,
previewImageSrc: document.imageUrl,
iconSrc: document.iconUrl,
width: 144
}]} />
<div className='ms-DocumentCard-details'>
<DocumentCardTitle
title={document.title}
shouldTruncate={true} />
<DocumentCardActivity
activity={document.activity.title}
people={
[
{ name: document.activity.actorName, profileImageSrc: document.activity.actorImageUrl }
]
}
/>
</div>
</DocumentCard>
);
});
return (
<div className={styles.helloWorld}>
{documents}
</div>
);
}
}

First, the component iterates through the documents passed by using its documents property. For each document, it builds an Office UI Fabric DocumentCard, filling its properties with the
relevant information about that particular document. Finally, when cards for all documents have been built, the component adds them to its body and returns the complete markup.

Load the information about the recent documents


In this example, the information about the recently modified documents is loaded from a static data set. You could, however, easily change this implementation to load the data from a
SharePoint document library instead.
1. In the code editor, open the ./src/webparts/recentDocuments/RecentDocumentsWebPart.ts file. Add an import statement for the IDocument interface under the other import
statements at the top of the file by using the following code:

import { IDocument } from './IDocument';

2. In the RecentDocumentsWebPart class, add a new private variable named documents by using the following code:
export default class RecentDocumentsWebPart extends BaseClientSideWebPart<IRecentDocumentsWebPartProps> {
private static documents: IDocument[] = [
{
title: 'Proposal for Jacksonville Expansion Ad Campaign',
url: 'https://contoso-my.sharepoint.com/personal/miriamg_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BCBF65183-0378-485B-AB67-791E0FC81D72%7D&file=Jacksonville%2
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=ca6fa69c-347d-4c07-886c-67105dc5a357&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BCBF6
iconUrl: '',
activity: {
title: 'Modified, January 25 2017',
actorName: 'Miriam Graham',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=miriamg@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'Customer Feedback for ZT1000',
url: 'https://contoso-my.sharepoint.com/personal/miriamg_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7B5449CE24-BFB7-442E-843D-E0C86CEB71CC%7D&file=Customer%20Fee
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=ca6fa69c-347d-4c07-886c-67105dc5a357&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7B5449
iconUrl: '',
activity: {
title: 'Modified, January 23 2017',
actorName: 'Miriam Graham',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=miriamg@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'Asia Q3 Marketing Overview',
url: 'https://contoso-my.sharepoint.com/personal/alexw_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BFD077A94-AB7D-45F9-A810-36229E518A94%7D&file=Asia%20Q3%20Mark
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=18231116-2bf0-474c-93ee-eb362681b293&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BFD07
iconUrl: '',
activity: {
title: 'Modified, January 23 2017',
actorName: 'Alex Wilber',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=alexw@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'Trey Research Business Development Plan',
url: 'https://contoso.sharepoint.com/sites/contoso/Resources/Document%20Center/_layouts/15/WopiFrame.aspx?sourcedoc=%7B743A6C44-D3F8-4ECC-A1B7-EA9844911314%7D&file=Trey%20Research%
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=923a6ce1-7b67-4bd0-a59f-89d37f233804&guidWeb=c12486eb-661c-46c7-baba-073a8a45b610&guidFile=%7B743A
iconUrl: '',
activity: {
title: 'Modified, January 15 2017',
actorName: 'Alex Wilber',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=alexw@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'XT1000 Marketing Analysis',
url: 'https://contoso-my.sharepoint.com/personal/henriettam_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BA8B9F935-E5A1-47AD-B052-D5ED30E682AB%7D&file=XT1000%20Ma
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=b187e1dd-7687-49e0-87ff-6250e61e56ac&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BA8B9
iconUrl: '',
activity: {
title: 'Modified, December 15 2016',
actorName: 'Henrietta Mueller',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=henriettam@contoso.onmicrosoft.com&size=L'
}
}
];

// ...
}

3. Change the render method to load and render the information about the recently modified documents:

export default class RecentDocumentsWebPart extends BaseClientSideWebPart<IRecentDocumentsWebPartProps> {


// ...
public render(): void {
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'documents');

window.setTimeout((): void => {


const element: React.ReactElement<IRecentDocumentsProps> = React.createElement(
RecentDocuments,
{
documents: RecentDocumentsWebPart.documents.slice(0, 3)
}
);

this.context.statusRenderer.clearLoadingIndicator(this.domElement);
ReactDom.render(element, this.domElement);
}, 300);
}
// ...
}

4. Verify that the web part is working correctly and shows information about the three most recently modified documents by running the following command from a command prompt
in your project directory:

gulp serve

5. In the SharePoint Workbench, add the Recent Documents web part to the canvas.
Show the most recently modified document
The Recent Document web part shows information about the most recently modified document.

Add the second web part


To illustrate sharing data between web parts, add a second web part to the project.
1. Using a command prompt in the project folder, run the SharePoint Framework Yeoman generator.
yo @microsoft/sharepoint

2. When prompted, enter the following values:


WebPart as the type of client-side component to create.
Recent document as your web part name.
Shows information about the most recently modified document as your web part description.

Remove the standard description property


1. Remove the description property from the IRecentDocumentWebPartProps interface. In the code editor, open the
./src/webparts/recentDocument/IRecentDocumentWebPartProps.ts file, and paste the following code:

export interface IRecentDocumentWebPartProps {


}

2. Remove the standard description property from the web part manifest. Open the ./src/webparts/recentDocument/RecentDocumentWebPart.manifest.json file, and from the
properties property, remove the description property:

{
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",

"id": "71a6f643-1ac1-47ee-a9f1-502ef52f26d4",
"alias": "RecentDocumentWebPart",
"componentType": "WebPart",
"version": "0.0.1",
"manifestVersion": 2,

"preconfiguredEntries": [{
"groupId": "71a6f643-1ac1-47ee-a9f1-502ef52f26d4",
"group": { "default": "Under Development" },
"title": { "default": "Recent document" },
"description": { "default": "Shows information about the most recently modified document" },
"officeFabricIconFontName": "Page",
"properties": {
}
}]
}

3. Remove the standard description property from the web part property pane. In the code editor, open the ./src/webparts/recentDocument/RecentDocumentWebPart.ts file, and
replace its render method with the following code:

export default class RecentDocumentWebPart extends BaseClientSideWebPart<IRecentDocumentWebPartProps> {


// ...
public render(): void {
const element: React.ReactElement<IRecentDocumentProps> = React.createElement(
RecentDocument,
{
}
);

ReactDom.render(element, this.domElement);
}
// ...
}

4. Replace its getPropertyPaneConfiguration method with the following code:


export default class RecentDocumentWebPart extends BaseClientSideWebPart<IRecentDocumentWebPartProps> {
// ...

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: []
}
]
}
]
};
}
}

Reuse the IDocument and IDocumentActivity interfaces


The Recent Document web part displays information about the most recently modified document in a different way than the Recent Documents web part, but both web parts use the same
data structure representing a document. Instead of duplicating the IDocument and IDocumentActivity interfaces, you can reuse them across both web parts.
1. In Visual Studio Code, activate the Explorer pane, and from the ./src/webparts/recentDocuments folder, move the IDocument.ts and IDocumentActivity.ts files one level up, to
the ./src/webparts folder.

Having moved the files to another location in your project, you need to update the paths where they're referenced.
2. In the code editor, open the ./src/webparts/recentDocuments/components/IRecentDocumentsProps.ts file, and change its code to:

import { IDocument } from '../../IDocument';

export interface IRecentDocumentsProps {


documents: IDocument[];
}

3. Open the ./src/webparts/recentDocuments/components/RecentDocuments.tsx file, and update the import statement of the IDocument interface to:

import { IDocument } from '../../IDocument';

4. Open the ./src/webparts/recentDocuments/RecentDocumentsWebPart.ts file, and update the import statement of the IDocument interface to:

import { IDocument } from '../IDocument';

Show the most recent document in the RecentDocument React component


1. Add the document property to the IRecentDocumentProps interface. In the code editor, open the ./src/webparts/recentDocument/components/IRecentDocumentProps.ts file,
and paste the following code:

import { IDocument } from '../../IDocument';

export interface IRecentDocumentProps {


document: IDocument;
}

2. In the code editor, open the ./src/webparts/recentDocument/components/RecentDocument.tsx file, and paste the following code:

import * as React from 'react';


import {
DocumentCard,
DocumentCardPreview,
DocumentCardTitle,
DocumentCardActivity,
ImageFit
} from 'office-ui-fabric-react';
import { IDocument } from '../../IDocument';
import styles from './RecentDocument.module.scss';
import { IRecentDocumentProps } from './IRecentDocumentProps';

export default class RecentDocument extends React.Component<IRecentDocumentProps, void> {


public render(): React.ReactElement<IRecentDocumentProps> {
const document: IDocument = this.props.document;

return (
<div className={styles.helloWorld}>
<DocumentCard onClickHref={document.url}>
<DocumentCardPreview previewImages={[{
name: document.title,
url: document.url,
previewImageSrc: document.imageUrl,
iconSrc: document.iconUrl,
imageFit: ImageFit.cover,
width: 318,
height: 196,
accentColor: '#ce4b1f'
}]} />
<DocumentCardTitle
title={document.title}
shouldTruncate={true} />
<DocumentCardActivity
activity={document.activity.title}
people={
[
{ name: document.activity.actorName, profileImageSrc: document.activity.actorImageUrl }
]
}
/>
</DocumentCard>
</div>
);
}
}

The RecentDocument React component uses the information about the most recently modified document passed in the document property to render an Office UI Fabric DocumentCard.

Load the information about the recent document


In this example, the information about the most recently modified document is loaded from a static data set. You could, however, easily change this implementation to load the data from a
SharePoint document library instead.
1. In the code editor, open the ./src/webparts/recentDocument/RecentDocumentWebPart.ts file. Add an import statement for the IDocument interface under the other import
statements at the top of the file by using the following code:

import { IDocument } from '../IDocument';

2. In the RecentDocumentWebPart class, add a new private variable named document by using the following code:

export default class RecentDocumentWebPart extends BaseClientSideWebPart<IRecentDocumentWebPartProps> {


private static document: IDocument = {
title: 'Proposal for Jacksonville Expansion Ad Campaign',
url: 'https://contoso-my.sharepoint.com/personal/miriamg_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BCBF65183-0378-485B-AB67-791E0FC81D72%7D&file=Jacksonville%20Ad%
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=ca6fa69c-347d-4c07-886c-67105dc5a357&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BCBF65183
iconUrl: '',
activity: {
title: 'Modified, January 25 2017',
actorName: 'Miriam Graham',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=miriamg@contoso.onmicrosoft.com&size=L'
}
};

// ...
}

3. Change the render method to load and render the information about the most recently modified document:
export default class RecentDocumentsWebPart extends BaseClientSideWebPart<IRecentDocumentsWebPartProps> {
// ...
public render(): void {
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'documents');

window.setTimeout((): void => {


const element: React.ReactElement<IRecentDocumentProps> = React.createElement(
RecentDocument,
{
document: RecentDocumentWebPart.document
}
);

this.context.statusRenderer.clearLoadingIndicator(this.domElement);
ReactDom.render(element, this.domElement);
}, 300);
}
// ...
}

4. Verify that the web part is working correctly and shows information about the most recently modified document by running the following command from a command prompt in your
project folder:

gulp serve

5. In the SharePoint Workbench, add the Recent Document web part to the canvas.

The current implementation is a typical example of two web parts being developed independently. If they were both placed on the same page and were loading data from SharePoint, they
would execute two separate requests to retrieve similar information. If, at some point, you had to change where the information about the recently modified documents is loaded from, you
would have to update both web parts.
To improve the performance of loading the page and simplify maintaining the web part code, you can centralize the logic of retrieving the data and make the once retrieved data available to
both web parts.

Centralize loading data


To centralize loading the information about recently modified documents, build a service that is referenced by both web parts.

Move the data model interfaces


1. In the project folder, create the ./src/services/documentsService folder path.
2. From the ./src/webparts folder, move the IDocument.ts and IDocumentActivity.ts files to the ./src/services/documentsService folder.
Build the data access service
In the ./src/services/documentsService folder, create a new file named DocumentsService.ts, and paste the following code:
import { IDocument } from './IDocument';

export class DocumentsService {


private static documents: IDocument[] = [
{
title: 'Proposal for Jacksonville Expansion Ad Campaign',
url: 'https://contoso-my.sharepoint.com/personal/miriamg_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BCBF65183-0378-485B-AB67-791E0FC81D72%7D&file=Jacksonville%20Ad
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=ca6fa69c-347d-4c07-886c-67105dc5a357&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BCBF6518
iconUrl: '',
activity: {
title: 'Modified, January 25 2017',
actorName: 'Miriam Graham',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=miriamg@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'Customer Feedback for ZT1000',
url: 'https://contoso-my.sharepoint.com/personal/miriamg_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7B5449CE24-BFB7-442E-843D-E0C86CEB71CC%7D&file=Customer%20Feedba
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=ca6fa69c-347d-4c07-886c-67105dc5a357&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7B5449CE2
iconUrl: '',
activity: {
title: 'Modified, January 23 2017',
actorName: 'Miriam Graham',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=miriamg@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'Asia Q3 Marketing Overview',
url: 'https://contoso-my.sharepoint.com/personal/alexw_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BFD077A94-AB7D-45F9-A810-36229E518A94%7D&file=Asia%20Q3%20Marketi
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=18231116-2bf0-474c-93ee-eb362681b293&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BFD077A9
iconUrl: '',
activity: {
title: 'Modified, January 23 2017',
actorName: 'Alex Wilber',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=alexw@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'Trey Research Business Development Plan',
url: 'https://contoso.sharepoint.com/sites/contoso/Resources/Document%20Center/_layouts/15/WopiFrame.aspx?sourcedoc=%7B743A6C44-D3F8-4ECC-A1B7-EA9844911314%7D&file=Trey%20Research%20B
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=923a6ce1-7b67-4bd0-a59f-89d37f233804&guidWeb=c12486eb-661c-46c7-baba-073a8a45b610&guidFile=%7B743A6C4
iconUrl: '',
activity: {
title: 'Modified, January 15 2017',
actorName: 'Alex Wilber',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=alexw@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'XT1000 Marketing Analysis',
url: 'https://contoso-my.sharepoint.com/personal/henriettam_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BA8B9F935-E5A1-47AD-B052-D5ED30E682AB%7D&file=XT1000%20Marke
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=b187e1dd-7687-49e0-87ff-6250e61e56ac&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BA8B9F93
iconUrl: '',
activity: {
title: 'Modified, December 15 2016',
actorName: 'Henrietta Mueller',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=henriettam@contoso.onmicrosoft.com&size=L'
}
}
];

public static getRecentDocument(): Promise<IDocument> {


return new Promise<IDocument>((resolve: (document: IDocument) => void, reject: (error: any) => void): void => {
window.setTimeout((): void => {
resolve(DocumentsService.documents[0]);
}, 300);
});
}

public static getRecentDocuments(startFrom: number = 0): Promise<IDocument[]> {


return new Promise<IDocument[]>((resolve: (documents: IDocument[]) => void, reject: (error: any) => void): void => {
window.setTimeout((): void => {
resolve(DocumentsService.documents.slice(startFrom, startFrom + 3));
}, 300);
});
}
}

The DocumentsService class is a sample service that loads information about recent documents. In this example, it uses a static data set, but you could easily change its implementation to
load its data from a SharePoint document library. At this stage, the DocumentsService class offers a centralized point for all web parts to access their data, but it doesn't store the previously
loaded data. You will implement that later in this tutorial.

Create a barrel for the service files


When referencing files in a project, you point to their relative path. Whenever that path changes, you have to update all references to the particular file. Such changes are very likely at the
beginning of the project when the different elements are being added and the final project structure is unclear. To avoid frequent changes to file references in a project, you can use barrels.
A barrel is a container that combines a number of exported objects. By using barrels, you can abstract away the exact location of files from other elements in the project that are using them.
In the ./src/services/documentsService folder, create a new file named index.ts, and paste the following code:

export { IDocument } from './IDocument';


export { IDocumentActivity } from './IDocumentActivity';
export { DocumentsService } from './DocumentsService';

With this barrel defined, other elements in the project can reference any of the exported types by using the relative path to the ./src/services/documentsService folder instead of the exact
path to the individual files. For example, the IDocument interface can be referenced like this:
import { IDocument } from '../services/documentsService';

instead of:

import { IDocument } from '../services/documentsService/IDocument.ts';

If at some point you decided that it's better to move the IDocument.ts file to a subfolder or merge a few files together, the only thing that you would change is the path in the barrel
definition (./src/services/documentsService/index.ts). All elements in the project could still use the exact same relative path to the documentsService folder to reference the IDocument
interface.

Update references to the moved files to use the barrel


Because you have moved the IDocument.ts and IDocumentActivity.ts files to another location, you have to update their references. Thanks to the barrel, this is the last time that you have
to do this.
Update references in the Recent Documents web part
1. In the code editor, open the ./src/webparts/recentDocuments/components/IRecentDocumentsProps.ts file, and change its code to:

import { IDocument } from '../../../services/documentsService';

export interface IRecentDocumentsProps {


documents: IDocument[];
}

2. Open the ./src/webparts/recentDocuments/components/RecentDocuments.tsx file, and change the import statement of the IDocument interface to:

import { IDocument } from '../../../services/documentsService';

3. Open the ./src/webparts/recentDocuments/RecentDocumentsWebPart.ts file, and change the import statement of the IDocument interface to:

import { IDocument } from '../../services/documentsService';

Update references in the Recent Document web part


1. In the code editor, open the ./src/webparts/recentDocument/components/IRecentDocumentProps.ts file, and change its code to:

import { IDocument } from '../../../services/documentsService';

export interface IRecentDocumentProps {


document: IDocument;
}

2. Open the ./src/webparts/recentDocument/components/RecentDocument.tsx file, and change the import statement of the IDocument interface to:

import { IDocument } from '../../../services/documentsService';

3. Open the ./src/webparts/recentDocument/RecentDocumentWebPart.ts file, and change the import statement of the IDocument interface to:

import { IDocument } from '../../services/documentsService';

4. Verify that your changes work as expected, by running the following command from a command prompt in your project folder:

gulp serve
Load web part data by using the data service
With the data service ready, the next step is to refactor both web parts to use the data service to load their data.
Load information about the recently modified documents
1. In the code editor, open the ./src/webparts/recentDocuments/RecentDocumentsWebPart.ts file. Expand the import statement referencing the IDocument interface to:

import { IDocument, DocumentsService } from '../../services/documentsService';

2. Update the render method by using the following code:

export default class RecentDocumentsWebPart extends BaseClientSideWebPart<IRecentDocumentsWebPartProps> {


// ...
public render(): void {
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'documents');

DocumentsService.getRecentDocuments()
.then((documents: IDocument[]): void => {
const element: React.ReactElement<IRecentDocumentsProps> = React.createElement(
RecentDocuments,
{
documents: documents
}
);

this.context.statusRenderer.clearLoadingIndicator(this.domElement);
ReactDom.render(element, this.domElement);
});
}
// ...
}

Load information about the most recently modified document


1. In the code editor, open the ./src/webparts/recentDocument/RecentDocumentWebPart.ts file. Expand the import statement referencing the IDocument interface to:

import { IDocument, DocumentsService } from '../../services/documentsService';

2. Update the render method by using the following code:


export default class RecentDocumentWebPart extends BaseClientSideWebPart<IRecentDocumentWebPartProps> {
// ...
public render(): void {
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'document');

DocumentsService.getRecentDocument()
.then((document: IDocument): void => {
const element: React.ReactElement<IRecentDocumentProps> = React.createElement(
RecentDocument,
{
document: document
}
);

this.context.statusRenderer.clearLoadingIndicator(this.domElement);
ReactDom.render(element, this.domElement);
});
}
// ...
}

3. Confirm that both web parts are working correctly by running the following command from a command prompt in your project folder:

gulp serve

Share data between web parts


Now that both web parts use the data service to load their data, the next step is to extend the data service so that it loads the data only once and reuses it for both web parts.
1. In the code editor, open the ./src/services/documentsService/DocumentsService.ts file, and paste the following code:

import { IDocument } from './IDocument';

export class DocumentsService {


private static documents: IDocument[] = [
{
title: 'Proposal for Jacksonville Expansion Ad Campaign',
url: 'https://contoso-my.sharepoint.com/personal/miriamg_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BCBF65183-0378-485B-AB67-791E0FC81D72%7D&file=Jacksonville%2
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=ca6fa69c-347d-4c07-886c-67105dc5a357&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BCBF6
iconUrl: '',
activity: {
title: 'Modified, January 25 2017',
actorName: 'Miriam Graham',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=miriamg@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'Customer Feedback for ZT1000',
url: 'https://contoso-my.sharepoint.com/personal/miriamg_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7B5449CE24-BFB7-442E-843D-E0C86CEB71CC%7D&file=Customer%20Fee
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=ca6fa69c-347d-4c07-886c-67105dc5a357&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7B5449
iconUrl: '',
activity: {
title: 'Modified, January 23 2017',
actorName: 'Miriam Graham',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=miriamg@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'Asia Q3 Marketing Overview',
url: 'https://contoso-my.sharepoint.com/personal/alexw_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BFD077A94-AB7D-45F9-A810-36229E518A94%7D&file=Asia%20Q3%20Mark
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=18231116-2bf0-474c-93ee-eb362681b293&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BFD07
iconUrl: '',
activity: {
title: 'Modified, January 23 2017',
actorName: 'Alex Wilber',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=alexw@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'Trey Research Business Development Plan',
url: 'https://contoso.sharepoint.com/sites/contoso/Resources/Document%20Center/_layouts/15/WopiFrame.aspx?sourcedoc=%7B743A6C44-D3F8-4ECC-A1B7-EA9844911314%7D&file=Trey%20Research%
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=923a6ce1-7b67-4bd0-a59f-89d37f233804&guidWeb=c12486eb-661c-46c7-baba-073a8a45b610&guidFile=%7B743A
iconUrl: '',
activity: {
title: 'Modified, January 15 2017',
actorName: 'Alex Wilber',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=alexw@contoso.onmicrosoft.com&size=L'
}
},
{
title: 'XT1000 Marketing Analysis',
url: 'https://contoso-my.sharepoint.com/personal/henriettam_contoso_onmicrosoft_com/_layouts/15/WopiFrame.aspx?sourcedoc=%7BA8B9F935-E5A1-47AD-B052-D5ED30E682AB%7D&file=XT1000%20Ma
imageUrl: 'https://contoso-my.sharepoint.com/_layouts/15/getpreview.ashx?guidSite=b187e1dd-7687-49e0-87ff-6250e61e56ac&guidWeb=237a3f3f-59a4-46e8-b0a8-6effd78bd327&guidFile=%7BA8B9
iconUrl: '',
activity: {
title: 'Modified, December 15 2016',
actorName: 'Henrietta Mueller',
actorImageUrl: 'https://contoso-my.sharepoint.com/_vti_bin/DelveApi.ashx/people/profileimage?userId=henriettam@contoso.onmicrosoft.com&size=L'
}
}
];

public static getRecentDocument(): Promise<IDocument> {


return new Promise<IDocument>((resolve: (document: IDocument) => void, reject: (error: any) => void): void => {
DocumentsService.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments[0]);
});
});
}

public static getRecentDocuments(startFrom: number = 0): Promise<IDocument[]> {


return new Promise<IDocument[]>((resolve: (documents: IDocument[]) => void, reject: (error: any) => void): void => {
DocumentsService.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments.slice(startFrom, startFrom + 3));
});
});
}

private static ensureRecentDocuments(): Promise<IDocument[]> {


return new Promise<IDocument[]>((resolve: (recentDocuments: IDocument[]) => void, reject: (error: any) => void): void => {
if ((window as any).loadedData) {
// data already loaded. reuse
resolve((window as any).loadedData);
return;
}

if ((window as any).loadingData) {
// data is being loaded. wait a moment and try again
window.setTimeout((): void => {
DocumentsService.ensureRecentDocuments()
.then((recentDocuments: IDocument[]): void => {
resolve(recentDocuments);
});
}, 100);
}
else {
(window as any).loadingData = true;
window.setTimeout((): void => {
// store the data for subsequent requests and resolve the Promise
(window as any).loadedData = DocumentsService.documents;
(window as any).loadingData = false;
resolve((window as any).loadedData);
}, 300);
}
});
}
}

The first time a web part calls the data service to load its data, the service sets the loadingData global variable to true . This indicates that data is currently being loaded. This is
required to prevent data from being loaded multiple times should, for instance, another web part request loading its data while the initial request to load data has not yet completed. In
this example, the data is loaded from a static data set, but you could easily change the implementation to load the data from a SharePoint document library.
After the data is loaded, it is stored in the loadedData global variable. The value of the loadingData variable is set to false and the promise is resolved with the retrieved data. The
next time a web part requests its data, the data service returns the data loaded previously, eliminating any additional requests to the remote APIs.
2. Confirm that both web parts are working correctly by running the following command from a command prompt in your project folder:

gulp serve

3. If you were to add logging statements in the different parts of the DocumentsService.ensureRecentDocuments method, you would see that the data is loaded once and reused for the
second web part.
See also
Share data between client-side web parts
Build custom controls for the property pane
5/3/2018 • 18 minutes to read Edit Online

The SharePoint Framework contains a set of standard controls for the property pane. But sometimes you need additional functionality beyond the basic controls. You might need
asynchronous updates to the data on a control or a specific user interface. Build a custom control for the property pane to get the functionality you need.
In this article, you will build a custom dropdown control that loads its data asynchronously from an external service without blocking the user interface of the web part.

The source of the working web part is available on GitHub at sp-dev-fx-webparts/samples/react-custompropertypanecontrols/.


NOTE

Before following the steps in this article, be sure to set up your development environment for building SharePoint Framework solutions.

Create new project


1. Start by creating a new folder for your project:

md react-custompropertypanecontrol

2. Go to the project folder:

cd react-custompropertypanecontrol

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:

yo @microsoft/sharepoint

4. When prompted, enter the following values:


react-custompropertypanecontrol as your solution name
Use the current folder for the location to place the files
List items as your web part name
Shows list items from the selected list as your web part description
React as the starting point to build the web part
5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer.

Define web part property for storing the selected list


The web part you are building shows list items from the selected SharePoint list. Users are able to select a list in the web part properties. To store the selected list, create a new web part
property named listName.
1. In the code editor, open the src/webparts/listItems/ListItemsWebPartManifest.json file. Replace the default description property with a new property named listName .
2. Open the src/webparts/listItems/IListItemsWebPartProps.ts file and replace its contents with:

export interface IListItemsWebPartProps {


listName: string;
}

3. In the src/webparts/listItems/ListItemsWebPart.ts file, change the render method to:

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
public render(): void {
const element: React.ReactElement<IListItemsProps> = React.createElement(ListItems, {
listName: this.properties.listName
});

ReactDom.render(element, this.domElement);
}
// ...
}

4. Update the getPropertyPaneConfiguration method to:

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('listName', {
label: strings.ListFieldLabel
})
]
}
]
}
]
};
}
// ...
}

5. In the src/webparts/listItems/loc/mystrings.d.ts file, change the IListItemsWebPartStrings interface to:

declare interface IListItemsWebPartStrings {


PropertyPaneDescription: string;
BasicGroupName: string;
ListFieldLabel: string;
}

6. In the src/webparts/listItems/loc/en-us.js file, add the missing definition for the ListFieldLabel string.
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListFieldLabel": "List"
}
});

7. In the src/webparts/listItems/components/ListItems.tsx file, change the contents of the render method to:

export default class ListItems extends React.Component<IListItemsProps, {}> {


public render(): React.ReactElement<IListItemsProps> {
return (
<div className={styles.listItems}>
<div className={styles.container}>
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className="ms-Grid-col ms-lg10 ms-xl8 ms-xlPush2 ms-lgPush1">
<span className="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
<p className="ms-font-l ms-fontColor-white">Customize SharePoint experiences using web parts.</p>
<p className="ms-font-l ms-fontColor-white">{escape(this.props.listName)}</p>
<a href="https://aka.ms/spfx" className={styles.button}>
<span className={styles.label}>Learn more</span>
</a>
</div>
</div>
</div>
</div>
);
}
}

8. Open the src/webparts/listItems/components/IListItemsProps.ts file, and replace its contents with:

export interface IListItemsProps {


listName: string;
}

9. Run the following command to verify that the project is running:

gulp serve

10. In the web browser, add the List items web part to the canvas and open its properties. Verify that the value set for the List property is displayed in the web part body.

Create asynchronous dropdown property pane control


The SharePoint Framework offers you a standard dropdown control that allows users to select a specific value. The dropdown control is built in a way that requires all its values to be known
upfront. If you want to load the values dynamically or you're loading values asynchronously from an external service and you don't want to block the whole web part, building a custom
dropdown control is a viable option.
When creating a custom property pane control that uses React in the SharePoint Framework, the control consists of a class that registers the control with the web part, and a React
component that renders the dropdown and manages its data.
NOTE

In drop 6 of the SharePoint Framework, there is a bug in the Office UI Fabric React Dropdown component that causes the control built in this article to work incorrectly. A temporary
workaround is to edit the node_modules/@microsoft/office-ui-fabric-react-bundle/dist/office-ui-fabric-react.bundle.js file and change line 12027 from:
isDisabled: this.props.isDisabled !== undefined ? this.props.isDisabled : this.props.disabled

to:

isDisabled: newProps.isDisabled !== undefined ? newProps.isDisabled : newProps.disabled

Add asynchronous dropdown property pane control React component


1. Create the components folder. In the project src folder, create a hierarchy of three new folders so that your folder structure appears as
src/controls/PropertyPaneAsyncDropdown/components.

2. Define asynchronous dropdown React component properties. In the src/controls/PropertyPaneAsyncDropdown/components folder, create a new file named
IAsyncDropdownProps.ts, and enter the following code:

import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';

export interface IAsyncDropdownProps {


label: string;
loadOptions: () => Promise<IDropdownOption[]>;
onChanged: (option: IDropdownOption, index?: number) => void;
selectedKey: string | number;
disabled: boolean;
stateKey: string;
}

The IAsyncDropdownProps class defines properties that can be set on the React component used by the custom property pane control:
The label property specifies the label for the dropdown control.
The function associated with the loadOptions delegate is called by the control to load the available options.
The function associated with the onChanged delegate is called after the user selects an option in the dropdown.
The selectedKey property specifies the selected value, which can be a string or a number.
The disabled property specifies if the dropdown control is disabled or not.
The stateKey property is used to force the React component to re-render.
3. Define asynchronous dropdown React component interface. In the src/controls/PropertyPaneAsyncDropdown/components folder, create a new file named
IAsyncDropdownState.ts, and enter the following code:

import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';

export interface IAsyncDropdownState {


loading: boolean;
options: IDropdownOption[];
error: string;
}

The IAsyncDropdownState interface describes the state of the React component:


The loading property determines if the component is loading its options at the given moment.
The options property contains all available options.
If an error occurred, it is assigned to the error property from where it is communicated to the user.
4. Define the asynchronous dropdown React component. In the src/controls/PropertyPaneAsyncDropdown/components folder, create a new file named AsyncDropdown.tsx, and
enter the following code:
import * as React from 'react';
import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
import { Spinner } from 'office-ui-fabric-react/lib/components/Spinner';
import { IAsyncDropdownProps } from './IAsyncDropdownProps';
import { IAsyncDropdownState } from './IAsyncDropdownState';

export default class AsyncDropdown extends React.Component<IAsyncDropdownProps, IAsyncDropdownState> {


private selectedKey: React.ReactText;

constructor(props: IAsyncDropdownProps, state: IAsyncDropdownState) {


super(props);
this.selectedKey = props.selectedKey;

this.state = {
loading: false,
options: undefined,
error: undefined
};
}

public componentDidMount(): void {


this.loadOptions();
}

public componentDidUpdate(prevProps: IAsyncDropdownProps, prevState: IAsyncDropdownState): void {


if (this.props.disabled !== prevProps.disabled ||
this.props.stateKey !== prevProps.stateKey) {
this.loadOptions();
}
}

private loadOptions(): void {


this.setState({
loading: true,
error: undefined,
options: undefined
});

this.props.loadOptions()
.then((options: IDropdownOption[]): void => {
this.setState({
loading: false,
error: undefined,
options: options
});
}, (error: any): void => {
this.setState((prevState: IAsyncDropdownState, props: IAsyncDropdownProps): IAsyncDropdownState => {
prevState.loading = false;
prevState.error = error;
return prevState;
});
});
}

public render(): JSX.Element {


const loading: JSX.Element = this.state.loading ? <div><Spinner label={'Loading options...'} /></div> : <div />;
const error: JSX.Element = this.state.error !== undefined ? <div className={'ms-TextField-errorMessage ms-u-slideDownIn20'}>Error while loading items: {this.state.error}</div> : <div />;

return (
<div>
<Dropdown label={this.props.label}
disabled={this.props.disabled || this.state.loading || this.state.error !== undefined}
onChanged={this.onChanged.bind(this)}
selectedKey={this.selectedKey}
options={this.state.options} />
{loading}
{error}
</div>
);
}

private onChanged(option: IDropdownOption, index?: number): void {


this.selectedKey = option.key;
// reset previously selected options
const options: IDropdownOption[] = this.state.options;
options.forEach((o: IDropdownOption): void => {
if (o.key !== option.key) {
o.selected = false;
}
});
this.setState((prevState: IAsyncDropdownState, props: IAsyncDropdownProps): IAsyncDropdownState => {
prevState.options = options;
return prevState;
});
if (this.props.onChanged) {
this.props.onChanged(option, index);
}
}
}

The AsyncDropdown class represents the React component used to render the asynchronous dropdown property pane control:
When the component first loads, the componentDidMount method, or its disabled or stateKey properties, change, and it loads the available options by calling the
loadOptions method passed through the properties.
After the options are loaded, the component updates its state showing the available options.
The dropdown itself is rendered by using the Office UI Fabric React dropdown component.
When the component is loading the available options, it displays a spinner by using the Office UI Fabric React spinner component.
The next step is to define the custom property pane control. This control is used inside the web part when defining properties in the property pane, and renders using the previously defined
React component.
Add asynchronous dropdown property pane control
1. Define asynchronous dropdown property pane control properties. A custom property pane control has two sets of properties.
The first set of properties are exposed publicly and are used to define the web part property inside the web part. These properties are component-specific properties, such as the label
displayed next to the control, minimum and maximum values for a spinner, or available options for a dropdown. When defining a custom property pane control, the type describing
these properties must be passed as the TProperties type when implementing the IPropertyPaneField<TProperties> interface.
The second set of properties are private properties used internally inside the custom property pane control. These properties have to adhere to the SharePoint Framework APIs for
the custom control to render correctly. These properties must implement the IPropertyPaneCustomFieldProps interface from the @microsoft/sp-webpart-base package.
2. Define the public properties for the asynchronous dropdown property pane control. In the src/controls/PropertyPaneAsyncDropdown folder, create a new file named
IPropertyPaneAsyncDropdownProps.ts, and enter the following code:

import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';

export interface IPropertyPaneAsyncDropdownProps {


label: string;
loadOptions: () => Promise<IDropdownOption[]>;
onPropertyChange: (propertyPath: string, newValue: any) => void;
selectedKey: string | number;
disabled?: boolean;
}

In the IPropertyPaneAsyncDropdownProps interface:


The label property defines the label displayed next to the dropdown.
The loadOptions delegate defines the method that is called to load the available dropdown options.
The onPropertyChange delegate defines a method that is called when the user selects a value in the dropdown.
The selectedKey property returns the selected dropdown value.
The disabled property specifies whether the control is disabled or not.
3. Define the internal properties for the asynchronous dropdown property pane control. In the src/controls/PropertyPaneAsyncDropdown folder, create a new file named
IPropertyPaneAsyncDropdownInternalProps.ts, and enter the following code:

import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-webpart-base';


import { IPropertyPaneAsyncDropdownProps } from './IPropertyPaneAsyncDropdownProps';

export interface IPropertyPaneAsyncDropdownInternalProps extends IPropertyPaneAsyncDropdownProps, IPropertyPaneCustomFieldProps {


}

While the IPropertyPaneAsyncDropdownInternalProps interface doesn't define any new properties, it combines the properties from the previously defined
IPropertyPaneAsyncDropdownProps interface and the standard SharePoint Framework IPropertyPaneCustomFieldProps interface, which is required for a custom control to
run correctly.
4. Define the asynchronous dropdown property pane control. In the src/controls/PropertyPaneAsyncDropdown folder, create a new file named PropertyPaneAsyncDropdown.ts,
and enter the following code:
import * as React from 'react';
import * as ReactDom from 'react-dom';
import {
IPropertyPaneField,
PropertyPaneFieldType
} from '@microsoft/sp-webpart-base';
import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
import { IPropertyPaneAsyncDropdownProps } from './IPropertyPaneAsyncDropdownProps';
import { IPropertyPaneAsyncDropdownInternalProps } from './IPropertyPaneAsyncDropdownInternalProps';
import AsyncDropdown from './components/AsyncDropdown';
import { IAsyncDropdownProps } from './components/IAsyncDropdownProps';

export class PropertyPaneAsyncDropdown implements IPropertyPaneField<IPropertyPaneAsyncDropdownProps> {


public type: PropertyPaneFieldType = PropertyPaneFieldType.Custom;
public targetProperty: string;
public properties: IPropertyPaneAsyncDropdownInternalProps;
private elem: HTMLElement;

constructor(targetProperty: string, properties: IPropertyPaneAsyncDropdownProps) {


this.targetProperty = targetProperty;
this.properties = {
key: properties.label,
label: properties.label,
loadOptions: properties.loadOptions,
onPropertyChange: properties.onPropertyChange,
selectedKey: properties.selectedKey,
disabled: properties.disabled,
onRender: this.onRender.bind(this)
};
}

public render(): void {


if (!this.elem) {
return;
}

this.onRender(this.elem);
}

private onRender(elem: HTMLElement): void {


if (!this.elem) {
this.elem = elem;
}

const element: React.ReactElement<IAsyncDropdownProps> = React.createElement(AsyncDropdown, {


label: this.properties.label,
loadOptions: this.properties.loadOptions,
onChanged: this.onChanged.bind(this),
selectedKey: this.properties.selectedKey,
disabled: this.properties.disabled,
// required to allow the component to be re-rendered by calling this.render() externally
stateKey: new Date().toString()
});
ReactDom.render(element, elem);
}

private onChanged(option: IDropdownOption, index?: number): void {


this.properties.onPropertyChange(this.targetProperty, option.key);
}
}

The PropertyPaneAsyncDropdown class implements the standard SharePoint Framework IPropertyPaneField interface by using the IPropertyPaneAsyncDropdownProps
interface as a contract for its public properties that can be set from inside the web part. The class contains the following three public properties defined by the IPropertyPaneField
interface:
type: Must be set to PropertyPaneFieldType.Custom for a custom property pane control.
targetProperty: Used to specify the name of the web part property to be used with the control.
properties: Used to define control-specific properties.
Notice how the properties property is of the internal IPropertyPaneAsyncDropdownInternalProps type rather than the public IPropertyPaneAsyncDropdownProps interface
implemented by the class. This is on purpose so that the properties property can define the onRender method required by the SharePoint Framework. If the onRender method was
a part of the public IPropertyPaneAsyncDropdownProps interface, when using the asynchronous dropdown control in the web part, you would be required to assign a value to it
inside the web part, which isn't desirable.
The PropertyPaneAsyncDropdown class defines a public render method, which can be used to repaint the control. This is useful in situations such as when you have cascading
dropdowns where the value set in one determines the options available in another. By calling the render method after selecting an item, you can have the dependent dropdown load
available options. For this to work, you have to make React detect that the control has changed. This is done by setting the value of the stateKey to the current date. Using this trick,
every time the onRender method is called, the component not only is re-rendered but also updates its available options.

Use the asynchronous dropdown property pane control in the web part
With the asynchronous dropdown property pane control ready, the next step is to use it inside the web part, allowing users to select a list.

Add list info interface


To pass information about available lists around in a consistent manner, define an interface that represents information about a list. In the src/webparts/listItems folder, create a new file
named IListInfo.ts, and enter the following code:

export interface IListInfo {


Id: string;
Title: string;
}

Use the asynchronous dropdown property pane control to render the listName web part property
1. Reference required types. In the top section of the src/webparts/listItems/ListItemsWebPart.ts file, import the previously created PropertyPaneAsyncDropdown class by
adding:
import { PropertyPaneAsyncDropdown } from '../../controls/PropertyPaneAsyncDropdown/PropertyPaneAsyncDropdown';

2. After that code, add a reference to the IDropdownOption interface and two helpers functions required to work with web part properties.

import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';


import { update, get } from '@microsoft/sp-lodash-subset';

3. Add method to load available lists. In the ListItemsWebPart class, add a method to load available lists. In this article you use mock data, but you could also call the SharePoint REST
API to retrieve the list of available lists from the current web. To simulate loading options from an external service, the method uses a two second delay.

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
private loadLists(): Promise<IDropdownOption[]> {
return new Promise<IDropdownOption[]>((resolve: (options: IDropdownOption[]) => void, reject: (error: any) => void) => {
setTimeout(() => {
resolve([{
key: 'sharedDocuments',
text: 'Shared Documents'
},
{
key: 'myDocuments',
text: 'My Documents'
}]);
}, 2000);
});
}
}

4. Add method to handle the change of the value in the dropdown. In the ListItemsWebPart class, add a new method named onListChange.

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
private onListChange(propertyPath: string, newValue: any): void {
const oldValue: any = get(this.properties, propertyPath);
// store new value in web part properties
update(this.properties, propertyPath, (): any => { return newValue; });
// refresh web part
this.render();
}
}

After selecting a list in the list dropdown, the selected value should be persisted in web part properties, and the web part should be re-rendered to reflect the selected property.
5. Render the list web part property by using the asynchronous dropdown property pane control. In the ListItemsWebPart class, change the getPropertyPaneConfiguration method
to use the asynchronous dropdown property pane control to render the listName web part property.

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
new PropertyPaneAsyncDropdown('listName', {
label: strings.ListFieldLabel,
loadOptions: this.loadLists.bind(this),
onPropertyChange: this.onListChange.bind(this),
selectedKey: this.properties.listName
})
]
}
]
}
]
};
}
// ...
}

6. At this point, you should be able to select a list by using the newly created asynchronous dropdown property pane control. To verify that the control is working as expected, open the
command-line and run:

gulp serve
Implement cascading dropdowns using the asynchronous dropdown property pane control
When building SharePoint Framework web parts, you might need to implement a configuration where the available options depend on another option chosen previously. A common
example is to first let users choose a list and from that list select a list item. The list of available items would depend on the selected list. Here is how to implement such a scenario by using
the asynchronous dropdown property pane control implemented in previous steps.

Add item web part property


1. In the code editor, open the src/webparts/listItems/ListItemsWebPart.manifest.json file. To the properties section, add a new property named item so that it appears as follows:

// ...
"properties": {
"listName": "",
"item": ""
}
// ...

2. Change the code in the src/webparts/listItems/IListItemsWebPartProps.ts file to:

export interface IListItemsWebPartProps {


listName: string;
item: string;
}

3. Change the contents of the src/webparts/listItems/components/IListItemsProps.ts file to:


export interface IListItemsProps {
listName: string;
item: string;
}

4. In the src/webparts/listItems/ListItemsWebPart.ts file, change the code of the render method to:

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
public render(): void {
const element: React.ReactElement<IListItemsProps> = React.createElement(ListItems, {
listName: this.properties.listName,
item: this.properties.item
});

ReactDom.render(element, this.domElement);
}
// ...
}

5. In the src/webparts/listItems/loc/mystrings.d.ts file, change the IListItemsWebPartStrings interface to:

declare interface IListItemsWebPartStrings {


PropertyPaneDescription: string;
BasicGroupName: string;
ListFieldLabel: string;
ItemFieldLabel: string;
}

6. In the src/webparts/listItems/loc/en-us.js file, add the missing definition for the ItemFieldLabel string:

define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListFieldLabel": "List",
"ItemFieldLabel": "Item"
}
});

Render the value of the item web part property


In the src/webparts/listItems/components/ListItems.tsx file, change the render method to:

export default class ListItems extends React.Component<IListItemsProps, {}> {


public render(): React.ReactElement<IListItemsProps> {
return (
<div className={styles.listItems}>
<div className={styles.container}>
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className="ms-Grid-col ms-lg10 ms-xl8 ms-xlPush2 ms-lgPush1">
<span className="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
<p className="ms-font-l ms-fontColor-white">Customize SharePoint experiences using web parts.</p>
<p className="ms-font-l ms-fontColor-white">{escape(this.props.listName)}</p>
<p className="ms-font-l ms-fontColor-white">{escape(this.props.item)}</p>
<a href="https://aka.ms/spfx" className={styles.button}>
<span className={styles.label}>Learn more</span>
</a>
</div>
</div>
</div>
</div>
);
}
}

Add method to load list items


In the src/webparts/listItems/ListItemsWebPart.ts file, in the ListItemsWebPart class, add a new method to load available list items from the selected list. Like the method for loading
available lists, you use mock data. Depending on the previously selected list, the loadItems method returns mock list items. When no list has been selected, the method resolves the promise
without any data.
export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
// ...
private loadItems(): Promise<IDropdownOption[]> {
if (!this.properties.listName) {
// resolve to empty options since no list has been selected
return Promise.resolve();
}

const wp: ListItemsWebPart = this;

return new Promise<IDropdownOption[]>((resolve: (options: IDropdownOption[]) => void, reject: (error: any) => void) => {
setTimeout(() => {
const items = {
sharedDocuments: [
{
key: 'spfx_presentation.pptx',
text: 'SPFx for the masses'
},
{
key: 'hello-world.spapp',
text: 'hello-world.spapp'
}
],
myDocuments: [
{
key: 'isaiah_cv.docx',
text: 'Isaiah CV'
},
{
key: 'isaiah_expenses.xlsx',
text: 'Isaiah Expenses'
}
]
};
resolve(items[wp.properties.listName]);
}, 2000);
});
}
}

Add method to handle the selection of an item


In the ListItemsWebPart class, add a new method named onListItemChange. After selecting an item in the items dropdown, the web part should store the new value in web part
properties and re-render the web part to reflect the changes in the user interface.

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
private onListItemChange(propertyPath: string, newValue: any): void {
const oldValue: any = get(this.properties, propertyPath);
// store new value in web part properties
update(this.properties, propertyPath, (): any => { return newValue; });
// refresh web part
this.render();
}
}

Render the item web part property in the property pane


1. In the ListItemsWebPart class, add a new class property named itemsDropdown:

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


private itemsDropDown: PropertyPaneAsyncDropdown;
// ...
}

2. Change the code of the getPropertyPaneConfiguration method to:


export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
// ...
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
// reference to item dropdown needed later after selecting a list
this.itemsDropDown = new PropertyPaneAsyncDropdown('item', {
label: strings.ItemFieldLabel,
loadOptions: this.loadItems.bind(this),
onPropertyChange: this.onListItemChange.bind(this),
selectedKey: this.properties.item,
// should be disabled if no list has been selected
disabled: !this.properties.listName
});

return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
new PropertyPaneAsyncDropdown('listName', {
label: strings.ListFieldLabel,
loadOptions: this.loadLists.bind(this),
onPropertyChange: this.onListChange.bind(this),
selectedKey: this.properties.listName
}),
this.itemsDropDown
]
}
]
}
]
};
}
// ...
}

The dropdown for the item property is initialized similarly to the dropdown for the listName property. The only difference is because after selecting a list, the items dropdown has to
be refreshed, an instance of the control has to be assigned to the class variable.

Load items for the selected list


Initially when no list is selected, the items dropdown is disabled and becomes enabled after the user selects a list. After selecting a list, the items dropdown also loads list items from that list.
1. To implement this logic, extend the previously defined onListChange method to:

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
private onListChange(propertyPath: string, newValue: any): void {
const oldValue: any = get(this.properties, propertyPath);
// store new value in web part properties
update(this.properties, propertyPath, (): any => { return newValue; });
// reset selected item
this.properties.item = undefined;
// store new value in web part properties
update(this.properties, 'item', (): any => { return this.properties.item; });
// refresh web part
this.render();
// reset selected values in item dropdown
this.itemsDropDown.properties.selectedKey = this.properties.item;
// allow to load items
this.itemsDropDown.properties.disabled = false;
// load items and re-render items dropdown
this.itemsDropDown.render();
}
// ...
}

After selecting a list, the selected item is reset, persisted in web part properties, and reset in the items dropdown. The dropdown for selecting an item becomes enabled, and the
dropdown is refreshed in order to load its options.
2. To verify that everything is working as expected, in the command-line run:

gulp serve

After adding the web part to the page for the first time and opening its property pane, you should see both dropdowns disabled and loading their options.
After the options have been loaded, the list dropdown becomes enabled. Because no list has been selected yet, the item dropdown remains disabled.

After selecting a list in the list dropdown the item dropdown will load items available in that list.
After the available items have been loaded, the item dropdown becomes enabled.

After selecting an item in the item dropdown the web part is refreshed showing the selected item in its body.
See also
Use cascading dropdowns in web part properties
Use cascading dropdowns in web part properties
5/3/2018 • 13 minutes to read Edit Online

When designing the property pane for your SharePoint client-side web parts, you may have one web part property that displays its options based on the value selected in another property.
This scenario typically occurs when implementing cascading dropdown controls. In this article, you learn how to create cascading dropdown controls in the web part property pane without
developing a custom property pane control.

The source of the working web part is available on GitHub at sp-dev-fx-webparts/samples/react-custompropertypanecontrols/.


NOTE

Before following the steps in this article, be sure to set up your SharePoint client-side web part development environment.

Create new project


1. Start by creating a new folder for your project:

md react-cascadingdropdowns

2. Go to the project folder:

cd react-cascadingdropdowns

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:

yo @microsoft/sharepoint

4. When prompted, enter the following values:


react-cascadingdropdowns as your solution name
Use the current folder for the location to place the files
React as the starting point to build the web part
List items as your web part name
Shows list items from the selected list as your web part description
5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer.

Define a web part property to store the selected list


You will build a web part that displays list items from a selected SharePoint list. Users are able to select a list in the web part property pane. To store the selected list, create a new web part
property named listName.
1. In the code editor, open the src/webparts/listItems/ListItemsWebPartManifest.json file. Replace the default description property with a new property named listName .
2. Open the src/webparts/listItems/IListItemsWebPartProps.ts file, and replace its contents with:

export interface IListItemsWebPartProps {


listName: string;
}

3. In the src/webparts/listItems/ListItemsWebPart.ts file, change the render method to:

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
public render(): void {
const element: React.ReactElement<IListItemsProps> = React.createElement(ListItems, {
listName: this.properties.listName
});

ReactDom.render(element, this.domElement);
}
// ...
}

4. Update propertyPaneSettings to:

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('listName', {
label: strings.ListNameFieldLabel
})
]
}
]
}
]
};
}
// ...
}

5. In the src/webparts/listItems/loc/mystrings.d.ts file, change the IListItemsStrings interface to:

declare interface IListItemsStrings {


PropertyPaneDescription: string;
BasicGroupName: string;
ListNameFieldLabel: string;
}

6. In the src/webparts/listItems/loc/en-us.js file, add the missing definition for the ListNameFieldLabel string:
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListNameFieldLabel": "List"
}
});

7. In the src/webparts/listItems/components/ListItems.tsx file, change the contents of the render method to:

export default class ListItems extends React.Component<IListItemsProps, {}> {


public render(): JSX.Element {
return (
<div className={styles.listItems}>
<div className={styles.container}>
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span className="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
<p className="ms-font-l ms-fontColor-white">Customize SharePoint experiences using web parts.</p>
<p className="ms-font-l ms-fontColor-white">{escape(this.props.listName)}</p>
<a href="https://aka.ms/spfx" className={styles.button}>
<span className={styles.label}>Learn more</span>
</a>
</div>
</div>
</div>
</div>
);
}
}

8. In the src/webparts/listItems/components/IListItemsProps.ts file, change the IListItemsProps interface to:

export interface IListItemsProps {


listName: string;
}

9. Run the following command to verify that the project is running:

gulp serve

10. In the web browser, add the List items web part to the canvas and open its properties. Verify that the value set for the List property is displayed in the web part body.

Populate the dropdown with SharePoint lists to choose from


At this point, a user specifies which list the web part should use by manually entering the list name. This is error-prone, and ideally you want users to choose one of the lists existing in the
current SharePoint site.

Use dropdown control to render the listName property


1. In the ListItemsWebPart class, add a reference to the PropertyPaneDropdown class in the top section of the web part. Replace the import clause that loads the
PropertyPaneTextField class with:

import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
PropertyPaneDropdown,
IPropertyPaneDropdownOption
} from '@microsoft/sp-webpart-base';

2. In the ListItemsWebPart class, add a new variable named lists to store information about all available lists in the current site:

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


private lists: IPropertyPaneDropdownOption[];
// ...
}
3. Add a new class variable named listsDropdownDisabled. This variable determines whether the list dropdown is enabled or not. Until the web part retrieves the information about
the lists available in the current site, the dropdown should be disabled.

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
private listsDropdownDisabled: boolean = true;
// ...
}

4. Change the propertyPaneSettings getter to use the dropdown control to render the listName property:

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
protected get propertyPaneSettings(): IPropertyPaneSettings {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneDropdown('listName', {
label: strings.ListNameFieldLabel,
options: this.lists,
disabled: this.listsDropdownDisabled
})
]
}
]
}
]
};
}
}

5. Run the following command to verify that it's working as expected:

gulp serve

Show available lists in the list dropdown


Previously, you associated the dropdown control of the listName property with the lists class property. Because you haven't loaded any values into it yet, the List dropdown in the web part
property pane remains disabled. In this section, you will extend the web part to load the information about available lists.
1. In the ListItemsWebPart class, add a method to load available lists. You will use mock data, but you could also call the SharePoint REST API to retrieve the list of available lists from
the current web. To simulate loading options from an external service, the method uses a two-second delay.

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
private loadLists(): Promise<IPropertyPaneDropdownOption[]> {
return new Promise<IPropertyPaneDropdownOption[]>((resolve: (options: IPropertyPaneDropdownOption[]) => void, reject: (error: any) => void) => {
setTimeout((): void => {
resolve([{
key: 'sharedDocuments',
text: 'Shared Documents'
},
{
key: 'myDocuments',
text: 'My Documents'
}]);
}, 2000);
});
}
}

2. Load information about available lists into the list dropdown. In the ListItemsWebPart class, override the onPropertyPaneConfigurationStart method by using the following code:
export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
// ...
protected onPropertyPaneConfigurationStart(): void {
this.listsDropdownDisabled = !this.lists;

if (this.lists) {
return;
}

this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'lists');

this.loadLists()
.then((listOptions: IPropertyPaneDropdownOption[]): void => {
this.lists = listOptions;
this.listsDropdownDisabled = false;
this.context.propertyPane.refresh();
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
this.render();
});
}
// ...
}

The onPropertyPaneConfigurationStart method is called by the SharePoint Framework after the web part property pane for the web part has been opened.
First, the method checks if the information about the lists available in the current site has been loaded.
If the list information is loaded, the list dropdown is enabled.
If the list information about lists has not been loaded yet, the loading indicator is displayed, which informs the user that the web part is loading information about lists.

After the information about available lists has been loaded, the method assigns the retrieved data to the lists class variable, from which it can be used by the list dropdown.
Next, the dropdown is enabled allowing the user to select a list. By calling this.context.propertyPane.refresh(), the web part property pane is refreshed and it reflects the latest
changes to the list dropdown.
After list information is loaded, the loading indicator is removed by a call to the clearLoadingIndicator method. Because calling this method clears the web part user interface, the
render method is called to force the web part to re-render.
3. Run the following command to confirm that everything is working as expected:

gulp serve

When you add a web part to the canvas and open its property pane, you should see the lists dropdown filled with available lists for the user to choose from.
Allow users to select an item from the selected list
When building web parts, you often need to allow users to choose an option from a set of values determined by a previously selected value, such as choosing a country/region based on the
selected continent, or choosing a list item from a selected list. This user experience is often referred to as cascading dropdowns. Using the standard SharePoint Framework client-side web
parts capabilities, you can build cascading dropdowns in the web part property pane. To do this, you extend the previously built web part with the ability to choose a list item based on the
previously selected list.

Add item web part property


1. In the code editor, open the src/webparts/listItems/ListItemsWebPart.manifest.json file. To the properties section, add a new property named itemName so that it appears as
follows:

{
// ...
"properties": {
"listName": "",
"itemName": ""
}
// ...
}
2. Change the code in the src/webparts/listItems/IListItemsWebPartProps.ts file to:

export interface IListItemsWebPartProps {


listName: string;
itemName: string;
}

3. Change the code in the src/webparts/listItems/components/IListItemsProps.ts file to:

export interface IListItemsProps {


listName: string;
itemName: string;
}

4. In the src/webparts/listItems/ListItemsWebPart.ts file, change the code of the render method to:

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
public render(): void {
const element: React.ReactElement<IListItemsProps> = React.createElement(ListItems, {
listName: this.properties.listName,
itemName: this.properties.itemName
});

ReactDom.render(element, this.domElement);
}
// ...
}

5. In the src/webparts/listItems/loc/mystrings.d.ts file, change the IListItemsStrings interface to:

declare interface IListItemsStrings {


PropertyPaneDescription: string;
BasicGroupName: string;
ListNameFieldLabel: string;
ItemNameFieldLabel: string;
}

6. In the src/webparts/listItems/loc/en-us.js file, add the missing definition for the ItemNameFieldLabel string.

define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListNameFieldLabel": "List",
"ItemNameFieldLabel": "Item"
}
});

Render the value of the item web part property


In the src/webparts/listItems/components/ListItems.tsx file, change the render method to:
export default class ListItems extends React.Component<IListItemsProps, {}> {
public render(): JSX.Element {
return (
<div className={styles.listItems}>
<div className={styles.container}>
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span className="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
<p className="ms-font-l ms-fontColor-white">Customize SharePoint experiences using web parts.</p>
<p className="ms-font-l ms-fontColor-white">{escape(this.props.listName)}</p>
<p className="ms-font-l ms-fontColor-white">{escape(this.props.itemName)}</p>
<a href="https://aka.ms/spfx" className={styles.button}>
<span className={styles.label}>Learn more</span>
</a>
</div>
</div>
</div>
</div>
);
}
}

Allow users to choose the item from a list


Similar to how users can select a list by using a dropdown, they should be able to select the item from the list of available items.
1. In the ListItemsWebPart class, add a new variable named items, which you use to store information about all available items in the currently selected list.

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
private items: IPropertyPaneDropdownOption[];
// ...
}

2. Add a new class variable named itemsDropdownDisabled. This variable determines whether the items dropdown should be enabled or not. Users should be able to select an item
only after they selected a list.

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
private itemsDropdownDisabled: boolean = true;
// ...
}

3. Change the propertyPaneSettings getter to use the dropdown control to render the itemName property.

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneDropdown('listName', {
label: strings.ListNameFieldLabel,
options: this.lists,
disabled: this.listsDropdownDisabled
}),
PropertyPaneDropdown('itemName', {
label: strings.ItemNameFieldLabel,
options: this.items,
disabled: this.itemsDropdownDisabled
})
]
}
]
}
]
};
}
}

4. Run the following command to verify that it's working as expected:

gulp serve
Show items available in the selected list in the item dropdown
Previously, you defined a dropdown control to render the itemName property in the web part property pane. Next, you extend the web part to load the information about items available in
the selected list, and show the items in the item dropdown.
1. Add method to load list items. In the src/webparts/listItems/ListItemsWebPart.ts file, in the ListItemsWebPart class, add a new method to load available list items from the
selected list. (Like the method for loading available lists, you use mock data.)

export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {


// ...
private loadItems(): Promise<IPropertyPaneDropdownOption[]> {
if (!this.properties.listName) {
// resolve to empty options since no list has been selected
return Promise.resolve();
}

const wp: ListItemsWebPart = this;

return new Promise<IPropertyPaneDropdownOption[]>((resolve: (options: IPropertyPaneDropdownOption[]) => void, reject: (error: any) => void) => {
setTimeout(() => {
const items = {
sharedDocuments: [
{
key: 'spfx_presentation.pptx',
text: 'SPFx for the masses'
},
{
key: 'hello-world.spapp',
text: 'hello-world.spapp'
}
],
myDocuments: [
{
key: 'isaiah_cv.docx',
text: 'Isaiah CV'
},
{
key: 'isaiah_expenses.xlsx',
text: 'Isaiah Expenses'
}
]
};
resolve(items[wp.properties.listName]);
}, 2000);
});
}
}

The loadItems method returns mock list items for the previously selected list. When no list has been selected, the method resolves the promise without any data.
2. Load information about available items into the item dropdown. In the ListItemsWebPart class, extend the onPropertyPaneConfigurationStart method to load items for the
selected list:
export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
// ...
protected onPropertyPaneConfigurationStart(): void {
this.listsDropdownDisabled = !this.lists;
this.itemsDropdownDisabled = !this.properties.listName || !this.items;

if (this.lists) {
return;
}

this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'options');

this.loadLists()
.then((listOptions: IPropertyPaneDropdownOption[]): Promise<IPropertyPaneDropdownOption[]> => {
this.lists = listOptions;
this.listsDropdownDisabled = false;
this.context.propertyPane.refresh();
return this.loadItems();
})
.then((itemOptions: IPropertyPaneDropdownOption[]): void => {
this.items = itemOptions;
this.itemsDropdownDisabled = !this.properties.listName;
this.context.propertyPane.refresh();
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
this.render();
});
}
// ...
}

When initializing, the web part first determines if the items dropdown should be enabled or not. If the user previously selected a list, they can select an item from that list. If no list was
selected, the item dropdown is disabled.
You extended the previously defined code, which loads the information about available lists, to load the information about items available in the selected list. The code then assigns the
retrieved information to the items class variable for use by the item dropdown. Finally, the code clears the loading indicator and allows the user to start working with the web part.
3. Run the following command to confirm that everything is working as expected:

gulp serve

As required, initially the item dropdown is disabled, requiring users to select a list first. But at this point, even after a list has been selected, the item dropdown remains disabled.

4. Update web part property pane after selecting a list. When a user selects a list in the property pane, the web part should update, enabling the item dropdown and showing the list of
items available in the selected list.
In the ListItemsWebPart.ts file, in the ListItemsWebPart class, override the onPropertyPaneFieldChanged method with the following code:
export default class ListItemsWebPart extends BaseClientSideWebPart<IListItemsWebPartProps> {
// ...
protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
if (propertyPath === 'listName' &&
newValue) {
// push new list value
super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
// get previously selected item
const previousItem: string = this.properties.itemName;
// reset selected item
this.properties.itemName = undefined;
// push new item value
this.onPropertyPaneFieldChanged('itemName', previousItem, this.properties.itemName);
// disable item selector until new items are loaded
this.itemsDropdownDisabled = true;
// refresh the item selector control by repainting the property pane
this.context.propertyPane.refresh();
// communicate loading items
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'items');

this.loadItems()
.then((itemOptions: IPropertyPaneDropdownOption[]): void => {
// store items
this.items = itemOptions;
// enable item selector
this.itemsDropdownDisabled = false;
// clear status indicator
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
// re-render the web part as clearing the loading indicator removes the web part body
this.render();
// refresh the item selector control by repainting the property pane
this.context.propertyPane.refresh();
});
}
else {
super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
}
}
// ...
}

After the user selected a list, the web part persists the newly selected value. Because the selected list changed, the web part resets the previously selected list item. Now that a list is
selected, the web part property pane loads list items for that particular list. While loading items, the user shouldn't be able to select an item.
After the items for the selected list are loaded, they are assigned to the items class variable from where they can be referenced by the item dropdown. Now that the information about
available list items is available, the item dropdown is enabled allowing users to choose an item. The loading indicator is removed, which clears the web part body which is why the web
part should re-render. Finally, the web part property pane refreshes to reflect the latest changes.
NOTE

In drop 6 of the SharePoint Framework there is a bug in the Office UI Fabric React Dropdown component that causes the dropdown control to work incorrectly. A temporary
workaround is to edit the node_modules/@microsoft/office-ui-fabric-react-bundle/dist/office-ui-fabric-react.bundle.js file and change line 12027 from:

isDisabled: this.props.isDisabled !== undefined ? this.props.isDisabled : this.props.disabled

to:

isDisabled: newProps.isDisabled !== undefined ? newProps.isDisabled : newProps.disabled

See also
Build custom controls for the property pane
Migrate existing Script Editor web part customizations to the SharePoint Framework
5/3/2018 • 17 minutes to read Edit Online

SharePoint Framework is a model for building SharePoint customizations. If you have been building client-side SharePoint solutions by using the Script Editor web part, you might be
wondering what the possible advantages are of migrating them to the SharePoint Framework.
This article highlights the benefits of migrating existing client-side customizations to the SharePoint Framework and points out a number of considerations that you should take into account
when planning the migration.
NOTE

The information in this article applies to customizations built using both the Content- and the Script Editor web part. Wherever there is a reference to the Script Editor web part, you should
read Content Editor web part and Script Editor Web Part.

Benefits of migrating existing client-side customizations to the SharePoint Framework


SharePoint Framework has been built from the ground up as a SharePoint development model focusing on client-side development. While it primarily offers extensibility capabilities for
modern team sites, customizations built on the SharePoint Framework also work with the classic SharePoint experience. Building your customizations by using the SharePoint Framework
offers you a number of benefits over using any other SharePoint development model available to date.

Build once, reuse across all devices


The modern SharePoint user experience has been designed to natively support access to information stored in SharePoint on any device. Additionally, the modern experience supports the
SharePoint mobile app. Solutions built using the SharePoint Framework seamlessly integrate with the modern SharePoint experience and can be used across the different devices as well as
inside the SharePoint mobile app. Because SharePoint Framework solutions also work with the classic SharePoint experience, they can be used by organizations that haven't migrated to the
modern experience yet.

More robust and future-proof


In the past, developers were customizing SharePoint by attaching to specific DOM elements in the user interface. Using this approach, they could change the standard user experience or
provide additional functionality to end users. Such solutions were however error-prone. Because the SharePoint page DOM was never meant as an extensibility surface, whenever it changed,
solutions relying on it would break.
SharePoint Framework offers developers standardized API and extensibility points to build client-side solutions and provide end-users with additional capabilities. Developers can use the
SharePoint Framework to build solutions in a supported and future-proof way, and don't need to be concerned with how future changes to the SharePoint user interface could affect your
solution.

Easier access to information in SharePoint and Office 365


Microsoft is continuously extending capabilities of SharePoint and Office 365. As organizations make more use of both platforms, it's becoming increasingly important for developers to be
able to tap into the information and insights stored in Office 365 to build rich solutions. One of the goals of the SharePoint Framework is to make it easy for developers to connect to various
SharePoint and Office 365 APIs.

Enable users to configure solutions to their needs


Client-side solutions built through script embedding often didn't offer end-users an easy way to configure them to their needs. The only way to configure such solution, was by altering its
code or through a custom user interface built specifically for that purpose.
SharePoint Framework client-side web parts offer a standard way for configuring web parts using a property pane - familiar to users who worked with classic web parts in the past.
Developers building client-side web parts can choose whether their web part should have a reactive property pane (default), where each change to a web part property is directly reflected in
the web part body, or a non-reactive property pane, where changes to web part properties must be explicitly applied.

Work on no-script sites


To help organizations govern their customizations, Microsoft released the no-script capability in SharePoint Online. When the tenant or a particular site collection has the no-script flag
enabled, customizations relying on script injection and embedding are disabled.
Because SharePoint Framework client-side web parts are deployed through the app catalog with a prior approval, they are allowed to run in no-script sites. By default, modern team sites
have the no-script setting enabled and it's not possible to embed scripts in these sites. This makes using the SharePoint Framework the only supported way to build client-side
customizations in modern team sites.

Similarities between SharePoint Framework solutions and Script Editor web part customizations
While built on a new development model using a new toolchain, SharePoint Framework solutions are similar to the Script Editor web part customizations you have built in the past. Because
they share the same concepts, it makes it easier for you to migrate them to the new SharePoint Framework.

Run as a part of the page


Similar to customizations embedded in Script Editor web parts, SharePoint Framework solutions are part of the page. This gives these solutions access to the page's DOM and allows them
to communicate with other components on the same page. Also, it allows developers to more easily make their solutions responsive to adapt to the different form factors on which a
SharePoint page could be displayed, including the SharePoint mobile app.
Unlike SharePoint Add-ins, SharePoint Framework client-side web parts are not isolated in an iframe. As a consequence, whatever resources the particular client-side web part has access to,
other elements on the page can access as well. This is important to keep in mind when building solutions that rely on OAuth implicit flow with bearer access tokens or use cookies or browser
storage for storing sensitive information. Because client-side web parts run as a part of the page, other elements on that page are able to access all these resources as well.

Use any library to build your web part


When building customizations using the Script Editor web part, you might have used libraries such as jQuery or Knockout to make your customization dynamic and better respond to user
interaction. When building SharePoint Framework client-side web parts, you can use any client-side library to enrich your solution, the same way you would have done it in the past. An
additional benefit that the SharePoint Framework offers you is isolation of your script. Even though the web part is executed as a part of the page, its script is packaged as a module allowing,
for example, different web parts on the same page to use a different version of jQuery without colliding with each other. This is a powerful feature that allows you to focus on delivering
business value instead of technical migrations and compromising on functionality.

Run as the current user


In customizations built using the Script Editor web part, whenever you needed to communicate with SharePoint, all you had to do was to call its API. The client-side solution was running in
the browser in the context of the current user, and by automatically sending the authentication cookie along with the request, your solution could directly connect to SharePoint. No
additional authentication, such as when using SharePoint Add-ins, was necessary to communicate with SharePoint. The same mechanism applies to customizations built on the SharePoint
Framework that also run under the context of the currently authenticated user and also don't require any additional authentication steps to communicate with SharePoint.

Use only client-side code


Both SharePoint Framework and Script Editor web part solutions run in the browser and can contain only client-side JavaScript code. Client-side solutions have a number of limitations, such
as not being able to elevate permissions in SharePoint or reach out to external APIs that don't support cross-origin communication (CORS) or authentication using OAuth implicit flow. In
such cases, the client-side solution could leverage a remote server-side API to perform the necessary operation and return the results to the client.

Host solution in SharePoint


One of the benefits of building SharePoint customizations using Script Editor web parts was the fact that their code could be hosted in a regular SharePoint document library. Compared to
SharePoint Add-ins, it required less infrastructure and simplified hosting the solution. Additionally, organizations could use SharePoint permissions to control access to the solution files.
While hosting SharePoint Framework solutions on a CDN offers a number of advantages, it is not required, and you could choose to host their code in a regular SharePoint document
library. SharePoint Framework packages (.sppkg files) deployed to the app catalog specify the URL at which SharePoint Framework can find the solution's code. There are no restrictions with
regards to what that URL must be, as long as the user browsing the page with the web part on it can download the script from the specified location.
Office 365 offers the public CDN capability that allows you to publish files from a specific SharePoint document library to a CDN. Office 365 public CDN strikes a nice balance between the
benefits of using a CDN and the simplicity of hosting code files in a SharePoint document library. If your organization doesn't mind their code files being publicly available, using the Office
365 public CDN is an option worth considering.

Differences between SharePoint Framework solutions and Script Editor web part customizations
SharePoint customizations built using the SharePoint Framework and Script Editor web part are very similar. They all run as a part of the page under the context of the current user and are
built using client-side JavaScript. But there are also some significant differences that might influence your architectural decisions and which you should keep in mind when designing your
solution.

Run in no-script sites


When building client-side customizations using the Script Editor web part, you had to take into account whether the site where the customization would be used was a no-script site or not. If
the site was a no-script site, you either had to request the admin to disable the no-script setting or build your solution differently, for example, by using the add-in model.
Because SharePoint Framework solutions are deployed through the app catalog with a prior approval, they are not subject to the no-script restrictions and work on all sites.

Deployed and updated through IT


Script Editor web parts are used to build SharePoint customizations primarily by citizen developers. With nothing more than site owner permissions, citizen developers can build compelling
SharePoint customizations that add business value. Whenever the customization needs to be updated, users with the necessary permissions can apply updates to the solution's script files
and the changes are immediately visible to all users.
Script Editor web part solutions make it hard for IT organizations to keep track of what customizations are being used and where they are being used. Additionally, organizations can't tell
which external scripts are being used in their intranet and have access to their data.
SharePoint Framework gives the control back to the IT. Because SharePoint Framework solutions are deployed and managed centrally in the app catalog, organizations have the opportunity
to review the solution before deploying it. Additionally, any updates are deployed via the app catalog as well, allowing organizations to verify and approve them before deployment.

Focus more on uniform user experience


When building customizations using the Script Editor web part, citizen developers owned the complete DOM of their customization. There were no guidelines related to the user experience
and how such customization should work. As a result, different developers built customizations in different ways, which led to an inconsistent user experience for end users.
One of the goals of the SharePoint Framework is to standardize building client-side customizations so that they are uniform from the deployment, maintenance, and user experience point of
view. Using Office UI Fabric, developers can more easily make their custom solutions look and behave like they are an integral part of SharePoint, simplifying user adoption. SharePoint
Framework toolchain generates package files for the solutions that are deployed to the app catalog, and script bundles that are deployed to the hosting location of your choice. Every solution
is structured and managed in the same way.

Don't modify DOM outside of the customization


Script Editor web parts were frequently used in the past to modify parts of the page, such as adding buttons to the toolbar or changing the heading or branding of the page. Such
customizations relied on the existence of specific DOM elements, and whenever SharePoint UI would be updated, there was a chance that such customization would break.
SharePoint Framework encourages a more structured and reliable approach to customizing SharePoint. Rather than using specific DOM elements to customize SharePoint, SharePoint
Framework provides developers with a public API that they can use to extend SharePoint. Client-side web parts are the only shape supported by the SharePoint Framework, but other
shapes, such as equivalents of JSLink and User Custom Actions, are being taken into consideration for the future so that developers can implement the most common customization
scenarios by using the SharePoint Framew../ork.

Distributed as packages
SharePoint client-side customizations often used SharePoint lists and libraries to store their data. When built using the Script Editor web part, there was no easy way to automatically
provision the necessary prerequisites. Deploying the same customization to another site often meant copying the web part but also correctly recreating and maintaining the necessary data
storage.
SharePoint Framework solutions are distributed as packages capable of provisioning their prerequisites, such as fields, content types, or lists, automatically. Developers building the package
can specify which artifacts are required by the solution, and whenever it's installed in a site, the specified artifacts are created. This significantly simplifies the process of deploying and
managing the solution on multiple sites.

Use TypeScript for building more robust and easier to maintain solutions
When building customizations using the Script Editor web part, citizen developers often used plain JavaScript. Often such solutions didn't contain any automated tests, and refactoring the
code was error-prone.
SharePoint Framework allows developers to benefit from the TypeScript type system when building solutions. Thanks to the type system, errors are caught during development rather than
on runtime. Also, refactoring code can be done more easily as changes to the code are safeguarded by TypeScript. Because all JavaScript is valid TypeScript, the entry barrier is low and you
can migrate your plain JavaScript to TypeScript gradually over time increasing the maintainability of your solution.

Can't rely on the spPageContextInfo object


When building reusable client-side customizations, in the past developers used the spPageContextInfo JavaScript object to get information about the current page, site, or user. This object
offered them an easy way to make their solution reusable across the different sites in SharePoint and not have to use fixed URLs.
While the spPageContextInfo object is still present on classic SharePoint pages, it cannot be reliably used with modern SharePoint pages and libraries. When building solutions on the
SharePoint Framework, developers are recommended to use the IWebPartContext.pageContext object instead, which contains the context information for the particular solution.
No access to SharePoint JavaScript Object Model by default
When building client-side customizations for the classic SharePoint user experience, many developers used the JavaScript Object Model (JSOM) to communicate with SharePoint. JSOM
offered them intellisense and easy access to the SharePoint API in a way similar to the Client-Side Object Model (CSOM). In classic SharePoint pages, the core piece of JSOM was by default
present on the page, and developers could load additional pieces to communicate with SharePoint Search, for example.
The modern SharePoint user experience doesn't include SharePoint JSOM by default. While developers can load it themselves, the recommendation is to use the REST API instead. Using
REST is more universal and interchangeable between the different client-side libraries such as jQuery, Angular, or React.
Microsoft is not actively investing in JSOM anymore. If you prefer working with an API, you could alternatively use the SharePoint Patterns and Practices JavaScript Core Library, which
offers you a fluent API and TypeScript typings.

Migrate existing customization to the SharePoint Framework


Migrating existing Script Editor web part customizations to the SharePoint Framework offers both end-users and developers a number of benefits. When considering migrating existing
customizations to the SharePoint Framework, you can choose to either reuse as much of the existing scripts as possible or completely rewrite the customization.

Reuse existing scripts


When migrating existing Script Editor web part customizations to the SharePoint Framework, you can choose to reuse your existing scripts. Even though the SharePoint Framework
encourages using TypeScript, you can use plain JavaScript and gradually transform it to TypeScript. If you need to support a particular solution for a limited period of time or have a limited
budget, this approach might be good enough for you.
Reusing existing scripts in a SharePoint Framework solution is not always possible. SharePoint Framework solutions, for example, are packaged as JavaScript modules and load
asynchronously on a page. Some JavaScript libraries don't work correctly when referenced in a module or have to be referenced in a specific way. Additionally, relying on page events such as
onload or using the jQuery ready function might lead to undesirable results.

Given the variety of JavaScript libraries, there is no easy way to tell upfront if your existing scripts can be reused in a SharePoint Framework solution or if you need to rewrite it after all. The
only way to determine this is by trying to move the different pieces to a SharePoint Framework solution and see if they work as expected.

Rewrite the customization


If you need to support your solution for a longer period of time, would like to make better use of the SharePoint Framework, or if it turns out that your existing scripts cannot be reused with
the SharePoint Framework, you might need to completely rewrite your customization. While it's more costly than reusing existing scripts, it offers you better results over a longer period of
time: a solution that is better performing, and easier to maintain and use.
When rewriting an existing Script Editor web part customization to a SharePoint Framework solution, you should start with the desired functionality in mind. For implementing the user
experience, you should consider using the Office UI Fabric so that your solution looks like an integral part of SharePoint. For specific components such as charts or sliders, you should try
looking for modern libraries that are distributed as modules and have TypeScript typings. This makes it easier for you to integrate the component in your solution.
While there is no single answer as to which component is the best to use for which scenario, the SharePoint Framework is flexible enough to accommodate most popular scenarios, and you
should be able to transform your existing client-side customizations into fully-featured SharePoint Framework solutions.

Migration tips
When transforming existing Script Editor web part customizations to the SharePoint Framework, there are a few common patterns.
Move existing code to SharePoint Framework
SharePoint customizations built using the Script Editor web part often consist of some HTML markup, included in the web part, and one or more references to JavaScript files. When
transforming your existing customization to a SharePoint Framework solution, the HTML markup from the Script Editor web part would most likely have to be moved to the render method
of the SharePoint Framework client-side web part. References to external scripts would be changed to references in the externals property in the config.json file. Internal scripts would be
copied to the web part source folder and referenced from the web part class by using require() statements.
Reference functions from script files
To reference functions from script files, these functions need to be defined as an export. Consider an existing JavaScript file that you would like to use in a SharePoint Framework client-side
web part:

var greeting = function() {


alert('How are you doing?');
return false;
}

To be able to call the greeting function from the web part class, you would need to change the JavaScript file to:

var greeting = function() {


alert('How are you doing?');
return false;
}

module.exports = {
greeting: greeting
};

Then, in the web part class, you can refer to the script and call the greeting function:

public render(): void {


this.domElement.innerHTML = `
<input type="button" value="Click me"/>`;

const myScript = require('./my-script.js');


this.domElement.querySelector('input').addEventListener('click', myScript.greeting);
}

Execute AJAX calls


Many client-side customizations use jQuery for executing AJAX requests for its simplicity and cross-browser compatibility. If this is all that you're using jQuery for, you can execute the AJAX
calls by using the standard HTTP client provided with the SharePoint Framework.
SharePoint Framework offers you two types of HTTP client: the SPHttpClient, meant for executing requests to the SharePoint REST API, and the HttpClient designed for issuing web
requests to other REST APIs. Here is how you would execute a call by using the SPHttpClient to get the title of the current SharePoint site:
this.context.spHttpClient.get(`${this.context.pageContext.web.absoluteUrl}/_api/web?$select=Title`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
})
.then((response: SPHttpClientResponse): Promise<{Title: string}> => {
return response.json();
})
.then((web: {Title: string}): void => {
// web.Title
}, (error: any): void => {
// error
});

See also
Migrate SharePoint JavaScript customizations to SharePoint Framework – reference functions from script files
Migrate SharePoint JavaScript customizations to SharePoint Framework – jQuery AJAX calls and showing data
Migrate jQuery and DataTables solution built using Script Editor web part to SharePoint
Framework
5/3/2018 • 15 minutes to read Edit Online

One of the frequently used jQuery plug-ins is DataTables. With DataTables, you can easily build powerful data overviews of data coming from both SharePoint and external APIs.

List of IT requests built using the Script Editor web part


To illustrate the process of migrating a SharePoint customization using DataTables to the SharePoint Framework, use the following solution that shows an overview of IT support requests
retrieved from a SharePoint list.

The solution is built by using the standard SharePoint Script Editor web part. Following is the code used by the customization.
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://cdn.datatables.net/1.10.15/js/jquery.dataTables.js"></script>
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" />
<table id="requests" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Business unit</th>
<th>Category</th>
<th>Status</th>
<th>Due date</th>
<th>Assigned to</th>
</tr>
</thead>
</table>
<script>
// UMD
(function(factory) {
"use strict";

if (typeof define === 'function' && define.amd) {


// AMD
define(['jquery'], function ($) {
return factory( $, window, document );
});
}
else if (typeof exports === 'object') {
// CommonJS
module.exports = function (root, $) {
if (!root) {
root = window;
}

if (!$) {
$ = typeof window !== 'undefined' ?
require('jquery') :
require('jquery')( root );
}

return factory($, root, root.document);


};
}
else {
// Browser
factory(jQuery, window, document);
}
}
(function($, window, document) {
$.fn.dataTable.render.moment = function (from, to, locale) {
// Argument shifting
if (arguments.length === 1) {
locale = 'en';
to = from;
from = 'YYYY-MM-DD';
}
else if (arguments.length === 2) {
locale = 'en';
}

return function (d, type, row) {


var m = window.moment(d, from, locale, true);

// Order and type get a number value from Moment, everything else
// sees the rendered value
return m.format(type === 'sort' || type === 'type' ? 'x' : to);
};
};
}));
</script>
<script>
$(document).ready(function() {
$('#requests').DataTable({
'ajax': {
'url': "../_api/web/lists/getbytitle('IT Requests')/items?$select=ID,BusinessUnit,Category,Status,DueDate,AssignedTo/Title&$expand=AssignedTo/Title",
'headers': { 'Accept': 'application/json;odata=nometadata' },
'dataSrc': function(data) {
return data.value.map(function(item) {
return [
item.ID,
item.BusinessUnit,
item.Category,
item.Status,
new Date(item.DueDate),
item.AssignedTo.Title
];
});
}
},
columnDefs: [{
targets: 4,
render: $.fn.dataTable.render.moment('YYYY/MM/DD')
}]
});
});
</script>

First, the customization loads the libraries it uses: jQuery, DataTables, and Moment.js (lines 1-4).
Next, it specifies the structure of the table used to present the data (lines 5-16).
After creating the table, it wraps Moment.js into a DataTables plug-in so that dates displayed in the table can be formatted (first script block on lines 17-70).
Finally, the customization uses DataTables to load and present the list of IT support requests. The data is loaded by using AJAX from a SharePoint list (lines 71-96).
Thanks to using DataTables, end users get a powerful solution where they can easily filter, sort, and page through the results without any additional development effort.

Migrate the IT requests overview solution from the Script Editor web part to the SharePoint Framework
NOTE

Before following the steps in this article, be sure to set up your development environment for building SharePoint Framework solutions.
Transforming this customization to the SharePoint Framework offers a number of benefits such as more user-friendly configuration and centralized management of the solution. Following is
a step-by-step description of how you would migrate the solution to the SharePoint Framework. First, you will migrate the solution to the SharePoint Framework with as few changes to the
original code as possible. Later, you will transform the solution's code to TypeScript to benefit from its development-time type safety features.
NOTE

The source code of the project in the different stages of migration is available at Tutorial: Migrate jQuery and DataTables solution built using Script Editor web part to SharePoint Framework

Create new SharePoint Framework project


1. Start by creating a new folder for your project:

md datatables-itrequests

2. Navigate to the project folder:

cd datatables-itrequests

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:

yo @microsoft/sharepoint

4. When prompted, define values as follows:


datatables-itrequests as your solution name
Use the current folder for the location to place the files
No javaScript web framework as the starting point to build the web part
IT requests as your web part name
Shows overview of IT support requests as your web part description
5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. In this tutorial, you will use Visual Studio Code.

Load JavaScript libraries


Similar to the original solution built using the Script Editor web part, first you need to load the JavaScript libraries required by the solution. In SharePoint Framework this usually consists of
two steps: specifying the URL from which the library should be loaded, and referencing the library in the code.
1. Specify the URLs from which libraries should be loaded. In the code editor, open the ./config/config.json file, and change the externals section to:

{
"externals": {
"jquery": "https://code.jquery.com/jquery-1.12.4.min.js",
"datatables.net": "https://cdn.datatables.net/1.10.15/js/jquery.dataTables.min.js",
"moment": "https://momentjs.com/downloads/moment.min.js"
}
}

2. Open the ./src/webparts/itRequests/ItRequestsWebPart.ts file, and after the last import statement add:

import 'jquery';
import 'datatables.net';
import 'moment';

Define data table


Just as in the original solution, the next step is to define the structure of the table used to display the data.
In the code editor, open the ./src/webparts/itRequests/ItRequestsWebPart.ts file, and change the render method to:
export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> {
public render(): void {
this.domElement.innerHTML = `
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" />
<table id="requests" class="display ${styles.helloWorld}" cellspacing="0" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Business unit</th>
<th>Category</th>
<th>Status</th>
<th>Due date</th>
<th>Assigned to</th>
</tr>
</thead>
</table>`;
}
// ...
}

Register Moment.js plugin for DataTables


The next step is to define the Moment.js plug-in for DataTables so that dates in the table can be formatted.
1. In the ./src/webparts/itRequests folder, create a new file named moment-plugin.js, and paste the following code:

// UMD
(function (factory) {
"use strict";

if (typeof define === 'function' && define.amd) {


// AMD
define(['jquery'], function ($) {
return factory($, window, document);
});
}
else if (typeof exports === 'object') {
// CommonJS
module.exports = function (root, $) {
if (!root) {
root = window;
}

if (!$) {
$ = typeof window !== 'undefined' ?
require('jquery') :
require('jquery')(root);
}

return factory($, root, root.document);


};
}
else {
// Browser
factory(jQuery, window, document);
}
}

(function ($, window, document) {


$.fn.dataTable.render.moment = function (from, to, locale) {
// Argument shifting
if (arguments.length === 1) {
locale = 'en';
to = from;
from = 'YYYY-MM-DD';
}
else if (arguments.length === 2) {
locale = 'en';
}

return function (d, type, row) {


var moment = require('moment');
var m = moment(d, from, locale, true);

// Order and type get a number value from Moment, everything else
// sees the rendered value
return m.format(type === 'sort' || type === 'type' ? 'x' : to);
};
};
}));

2. For the web part to load the plug-in, it has to reference the newly created moment-plugin.js file. In the code editor, open the ./src/webparts/itRequests/ItRequestsWebPart.ts file,
and after the last import statement add:

import './moment-plugin';

NOTE

You don't need to include the .js extension when referencing other files. SharePoint Framework automatically resolves the extension for you.

Initiate DataTables and load data


The last step is to include the code that initiates the data table and loads the data from SharePoint.
1. In the ./src/webparts/itRequests folder, create a new file named script.js, and paste the following code:
$(document).ready(function () {
$('#requests').DataTable({
'ajax': {
'url': "../../_api/web/lists/getbytitle('IT Requests')/items?$select=ID,BusinessUnit,Category,Status,DueDate,AssignedTo/Title&$expand=AssignedTo/Title",
'headers': { 'Accept': 'application/json;odata=nometadata' },
'dataSrc': function (data) {
return data.value.map(function (item) {
return [
item.ID,
item.BusinessUnit,
item.Category,
item.Status,
new Date(item.DueDate),
item.AssignedTo.Title
];
});
}
},
columnDefs: [{
targets: 4,
render: $.fn.dataTable.render.moment('YYYY/MM/DD')
}]
});
});

2. To reference this file in the web part, in the code editor, open the ./src/webparts/itRequests/ItRequestsWebPart.ts file, and change the render method to:

export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> {


public render(): void {
this.domElement.innerHTML = `
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" />
<table id="requests" class="display ${styles.helloWorld}" cellspacing="0" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Business unit</th>
<th>Category</th>
<th>Status</th>
<th>Due date</th>
<th>Assigned to</th>
</tr>
</thead>
</table>`;

require('./script');
}
// ...
}

3. Verify that the web part is working as expected in the command line by executing:

gulp serve --nobrowser

Because the web part loads its data from SharePoint, you have to test the web part by using the hosted SharePoint Framework Workbench. Navigate to
https://yourtenant.sharepoint.com/_layouts/workbench.aspx and add the web part to the canvas. You should now see the IT requests displayed by using the DataTables jQuery plug-in.

Add support for configuring the web part through web part properties
In the previous steps, you migrated the IT requests solutions from the Script Editor web part to the SharePoint Framework. While the solution already works as expected, it doesn't use any
of the SharePoint Framework benefits. The name of the list from which IT requests are loaded is included in the code, and the code itself is plain JavaScript, which is harder to refactor than
TypeScript.
The following steps illustrate how to extend the existing solution to allow users to specify the name of the list to load the data from. Later, you transform the code to TypeScript to benefit
from its type safety features.
Define web part property for storing the name of the list
1. Define a web part property to store the name of the list from which IT requests should be loaded. In the code editor, open the
./src/webparts/itRequests/ItRequestsWebPart.manifest.json file, and rename the default description property to listName and clear its value.

2. Update the web part properties interface to reflect the changes in the manifest. In the code editor, open the ./src/webparts/itRequests/IItRequestsWebPartProps.ts file, and
change its contents to:

export interface IItRequestsWebPartProps {


listName: string;
}

3. Update the display labels for the listName property. Open the ./src/webparts/itRequests/loc/mystrings.d.ts file, and change its contents to:

declare interface IItRequestsStrings {


PropertyPaneDescription: string;
BasicGroupName: string;
ListNameFieldLabel: string;
}

declare module 'itRequestsStrings' {


const strings: IItRequestsStrings;
export = strings;
}

4. Open the ./src/webparts/itRequests/loc/en-us.js file, and change its contents to:

define([], function() {
return {
"PropertyPaneDescription": "IT Requests settings",
"BasicGroupName": "Data",
"ListNameFieldLabel": "List name"
}
});

5. Update the web part to use the newly defined property. In the code editor, open the ./src/webparts/itRequests/ItRequestsWebPart.ts file, and change the
getPropertyPaneConfiguration method to:
export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> {
// ...
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('listName', {
label: strings.ListNameFieldLabel
})
]
}
]
}
]
};
}

protected get disableReactivePropertyChanges(): boolean {


return true;
}
}

To prevent the web part from reloading as users type the name of the list, you also configured the web part to use the non-reactive property pane by adding the
disableReactivePropertyChanges method and setting its return value to true.

Use the configured name of the list to load the data from
Initially, the name of the list from which the data should be loaded was embedded in the REST query. Now that users can configure this name, the configured value should be injected into
the REST query before loading the data. The easiest way to do that is by moving the contents of the script.js file to the main web part file.
1. In the code editor, open the ./src/webparts/itRequests/ItRequestsWebPart.ts file, and change the render method to:

var $: any = (window as any).$;

export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> {


public render(): void {
this.domElement.innerHTML = `
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" />
<table class="display ${styles.helloWorld}" cellspacing="0" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Business unit</th>
<th>Category</th>
<th>Status</th>
<th>Due date</th>
<th>Assigned to</th>
</tr>
</thead>
</table>`;

$(document).ready(() => {
$('table', this.domElement).DataTable({
'ajax': {
'url': `../../_api/web/lists/getbytitle('${escape(this.properties.listName)}')/items?$select=ID,BusinessUnit,Category,Status,DueDate,AssignedTo/Title&$expand=AssignedTo/Title`,
'headers': { 'Accept': 'application/json;odata=nometadata' },
'dataSrc': function (data) {
return data.value.map(function (item) {
return [
item.ID,
item.BusinessUnit,
item.Category,
item.Status,
new Date(item.DueDate),
item.AssignedTo.Title
];
});
}
},
columnDefs: [{
targets: 4,
render: $.fn.dataTable.render.moment('YYYY/MM/DD')
}]
});
});
}

// ...
}

2. Instead of referencing the code from the script.js file, all of its contents are a part of the web part's render method. In the REST query, in line 40, you can now replace the fixed name
of the list with the value of the listName property which holds the name of the list as configured by the user. Before using the value, it's being escaped by using the lodash's escape
function to disallow script injection.
At this point, the bulk of the code is still written using plain JavaScript. To avoid build issues with the $ jQuery variable, you had to define it as any type in line 18. Later, when
transforming the code to TypeScript, you replace it with a proper type definition.
As you have just moved the contents of the script.js file into the main web part file, the script.js is no longer necessary, and you can delete it from the project.
3. To verify that the web part is working as expected, run the following in the command line:
gulp serve --nobrowser

4. Navigate to the hosted Workbench and add the web part to the canvas. Open the web part property pane, specify the name of the list with IT requests, and select the Apply button to
confirm the changes.
You should now see IT requests displayed in the web part.

Transform the plain JavaScript code to TypeScript


Using TypeScript over plain JavaScript offers a number of benefits. Not only is TypeScript easier to maintain and refactor, but it also allows you to catch errors earlier. The following steps
describe how you would transform the original JavaScript code to TypeScript.

Add type definitions for used libraries


To function properly, TypeScript requires type definitions for the different libraries used in the project. Type definitions are often distributed as npm packages in the @types namespace.
1. Install type definitions for jQuery and DataTables by executing the following in the command line:

npm install --save-dev @types/jquery @types/jquery.datatables

Type definitions for Moment.js are distributed together with the Moment.js package. Even though you're loading Moment.js from a URL, in order to use its typings, you still need to
install the Moment.js package in the project.
2. Install the Moment.js package by executing the following in the command line:

npm install --save moment

Update package references


To use types from the installed type definitions, you have to change how you reference libraries.
1. In the code editor, open the ./src/webparts/itRequests/ItRequestsWebPart.ts file, and change the import 'jquery'; statement to:

import * as $ from 'jquery';

2. Having defined $ as jQuery, you can now remove the local definition of $ that you added previously:

var $: any = (window as any).$;

3. Because DataTables is a jQuery plug-in that attaches itself to jQuery, you cannot load its type definition directly. Instead, you have to add it to the list of types loaded globally. In the
code editor, open the ./tsconfig.json file, and to the types array, add jquery.datatables:
{
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "commonjs",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"types": [
"es6-promise",
"es6-collections",
"jquery.datatables",
"webpack-env"
]
}
}

Update main web part files to TypeScript


Now that you have type definitions for all libraries installed in the project, you can start transforming the plain JavaScript code to TypeScript.
1. Define an interface for the IT request information that you retrieve from the SharePoint list. In the code editor, open the ./src/webparts/itRequests/ItRequestsWebPart.ts file, and
just above the web part class, add the following code snippet:

interface IRequestItem {
ID: number;
BusinessUnit: string;
Category: string;
Status: string;
DueDate: string;
AssignedTo: { Title: string; };
}

2. Next, in the web part class, change the render method to:

export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> {


public render(): void {
this.domElement.innerHTML = `
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" />
<table class="display ${styles.helloWorld}" cellspacing="0" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Business unit</th>
<th>Category</th>
<th>Status</th>
<th>Due date</th>
<th>Assigned to</th>
</tr>
</thead>
</table>`;

$('table', this.domElement).DataTable({
'ajax': {
'url': `../../_api/web/lists/getbytitle('${escape(this.properties.listName)}')/items?$select=ID,BusinessUnit,Category,Status,DueDate,AssignedTo/Title&$expand=AssignedTo/Title`,
'headers': { 'Accept': 'application/json;odata=nometadata' },
'dataSrc': (data: { value: IRequestItem[] }): any[][] => {
return data.value.map((item: IRequestItem): any[] => {
return [
item.ID,
item.BusinessUnit,
item.Category,
item.Status,
new Date(item.DueDate),
item.AssignedTo.Title
];
});
}
},
columnDefs: [{
targets: 4,
render: $.fn.dataTable.render.moment('YYYY/MM/DD')
}]
});
}

// ...
}

3. Notice how the AJAX request, to retrieve the data from the SharePoint list, is now typed and helps you ensure you're referring to correct properties when passing them into an array
to DataTables. The data structure used by DataTables to represent a row in the table is an array of mixed types, so for simplicity it was defined as any[]. Using the any type in this
context is not bad, because the data returned inside the dataSrc property is used internally by DataTables.
As you're updating the render method, you have also added two more changes. First, you removed the id attribute from the table. This allows you to place multiple instances of the
same web part on the page. Also, you removed the reference to the $(document).ready() function, which isn't necessary because the DOM of the element where the data table is
rendered is set before the DataTables initiation code.

Update the Moment.js DataTables plugin to TypeScript


The last piece of the solution that needs to be transformed to TypeScript is the Moment.js DataTables plug-in.
1. Rename the ./src/webparts/itRequests/moment-plugin.js file to ./src/webparts/itRequests/moment-plugin.ts so that it is processed by the TypeScript compiler.
2. Open the moment-plugin.ts file in the code editor, and replace its contents with:
import * as $ from 'jquery';
import * as moment from 'moment';

/* tslint:disable:no-function-expression */
$.fn.dataTable.render.moment = function (from: string, to: string, locale: string): (d: any, type: string, row: any) => string {
/* tslint:enable */
// Argument shifting
if (arguments.length === 1) {
locale = 'en';
to = from;
from = 'YYYY-MM-DD';
}
else if (arguments.length === 2) {
locale = 'en';
}

return (d: any, type: string, row: any): string => {


let m: moment.Moment = moment(d, from, locale, true);

// Order and type get a number value from Moment, everything else
// sees the rendered value
return m.format(type === 'sort' || type === 'type' ? 'x' : to);
};
};

3. You start with loading references to jQuery and Moment.js to let TypeScript know what the corresponding variables refer to. Next, you define the plug-in function. Usually in
TypeScript you use the arrow notation for functions ( => ). In this case, however, because you need access to the arguments property, you have to use the regular function definition.
To prevent tslint from reporting a warning about not using the arrow notation, you can explicitly disable the no-function-expression rule around the function definition.
4. To confirm that everything is working as expected, in the command line, execute:

gulp serve --nobrowser

5. Navigate to the hosted Workbench and add the web part to the canvas. Although visually nothing has changed, the new code base uses TypeScript and its type definitions to help you
maintain the solution.
Migrate jQuery and FullCalendar solution built using Script Editor web part to SharePoint
Framework
5/3/2018 • 24 minutes to read Edit Online

When building SharePoint solutions, SharePoint developers often use the FullCalendar jQuery plug-in to display data in calendar view. FullCalendar is a great alternative to the standard
SharePoint calendar view, as it allows you to render as calendar data from multiple calendar lists, data from non-calendar lists, or even data from outside SharePoint. This article illustrates
how you would migrate a SharePoint customization by using FullCalendar built with the Script Editor web part to the SharePoint Framework.

List of tasks displayed as a calendar built using the Script Editor web part
To illustrate the process of migrating a SharePoint customization using FullCalendar to the SharePoint Framework, you will use the following solution that shows a calendar view of tasks
retrieved from a SharePoint list.

The solution is built using the standard SharePoint Script Editor web part. Following is the code used by the customization.

<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.js"></script>
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.css" />
<div id="calendar"></div>

<script>
var PATH_TO_DISPFORM = _spPageContextInfo.webAbsoluteUrl + "/Lists/Tasks/DispForm.aspx";
var TASK_LIST = "Tasks";
var COLORS = ['#466365', '#B49A67', '#93B7BE', '#E07A5F', '#849483', '#084C61', '#DB3A34'];

displayTasks();

function displayTasks() {
$('#calendar').fullCalendar('destroy');
$('#calendar').fullCalendar({
weekends: false,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
displayEventTime: false,
// open up the display form when a user clicks on an event
eventClick: function (calEvent, jsEvent, view) {
eventClick: function (calEvent, jsEvent, view) {
window.location = PATH_TO_DISPFORM + "?ID=" + calEvent.id;
},
editable: true,
timezone: "UTC",
droppable: true, // this allows things to be dropped onto the calendar
// update the end date when a user drags and drops an event
eventDrop: function (event, delta, revertFunc) {
updateTask(event.id, event.start, event.end);
},
// put the events on the calendar
events: function (start, end, timezone, callback) {
var startDate = start.format('YYYY-MM-DD');
var endDate = end.format('YYYY-MM-DD');

var restQuery = "/_api/Web/Lists/GetByTitle('" + TASK_LIST + "')/items?$select=ID,Title,\


Status,StartDate,DueDate,AssignedTo/Title&$expand=AssignedTo&\
$filter=((DueDate ge '" + startDate + "' and DueDate le '" + endDate + "')or(StartDate ge '" + startDate + "' and StartDate le '" + endDate + "'))";

$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + restQuery,
type: "GET",
dataType: "json",
headers: {
Accept: "application/json;odata=nometadata"
}
})
.done(function (data, textStatus, jqXHR) {
var personColors = {};
var colorNo = 0;

var events = data.value.map(function (task) {


var assignedTo = task.AssignedTo.map(function (person) {
return person.Title;
}).join(', ');

var color = personColors[assignedTo];


if (!color) {
color = COLORS[colorNo++];
personColors[assignedTo] = color;
}
if (colorNo >= COLORS.length) {
colorNo = 0;
}

return {
title: task.Title + " - " + assignedTo,
id: task.ID,
color: color, // specify the background color and border color can also create a class and use className parameter.
start: moment.utc(task.StartDate).add("1", "days"),
end: moment.utc(task.DueDate).add("1", "days") // add one day to end date so that calendar properly shows event ending on that day
};
});

callback(events);
});
}
});
}

function updateTask(id, startDate, dueDate) {


// subtract the previously added day to the date to store correct date
var sDate = moment.utc(startDate).add("-1", "days").format('YYYY-MM-DD') + "T" +
startDate.format("hh:mm") + ":00Z";
if (!dueDate) {
dueDate = startDate;
}
var dDate = moment.utc(dueDate).add("-1", "days").format('YYYY-MM-DD') + "T" +
dueDate.format("hh:mm") + ":00Z";

$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + '/_api/contextinfo',
type: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
})
.then(function (data, textStatus, jqXHR) {
return $.ajax({
url: _spPageContextInfo.webAbsoluteUrl +
"/_api/Web/Lists/getByTitle('" + TASK_LIST + "')/Items(" + id + ")",
type: 'POST',
data: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"X-RequestDigest": data.FormDigestValue,
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
});
})
.done(function (data, textStatus, jqXHR) {
alert("Update Successful");
})
.fail(function (jqXHR, textStatus, errorThrown) {
alert("Update Failed");
})
.always(function () {
displayTasks();
});
}
</script>
</script>

NOTE

This solution is based on the work of Mark Rackley, Office Servers and Services MVP and Chief Strategy Officer at PAIT Group. For more information about the original solution, see Using
FullCalendar.io to Create Custom Calendars in SharePoint.
First, the customization loads the libraries it uses: jQuery, Moment.js, and FullCalendar (lines 1-4).
Next, it defines the div into which the generated calendar view is injected (line 5).
It then defines two functions: displayTasks, used to display tasks in the calendar view, and updateTask, which is triggered after dragging and dropping a task to a different date and which
updates the dates on the underlying list item. Each function defines its own REST query, which is then used to communicate with the SharePoint List REST API to retrieve or update list
items.
Using the FullCalendar jQuery plug-in, with little effort users get rich solutions capable of things such as using different colors to mark different events or using drag and drop to reorganize
events.

Migrate the Tasks calendar solution from the Script Editor web part to the SharePoint Framework
NOTE

Before following the steps in this article, be sure to set up your development environment for building SharePoint Framework solutions.
Transforming a Script Editor web part-based customization to the SharePoint Framework offers a number of benefits such as more user-friendly configuration and centralized management
of the solution. Following is a step-by-step description of how you would migrate the solution to the SharePoint Framework.
First, you migrate the solution to the SharePoint Framework with as few changes to the original code as possible. Later, you transform the solution's code to TypeScript to benefit from its
development-time type safety features, and replace some of the code with the SharePoint Framework API to fully benefit from its capabilities and simplify the solution even further.
NOTE

The source code of the project in the different stages of migration is available at Tutorial: Migrate jQuery and FullCalendar solution built using Script Editor web part to SharePoint
Framework.

Create new SharePoint Framework project


1. Start by creating a new folder for your project:

md fullcalendar-taskscalendar

2. Navigate to the project folder:


cd fullcalendar-taskscalendar

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:

yo @microsoft/sharepoint

4. When prompted, define values as follows:


fullcalendar-taskscalendar as your solution name
Use the current folder for the location to place the files
WebPart as the client-side component to create
Tasks calendar as your web part name
Shows tasks in the calendar view as your web part description
No javaScript web framework as the starting point to build the web part

5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. In this tutorial, you will use Visual Studio Code.

Load JavaScript libraries


Similar to the original solution built by using the Script Editor web part, you first need to load the JavaScript libraries required by the solution. In SharePoint Framework, this usually consists
of two steps: specifying the URL from which the library should be loaded, and referencing the library in the code.
1. Specify the URLs from which libraries should be loaded. In the code editor, open the ./config/config.json file, and change the externals section to:

{
"externals": {
"jquery": "https://code.jquery.com/jquery-1.11.1.min.js",
"moment": "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js",
"fullcalendar": "https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.js"
}
}

2. Open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts file, and after the last import statement, add:

import 'jquery';
import 'moment';
import 'fullcalendar';

Define container div


Just as in the original solution, the next step is to define the location where the calendar should be rendered.
In the code editor, open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts file, and change the render method to:

export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> {


public render(): void {
this.domElement.innerHTML = `
<div class="${styles.tasksCalendar}">
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.css" />
<div id="calendar"></div>
</div>`;
}
// ...
}

Initiate FullCalendar and load data


The last step is to include the code that initiates the FullCalendar jQuery plug-in and loads the data from SharePoint.
1. In the ./src/webparts/tasksCalendar folder, create a new file named script.js, and paste in the following code:

var moment = require('moment');

var PATH_TO_DISPFORM = window.webAbsoluteUrl + "/Lists/Tasks/DispForm.aspx";


var TASK_LIST = "Tasks";
var COLORS = ['#466365', '#B49A67', '#93B7BE', '#E07A5F', '#849483', '#084C61', '#DB3A34'];

displayTasks();

function displayTasks() {
$('#calendar').fullCalendar('destroy');
$('#calendar').fullCalendar({
weekends: false,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
displayEventTime: false,
// open up the display form when a user clicks on an event
eventClick: function (calEvent, jsEvent, view) {
window.location = PATH_TO_DISPFORM + "?ID=" + calEvent.id;
},
editable: true,
timezone: "UTC",
droppable: true, // this allows things to be dropped onto the calendar
// update the end date when a user drags and drops an event
eventDrop: function (event, delta, revertFunc) {
updateTask(event.id, event.start, event.end);
},
// put the events on the calendar
events: function (start, end, timezone, callback) {
var startDate = start.format('YYYY-MM-DD');
var endDate = end.format('YYYY-MM-DD');

var restQuery = "/_api/Web/Lists/GetByTitle('" + TASK_LIST + "')/items?$select=ID,Title,\


Status,StartDate,DueDate,AssignedTo/Title&$expand=AssignedTo&\
$filter=((DueDate ge '" + startDate + "' and DueDate le '" + endDate + "')or(StartDate ge '" + startDate + "' and StartDate le '" + endDate + "'))";

$.ajax({
url: window.webAbsoluteUrl + restQuery,
type: "GET",
dataType: "json",
headers: {
Accept: "application/json;odata=nometadata"
}
})
.done(function (data, textStatus, jqXHR) {
var personColors = {};
var colorNo = 0;

var events = data.value.map(function (task) {


var assignedTo = task.AssignedTo.map(function (person) {
return person.Title;
}).join(', ');

var color = personColors[assignedTo];


if (!color) {
if (!color) {
color = COLORS[colorNo++];
personColors[assignedTo] = color;
}
if (colorNo >= COLORS.length) {
colorNo = 0;
}

return {
title: task.Title + " - " + assignedTo,
id: task.ID,
color: color, // specify the background color and border color can also create a class and use className parameter.
start: moment.utc(task.StartDate).add("1", "days"),
end: moment.utc(task.DueDate).add("1", "days") // add one day to end date so that calendar properly shows event ending on that day
};
});

callback(events);
});
}
});
}

function updateTask(id, startDate, dueDate) {


// subtract the previously added day to the date to store correct date
var sDate = moment.utc(startDate).add("-1", "days").format('YYYY-MM-DD') + "T" +
startDate.format("hh:mm") + ":00Z";
if (!dueDate) {
dueDate = startDate;
}
var dDate = moment.utc(dueDate).add("-1", "days").format('YYYY-MM-DD') + "T" +
dueDate.format("hh:mm") + ":00Z";

$.ajax({
url: window.webAbsoluteUrl + '/_api/contextinfo',
type: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
})
.then(function (data, textStatus, jqXHR) {
return $.ajax({
url: window.webAbsoluteUrl +
"/_api/Web/Lists/getByTitle('" + TASK_LIST + "')/Items(" + id + ")",
type: 'POST',
data: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"X-RequestDigest": data.FormDigestValue,
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
});
})
.done(function (data, textStatus, jqXHR) {
alert("Update Successful");
})
.fail(function (jqXHR, textStatus, errorThrown) {
alert("Update Failed");
})
.always(function () {
displayTasks();
});
}

This code is almost identical to the original code of the Script Editor web part customization. The only difference is that where the original code retrieved the URL of the current web
from the global _spPageContextInfo variable set by SharePoint (lines 8, 45, 96 and 104), the code in the SharePoint Framework uses a custom variable that you have to set in the
web part.
SharePoint Framework client-side web parts can be used both on classic and modern pages. While the _spPageContextInfo variable is present on classic pages, it's not available on
modern pages, which is why you can't rely on it and need a custom property that you can control yourself instead.
2. To reference this file in the web part, in the code editor, open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts file, and change the render method to:

export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> {


public render(): void {
this.domElement.innerHTML = `
<div class="${styles.tasksCalendar}">
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.css" />
<div id="calendar"></div>
</div>`;

(window as any).webAbsoluteUrl = this.context.pageContext.web.absoluteUrl;


require('./script');
}
// ...
}

3. Verify that the web part is working as expected by executing the following in the command line:

gulp serve --nobrowser

Because the web part loads its data from SharePoint, you have to test the web part by using the hosted SharePoint Framework workbench.
4. Navigate to https://yourtenant.sharepoint.com/_layouts/workbench.aspx and add the web part to the canvas. You should now see the tasks displayed in a calendar view by using the
FullCalendar jQuery plug-in.

Add support for configuring the web part through web part properties
In the previous steps, you migrated the Tasks calendar solutions from the Script Editor web part to the SharePoint Framework. While the solution already works as expected, it doesn't use
any of the SharePoint Framework benefits. The name of the list from which tasks are loaded is included in the code, and the code itself is plain JavaScript, which is harder to refactor than
TypeScript.
The following steps illustrate how to extend the existing solution to allow users to specify the name of the list to load the data from. Later, you transform the code to TypeScript to benefit
from its type safety features.

Define web part property for storing the name of the list
1. Define a web part property to store the name of the list from which tasks should be loaded. In the code editor, open the
./src/webparts/tasksCalendar/TasksCalendarWebPart.manifest.json file, and rename the default description property to listName and clear its value.
2. Update the web part properties interface to reflect the changes in the manifest. In the code editor, open the ./src/webparts/tasksCalendar/ITasksCalendarWebPartProps.ts file,
and change its contents to:

export interface ITasksCalendarWebPartProps {


listName: string;
}

3. Update the display labels for the listName property. Open the ./src/webparts/tasksCalendar/loc/mystrings.d.ts file, and change its contents to:

declare interface ITasksCalendarStrings {


PropertyPaneDescription: string;
BasicGroupName: string;
ListNameFieldLabel: string;
}

declare module 'tasksCalendarStrings' {


const strings: ITasksCalendarStrings;
export = strings;
}

4. Open the ./src/webparts/tasksCalendar/loc/en-us.js file, and change its contents to:

define([], function() {
return {
"PropertyPaneDescription": "Tasks calendar settings",
"BasicGroupName": "Data",
"ListNameFieldLabel": "List name"
}
});

5. Update the web part to use the newly defined property. In the code editor, open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts file, and change the
getPropertyPaneConfiguration method to:
export default class TasksCalendarWebPart extends BaseClientSideWebPart<ITasksCalendarWebPartProps> {
// ...
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('listName', {
label: strings.ListNameFieldLabel
})
]
}
]
}
]
};
}

protected get disableReactivePropertyChanges(): boolean {


return true;
}
}

To prevent the web part from reloading as users type the name of the list, you've also configured the web part to use the non-reactive property pane by adding the
disableReactivePropertyChanges method and setting its return value to true.

Use the configured name of the list to load the data from
Initially, the name of the list from which the data should be loaded was embedded in the REST queries. Now that users can configure this name, the configured value should be injected into
the REST queries before executing them. The easiest way to do that is by moving the contents of the script.js file to the main web part file.
1. In the code editor, open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts file.
2. Change the import statement to load the required libraries to:

var $: any = require('jquery');


var moment: any = require('moment');

import 'fullcalendar';

var COLORS = ['#466365', '#B49A67', '#93B7BE', '#E07A5F', '#849483', '#084C61', '#DB3A34'];

Because Moment.js is referenced in the code that you will be using later, its name must be known to TypeScript or building the project will fail. The same applies to jQuery. Because
FullCalendar is a jQuery plug-in that attaches itself to the jQuery object, it can be imported the same way as previously.
The last part includes copying the list of colors to use for marking the different events.
3. Copy the displayTasks and updateTask functions from the script.js file, and paste them as follows inside the TasksCalendarWebPart class:

export default class TasksCalendarWebPart extends BaseClientSideWebPart<ITasksCalendarWebPartProps> {


// ...

private displayTasks() {
$('#calendar').fullCalendar('destroy');
$('#calendar').fullCalendar({
weekends: false,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
displayEventTime: false,
// open up the display form when a user clicks on an event
eventClick: (calEvent, jsEvent, view) => {
(window as any).location = this.context.pageContext.web.absoluteUrl +
"/Lists/" + escape(this.properties.listName) + "/DispForm.aspx?ID=" + calEvent.id;
},
editable: true,
timezone: "UTC",
droppable: true, // this allows things to be dropped onto the calendar
// update the end date when a user drags and drops an event
eventDrop: (event, delta, revertFunc) => {
this.updateTask(event.id, event.start, event.end);
},
// put the events on the calendar
events: (start, end, timezone, callback) => {
var startDate = start.format('YYYY-MM-DD');
var endDate = end.format('YYYY-MM-DD');

var restQuery = "/_api/Web/Lists/GetByTitle('" + escape(this.properties.listName) + "')/items?$select=ID,Title,\


Status,StartDate,DueDate,AssignedTo/Title&$expand=AssignedTo&\
$filter=((DueDate ge '" + startDate + "' and DueDate le '" + endDate + "')or(StartDate ge '" + startDate + "' and StartDate le '" + endDate + "'))";

$.ajax({
url: this.context.pageContext.web.absoluteUrl + restQuery,
type: "GET",
dataType: "json",
headers: {
Accept: "application/json;odata=nometadata"
}
})
.done((data, textStatus, jqXHR) => {
var personColors = {};
var colorNo = 0;
var events = data.value.map((task) => {
var assignedTo = task.AssignedTo.map((person) => {
return person.Title;
}).join(', ');

var color = personColors[assignedTo];


if (!color) {
color = COLORS[colorNo++];
personColors[assignedTo] = color;
}
if (colorNo >= COLORS.length) {
colorNo = 0;
}

return {
title: task.Title + " - " + assignedTo,
id: task.ID,
color: color, // specify the background color and border color can also create a class and use className parameter.
start: moment.utc(task.StartDate).add("1", "days"),
end: moment.utc(task.DueDate).add("1", "days") // add one day to end date so that calendar properly shows event ending on that day
};
});

callback(events);
});
}
});
}

private updateTask(id, startDate, dueDate) {


// subtract the previously added day to the date to store correct date
var sDate = moment.utc(startDate).add("-1", "days").format('YYYY-MM-DD') + "T" +
startDate.format("hh:mm") + ":00Z";
if (!dueDate) {
dueDate = startDate;
}
var dDate = moment.utc(dueDate).add("-1", "days").format('YYYY-MM-DD') + "T" +
dueDate.format("hh:mm") + ":00Z";

$.ajax({
url: this.context.pageContext.web.absoluteUrl + '/_api/contextinfo',
type: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
})
.then((data, textStatus, jqXHR) => {
return $.ajax({
url: this.context.pageContext.web.absoluteUrl +
"/_api/Web/Lists/getByTitle('" + escape(this.properties.listName) + "')/Items(" + id + ")",
type: 'POST',
data: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"X-RequestDigest": data.FormDigestValue,
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
});
})
.done((data, textStatus, jqXHR) => {
alert("Update Successful");
})
.fail((jqXHR, textStatus, errorThrown) => {
alert("Update Failed");
})
.always(() => {
this.displayTasks();
});
}

// ...
}

There are a few changes in the code compared to the previous situation. Plain JavaScript functions are now changed into TypeScript methods by replacing the function keyword with
the private modifier. This is required to be able to add them to the TaskCalendarWebPart class. Because both methods are now in the same file as the web part, instead of defining a
global variable to hold the URL of the current site, you can access it directly from the web part context by using the this.context.pageContext.web.absoluteUrl property. Additionally, in
all REST queries, the fixed list name is replaced with the value of the listName property, which holds the name of the list as configured by the user. Before using the value, it's being
escaped by using the lodash's escape function to disallow script injection.
4. As the last step, change the render method to call the newly added displayTasks method:
export default class TasksCalendarWebPart extends BaseClientSideWebPart<ITasksCalendarWebPartProps> {
public render(): void {
this.domElement.innerHTML = `
<div class="${styles.tasksCalendar}">
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.css" />
<div id="calendar"></div>
</div>`;

this.displayTasks();
}
// ...
}

5. Because you have just moved the contents of the script.js file into the main web part file, the script.js is no longer necessary and you can delete it from the project.
6. To verify that the web part is working as expected, run the following in the command line:

gulp serve --nobrowser

7. Navigate to the hosted Workbench and add the web part to the canvas. Open the web part property pane, specify the name of the list with tasks, and select the Apply button to
confirm the changes. You should now see tasks displayed in a calendar view in the web part.

Transform the plain JavaScript code to TypeScript


Using TypeScript over plain JavaScript offers a number of benefits. Not only is TypeScript easier to maintain and refactor, but it also allows you to catch errors earlier. The following steps
describe how you would transform the original JavaScript code to TypeScript.

Add type definitions for used libraries


To function properly, TypeScript requires type definitions for the different libraries used in the project. Type definitions are often distributed as npm packages in the @types namespace.
1. Install type definitions for jQuery and FullCalendar by executing the following in the command line:

npm install --save-dev @types/jquery@1 @types/fullcalendar

Type definitions for Moment.js are distributed together with the Moment.js package. Even though you're loading Moment.js from a URL, to use its typings, you still need to install the
Moment.js package in the project.
2. Install the Moment.js package by executing the following in the command line:

npm install --save moment


Update package references
To use types from the installed type definitions, you have to change how you reference libraries.
In the code editor, open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts file, and change the import statements to:

import * as $ from 'jquery';


import 'fullcalendar';
import * as moment from 'moment';

Update main web part files to TypeScript


Now that you have type definitions for all libraries installed in the project, you can start transforming the plain JavaScript code to TypeScript.
1. Define an interface for a task that you retrieve from the SharePoint list. In the code editor, open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts file, and just above
the web part class, add the following code snippet:

interface ITask {
ID: number;
Title: string;
StartDate: string;
DueDate: string;
AssignedTo: [{ Title: string }];
}

2. In the web part class, change the displayTasks and updateTask methods to:

export default class TasksCalendarWebPart extends BaseClientSideWebPart<ITasksCalendarWebPartProps> {


private readonly colors: string[] = ['#466365', '#B49A67', '#93B7BE', '#E07A5F', '#849483', '#084C61', '#DB3A34'];

// ...

private displayTasks(): void {


$('#calendar').fullCalendar('destroy');
$('#calendar').fullCalendar({
weekends: false,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
displayEventTime: false,
// open up the display form when a user clicks on an event
eventClick: (calEvent: FC.EventObject, jsEvent: MouseEvent, view: FC.ViewObject): void => {
(window as any).location = `${this.context.pageContext.web.absoluteUrl}\
/Lists/${escape(this.properties.listName)}/DispForm.aspx?ID=${calEvent.id}`;
},
editable: true,
timezone: "UTC",
droppable: true, // this allows things to be dropped onto the calendar
// update the end date when a user drags and drops an event
eventDrop: (event: FC.EventObject, delta: moment.Duration, revertFunc: Function): void => {
this.updateTask(event.id, <moment.Moment>event.start, <moment.Moment>event.end);
},
// put the events on the calendar
events: (start: moment.Moment, end: moment.Moment, timezone: string, callback: Function): void => {
const startDate: string = start.format('YYYY-MM-DD');
const endDate: string = end.format('YYYY-MM-DD');

const restQuery: string = `/_api/Web/Lists/GetByTitle('${escape(this.properties.listName)}')/items?$select=ID,Title,\


Status,StartDate,DueDate,AssignedTo/Title&$expand=AssignedTo&\
$filter=((DueDate ge '${startDate}' and DueDate le '${endDate}')or(StartDate ge '${startDate}' and StartDate le '${endDate}'))`;

$.ajax({
url: this.context.pageContext.web.absoluteUrl + restQuery,
type: "GET",
dataType: "json",
headers: {
Accept: "application/json;odata=nometadata"
}
})
.done((data: { value: ITask[] }, textStatus: string, jqXHR: JQueryXHR): void => {
let personColors: { [person: string]: string; } = {};
let colorNo: number = 0;

const events: FC.EventObject[] = data.value.map((task: ITask): FC.EventObject => {


const assignedTo: string = task.AssignedTo.map((person: { Title: string }): string => {
return person.Title;
}).join(', ');

let color: string = personColors[assignedTo];


if (!color) {
color = this.colors[colorNo++];
personColors[assignedTo] = color;
}
if (colorNo >= this.colors.length) {
colorNo = 0;
}

return {
title: `${task.Title} - ${assignedTo}`,
id: task.ID,
// specify the background color and border color can also create a class and use className parameter
color: color,
start: moment.utc(task.StartDate).add("1", "days"),
// add one day to end date so that calendar properly shows event ending on that day
end: moment.utc(task.DueDate).add("1", "days")
};
});

callback(events);
});
});
}
});
}

private updateTask(id: number, startDate: moment.Moment, dueDate: moment.Moment): void {


// subtract the previously added day to the date to store correct date
const sDate: string = moment.utc(startDate).add("-1", "days").format('YYYY-MM-DD') + "T" +
startDate.format("hh:mm") + ":00Z";
if (!dueDate) {
dueDate = startDate;
}
const dDate: string = moment.utc(dueDate).add("-1", "days").format('YYYY-MM-DD') + "T" +
dueDate.format("hh:mm") + ":00Z";

$.ajax({
url: this.context.pageContext.web.absoluteUrl + '/_api/contextinfo',
type: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
})
.then((data: { FormDigestValue: string }, textStatus: string, jqXHR: JQueryXHR): JQueryXHR => {
return $.ajax({
url: `${this.context.pageContext.web.absoluteUrl}\
/_api/Web/Lists/getByTitle('${escape(this.properties.listName)}')/Items(${id})`,
type: 'POST',
data: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"X-RequestDigest": data.FormDigestValue,
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
});
})
.done((data: {}, textStatus: string, jqXHR: JQueryXHR): void => {
alert("Update Successful");
})
.fail((jqXHR: JQueryXHR, textStatus: string, errorThrown: string): void => {
alert("Update Failed");
})
.always((): void => {
this.displayTasks();
});
}

// ...
}

The first and most obvious change when transforming plain JavaScript to TypeScript are explicit types. While they are not required, they make it clear which type of data is expected
where. Any deviation from the specified contract is immediately caught by TypeScript, helping you find possible issues as soon as possible during the development process. This is
particularly useful when working with AJAX responses and their data.
Another change that you might have noticed already is the TypeScript string interpolation. Using string interpolation simplifies dynamic string composition and increases the
readability of your code.
Compare plain JavaScript:

var restQuery = "/_api/Web/Lists/GetByTitle('" + TASK_LIST + "')/items?$select=ID,Title,\


Status,StartDate,DueDate,AssignedTo/Title&$expand=AssignedTo&\
$filter=((DueDate ge '" + startDate + "' and DueDate le '" + endDate + "')or(StartDate ge '" + startDate + "' and StartDate le '" + endDate + "'))";

to:

const restQuery: string = `/_api/Web/Lists/GetByTitle('${escape(this.properties.listName)}')/items?$select=ID,Title,\


Status,StartDate,DueDate,AssignedTo/Title&$expand=AssignedTo&\
$filter=((DueDate ge '${startDate}' and DueDate le '${endDate}')or(StartDate ge '${startDate}' and StartDate le '${endDate}'))`;

The additional benefit of using TypeScript string interpolation is that you don't need to escape quotes, which also simplifies composing REST queries.
3. To confirm that everything is working as expected, execute the following in the command line:

gulp serve --nobrowser

4. Go to the hosted Workbench and add the web part to the canvas. Although visually nothing has changed, the new code base uses TypeScript and its type definitions to help you
maintain the solution.

Replace jQuery AJAX calls with SharePoint Framework API


At this moment, the solution uses jQuery AJAX calls to communicate with the SharePoint REST API. For regular GET requests, the jQuery AJAX API is just as convenient as using the
SharePoint Framework SPHttpClient. The real difference is when performing POST requests such as the one for updating the event:
$.ajax({
url: this.context.pageContext.web.absoluteUrl + '/_api/contextinfo',
type: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
})
.then((data: { FormDigestValue: string }, textStatus: string, jqXHR: JQueryXHR): JQueryXHR => {
return $.ajax({
url: `${this.context.pageContext.web.absoluteUrl}\
/_api/Web/Lists/getByTitle('${escape(this.properties.listName)}')/Items(${id})`,
type: 'POST',
data: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"X-RequestDigest": data.FormDigestValue,
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
});
})
.done((data: {}, textStatus: string, jqXHR: JQueryXHR): void => {
alert("Update Successful");
})
// ...

Because you want to update a list item, you need to provide SharePoint with a valid request digest token. While it's available on classic pages, it's valid for 3 minutes, so it's always the safest
to retrieve a valid token yourself before performing an update operation. After you obtain the request digest, you have to add it to request headers of the update request. If you don't, the
request fails.
SharePoint Framework SPHttpClient simplifies communicating with SharePoint because it automatically detects if the request is a POST request and needs a valid request digest. If it does,
the SPHttpClient automatically retrieves it from SharePoint and adds it to the request. By comparison, the same request issued using the SPHttpClient would look like this:

this.context.spHttpClient.post(`${this.context.pageContext.web.absoluteUrl}\
/_api/Web/Lists/getByTitle('${escape(this.properties.listName)}')/Items(${id})`, SPHttpClient.configurations.v1, {
body: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
})
.then((response: SPHttpClientResponse): void => {
// ...
});

1. To replace the original jQuery AJAX calls with the SharePoint Framework SPHttpClient API, in the code editor open the ./src/webparts/tasksCalendar/TasksCalendarWebPart.ts
file. To the list of imports add:

import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';

2. In the TasksCalendarWebPart class, replace the displayTasks and updateTask methods with the following code:

export default class TasksCalendarWebPart extends BaseClientSideWebPart<ITasksCalendarWebPartProps> {


// ...

private displayTasks(): void {


$('#calendar').fullCalendar('destroy');
$('#calendar').fullCalendar({
weekends: false,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
displayEventTime: false,
// open up the display form when a user clicks on an event
eventClick: (calEvent: FC.EventObject, jsEvent: MouseEvent, view: FC.ViewObject): void => {
(window as any).location = `${this.context.pageContext.web.absoluteUrl}\
/Lists/${escape(this.properties.listName)}/DispForm.aspx?ID=${calEvent.id}`;
},
editable: true,
timezone: "UTC",
droppable: true, // this allows things to be dropped onto the calendar
// update the end date when a user drags and drops an event
eventDrop: (event: FC.EventObject, delta: moment.Duration, revertFunc: Function): void => {
this.updateTask(event.id, <moment.Moment>event.start, <moment.Moment>event.end);
},
// put the events on the calendar
events: (start: moment.Moment, end: moment.Moment, timezone: string, callback: Function): void => {
const startDate: string = start.format('YYYY-MM-DD');
const endDate: string = end.format('YYYY-MM-DD');

const restQuery: string = `/_api/Web/Lists/GetByTitle('${escape(this.properties.listName)}')/items?$select=ID,Title,\


Status,StartDate,DueDate,AssignedTo/Title&$expand=AssignedTo&\
$filter=((DueDate ge '${startDate}' and DueDate le '${endDate}')or(StartDate ge '${startDate}' and StartDate le '${endDate}'))`;

this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + restQuery, SPHttpClient.configurations.v1, {


headers: {
headers: {
'Accept': "application/json;odata.metadata=none"
}
})
.then((response: SPHttpClientResponse): Promise<{ value: ITask[] }> => {
return response.json();
})
.then((data: { value: ITask[] }): void => {
let personColors: { [person: string]: string; } = {};
let colorNo: number = 0;

const events: FC.EventObject[] = data.value.map((task: ITask): FC.EventObject => {


const assignedTo: string = task.AssignedTo.map((person: { Title: string }): string => {
return person.Title;
}).join(', ');

let color: string = personColors[assignedTo];


if (!color) {
color = this.colors[colorNo++];
personColors[assignedTo] = color;
}
if (colorNo >= this.colors.length) {
colorNo = 0;
}

return {
title: `${task.Title} - ${assignedTo}`,
id: task.ID,
// specify the background color and border color can also create a class and use className paramter
color: color,
start: moment.utc(task.StartDate).add("1", "days"),
// add one day to end date so that calendar properly shows event ending on that day
end: moment.utc(task.DueDate).add("1", "days")
};
});

callback(events);
});
}
});
}

private updateTask(id: number, startDate: moment.Moment, dueDate: moment.Moment): void {


// subtract the previously added day to the date to store correct date
const sDate: string = moment.utc(startDate).add("-1", "days").format('YYYY-MM-DD') + "T" +
startDate.format("hh:mm") + ":00Z";
if (!dueDate) {
dueDate = startDate;
}
const dDate: string = moment.utc(dueDate).add("-1", "days").format('YYYY-MM-DD') + "T" +
dueDate.format("hh:mm") + ":00Z";

this.context.spHttpClient.post(`${this.context.pageContext.web.absoluteUrl}\
/_api/Web/Lists/getByTitle('${escape(this.properties.listName)}')/Items(${id})`, SPHttpClient.configurations.v1, {
body: JSON.stringify({
StartDate: sDate,
DueDate: dDate,
}),
headers: {
Accept: "application/json;odata=nometadata",
"Content-Type": "application/json;odata=nometadata",
"IF-MATCH": "*",
"X-Http-Method": "PATCH"
}
})
.then((response: SPHttpClientResponse): void => {
if (response.ok) {
alert("Update Successful");
}
else {
alert("Update Failed");
}

this.displayTasks();
});
}

// ...
}

IM P O R T A N T

If you're suppressing metadata in the responses of the SharePoint REST API, when using the SharePoint Framework SPHttpClient you have to ensure that you're using
application/json;odata.metadata=none and not application/json;odata=nometadata as the value of the Accept header. SPHttpClient uses OData 4.0 and requires the first value. If you
use the latter instead, the request fails with a 406 Not Acceptable response.
3. To confirm that everything is working as expected, execute the following in the command line:

gulp serve --nobrowser

4. Go to the hosted Workbench and add the web part to the canvas. Although there are still no visual changes, the new code uses the SharePoint Framework SPHttpClient, which
simplifies your code and maintains your solution.
Migrate AngularJS applications to SharePoint Framework
3/26/2018 • 19 minutes to read Edit Online

Many organizations have been using AngularJS for building SharePoint solutions in the past. This article shows how to migrate an existing AngularJS application styled using
ngOfficeUIFabric - AngularJS directives for Office UI Fabric, to a SharePoint Framework client-side web part. The sample application used for this tutorial manages To Do items stored in a
SharePoint list.

The source of the AngularJS application is available on GitHub at angular-migration/angular-todo.


The source of the AngularJS application migrated to SharePoint Framework is available on GitHub at samples/angular-todo.
NOTE

Before following the steps in this article, be sure to set up your development environment for building SharePoint Framework solutions.

Set up project
Before you start migrating your AngularJS application, create and set up a new SharePoint Framework project to host the AngularJS application.

Create new project


1. Create a new folder for your project:

md angular-todo

2. Go to the project folder:

cd angular-todo

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:

yo @microsoft/sharepoint

4. When prompted, define values as follows:


angular-todo as your solution name
Use the current folder for the location to place the files
To do as your web part name
Simple management of to do tasks as your web part description
No JavaScript web framework as the starting point to build the web part
5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. In this tutorial, you will use Visual Studio Code.

Add AngularJS and ngOfficeUIFabric


In this tutorial you load both AngularJS and ngOfficeUIFabric from CDN.
In the code editor, open the config/config.json file, and in the externals property, add the following lines:

"angular": {
"path": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.6/angular.min.js",
"globalName": "angular"
},
"ng-office-ui-fabric": "https://cdnjs.cloudflare.com/ajax/libs/ngOfficeUiFabric/0.12.3/ngOfficeUiFabric.js"

Add AngularJS typings for TypeScript


Because you are referencing AngularJS in your web part's code, you also need AngularJS typings for TypeScript. To install them run the following in the command line:
npm install @types/angular --save-dev

Migrate the AngularJS application as-is


Start with migrating the AngularJS application with only the minimal code changes. Later, you will upgrade the application's plain JavaScript code to TypeScript and improve its integration
with the client-side web part.

Create SharePoint list


In your SharePoint site, create a new list called Todo. In the list, add a new choice column called Status. As available choices enter:

Not started
In progress
Completed

Copy AngularJS application files to the web part project


1. In the web part project, in the src/webparts/toDo folder, create a new folder called app .
2. From the source application, copy the contents of the app folder to the newly created app folder in the web part project.
Load the AngularJS application in the client-side web part
1. In the code editor, open the ./src/webparts/toDo/ToDoWebPart.ts file. After the last import statement, add the following code:

import * as angular from 'angular';


import 'ng-office-ui-fabric';

2. Change the contents of the render method to:

export default class ToDoWebPart extends BaseClientSideWebPart<IToDoWebPartProps> {


// ...
public render(): void {
if (this.renderedOnce === false) {
require('./app/app.module');
require('./app/app.config');
require('./app/data.service');
require('./app/home.controller');

this.domElement.innerHTML = `
<div class="${styles.toDo}">
<div data-ng-controller="homeController as vm">
<div class="${styles.loading}" ng-show="vm.isLoading">
<uif-spinner>Loading...</uif-spinner>
</div>
<div class="entryform" ng-show="vm.isLoading === false">
<uif-textfield uif-label="New to do:" uif-underlined ng-model="vm.newItem" ng-keydown="vm.todoKeyDown($event)"></uif-textfield>
</div>
<uif-list class="items" ng-show="vm.isLoading === false" >
<uif-list-item ng-repeat="todo in vm.todoCollection" uif-item="todo" ng-class="{'done': todo.done}">
<uif-list-item-primary-text>{{todo.title}}</uif-list-item-primary-text>
<uif-list-item-actions>
<uif-list-item-action ng-click="vm.completeTodo(todo)" ng-show="todo.done === false">
<uif-icon uif-type="check"></uif-icon>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.undoTodo(todo)" ng-show="todo.done">
<uif-icon uif-type="reactivate"></uif-icon>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.deleteTodo(todo)">
<uif-icon uif-type="trash"></uif-icon>
</uif-list-item-action>
</uif-list-item-actions>
</uif-list-item>
</uif-list>
</div>
</div>`;

angular.bootstrap(this.domElement, ['todoapp']);
}
}
// ...
}

Update site path


In the code editor, open the ./src/webparts/toDo/app/app.config.js file. Change the value of the sharepointApi constant to the server-relative URL of the SharePoint site where you
created the Todo list, followed by /_api/ .

Add CSS styles


You also need to implement CSS styles that you are using the template. In the code editor, open the ToDoWebPart.module.scss file and replace its contents with:

.toDo {
.loading {
margin: 0 auto;
width: 6em;
}
}

Trust the development certificate


By default, the development certificate required to load SharePoint Workbench and its resources over HTTPS is not trusted, and causes the web browser to show a warning when navigating
to the SharePoint Workbench. In situations when you want to run SharePoint Workbench in the context of SharePoint, some web browsers prevent the Workbench from loading if the SSL
certificate isn't trusted. To avoid this issue, you should trust the development certificate provided with the SharePoint Framework.
In the command line, execute:

gulp trust-dev-cert

Preview web part in the hosted Workbench


1. In the command line, execute:

gulp serve --nobrowser

2. To the URL of your SharePoint site, add /_layouts/workbench.aspx , for example, https://contoso.sharepoint.com/_layouts/workbench.aspx , and navigate to it in the web browser.
If you followed all steps correctly, you should see the web part in the browser showing the form to add To Do items.
3. Add a few To Do items to verify that the web part is working as expected.

Fix web part styling


Although the web part is working correctly, it doesn't look the same as the AngularJS application you started with. This is caused because ngOfficeUIFabric uses an older version of Office UI
Fabric than the one available in the SharePoint Workbench. The easy fix would be to load the CSS styles used by ngOfficeUIFabric. The problem with that is that these styles would collide
with the Office UI Fabric styles used by the SharePoint Workbench, breaking its user interface. A better solution is to add the styles required by the specific components to the web part
styles.
1. In the code editor, open the ./src/webparts/toDo/ToDoWebPart.module.scss file. Change its contents to:

.toDo {
.loading {
margin: 0 auto;
width: 6em;
}

.done :global .ms-ListItem-primaryText {


text-decoration: line-through;
}

ul, li {
margin: 0;
padding: 0;
}

:global {
.ms-Spinner{position:relative;height:20px}.ms-Spinner.ms-Spinner--large{height:28px}.ms-Spinner.ms-Spinner--large .ms-Spinner-label{left:34px;top:6px}.ms-Spinner-circle{position:absolute;b
.ms-TextField{color:#333;font-family:Segoe UI Regular WestEuropean,Segoe UI,Tahoma,Arial,sans-serif;font-size:14px;font-weight:400;box-sizing:border-box;margin:0;padding:0;box-shadow:none;
.ms-Label{margin:0;padding:0;box-shadow:none;box-sizing:border-box;display:block;padding:5px 0}.ms-Label.is-required:after{content:' *';color:#a80000}.ms-Label.is-disabled{color:#a6a6a6}@m
.ms-ListItem{font-family:"Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;-webkit-font-smoothing:antialiased;font-size:14px;font-weigh
}
}

2. In the ./src/webparts/toDo/ToDoWebPart.ts file, in the render method, change the application rendering template to use new Office UI Fabric icons.
export default class ToDoWebPart extends BaseClientSideWebPart<IToDoWebPartProps> {
// ...
public render(): void {
if (this.renderedOnce === false) {
require('./app/app.module');
require('./app/app.config');
require('./app/data.service');
require('./app/home.controller');

this.domElement.innerHTML = `
<div class="${styles.toDo}">
<div data-ng-controller="homeController as vm">
<div class="${styles.loading}" ng-show="vm.isLoading">
<uif-spinner>Loading...</uif-spinner>
</div>
<div id="entryform" ng-show="vm.isLoading === false">
<uif-textfield uif-label="New to do:" uif-underlined ng-model="vm.newItem" ng-keydown="vm.todoKeyDown($event)"></uif-textfield>
</div>
<uif-list id="items" ng-show="vm.isLoading === false" >
<uif-list-item ng-repeat="todo in vm.todoCollection" uif-item="todo" ng-class="{'${styles.done}': todo.done}">
<uif-list-item-primary-text>{{todo.title}}</uif-list-item-primary-text>
<uif-list-item-actions>
<uif-list-item-action ng-click="vm.completeTodo(todo)" ng-show="todo.done === false">
<i class="ms-Icon ms-Icon--CheckMark" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.undoTodo(todo)" ng-show="todo.done">
<i class="ms-Icon ms-Icon--RevToggleKey" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.deleteTodo(todo)">
<i class="ms-Icon ms-Icon--Delete" aria-hidden="true"></i>
</uif-list-item-action>
</uif-list-item-actions>
</uif-list-item>
</uif-list>
</div>
</div>`;

angular.bootstrap(this.domElement, ['todoapp']);
}
}
// ...
}

If you refresh the web part in the web browser, you see that it is now correctly styled.

Upgrade the AngularJS application to TypeScript


The original AngularJS application is written in plain JavaScript, which makes maintaining it error-prone. When building SharePoint Framework client-side web parts, you can use TypeScript
and benefit from its design-time type safety features. In the next section, you will migrate the plain JavaScript AngularJS code to TypeScript.

Upgrade application configuration


In your project, rename the ./src/webparts/toDo/app/app.config.js file to app.config.ts . Change its contents to:

import * as angular from 'angular';

export default function() {


const todoapp: ng.IModule = angular.module('todoapp');
todoapp.constant('sharepointApi', '/todo/_api/');
todoapp.constant('todoListName', 'Todo');
todoapp.constant('hideFinishedTasks', false);
}

Upgrade data service


In your project, rename the ./src/webparts/toDo/app/data.service.js file to DataService.ts . Change its contents to:

import * as angular from 'angular';


import * as angular from 'angular';

export interface ITodo {


id: number;
title: string;
done: boolean;
}

interface ITodoItem {
Id: number;
Title: string;
Status: string;
}

export interface IDataService {


getTodos: () => angular.IPromise<ITodo[]>;
addTodo: (todo: string) => angular.IPromise<{}>;
deleteTodo: (todo: ITodo) => angular.IPromise<{}>;
setTodoStatus: (todo: ITodo, done: boolean) => angular.IPromise<{}>;
}

export default class DataService implements IDataService {


public static $inject: string[] = ['$q', '$http', 'sharepointApi', 'todoListName', 'hideFinishedTasks'];

constructor(private $q: angular.IQService,


private $http: angular.IHttpService,
private sharepointApi: string,
private todoListName: string,
private hideFinishedTasks: boolean) {
}

public getTodos(): angular.IPromise<ITodo[]> {


const deferred: angular.IDeferred<ITodo[]> = this.$q.defer();

let url: string = `${this.sharepointApi}web/lists/getbytitle('${this.todoListName}')/items?$select=Id,Title,Status&$orderby=ID desc`;

if (this.hideFinishedTasks === true) {


url += "&$filter=Status ne 'Completed'";
}

this.$http({
url: url,
method: 'GET',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ value: ITodoItem[] }>): void => {
const todos: ITodo[] = [];
for (let i: number = 0; i < result.data.value.length; i++) {
const todo: ITodoItem = result.data.value[i];
todos.push({
id: todo.Id,
title: todo.Title,
done: todo.Status === 'Completed'
});
}
deferred.resolve(todos);
});

return deferred.promise;
}

public addTodo(todo: string): angular.IPromise<{}> {


const deferred: angular.IDeferred<{}> = this.$q.defer();

let listItemEntityTypeFullName: string = undefined;


this.getListItemEntityTypeFullName()
.then((entityTypeName: string): angular.IPromise<string> => {
listItemEntityTypeFullName = entityTypeName;
return this.getRequestDigest();
})
.then((requestDigest: string): void => {
const body: string = JSON.stringify({
'__metadata': { 'type': listItemEntityTypeFullName },
'Title': todo
});
this.$http({
url: `${this.sharepointApi}web/lists/getbytitle('${this.todoListName}')/items`,
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata',
'Content-type': 'application/json;odata=verbose',
'X-RequestDigest': requestDigest
},
data: body
}).then((result: angular.IHttpPromiseCallbackArg<{}>): void => {
deferred.resolve();
});
});

return deferred.promise;
}

public deleteTodo(todo: ITodo): angular.IPromise<{}> {


const deferred: angular.IDeferred<{}> = this.$q.defer();

this.getRequestDigest()
.then((requestDigest: string): void => {
this.$http({
url: `${this.sharepointApi}web/lists/getbytitle('${this.todoListName}')/items(${todo.id})`,
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata',
'X-RequestDigest': requestDigest,
'IF-MATCH': '*',
'X-HTTP-Method': 'DELETE'
'X-HTTP-Method': 'DELETE'
}
}).then((result: angular.IHttpPromiseCallbackArg<{}>): void => {
deferred.resolve();
});
});

return deferred.promise;
}

public setTodoStatus(todo: ITodo, done: boolean): angular.IPromise<{}> {


const deferred: angular.IDeferred<{}> = this.$q.defer();

let listItemEntityTypeFullName: string = undefined;


this.getListItemEntityTypeFullName()
.then((entityTypeName: string): angular.IPromise<string> => {
listItemEntityTypeFullName = entityTypeName;
return this.getRequestDigest();
})
.then((requestDigest: string): void => {
const body: string = JSON.stringify({
'__metadata': { 'type': listItemEntityTypeFullName },
'Status': done ? 'Completed' : 'Not started'
});
this.$http({
url: `${this.sharepointApi}web/lists/getbytitle('${this.todoListName}')/items(${todo.id})`,
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata',
'Content-type': 'application/json;odata=verbose',
'X-RequestDigest': requestDigest,
'IF-MATCH': '*',
'X-HTTP-Method': 'MERGE'
},
data: body
}).then((result: angular.IHttpPromiseCallbackArg<{}>): void => {
deferred.resolve();
});
});

return deferred.promise;
}

private getRequestDigest(): angular.IPromise<string> {


const deferred: angular.IDeferred<string> = this.$q.defer();

this.$http({
url: this.sharepointApi + 'contextinfo',
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ FormDigestValue: string }>): void => {
deferred.resolve(result.data.FormDigestValue);
}, (err: any): void => {
deferred.reject(err);
});

return deferred.promise;
}

private getListItemEntityTypeFullName(): angular.IPromise<string> {


const deferred: angular.IDeferred<string> = this.$q.defer();

this.$http({
url: `${this.sharepointApi}web/lists/getbytitle('${this.todoListName}')?$select=ListItemEntityTypeFullName`,
method: 'GET',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ ListItemEntityTypeFullName: string }>): void => {
deferred.resolve(result.data.ListItemEntityTypeFullName);
}, (err: any): void => {
deferred.reject(err);
});

return deferred.promise;
}
}

Upgrade home controller


In your project, rename the ./src/webparts/toDo/app/home.controller.js file to HomeController.ts . Change its contents to:
import * as angular from 'angular';
import { IDataService, ITodo } from './DataService';

export default class HomeController {


public isLoading: boolean = false;
public newItem: string = null;
public todoCollection: ITodo[] = [];

public static $inject: string[] = ['DataService', '$window'];

constructor(private dataService: IDataService, private $window: angular.IWindowService) {


this.loadTodos();
}

private loadTodos(): void {


this.isLoading = true;
this.dataService.getTodos()
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
})
.finally((): void => {
this.isLoading = false;
});
}

public todoKeyDown($event: KeyboardEvent): void {


if ($event.keyCode === 13 && this.newItem.length > 0) {
$event.preventDefault();

this.todoCollection.unshift({ id: -1, title: this.newItem, done: false });

this.dataService.addTodo(this.newItem)
.then((): void => {
this.newItem = null;
this.dataService.getTodos()
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}
}

public deleteTodo(todo: ITodo): void {


if (this.$window.confirm('Are you sure you want to delete this todo item?')) {
let index: number = -1;
for (let i: number = 0; i < this.todoCollection.length; i++) {
if (this.todoCollection[i].id === todo.id) {
index = i;
break;
}
}

if (index > -1) {


this.todoCollection.splice(index, 1);
}

this.dataService.deleteTodo(todo)
.then((): void => {
this.dataService.getTodos()
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}
}

public completeTodo(todo: ITodo): void {


todo.done = true;

this.dataService.setTodoStatus(todo, true)
.then((): void => {
this.dataService.getTodos()
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}

public undoTodo(todo: ITodo): void {


todo.done = false;

this.dataService.setTodoStatus(todo, false)
.then((): void => {
this.dataService.getTodos()
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}
}

Upgrade application module


In your project, rename the ./src/webparts/toDo/app/app.module.js file to app.module.ts . Change its contents to:
import * as angular from 'angular';
import config from './app.config';
import HomeController from './HomeController';
import DataService from './DataService';

import 'ng-office-ui-fabric';

const todoapp: angular.IModule = angular.module('todoapp', [


'officeuifabric.core',
'officeuifabric.components'
]);

config();

todoapp
.controller('HomeController', HomeController)
.service('DataService', DataService);

Update reference to AngularJS application in the web part


Now that the AngularJS application is built using TypeScript, and its different pieces reference each other, it's no longer necessary for the web part to reference all pieces of the application.
Instead, it only needs to load the main module, which in turn loads all other elements that build up the AngularJS application.
1. In the code editor, open the ./src/webparts/toDo/ToDoWebPart.ts file. Change the render method to:

export default class ToDoWebPart extends BaseClientSideWebPart<IToDoWebPartProps> {


// ...
public render(): void {
if (this.renderedOnce === false) {
require('./app/app.module');

this.domElement.innerHTML = `
<div class="${styles.toDo}">
<div data-ng-controller="HomeController as vm">
<div class="${styles.loading}" ng-show="vm.isLoading">
<uif-spinner>Loading...</uif-spinner>
</div>
<div id="entryform" ng-show="vm.isLoading === false">
<uif-textfield uif-label="New to do:" uif-underlined ng-model="vm.newItem" ng-keydown="vm.todoKeyDown($event)"></uif-textfield>
</div>
<uif-list id="items" ng-show="vm.isLoading === false" >
<uif-list-item ng-repeat="todo in vm.todoCollection" uif-item="todo" ng-class="{'${styles.done}': todo.done}">
<uif-list-item-primary-text>{{todo.title}}</uif-list-item-primary-text>
<uif-list-item-actions>
<uif-list-item-action ng-click="vm.completeTodo(todo)" ng-show="todo.done === false">
<i class="ms-Icon ms-Icon--CheckMark" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.undoTodo(todo)" ng-show="todo.done">
<i class="ms-Icon ms-Icon--RevToggleKey" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.deleteTodo(todo)">
<i class="ms-Icon ms-Icon--Delete" aria-hidden="true"></i>
</uif-list-item-action>
</uif-list-item-actions>
</uif-list-item>
</uif-list>
</div>
</div>`;

angular.bootstrap(this.domElement, ['todoapp']);
}
}
// ...
}

2. To verify that the upgrade to TypeScript has been successful, in the command line, run:

gulp serve --nobrowser

3. In the web browser, refresh the SharePoint Workbench, which should display your web part as previously.
Even though the way the web part works hasn't changed, your code is improved. In case of a future update, you can more easily verify the correctness and integrity of your code already
during development.

Improve integration of the AngularJS application with the SharePoint Framework


At this point the AngularJS application works correctly and is wrapped in a SharePoint Framework client-side web part. While users can add the web part to the page, they cannot configure
how the web part should work. All of the configuration is embedded in the AngularJS application's code. In this section, you will extend the web part to allow configuration of the name of
the list where the To Do items are stored and whether the web part should show finished tasks or not.

Define web part properties


1. In the code editor, open the ./src/webparts/toDo/ToDoWebPart.manifest.json file. Change the properties section to:

"properties": {
"todoListName": "Todo",
"hideFinishedTasks": false
}

2. In the ./src/webparts/toDo/ToDoWebPart.ts file, change the definition of the IToDoWebPartProps interface to:

export interface IToDoWebPartProps {


todoListName: string;
hideFinishedTasks: boolean;
}

3. In the ./src/webparts/toDo/ToDoWebPart.ts file, change the first import statement to:

import {
BaseClientSideWebPart,
IPropertyPaneSettings,
PropertyPaneTextField,
PropertyPaneToggle
} from '@microsoft/sp-webpart-base';

4. In the same file, change the getPropertyPaneConfiguration method to:

export default class ToDoWebPart extends BaseClientSideWebPart<IToDoWebPartProps> {


// ...
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('todoListName', {
label: strings.ListNameFieldLabel
}),
PropertyPaneToggle('hideFinishedTasks', {
label: strings.HideFinishedTasksFieldLabel
})
]
}
]
}
]
};
}
// ...
}

5. Add the missing resource strings by changing the ./src/webparts/toDo/loc/mystrings.d.ts file contents to:
declare interface IToDoWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
ListNameFieldLabel: string;
HideFinishedTasksFieldLabel: string;
}

declare module 'ToDoWebPartStrings' {


const strings: IToDoWebPartStrings;
export = strings;
}

6. In the ./src/webparts/toDo/loc/en-us.js file, add translations for the newly added strings:

define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListNameFieldLabel": "List name",
"HideFinishedTasksFieldLabel": "Hide finished tasks"
}
});

Pass web part properties values to the AngularJS application


At this moment users can configure how the web part should work, but the AngularJS application isn't using these values. In the following sections, you will extend the AngularJS application
to use the configuration values provided by users through the web part property pane. One way to do that is to broadcast an AngularJS event in the render method and subscribe to this
event in the controller used in the web part.

Delete AngularJS configuration file


In your project, delete the ./src/webparts/toDo/app/app.config.ts file. In the following steps you will update the application to get the configuration values from web part properties.

Remove reference to configuration


In the ./src/webparts/toDo/app/app.module.ts file, remove the reference to the AngularJS configuration by changing its contents to:

import * as angular from 'angular';


import HomeController from './HomeController';
import DataService from './DataService';

import 'ng-office-ui-fabric';

const todoapp: angular.IModule = angular.module('todoapp', [


'officeuifabric.core',
'officeuifabric.components'
]);

todoapp
.controller('HomeController', HomeController)
.service('DataService', DataService);

Update data service to accept configuration value in method parameters


Originally the data service retrieved its configuration from the constants defined in the app.config.ts file. To use the configuration values configured in the web part properties instead, the
specific methods must accept parameters.
In the code editor, open the ./src/webparts/toDo/app/DataService.ts file, and change its contents to:

import * as angular from 'angular';

export interface ITodo {


id: number;
title: string;
done: boolean;
}

interface ITodoItem {
Id: number;
Title: string;
Status: string;
}

export interface IDataService {


getTodos: (sharePointApi: string, todoListName: string, hideFinishedTasks: boolean) => angular.IPromise<ITodo[]>;
addTodo: (todo: string, sharePointApi: string, todoListName: string) => angular.IPromise<{}>;
deleteTodo: (todo: ITodo, sharePointApi: string, todoListName: string) => angular.IPromise<{}>;
setTodoStatus: (todo: ITodo, done: boolean, sharePointApi: string, todoListName: string) => angular.IPromise<{}>;
}

export default class DataService implements IDataService {


public static $inject: string[] = ['$q', '$http'];

constructor(private $q: angular.IQService, private $http: angular.IHttpService) {


}

public getTodos(sharePointApi: string, todoListName: string, hideFinishedTasks: boolean): angular.IPromise<ITodo[]> {


const deferred: angular.IDeferred<ITodo[]> = this.$q.defer();

let url: string = `${sharePointApi}web/lists/getbytitle('${todoListName}')/items?$select=Id,Title,Status&$orderby=ID desc`;

if (hideFinishedTasks === true) {


url += "&$filter=Status ne 'Completed'";
}

this.$http({
url: url,
method: 'GET',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ value: ITodoItem[] }>): void => {
const todos: ITodo[] = [];
for (let i: number = 0; i < result.data.value.length; i++) {
const todo: ITodoItem = result.data.value[i];
todos.push({
id: todo.Id,
title: todo.Title,
done: todo.Status === 'Completed'
});
}
deferred.resolve(todos);
});

return deferred.promise;
}

public addTodo(todo: string, sharePointApi: string, todoListName: string): angular.IPromise<{}> {


const deferred: angular.IDeferred<{}> = this.$q.defer();

let listItemEntityTypeFullName: string = undefined;


this.getListItemEntityTypeFullName(sharePointApi, todoListName)
.then((entityTypeName: string): angular.IPromise<string> => {
listItemEntityTypeFullName = entityTypeName;
return this.getRequestDigest(sharePointApi);
})
.then((requestDigest: string): void => {
const body: string = JSON.stringify({
'__metadata': { 'type': listItemEntityTypeFullName },
'Title': todo
});
this.$http({
url: `${sharePointApi}web/lists/getbytitle('${todoListName}')/items`,
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata',
'Content-type': 'application/json;odata=verbose',
'X-RequestDigest': requestDigest
},
data: body
}).then((result: angular.IHttpPromiseCallbackArg<{}>): void => {
deferred.resolve();
});
});

return deferred.promise;
}

public deleteTodo(todo: ITodo, sharePointApi: string, todoListName: string): angular.IPromise<{}> {


const deferred: angular.IDeferred<{}> = this.$q.defer();

this.getRequestDigest(sharePointApi)
.then((requestDigest: string): void => {
this.$http({
url: `${sharePointApi}web/lists/getbytitle('${todoListName}')/items(${todo.id})`,
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata',
'X-RequestDigest': requestDigest,
'IF-MATCH': '*',
'X-HTTP-Method': 'DELETE'
}
}).then((result: angular.IHttpPromiseCallbackArg<{}>): void => {
deferred.resolve();
});
});

return deferred.promise;
}

public setTodoStatus(todo: ITodo, done: boolean, sharePointApi: string, todoListName: string): angular.IPromise<{}> {
const deferred: angular.IDeferred<{}> = this.$q.defer();

let listItemEntityTypeFullName: string = undefined;


this.getListItemEntityTypeFullName(sharePointApi, todoListName)
.then((entityTypeName: string): angular.IPromise<string> => {
listItemEntityTypeFullName = entityTypeName;
return this.getRequestDigest(sharePointApi);
})
.then((requestDigest: string): void => {
const body: string = JSON.stringify({
'__metadata': { 'type': listItemEntityTypeFullName },
'Status': done ? 'Completed' : 'Not started'
});
this.$http({
url: `${sharePointApi}web/lists/getbytitle('${todoListName}')/items(${todo.id})`,
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata',
'Content-type': 'application/json;odata=verbose',
'X-RequestDigest': requestDigest,
'IF-MATCH': '*',
'X-HTTP-Method': 'MERGE'
},
data: body
}).then((result: angular.IHttpPromiseCallbackArg<{}>): void => {
deferred.resolve();
});
});

return deferred.promise;
}

private getRequestDigest(sharePointApi: string): angular.IPromise<string> {


const deferred: angular.IDeferred<string> = this.$q.defer();
const deferred: angular.IDeferred<string> = this.$q.defer();

this.$http({
url: sharePointApi + 'contextinfo',
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ FormDigestValue: string }>): void => {
deferred.resolve(result.data.FormDigestValue);
}, (err: any): void => {
deferred.reject(err);
});

return deferred.promise;
}

private getListItemEntityTypeFullName(sharePointApi: string, todoListName: string): angular.IPromise<string> {


const deferred: angular.IDeferred<string> = this.$q.defer();

this.$http({
url: `${sharePointApi}web/lists/getbytitle('${todoListName}')?$select=ListItemEntityTypeFullName`,
method: 'GET',
headers: {
'Accept': 'application/json;odata=nometadata'
}
}).then((result: angular.IHttpPromiseCallbackArg<{ ListItemEntityTypeFullName: string }>): void => {
deferred.resolve(result.data.ListItemEntityTypeFullName);
}, (err: any): void => {
deferred.reject(err);
});

return deferred.promise;
}
}

Broadcast properties change event


1. In the ./src/webparts/toDo/ToDoWebPart.ts file, to the ToDoWebPart class, add a new property called $injector :

export default class ToDoWebPart extends BaseClientSideWebPart<IToDoWebPartProps> {


private $injector: angular.auto.IInjectorService;
// ...
}

2. In the same file, update the render method to:

export default class ToDoWebPart extends BaseClientSideWebPart<IToDoWebPartProps> {


// ...
public render(): void {
if (this.renderedOnce === false) {
require('./app/app.module');

this.domElement.innerHTML = `
<div class="${styles.toDo}">
<div data-ng-controller="HomeController as vm">
<div class="${styles.configurationNeeded}" ng-show="vm.configurationNeeded">
Please configure the web part
</div>
<div ng-show="vm.configurationNeeded === false">
<div id="loading" ng-show="vm.isLoading">
<uif-spinner>Loading...</uif-spinner>
</div>
<div id="entryform" ng-show="vm.isLoading === false">
<uif-textfield uif-label="New to do:" uif-underlined ng-model="vm.newItem" ng-keydown="vm.todoKeyDown($event)"></uif-textfield>
</div>
<uif-list id="items" ng-show="vm.isLoading === false" >
<uif-list-item ng-repeat="todo in vm.todoCollection" uif-item="todo" ng-class="{'${styles.done}': todo.done}">
<uif-list-item-primary-text>{{todo.title}}</uif-list-item-primary-text>
<uif-list-item-actions>
<uif-list-item-action ng-click="vm.completeTodo(todo)" ng-show="todo.done === false">
<i class="ms-Icon ms-Icon--CheckMark" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.undoTodo(todo)" ng-show="todo.done">
<i class="ms-Icon ms-Icon--RevToggleKey" aria-hidden="true"></i>
</uif-list-item-action>
<uif-list-item-action ng-click="vm.deleteTodo(todo)">
<i class="ms-Icon ms-Icon--Delete" aria-hidden="true"></i>
</uif-list-item-action>
</uif-list-item-actions>
</uif-list-item>
</uif-list>
</div>
</div>
</div>`;

this.$injector = angular.bootstrap(this.domElement, ['todoapp']);


}

this.$injector.get('$rootScope').$broadcast('configurationChanged', {
sharePointApi: this.context.pageContext.web.absoluteUrl + '/_api/',
todoListName: this.properties.todoListName,
hideFinishedTasks: this.properties.hideFinishedTasks
});
}
// ...
}

3. In the ./src/webparts/toDo/ToDoWebPart.module.scss file, add the missing styles for the .configurationNeeded class:
.toDo {
/* ... */
.configurationNeeded {
margin: 0 auto;
width: 100%;
text-align: center;
}
/* ... */
}

Subscribe to the properties changed event


1. In the code editor, open the ./src/webparts/toDo/app/HomeController.ts file. In the HomeController class, add the following properties:

export default class HomeController {


// ...
private sharePointApi: string = undefined;
private todoListName: string = undefined;
private hideFinishedTasks: boolean = false;
private configurationNeeded: boolean = true;
// ...
}

2. Extend the constructor of the HomeController class with injecting the root scope service, and change its contents to:

export default class HomeController {


// ...
public static $inject: string[] = ['DataService', '$window', '$rootScope'];

constructor(private dataService: IDataService,


private $window: angular.IWindowService,
$rootScope: angular.IRootScopeService) {
const vm: HomeController = this;
this.init(undefined, undefined);

$rootScope.$on('configurationChanged',
(event: angular.IAngularEvent,
args: {
sharePointApi: string;
todoListName: string;
hideFinishedTasks: boolean;
}): void => {
vm.init(args.sharePointApi, args.todoListName, args.hideFinishedTasks);
});
}

// ...
}

3. To the HomeController class, add the init method:

export default class HomeController {


// ...
private init(sharePointApi: string, todoListName: string, hideFinishedTasks?: boolean): void {
if (sharePointApi !== undefined && sharePointApi.length > 0 &&
todoListName !== undefined && todoListName.length > 0) {
this.sharePointApi = sharePointApi;
this.todoListName = todoListName;
this.hideFinishedTasks = hideFinishedTasks;
this.loadTodos();
this.configurationNeeded = false;
}
else {
this.configurationNeeded = true;
}
}
// ...
}

4. Update all remaining methods in the HomeController class to use the configuration values from the class properties:
export default class HomeController {
// ...
private loadTodos(): void {
this.isLoading = true;
this.dataService.getTodos(this.sharePointApi, this.todoListName, this.hideFinishedTasks)
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
})
.finally((): void => {
this.isLoading = false;
});
}

public todoKeyDown($event: KeyboardEvent): void {


if ($event.keyCode === 13 && this.newItem.length > 0) {
$event.preventDefault();

this.todoCollection.unshift({ id: -1, title: this.newItem, done: false });

this.dataService.addTodo(this.newItem, this.sharePointApi, this.todoListName)


.then((): void => {
this.newItem = null;
this.dataService.getTodos(this.sharePointApi, this.todoListName, this.hideFinishedTasks)
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}
}

public deleteTodo(todo: ITodo): void {


if (this.$window.confirm('Are you sure you want to delete this todo item?')) {
let index: number = -1;
for (let i: number = 0; i < this.todoCollection.length; i++) {
if (this.todoCollection[i].id === todo.id) {
index = i;
break;
}
}

if (index > -1) {


this.todoCollection.splice(index, 1);
}

this.dataService.deleteTodo(todo, this.sharePointApi, this.todoListName)


.then((): void => {
this.dataService.getTodos(this.sharePointApi, this.todoListName, this.hideFinishedTasks)
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}
}

public completeTodo(todo: ITodo): void {


todo.done = true;

this.dataService.setTodoStatus(todo, true, this.sharePointApi, this.todoListName)


.then((): void => {
this.dataService.getTodos(this.sharePointApi, this.todoListName, this.hideFinishedTasks)
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}

public undoTodo(todo: ITodo): void {


todo.done = false;

this.dataService.setTodoStatus(todo, false, this.sharePointApi, this.todoListName)


.then((): void => {
this.dataService.getTodos(this.sharePointApi, this.todoListName, this.hideFinishedTasks)
.then((todos: ITodo[]): void => {
this.todoCollection = todos;
});
});
}
}

5. Verify that the web part is working correctly by executing the following in the command line:

gulp serve --nobrowser

6. In your web browser, go to the SharePoint Workbench and add the web part to canvas. If you toggle the Hide finished tasks option, you should see completed tasks being displayed
or hidden accordingly.
Work with __REQUESTDIGEST
3/26/2018 • 3 minutes to read Edit Online

When executing non-GET REST requests to the SharePoint API, you must add a valid request digest to your request. This digest proves validity of your request to SharePoint. Because this
token is valid only for a limited period of time, you have to ensure that the token you have is valid before adding it to your request or the request fails.
In classic pages, SharePoint includes a request digest token on the page in a hidden field named __REQUESTDIGEST. One of the most common approaches to work with the request digest
is to obtain it from that field and add it to the request, for example:

var digest = $('#__REQUESTDIGEST').val();


$.ajax({
url: '/_api/web/...'
method: "POST",
headers: {
"Accept": "application/json; odata=nometadata",
"X-RequestDigest": digest
},
success: function (data) {
// ...
},
error: function (data, errorCode, errorMessage) {
// ...
}
});

Such a request would work initially, but if the user has the page open for a longer period of time, the request digest on the page expires and the request fails with a 403 FORBIDDEN result.
By default, a request digest token is valid for 30 minutes, so before using it, you have to ensure that it's still valid. In the past you had to do this manually, by comparing the timestamp from
the request digest with the current time.
SharePoint Framework simplifies this process by offering you two ways of ensuring that your request has a valid request digest token.

Use the SPHttpClient to communicate with the SharePoint REST API


The recommended way to communicate with the SharePoint REST API is to use the SPHttpClient provided with the SharePoint Framework. This class wraps issuing REST requests to the
SharePoint REST API with convenient logic that simplifies your code.
For example, whenever you issue a non-GET request using the SPHttpClient, it automatically obtains a valid request digest and adds it to the request. This significantly simplifies your
solution because you don't need to build code to manage request digest tokens and ensure their validity.
If you're building new customizations on the SharePoint Framework, you should always use the SPHttpClient to communicate with the SharePoint REST API.
Sometimes, however, you might not be able to use the SPHttpClient. This can be the case, for example, when you're migrating an existing customization to the SharePoint Framework and
want to keep as much of the original code as possible, or you're building a customization by using a library such as Angular(JS) that has its own services for issuing web requests. In such
cases you can obtain a valid request digest token from the DigestCache.

Retrieve a valid request digest by using the DigestCache service


If you can't use the SPHttpClient for communicating with the SharePoint REST API, you can obtain a valid request digest token by using the DigestCache service provided with the
SharePoint Framework.
The benefit of using the DigestCache service over manually obtaining a valid request digest token is that the DigestCache automatically checks if the previously retrieved request digest is
still valid. If it's expired, the DigestCache service automatically requests a new request digest token from SharePoint and stores it from subsequent requests. Using the DigestCache simplifies
your code and makes your solution more robust.

To use the DigestCache service in your code


1. Import the DigestCache and IDigestCache types from the @microsoft/sp-http package:

// ...
import { IDigestCache, DigestCache } from '@microsoft/sp-http';

export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {


// ...
}

2. Whenever you need a valid request digest token, retrieve a reference to the DigestCache service, and call its fetchDigest method:

// ...
import { IDigestCache, DigestCache } from '@microsoft/sp-http';

export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {


protected onInit(): Promise<void> {
return new Promise<void>((resolve: () => void, reject: (error: any) => void): void => {
const digestCache: IDigestCache = this.context.serviceScope.consume(DigestCache.serviceKey);
digestCache.fetchDigest(this.context.pageContext.web.serverRelativeUrl).then((digest: string): void => {
// use the digest here
resolve();
});
});
}

// ...
}

See also
SharePoint Framework Overview
Connect to SharePoint using the JavaScript Object Model (JSOM)
5/3/2018 • 14 minutes to read Edit Online

In the past, when building SharePoint customizations, you might have used the SharePoint JavaScript Object Model (JSOM) to communicate with SharePoint. This is no longer the
recommended path (see Considerations later in this article), but there are still valid use cases such as code migration.
To use SharePoint JSOM in your SharePoint Framework component, you must first reference it. In the past it was already available on the page for you to use. In the SharePoint Framework,
it has to be explicitly loaded.
There are two ways to reference SharePoint JSOM in the SharePoint Framework:
Declarative - through configuration
Imperative - through code
Each of these approaches has advantages and disadvantages, and it's important for you to understand each of them.
NOTE

Before following the steps in this article, be sure to set up your SharePoint Framework development environment.

Create a new project


1. From the console, create a new folder for your project:

md react-sharepointlists

2. Go to the project folder:

cd react-sharepointlists

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:

yo @microsoft/sharepoint

4. When prompted, enter the following values:


react-sharepointlists as your solution name.
Select Webpart as the client-side component type to be created.
Use the current folder for the location to place the files.
React as the starting framework to build the web part.
SharePoint lists as your web part name.
Shows names of lists in the current site as your web part description.

5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor you prefer.
7. To open the directory in Visual Studio Code, from the console enter:

code .

Reference JSOM declaratively


Register the SharePoint JSOM API as external scripts
When referencing JSOM declaratively, the first step is to register the SharePoint JSOM API as external scripts within your SharePoint Framework project.
1. In your code editor, open the ./config/config.json file, and add the following to the externals section:

{
// ...
"externals": {
"sp-init": {
"path": "https://contoso.sharepoint.com/_layouts/15/init.js",
"globalName": "$_global_init"
},
"microsoft-ajax": {
"path": "https://contoso.sharepoint.com/_layouts/15/MicrosoftAjax.js",
"globalName": "Sys",
"globalDependencies": [
"sp-init"
]
},
"sp-runtime": {
"path": "https://contoso.sharepoint.com/_layouts/15/SP.Runtime.js",
"globalName": "SP",
"globalDependencies": [
"microsoft-ajax"
]
},
"sharepoint": {
"path": "https://contoso.sharepoint.com/_layouts/15/SP.js",
"globalName": "SP",
"globalDependencies": [
"sp-runtime"
]
}
}
// ...
}

Each of the entries points to different script files that together allow you to use SharePoint JSOM in your SPFx component. All of these scripts are distributed as non-module scripts.
This is why each registration entry requires a URL, (specified using the path property) and the name used by the script (provided in the globalName property). To ensure that these
scripts load in the right order, the dependencies between these scripts are specified by using the globalDependencies property.
Additional scripts may need to be added depending on the JSOM functionality that you are using (e.g. sp.taxonomy.js).

Install TypeScript typings for SharePoint JSOM


The next step is to install and configure TypeScript typings for SharePoint JSOM, which allows you to benefit from TypeScript's type safety features when working with SharePoint JSOM.
1. From the console, execute the following command within your project directory:
npm install @types/microsoft-ajax @types/sharepoint --save-dev

SharePoint JSOM is not distributed as a module, so you cannot import it directly in your code. Instead, you need to register its TypeScript typings globally.
2. In the code editor, open the ./tsconfig.json file, and in the types property, right after the webpack-env entry, add references to microsoft-ajax and sharepoint:

{
"compilerOptions": {
// ...
"types": [
"es6-promise",
"es6-collections",
"webpack-env",
"microsoft-ajax",
"sharepoint"
]
}
}

Reference SharePoint JSOM scripts in a React component


To load the SharePoint JSOM scripts in your SPFx component, you have to reference them in the component's code. In this example, you add the references in a React component where
JSOM is used to communicate with SharePoint.
In the code editor, open the ./src/webparts/sharePointLists/components/SharePointLists.tsx file. After the last import statement, add the following code:

require('sp-init');
require('microsoft-ajax');
require('sp-runtime');
require('sharepoint');

These names correspond to the external references that you added previously, so SharePoint Framework loads these scripts from the specified URLs.
To demonstrate using SharePoint JSOM for communicating with SharePoint, you need to retrieve and render the titles of all SharePoint lists located in the current site.

Add siteUrl to the React component's properties


To connect to SharePoint, the React component must know the URL of the current site. That URL is available in the parent web part and can be passed into the component through its
properties.
1. In the code editor, open the ./src/webparts/sharePointLists/components/ISharePointListsProps.ts file, and add the siteUrl property to the ISharePointListsProps interface:

export interface ISharePointListsProps {


description: string;
siteUrl: string;
}

2. To pass the URL of the current site into the component, open the ./src/webparts/sharePointLists/SharePointListsWebPart.ts file in the code editor, and change the render
method to:

export default class SharePointListsWebPart extends BaseClientSideWebPart<ISharePointListsWebPartProps> {


public render(): void {
const element: React.ReactElement<ISharePointListsProps > = React.createElement(
SharePointLists,
{
description: this.properties.description,
siteUrl: this.context.pageContext.web.absoluteUrl
}
);

ReactDom.render(element, this.domElement);
}

// ...
}

Define the React component's state


The React component loads data from SharePoint and renders it to the user. The current state of the React component is modeled by using a state interface that we add.
In the code editor, in the ./src/webparts/sharePointLists/components folder, create a new file named ISharePointListsState.ts and paste in the following contents:

export interface ISharePointListsState {


listTitles: string[];
loadingLists: boolean;
error: string;
}

Add state to the React component


Having defined the interface describing the shape of the component's state, the next step is to have the React component use that state interface.
1. In the code editor, open the ./src/webparts/sharePointLists/components/SharePointLists.tsx file. Under the existing import statements, add:

import { ISharePointListsState } from './ISharePointListsState';

2. Change the signature of the SharePointLists class to:

export default class SharePointLists extends React.Component<ISharePointListsProps, ISharePointListsState> {


// ...
}
3. In the SharePointLists class, add a constructor with the default state value:

export default class SharePointLists extends React.Component<ISharePointListsProps, ISharePointListsState> {


constructor(props?: ISharePointListsProps, context?: any) {
super();

this.state = {
listTitles: [],
loadingLists: false,
error: null
};
}

// ...
}

Load information about SharePoint lists from the current site using JSOM
The sample client-side web part used in this article loads information about SharePoint lists in the current site after selecting a button.

1. In the code editor, open the ./src/webparts/sharePointLists/components/SharePointLists.tsx file. In the SharePointLists class, add a new method named getListsTitles :

export default class SharePointLists extends React.Component<ISharePointListsProps, ISharePointListsState> {


constructor(props?: ISharePointListsProps, context?: any) {
super();

this.state = {
listTitles: [],
loadingLists: false,
error: null
};

this.getListsTitles = this.getListsTitles.bind(this);
}

// ...

private getListsTitles(): void {


}
}

2. To ensure the correct scoping of the method, we bind it to the web part in the constructor. In the getListsTitles method, use SharePoint JSOM to load the titles of SharePoint lists in
the current site:
export default class SharePointLists extends React.Component<ISharePointListsProps, ISharePointListsState> {
// ...
private getListsTitles(): void {
this.setState({
loadingLists: true,
listTitles: [],
error: null
});

const context: SP.ClientContext = new SP.ClientContext(this.props.siteUrl);


const lists: SP.ListCollection = context.get_web().get_lists();
context.load(lists, 'Include(Title)');
context.executeQueryAsync((sender: any, args: SP.ClientRequestSucceededEventArgs): void => {
const listEnumerator: IEnumerator<SP.List> = lists.getEnumerator();

const titles: string[] = [];


while (listEnumerator.moveNext()) {
const list: SP.List = listEnumerator.get_current();
titles.push(list.get_title());
}

this.setState((prevState: ISharePointListsState, props: ISharePointListsProps): ISharePointListsState => {


prevState.listTitles = titles;
prevState.loadingLists = false;
return prevState;
});
}, (sender: any, args: SP.ClientRequestFailedEventArgs): void => {
this.setState({
loadingLists: false,
listTitles: [],
error: args.get_message()
});
});
}
}

We start by resetting the component's state to communicate to the user that the component is loading information from SharePoint. Using the URL of the current site passed to the
component through its properties, we instantiate a new SharePoint context. Using SharePoint JSOM, we load lists from the current site. To optimize the request for performance, we specify
that only the Title property should be loaded.
Next, we execute the query by calling the executeQueryAsync method and passing two callback functions. After the query is completed, we enumerate through the collection of retrieved lists,
store their titles in an array, and update the component's state.

Render the titles of SharePoint lists in the current site


Having loaded the titles of SharePoint lists in the current site, the final step is to render them in the component.
1. In the code editor, open the ./src/webparts/sharePointLists/components/SharePointLists.tsx file, and update the render method:

export default class SharePointLists extends React.Component<ISharePointListsProps, ISharePointListsState> {


// ...
public render(): React.ReactElement<ISharePointListsProps> {
const titles: JSX.Element[] = this.state.listTitles.map((listTitle: string, index: number, listTitles: string[]): JSX.Element => {
return <li key={index}>{listTitle}</li>;
});

return (
<div className={styles.sharePointLists}>
<div className={styles.container}>
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span className="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
<p className="ms-font-l ms-fontColor-white">Customize SharePoint experiences using web parts.</p>
<p className="ms-font-l ms-fontColor-white">{escape(this.props.description)}</p>
<a className={styles.button} onClick={this.getListsTitles} role="button">
<span className={styles.label}>Get lists titles</span>
</a><br />
{this.state.loadingLists &&
<span>Loading lists...</span>}
{this.state.error &&
<span>An error has occurred while loading lists: {this.state.error}</span>}
{this.state.error === null && titles &&
<ul>
{titles}
</ul>}
</div>
</div>
</div>
</div>
);
}
// ...
}

2. At this point, you should be able to add your web part to the page and see the titles of SharePoint lists in the current site. To verify that the project is working correctly, run the
following command from the console:

gulp serve --nobrowser

3. As you are using SharePoint JSOM to communicate with SharePoint, you have to test the web part by using the hosted version of the SharePoint Workbench (which is why the
--nobrowser parameter is specified to prevent the automatic loading of the local Workbench).
Referencing SharePoint JSOM scripts declaratively as external scripts is convenient and allows you to keep your code clean. One disadvantage, however, is that it requires specifying absolute
URLs to the location from which SharePoint JSOM scripts should be loaded. If you're using separate SharePoint tenants for development, testing, and production, it requires some additional
work to change these URLs for the different environments accordingly. In such cases, you may consider referencing JSOM imperatively by using the SPComponentLoader to load the scripts
in the SPFx component's code.

Reference JSOM imperatively


Another way to load JavaScript libraries in SharePoint Framework projects is to use the SPComponentLoader , a utility class provided with the SharePoint Framework designed to help you load
scripts and other resources in your components. One benefit of using the SPComponentLoader over loading scripts declaratively is that it allows you to use server-relative URLs, which is more
convenient when using different SharePoint tenants for the different stages of your development process.
For this portion of the tutorial, we'll be adjusting the code we created previously in the Declarative section.

Declarative reference cleanup


If you followed the steps in the declarative reference sections earlier, you need to remove those references.
1. Remove the existing external script references. In the code editor, open the ./config/config.json file, and from the externals property, remove all entries:

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"share-point-lists-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/sharePointLists/SharePointListsWebPart.js",
"manifest": "./src/webparts/sharePointLists/SharePointListsWebPart.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {
"SharePointListsWebPartStrings": "lib/webparts/sharePointLists/loc/{locale}.js"
}
}

With the SharePoint JSOM scripts no longer being registered as external scripts, you cannot reference them directly in your code.
2. In the code editor, open the ./src/webparts/sharePointLists/components/SharePointLists.tsx file, and remove the require statements pointing to the different SharePoint JSOM
scripts.

Wait to load data until the JSOM scripts are loaded


The primary functionality of the client-side web part that we are building in this tutorial depends on SharePoint JSOM. Depending on a number of factors, loading these scripts could take a
few moments. When building SPFx components that utilize JSOM, you should take that into account. When added to the page, the web part should communicate to the user that it's loading
its prerequisites and should make it clear when it's ready to be used.
To support this, extend the React component's state with an additional property to track the status of loading the JSOM scripts.
1. In the code editor, open the ./src/webparts/sharePointLists/components/ISharePointListsState.ts file, and paste the following code:
export interface ISharePointListsState {
listTitles: string[];
loadingLists: boolean;
error: string;
loadingScripts: boolean;
}

2. Add the newly added property to the state definitions in the React component. In the code editor, open the ./src/webparts/sharePointLists/components/SharePointLists.tsx file.
Update the constructor to the following code:

export default class SharePointLists extends React.Component<ISharePointListsProps, ISharePointListsState> {


constructor(props?: ISharePointListsProps, context?: any) {
super();

this.state = {
listTitles: [],
loadingLists: false,
error: null,
loadingScripts: true
};

this.getListsTitles = this.getListsTitles.bind(this);
}
// ...
}

3. In the same file, update the getListsTitles method to the following code:

export default class SharePointLists extends React.Component<ISharePointListsProps, ISharePointListsState> {


// ...
private getListsTitles(): void {
this.setState({
loadingLists: true,
listTitles: [],
error: null,
loadingScripts: false
});

const context: SP.ClientContext = new SP.ClientContext(this.props.siteUrl);


const lists: SP.ListCollection = context.get_web().get_lists();
context.load(lists, 'Include(Title)');
context.executeQueryAsync((sender: any, args: SP.ClientRequestSucceededEventArgs): void => {
const listEnumerator: IEnumerator<SP.List> = lists.getEnumerator();

const titles: string[] = [];


while (listEnumerator.moveNext()) {
const list: SP.List = listEnumerator.get_current();
titles.push(list.get_title());
}

this.setState((prevState: ISharePointListsState, props: ISharePointListsProps): ISharePointListsState => {


prevState.listTitles = titles;
prevState.loadingLists = false;
return prevState;
});
}, (sender: any, args: SP.ClientRequestFailedEventArgs): void => {
this.setState({
loadingLists: false,
listTitles: [],
error: args.get_message(),
loadingScripts: false
});
});
}
}

4. To communicate the status of loading the SharePoint JSOM scripts to the user, update the render method to the following code:
export default class SharePointLists extends React.Component<ISharePointListsProps, ISharePointListsState> {
// ...
public render(): React.ReactElement<ISharePointListsProps> {
const titles: JSX.Element[] = this.state.listTitles.map((listTitle: string, index: number, listTitles: string[]): JSX.Element => {
return <li key={index}>{listTitle}</li>;
});

return (
<div className={styles.sharePointLists}>
<div className={styles.container}>
{this.state.loadingScripts &&
<div className="ms-Grid" style={{ color: "#666", backgroundColor: "#f4f4f4", padding: "80px 0", alignItems: "center", boxAlign: "center" }}>
<div className="ms-Grid-row" style={{ color: "#333" }}>
<div className="ms-Grid-col ms-u-hiddenSm ms-u-md3"></div>
<div className="ms-Grid-col ms-u-sm12 ms-u-md6" style={{ height: "100%", whiteSpace: "nowrap", textAlign: "center" }}>
<i className="ms-fontSize-su ms-Icon ms-Icon--CustomList" style={{ display: "inline-block", verticalAlign: "middle", whiteSpace: "normal" }}></i><span className="ms-fontWeigh
</div>
<div className="ms-Grid-col ms-u-hiddenSm ms-u-md3"></div>
</div>
<div className="ms-Grid-row" style={{ width: "65%", verticalAlign: "middle", margin: "0 auto", textAlign: "center" }}>
<span style={{ color: "#666", fontSize: "17px", display: "inline-block", margin: "24px 0", fontWeight: 100 }}>Loading SharePoint JSOM scripts...</span>
</div>
<div className="ms-Grid-row"></div>
</div>}
{this.state.loadingScripts === false &&
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span className="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
<p className="ms-font-l ms-fontColor-white">Customize SharePoint experiences using web parts.</p>
<p className="ms-font-l ms-fontColor-white">{escape(this.props.description)}</p>
<a className={styles.button} onClick={this.getListsTitles} role="button">
<span className={styles.label}>Get lists titles</span>
</a><br />
{this.state.loadingLists &&
<span>Loading lists...</span>}
{this.state.error &&
<span>An error has occurred while loading lists: {this.state.error}</span>}
{this.state.error === null && titles &&
<ul>
{titles}
</ul>}
</div>
</div>
}
</div>
</div>
);
}
// ...
}

5. When the React component's state indicates that the SharePoint JSOM scripts are being loaded, it displays a placeholder. After the scripts have been loaded, the web part displays the
expected content with the button allowing users to load the information about SharePoint lists in the current site.

Load SharePoint JSOM scripts by using SPComponentLoader


SPFx components should load SharePoint JSOM scripts only once. In this example, given that the web part consists of a single React component, the best place to load SharePoint JSOM
scripts is inside the React component's componentDidMount method, which executes only once after the component has been instantiated.
1. In the code editor, open the ./src/webparts/sharePointLists/components/SharePointLists.tsx file. In the top section of the file, add an import statement referencing the
SPComponentLoader . In the SharePointLists class, add the componentDidMount method:

import { SPComponentLoader } from '@microsoft/sp-loader';

export default class SharePointLists extends React.Component<ISharePointListsProps, ISharePointListsState> {


// ...
public componentDidMount(): void {
SPComponentLoader.loadScript('/_layouts/15/init.js', {
globalExportsName: '$_global_init'
})
.then((): Promise<{}> => {
return SPComponentLoader.loadScript('/_layouts/15/MicrosoftAjax.js', {
globalExportsName: 'Sys'
});
})
.then((): Promise<{}> => {
return SPComponentLoader.loadScript('/_layouts/15/SP.Runtime.js', {
globalExportsName: 'SP'
});
})
.then((): Promise<{}> => {
return SPComponentLoader.loadScript('/_layouts/15/SP.js', {
globalExportsName: 'SP'
});
})
.then((): void => {
this.setState((prevState: ISharePointListsState, props: ISharePointListsProps): ISharePointListsState => {
prevState.loadingScripts = false;
return prevState;
});
});
}
// ...
}

2. Using a series of chained promises, we load the different scripts that together enable using SharePoint JSOM in your SharePoint Framework component. Note that by using the
SPComponentLoader , you can use server-relative URLs that load the scripts from the current SharePoint tenant. After all scripts have been loaded, you update the React component's
state confirming that all prerequisites have been loaded and the web part is ready to use.
3. Confirm that the web part is working as expected by running the following command from the console:

gulp serve --nobrowser

Just as before, the web part should show the titles of SharePoint lists in the current site.

While using the SPComponentLoader requires some additional effort, it allows you to use server-relative URLs, which is beneficial in scenarios when you're using different tenants for
development, testing, and production.

Considerations
In the past, when building client-side customizations on SharePoint, you might have used SharePoint JSOM to communicate with SharePoint. However, the recommended approach is to use
the SharePoint REST API either directly or through the PnP JavaScript Core Library.
When SharePoint JSOM was introduced, it was the first step towards supporting client-side solutions on SharePoint. However, it is no longer being actively maintained and might not offer
access to all capabilities available through the REST API. Additionally, whether using the SharePoint REST API directly or through the PnP JavaScript Core Library, you can use promises
which significantly simplify writing asynchronous code (a common problem when utilizing JSOM).
Although there are still a limited number of cases where SharePoint JSOM provides access to data and methods not yet covered by the SharePoint REST API, where possible, the REST API
should be preferred.
If you have existing customizations using SharePoint JSOM and are considering migrating them to the SharePoint Framework, this article should provide you with the necessary
information about using SharePoint JSOM in SharePoint Framework solutions. Longer term, however, you should consider changing how you communicate with SharePoint to either using
the SharePoint REST API directly or through the PnP JavaScript Core Library.
Overview of SharePoint Framework Extensions
3/26/2018 • 2 minutes to read Edit Online

You can use SharePoint Framework (SPFx) Extensions to extend the SharePoint user experience. With SharePoint Framework Extensions, you can customize more facets of the SharePoint
experience, including notification areas, toolbars, and list data views. SharePoint Framework Extensions are available in all Office 365 subscriptions for production usage.
NOTE

You can get an Office 365 developer subscription when you join the Office 365 Developer Program. See the Office 365 Developer Program documentation for step-by-step instructions
about how to join the Office 365 Developer Program and sign up and configure your subscription.
SharePoint Framework Extensions enable you to extend the SharePoint user experience within modern pages and document libraries, while using the familiar SharePoint Framework tools
and libraries for client-side development. Specifically, the SharePoint Framework includes three new extension types:
Application Customizers. Adds scripts to the page, and accesses well-known HTML element placeholders and extends them with custom renderings.
Field Customizers. Provides modified views to data for fields within a list.
Command Sets. Extends the SharePoint command surfaces to add new actions, and provides client-side code that you can use to implement behaviors.
You can build extensions alongside common scripting frameworks, such as AngularJS and React, in addition to plain JavaScript projects. For example, you can use React along with
components from Office UI Fabric React to create experiences based on the same components used in Office 365.
NOTE

There is a known bug with list and library extension support in the classic experiences. These only work currently in context of modern team sites, also known as group associated team sites.
Work is being done to address this issue.

Get started
1. If you haven't installed the SharePoint Framework, follow the steps to Set up your development environment.
2. After you install the SharePoint Framework, run the following command to update your Yeoman templates with the latest version:

npm install -g @microsoft/generator-sharepoint

3. Next, you can Build your first SharePoint Framework Extension (Hello World part 1).

Stay up to date
To keep track of improvements to the SharePoint Framework, including updates to extensions, see the following:
@SharePoint and @OfficeDev on Twitter
Office Developer Blog

Provide feedback
We invite you to give us your feedback on the SharePoint Framework General Availability release. You can use the following resources to provide feedback directly to the SharePoint
engineering team:
sp-dev-docs repository issue list - Questions, issues, and comments.
SharePoint StackExchange - Tag with #spfx, #spfx-extensions, and #spfx-tooling.
SharePoint Developer - Microsoft Tech Community group.
SharePoint Developer UserVoice - Request new capabilities and features.

See also
Overview of the SharePoint Framework
SharePoint Framework development tools and libraries
Build your first SharePoint Framework Extension (Hello World part 1)
7/9/2018 • 6 minutes to read Edit Online

SharePoint Framework (SPFx) Extensions are client-side components that run inside the context of a SharePoint page. You can deploy extensions to SharePoint Online, and you can use
modern JavaScript tools and libraries to build them.
You can also follow the steps in this article by watching the video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/yrFNu6K7iuU

Create an extension project


1. Create a new project directory in your favorite location.

md app-extension

2. Go to the project directory.

cd app-extension

3. Create a new HelloWorld extension by running the Yeoman SharePoint Generator.

yo @microsoft/sharepoint

4. When prompted:
Accept the default app-extension as your solution name, and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder, and select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select Application Customizer as the extension type to be created.
5. The next set of prompts ask for specific information about your extension. When prompted:
Accept the default HelloWorld as your extension name, and select Enter.
Accept the default HelloWorld description as your extension description, and select Enter.
For the next question Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites...., ensure you select No (N) , and select Enter.
If you select Yes (y), the scaffolding will not generate the Elements.xml feature deployment file.
NOTE

If you use a name for the extension that is too long, you might encounter issues. The entries provided are used to generate an alias entry for the Application Customizer
manifest JSON file. If the alias is longer than 40 characters, you get an exception when you try to serve the extension by using gulp serve --nobrowser . You can resolve this by
updating the alias entry afterward.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:

For information about troubleshooting any errors, see Known issues.


6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

7. Next, type the following into the console to start Visual Studio Code.

code .

NOTE

Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your extension.
Notice how the default solution structure looks like the solution structure for client-side web parts. This is the basic SharePoint Framework solution structure, with similar
configuration options across all solution types.

8. Open HelloWorldApplicationCustomizer.manifest.json in the src\extensions\helloWorld folder.


This file defines your extension type and a unique identifier for your extension. You’ll need this ID later when you debug and deploy your extension to SharePoint.
Code your Application Customizer
Open the HelloWorldApplicationCustomizer.ts file in the src\extensions\helloWorld folder.
Notice that base class for the Application Customizer is imported from the sp-application-base package, which contains SharePoint framework code required by the Application
Customizer.

The logic for your Application Customizer is contained in the onInit method, which is called when the client-side extension is first activated on the page. This event occurs after this.context
and this.properties are assigned. As with web parts, onInit() returns a promise that you can use to perform asynchronous operations.
NOTE

The class constructor is called at an early stage, when this.context and this.properties are undefined. Custom initiation logic is not supported here.
The following are the contents of onInit() in the default solution. This default solution writes a log to the Dev Dashboard, and then displays a simple JavaScript alert when the page renders.

If your Application Customizer uses the ClientSideComponentProperties JSON input, it is deserialized into the BaseExtension.properties object. You can define an interface to describe
it. The default template is looking for a property called testMessage. If that property is provided, it outputs it in an alert message.

Debug your Application Customizer


You cannot currently use the local Workbench to test SharePoint Framework Extensions. You need to test them against a live SharePoint Online site. You don't have to deploy your
customization to the app catalog to do this, which makes the debugging experience simple and efficient.
1. Compile your code and host the compiled files from your local computer by running the following command:

gulp serve --nobrowser

NOTE

If you do not have the SPFx developer certificate installed, Workbench notifies you that it is not configured to load scripts from localhost. If this happens, stop the process that is
currently running in the console window, run the gulp trust-dev-cert command in your project directory console to install the developer certificate, and then run the
gulp serve --nobrowser command again.

You use the --nobrowser option because you don't need to launch the local Workbench since you can't debug extensions locally.
When the code compiles without errors, it serves the resulting manifest from https://localhost:4321.
2. To test your extension, go to a modern list view page in your SharePoint environment and append the following query string parameters to the URL. Notice that you need to update
the ID to match your own extension identifier. This is available in the HelloWorldApplicationCustomizer.manifest.json file.

?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":"ClientSideExtension.ApplicationCustomizer","p

More detail about the URL query parameters:


loadSPFX=true. Ensures that the SharePoint Framework is loaded on the page. For performance reasons, the framework does not load unless at least one extension is
registered. Because no components are registered, you must explicitly load the framework.
debugManifestsFile. Specifies that you want to load SPFx components that are locally served. The loader only looks for components in the app catalog (for your deployed
solution) and the SharePoint manifest server (for the system libraries).
customActions. Simulates a custom action. When you deploy and register this component in a site, you'll create this CustomAction object and describe all the different
properties you can set on it.
Key. Use the GUID of the extension as the key to associate with the custom action. This has to match the ID value of your extension, which is available in the extension
manifest.json file.
Location. The type of custom action. Use ClientSideExtension.ApplicationCustomizer for the Application Customizer extension.
Properties. An optional JSON object that contains properties that are available via the this.properties member. In this HelloWorld example, it defined a testMessage
property.
3. Go to a modern list in SharePoint Online. This can be either a list or a library. Application Customizers are also supported in modern pages and on the Site Contents page.
4. Extend the URL with the additional query parameters described. Notice that you need to update the GUID to match the ID of your custom Application Customizer.
The full URL should look similar to the following:

contoso.sharepoint.com/Lists/Contoso/AllItems.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":

Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages

1. Select Load debug scripts to continue loading scripts from your local host.

You should now see the dialog message on your page.

This dialog is thrown by your SharePoint Framework Extension. Note that because you provided the testMessage property as part of the debug query parameters, it's included in the
alert message. You can configure your extension instances based on the client component properties, which are passed for the instance in runtime mode.
NOTE

If you have issues with debugging, double-check the URL query parameters used for the query. Some browsers encode the parameters and in some scenarios this affects the behavior.

Next steps
Congratulations, you got your first SharePoint Framework Extension running!
To continue building out your extension, see Using page placeholders from Application Customizer (Hello World part 2). You use the same project and take advantage of specific content
placeholders for modifying the UI of SharePoint. Notice that the gulp serve command is still running in your console window (or in Visual Studio Code if you are using the editor). You can
continue to let it run while you go to the next article.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Build your first SharePoint Framework Extension (Hello World part 1)
7/9/2018 • 6 minutes to read Edit Online

SharePoint Framework (SPFx) Extensions are client-side components that run inside the context of a SharePoint page. You can deploy extensions to SharePoint Online, and you can use
modern JavaScript tools and libraries to build them.
You can also follow the steps in this article by watching the video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/yrFNu6K7iuU

Create an extension project


1. Create a new project directory in your favorite location.

md app-extension

2. Go to the project directory.

cd app-extension

3. Create a new HelloWorld extension by running the Yeoman SharePoint Generator.

yo @microsoft/sharepoint

4. When prompted:
Accept the default app-extension as your solution name, and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder, and select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select Application Customizer as the extension type to be created.
5. The next set of prompts ask for specific information about your extension. When prompted:
Accept the default HelloWorld as your extension name, and select Enter.
Accept the default HelloWorld description as your extension description, and select Enter.
For the next question Do you want to allow the tenant admin the choice of being able to deploy the solution to all sites...., ensure you select No (N) , and select Enter.
If you select Yes (y), the scaffolding will not generate the Elements.xml feature deployment file.
NOTE

If you use a name for the extension that is too long, you might encounter issues. The entries provided are used to generate an alias entry for the Application Customizer
manifest JSON file. If the alias is longer than 40 characters, you get an exception when you try to serve the extension by using gulp serve --nobrowser . You can resolve this by
updating the alias entry afterward.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:

For information about troubleshooting any errors, see Known issues.


6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

7. Next, type the following into the console to start Visual Studio Code.

code .

NOTE

Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your extension.
Notice how the default solution structure looks like the solution structure for client-side web parts. This is the basic SharePoint Framework solution structure, with similar
configuration options across all solution types.

8. Open HelloWorldApplicationCustomizer.manifest.json in the src\extensions\helloWorld folder.


This file defines your extension type and a unique identifier for your extension. You’ll need this ID later when you debug and deploy your extension to SharePoint.
Code your Application Customizer
Open the HelloWorldApplicationCustomizer.ts file in the src\extensions\helloWorld folder.
Notice that base class for the Application Customizer is imported from the sp-application-base package, which contains SharePoint framework code required by the Application
Customizer.

The logic for your Application Customizer is contained in the onInit method, which is called when the client-side extension is first activated on the page. This event occurs after this.context
and this.properties are assigned. As with web parts, onInit() returns a promise that you can use to perform asynchronous operations.
NOTE

The class constructor is called at an early stage, when this.context and this.properties are undefined. Custom initiation logic is not supported here.
The following are the contents of onInit() in the default solution. This default solution writes a log to the Dev Dashboard, and then displays a simple JavaScript alert when the page renders.

If your Application Customizer uses the ClientSideComponentProperties JSON input, it is deserialized into the BaseExtension.properties object. You can define an interface to describe
it. The default template is looking for a property called testMessage. If that property is provided, it outputs it in an alert message.

Debug your Application Customizer


You cannot currently use the local Workbench to test SharePoint Framework Extensions. You need to test them against a live SharePoint Online site. You don't have to deploy your
customization to the app catalog to do this, which makes the debugging experience simple and efficient.
1. Compile your code and host the compiled files from your local computer by running the following command:

gulp serve --nobrowser

NOTE

If you do not have the SPFx developer certificate installed, Workbench notifies you that it is not configured to load scripts from localhost. If this happens, stop the process that is
currently running in the console window, run the gulp trust-dev-cert command in your project directory console to install the developer certificate, and then run the
gulp serve --nobrowser command again.

You use the --nobrowser option because you don't need to launch the local Workbench since you can't debug extensions locally.
When the code compiles without errors, it serves the resulting manifest from https://localhost:4321.
2. To test your extension, go to a modern list view page in your SharePoint environment and append the following query string parameters to the URL. Notice that you need to update
the ID to match your own extension identifier. This is available in the HelloWorldApplicationCustomizer.manifest.json file.

?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":"ClientSideExtension.ApplicationCustomizer","p

More detail about the URL query parameters:


loadSPFX=true. Ensures that the SharePoint Framework is loaded on the page. For performance reasons, the framework does not load unless at least one extension is
registered. Because no components are registered, you must explicitly load the framework.
debugManifestsFile. Specifies that you want to load SPFx components that are locally served. The loader only looks for components in the app catalog (for your deployed
solution) and the SharePoint manifest server (for the system libraries).
customActions. Simulates a custom action. When you deploy and register this component in a site, you'll create this CustomAction object and describe all the different
properties you can set on it.
Key. Use the GUID of the extension as the key to associate with the custom action. This has to match the ID value of your extension, which is available in the extension
manifest.json file.
Location. The type of custom action. Use ClientSideExtension.ApplicationCustomizer for the Application Customizer extension.
Properties. An optional JSON object that contains properties that are available via the this.properties member. In this HelloWorld example, it defined a testMessage
property.
3. Go to a modern list in SharePoint Online. This can be either a list or a library. Application Customizers are also supported in modern pages and on the Site Contents page.
4. Extend the URL with the additional query parameters described. Notice that you need to update the GUID to match the ID of your custom Application Customizer.
The full URL should look similar to the following:

contoso.sharepoint.com/Lists/Contoso/AllItems.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":

Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages

1. Select Load debug scripts to continue loading scripts from your local host.

You should now see the dialog message on your page.

This dialog is thrown by your SharePoint Framework Extension. Note that because you provided the testMessage property as part of the debug query parameters, it's included in the
alert message. You can configure your extension instances based on the client component properties, which are passed for the instance in runtime mode.
NOTE

If you have issues with debugging, double-check the URL query parameters used for the query. Some browsers encode the parameters and in some scenarios this affects the behavior.

Next steps
Congratulations, you got your first SharePoint Framework Extension running!
To continue building out your extension, see Using page placeholders from Application Customizer (Hello World part 2). You use the same project and take advantage of specific content
placeholders for modifying the UI of SharePoint. Notice that the gulp serve command is still running in your console window (or in Visual Studio Code if you are using the editor). You can
continue to let it run while you go to the next article.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Use page placeholders from Application Customizer (Hello World part 2)
7/9/2018 • 6 minutes to read Edit Online

Application Customizers provide access to well-known locations on SharePoint pages that you can modify based on your business and functional requirements. For example, you can create
dynamic header and footer experiences that render across all the pages in SharePoint Online.
This model is similar to using a UserCustomAction collection in a Site or Web object to modify the page experience via custom JavaScript. The key difference or advantage with
SharePoint Framework (SPFx) Extensions is that your page elements won't change if changes are made to the HTML/DOM structure in SharePoint Online.
This article describes how to extend your Hello World extension to take advantage of page placeholders.
You can also follow these steps by watching the video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/3LXuYBaJ1Lc

Get access to page placeholders


Application Customizer extensions are supported with Site , Web , and List scopes. You can control the scope by deciding where or how the Application Customizer is registered in your
SharePoint tenant. When the Application Customizer exists in the scope and is being rendered, you can use the following method to get access to the placeholder.

// Handling the Bottom placeholder


if (!this._bottomPlaceholder) {
this._bottomPlaceholder =
this.context.placeholderProvider.tryCreateContent(
PlaceholderName.Bottom,
{ onDispose: this._onDispose });
...
}

After you get the placeholder object, you have full control over what is presented to the end user.
Notice that you're requesting a well-known placeholder by using the corresponding well-known identifier. In this case, the code is accessing the footer section of the page by using the
Bottom identifier.

Modify the Application Customizer to access and modify placeholders by adding custom HTML elements
1. In Visual Studio Code (or your preferred IDE), open src\extensions\helloWorld\HelloWorldApplicationCustomizer.ts.
2. Add the PlaceholderContent and PlaceholderName to the import from @microsoft/sp-application-base by updating the import statement as follows:

import {
BaseApplicationCustomizer,
PlaceholderContent,
PlaceholderName
} from '@microsoft/sp-application-base';

Also add the following import statements after the strings import at the top of the file:

import styles from './AppCustomizer.module.scss';


import { escape } from '@microsoft/sp-lodash-subset';
You use escape to escape Application Customizer properties. You'll create style definitions for the output in the following steps.
3. Create a new file named AppCustomizer.module.scss under the src\extensions\helloWorld folder.
4. Update AppCustomizer.module.scss as follows:
NOTE

These are the styles that are used in the HTML output for the header and footer placeholders.

@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';

.app {
.top {
height:60px;
text-align:center;
line-height:2.5;
font-weight:bold;
display: flex;
align-items: center;
justify-content: center;
background-color: $ms-color-themePrimary;
color: $ms-color-white;

.bottom {
height:40px;
text-align:center;
line-height:2.5;
font-weight:bold;
display: flex;
align-items: center;
justify-content: center;
background-color: $ms-color-themePrimary;
color: $ms-color-white;
}
}

5. Install the @microsoft/sp-office-ui-fabric-core package to enable importing from SPFabricCore.scss

npm install @microsoft/sp-office-ui-fabric-core

6. In the HelloWorldApplicationCustomizer.ts file, update the IHelloWorldApplicationCustomizerProperties interface to add specific properties for Header and Footer, as
follows.
NOTE

If your Command Set uses the ClientSideComponentProperties JSON input, it is deserialized into the BaseExtension.properties object. You can define an interface to describe it.

export interface IHelloWorldApplicationCustomizerProperties {


Top: string;
Bottom: string;
}

7. Add the following private variables inside the HelloWorldApplicationCustomizer class. In this scenario, these can just be local variables in an onRender method, but if you want to
share them with other objects, define them as private variables.

export default class HelloWorldApplicationCustomizer


extends BaseApplicationCustomizer<IHelloWorldApplicationCustomizerProperties> {

// These have been added


private _topPlaceholder: PlaceholderContent | undefined;
private _bottomPlaceholder: PlaceholderContent | undefined;

8. Update the onInit method code as follows:

@override
public onInit(): Promise<void> {
Log.info(LOG_SOURCE, `Initialized ${strings.Title}`);

// Added to handle possible changes on the existence of placeholders.


this.context.placeholderProvider.changedEvent.add(this, this._renderPlaceHolders);

// Call render method for generating the HTML elements.


this._renderPlaceHolders();
return Promise.resolve<void>();
}

9. Create a new _renderPlaceHolders private method with the following code:


private _renderPlaceHolders(): void {

console.log('HelloWorldApplicationCustomizer._renderPlaceHolders()');
console.log('Available placeholders: ',
this.context.placeholderProvider.placeholderNames.map(name => PlaceholderName[name]).join(', '));

// Handling the top placeholder


if (!this._topPlaceholder) {
this._topPlaceholder =
this.context.placeholderProvider.tryCreateContent(
PlaceholderName.Top,
{ onDispose: this._onDispose });

// The extension should not assume that the expected placeholder is available.
if (!this._topPlaceholder) {
console.error('The expected placeholder (Top) was not found.');
return;
}

if (this.properties) {
let topString: string = this.properties.Top;
if (!topString) {
topString = '(Top property was not defined.)';
}

if (this._topPlaceholder.domElement) {
this._topPlaceholder.domElement.innerHTML = `
<div class="${styles.app}">
<div class="${styles.top}">
<i class="ms-Icon ms-Icon--Info" aria-hidden="true"></i> ${escape(topString)}
</div>
</div>`;
}
}
}

// Handling the bottom placeholder


if (!this._bottomPlaceholder) {
this._bottomPlaceholder =
this.context.placeholderProvider.tryCreateContent(
PlaceholderName.Bottom,
{ onDispose: this._onDispose });

// The extension should not assume that the expected placeholder is available.
if (!this._bottomPlaceholder) {
console.error('The expected placeholder (Bottom) was not found.');
return;
}

if (this.properties) {
let bottomString: string = this.properties.Bottom;
if (!bottomString) {
bottomString = '(Bottom property was not defined.)';
}

if (this._bottomPlaceholder.domElement) {
this._bottomPlaceholder.domElement.innerHTML = `
<div class="${styles.app}">
<div class="${styles.bottom}">
<i class="ms-Icon ms-Icon--Info" aria-hidden="true"></i> ${escape(bottomString)}
</div>
</div>`;
}
}
}
}

Note the following about this code:


Use this.context.placeholderProvider.tryCreateContent to get access to the placeholder.
Extension code should not assume that the expected placeholder is available.
The code expects custom properties called Top and Bottom . If the properties exist, they render inside the placeholders.
Notice that the code path for both the top and bottom placeholders is almost identical. The only differences are the variables used and the style definitions.
It is possible to use the class names defined in the style sheet directly but it is not recommended. In case no style sheet reference defined in the styles variable is found in the
code, the style sheet won't get added to the page. This is because unused references will get removed during bild process.
10. Add the following method after the _renderPlaceHolders method. In this case, you simply output a console message when the extension is removed from the page.

private _onDispose(): void {


console.log('[HelloWorldApplicationCustomizer._onDispose] Disposed custom top and bottom placeholders.');
}

You're now ready to test your code in SharePoint Online.

Test your code


1. Switch to the console window that is running gulp serve and check for errors. Gulp reports any errors in the console; you'll need to fix them before you proceed.
If you don't have the solution running, use the following command to check for errors.

gulp serve --nobrowser

2. Go to a modern list in SharePoint Online. This can be a list or a library. To test your extension, append the following query string parameters to the URL:
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":"ClientSideExtension.ApplicationCustomizer","p

Notice that the GUID used in this query parameter has to match the ID attribute of your Application Customizer. This is available in the
HelloWorldApplicationCustomizer.manifest.json file.
You use Header and Footer JSON properties to provide parameters or configurations to the Application Customizer. In this case, you simply output these values. You can also
adjust the behavior based on the properties used in production.
The full URL should look similar to the following:

contoso.sharepoint.com/Lists/Contoso/AllItems.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"locat

Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages

1. Select Load debug scripts to continue loading scripts from your local host.

You should now see the custom header and footer content in your page.

Next steps
Congratulations, you built your own custom header and footer using the Application Customizer!
To continue building out your extension, see Deploy your extension to SharePoint (Hello World part 3). You will learn how to deploy and preview the Hello World extension in a SharePoint
site collection without using Debug query parameters.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Deploy your extension to SharePoint (Hello World part 3)
4/20/2018 • 5 minutes to read Edit Online

This article describes how to deploy your SharePoint Framework Application Customizer to SharePoint and see it working on modern SharePoint pages.
Be sure you have completed the procedures in the following articles before you begin:
Build your first SharePoint Framework Extension (Hello World part 1)
Use page placeholders from Application Customizer (Hello World part 2)
You can also follow these steps by watching the video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/DzHdVxL A3Pc

Package the Hello World Application Customizer


1. In the console window, go to the extension project directory created in Build your first SharePoint Framework Extension (Hello World part 1).

cd app-extension

2. If gulp serve is still running, stop it from running by selecting Ctrl+C.


Unlike in Debug mode, to use an extension on modern SharePoint server-side pages, you need to deploy and register the extension with SharePoint in Site collection , Site , or
List scope. The scope defines where and how the Application Customizer is active. In this particular scenario, we'll register the Application Customizer by using the Site collection
scope.
Before we package our solution, we want to include the code needed to automate the extension activation within the site whenever the solution is installed on the site. In this case, we'll
use feature framework elements to perform these actions directly in the solution package, but you could also associate the Application Customizer to a SharePoint site by using REST
or CSOM as part of the site provisioning, for example.
3. Install the solution package to the site where it should be installed so that the extension manifest is being white listed for execution.
4. Associate the Application Customizer to the planned scope. This can be performed programmatically (CSOM/REST) or by using the feature framework inside of the SharePoint
Framework solution package. You need to associate the following properties in the UserCustomAction object at the site collection, site, or list level.
ClientSideComponentId. This is the identifier (GUID) of the Field Customizer, which has been installed in the app catalog.
ClientSideComponentProperties. This is an optional parameter, which can be used to provide properties for the Field Customizer instance.
Note that you can control the requirement to add a solution containing your extension to the site by using the skipFeatureDeployment setting in package-solution.json. Even though
you would not require the solution to be installed on the site, you need to associate ClientSideComponentId to specific objects for the extension to be visible.
In the following steps, we'll review the CustomAction definition, which was automatically created for the solution as part of the scaffolding for enabling the solution on a site when it's
being installed.
5. Return to your solution package in Visual Studio Code (or to your preferred editor).
6. Extend the sharepoint folder and assets subfolder in the root of the solution to see the existing elements.xml file.
Review the existing elements.xml file for SharePoint definitions
Review the existing XML structure in the elements.xml file. Note that the ClientSideComponentId property has been automatically updated based on the unique ID of your Application
Customizer available in the HelloWorldApplicationCustomizer.manifest.json file in the src\extensions\helloWorld folder.
ClientSideComponentProperties has also been automatically set with the default structure and JSON properties for this extension instance. Note how the JSON is escaped so that we can
set it properly within an XML attribute.
The configuration uses the specific location of ClientSideExtension.ApplicationCustomizer to define that this is an Application Customizer. Because this elements.xml is associated to a Web
scoped feature by default, this CustomAction is automatically added to the Web.UserCustomAction collection in the site where the solution is being installed.
To ensure that the configuration matches updates performed in the Application Customizer, update the ClientSideComponentProperties as in the following XML structure. Note that you
should not copy the whole structure because it would cause a mismatch with your ClientSideComponentId.

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<CustomAction
Title="SPFxApplicationCustomizer"
Location="ClientSideExtension.ApplicationCustomizer"
ClientSideComponentId="46606aa6-5dd8-4792-b017-1555ec0a43a4"
ClientSideComponentProperties="{&quot;Top&quot;:&quot;Top area of the page&quot;,&quot;Bottom&quot;:&quot;Bottom area in the page&quot;}">

</CustomAction>

</Elements>

Ensure that definitions are taken into account within the build pipeline
Open package-solution.json from the config folder. The package-solution.json file defines the package metadata as shown in the following code. To ensure that the element.xml file is
taken into account while the solution is being packaged, default scaffolding adds needed configuration to define a feature framework feature definition for the solution package.

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "app-extension-client-side-solution",
"id": "98a9fe4f-175c-48c1-adee-63fb927faa70",
"version": "1.0.0.0",
"features": [
{
"title": "Application Extension - Deployment of custom action.",
"description": "Deploys a custom action with ClientSideComponentId association",
"id": "4678966b-de68-445f-a74e-e553a7b937ab",
"version": "1.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
]
}
}
]
},
"paths": {
"zippedPackage": "solution/app-extension.sppkg"
}
}

Deploy the extension to SharePoint Online and host JavaScript from local host
Now you are ready to deploy the solution to a SharePoint site and have the CustomAction automatically associated on the site level.
1. In the console window, enter the following command to package your client-side solution that contains the extension so that we get the basic structure ready for packaging:
gulp bundle

2. Execute the following command so that the solution package is created:

gulp package-solution

The command creates the package in the sharepoint/solution folder:

app-extension.sppkg

3. You now need to deploy the package that was generated to the app catalog. To do this, go to your tenant's app catalog and open the Apps for SharePoint library.
4. Upload or drag and drop the app-extension.sppkg located in the sharepoint/solution folder to the app catalog. SharePoint displays a dialog and asks you to trust the client-side
solution.
Note that we did not update the URLs for hosting the solution for this deployment, so the URL is still pointing to https://localhost:4321 .
5. Select the Deploy button.

6. Move back to your console and ensure that the solution is running. If it's not running, execute the following command in the solution folder:

gulp serve --nobrowser

7. Go to the site where you want to test SharePoint asset provisioning. This could be any site collection in the tenant where you deployed this solution package.
8. Select the gear icon on the top navigation bar on the right, and then select Add an app to go to your Apps page.
9. In the Search box, enter app, and then select Enter to filter your apps.

10. Select the app-extension-client-side-solution app to install the solution on the site. When the installation is completed, refresh the page by selecting F5.
When the application has been successfully installed, you can see the header and footer being rendered just like with the debug query parameters.
Next steps
Congratulations, you have deployed an extension to a modern SharePoint page from the app catalog!
You can continue building out your Hello World extension in the next topic, Host extension from Office 365 CDN (Hello World part 4), where you learn how to deploy and load the extension
assets from a CDN instead of from localhost.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.
Host extension from Office 365 CDN (Hello World part 4)
4/20/2018 • 3 minutes to read Edit Online

This article describes how to deploy your SharePoint Framework Application Customizer to be hosted from an Office 365 CDN and how to deploy that to SharePoint for end users.
Be sure you have completed the procedures in the following articles before you begin:
Build your first SharePoint Framework Extension (Hello World part 1)
Use page placeholders from Application Customizer (Hello World part 2)
Deploy your extension to SharePoint (Hello World part 3)
You can also follow these steps by watching the video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/nh1qFArXG2Y

Enable the CDN in your Office 365 tenant


Office 365 CDN is the easiest way to host SharePoint Framework solutions directly from your tenant while still taking advantage of the Content Delivery Network (CDN) service for faster
load times of your assets.
1. Download the SharePoint Online Management Shell to ensure that you have the latest version.
2. Connect to your SharePoint Online tenant by using PowerShell:

Connect-SPOService -Url https://contoso-admin.sharepoint.com

3. Get the current status of public CDN settings from the tenant level by executing the following commands one-by-one:

Get-SPOTenantCdnEnabled -CdnType Public


Get-SPOTenantCdnOrigins -CdnType Public
Get-SPOTenantCdnPolicies -CdnType Public

4. Enable public CDN in the tenant:

Set-SPOTenantCdnEnabled -CdnType Public

Public CDN has now been enabled in the tenant by using the default file type configuration allowed. This means that the following file type extensions are supported: CSS, EOT, GIF,
ICO, JPEG, JPG, JS, MAP, PNG, SVG, TTF, and WOFF.
5. Open up a browser and move to a site collection where you'd like to host your CDN library. This could be any site collection in your tenant. In this tutorial, we create a specific library
to act as your CDN library, but you can also use a specific folder in any existing document library as the CDN endpoint.
6. Create a new document library on your site collection called CDN, and add a folder named helloworld to it.
7. In the PowerShell console, add a new CDN origin. In this case, we are setting the origin as */cdn , which means that any relative folder with the name of cdn acts as a CDN origin.

Add-SPOTenantCdnOrigin -CdnType Public -OriginUrl */cdn

8. Execute the following command to get the list of CDN origins from your tenant:

Get-SPOTenantCdnOrigins -CdnType Public

Note that your newly added origin is listed as a valid CDN origin. Final configuration of the origin takes approximately 15 minutes, so we can continue creating your test extension,
which is hosted from the origin after deployment is completed.

When the origin is listed without the (configuration pending) text, it is ready to be used in your tenant. This indicates an on-going configuration between SharePoint Online and the
CDN system.

Update your solution project for the CDN URLs


1. Return to the previously created solution to perform the needed URL updates.
2. Update the write-manifests.json file (under the config folder) as follows to point to your CDN endpoint. Use publiccdn.sharepointonline.com as the prefix, and then extend the URL
with the actual path of your tenant. The format of the CDN URL is as follows:

https://publiccdn.sharepointonline.com/<tenant host name>/sites/site/library/folder

3. Save your changes.


4. Execute the following tasks to bundle your solution. This executes a release build of your project using the CDN URL specified in the write-manifests.json file. The output of this
command is located in the ./temp/deploy folder. These are the files that you need to upload to the SharePoint folder acting as your CDN endpoint.

gulp bundle --ship

5. Execute the following task to package your solution. This command creates an app-extension.sppkg package in the sharepoint/solution folder, and prepares the assets in the
temp/deploy folder to be deployed to the CDN.

gulp package-solution --ship

6. Upload or drag-and-drop the newly created client-side solution package to the app catalog in your tenant, and then select the Deploy button.
7. Upload or drag-and-drop the files in the temp/deploy folder to the CDN/helloworld folder created earlier.
8. Install the new version of the solution to your site, and ensure that it's working properly without your locahost hosting the JavaScript file.

Congratulations, you have enabled a public CDN in your Office 365 tenant and taken advantage of it from your solution!
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.

See also
Build your first ListView Command Set extension
Build your first Field Customizer extension
Overview of SharePoint Framework Extensions
Build your first Field Customizer extension
7/9/2018 • 11 minutes to read Edit Online

Extensions are client-side components that run inside the context of a SharePoint page. Extensions can be deployed to SharePoint Online, and you can use modern JavaScript tools and
libraries to build them.
You can follow these steps by watching the video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/4wgZy5tm4yo

Create an extension project


1. Create a new project directory in your favorite location.

md field-extension

2. Go to the project directory.

cd field-extension

3. Create a new HelloWorld extension by running the Yeoman SharePoint Generator.

yo @microsoft/sharepoint

4. When prompted:
Accept the default value of field-extension as your solution name, and then select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder, and select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select Field Customizer as the extension type to be created.
5. The next set of prompts ask for specific information about your extension:
Accept the default value of HelloWorld as your extension name, and then select Enter.
Accept the default value of HelloWorld description as your extension description, and select Enter.
Accept the default value of No JavaScript Framework as the framework selection, and select Enter.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:

For information about troubleshooting any errors, see Known issues.


6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

7. Type the following into the console to start Visual Studio Code.

code .

NOTE

Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your extension.
Note how the default solution structure looks like the solution structure of client-side web parts. This is the basic SharePoint Framework solution structure, with similar configuration
options across all solution types.
8. Open HelloWorldFieldCustomizer.manifest.json in the src\extensions\helloWorld folder.
This file defines your extension type and a unique identifier id for your extension. You need this unique identifier later when debugging and deploying your extension to SharePoint.

Code your Field Customizer


Open the HelloWorldFieldCustomizer.ts file in the src\extensions\helloWorld folder.
Notice that the base class for the Field Customizer is imported from the sp-listview-extensibility package, which contains SharePoint Framework code required by the Field Customizer.

import { Log } from '@microsoft/sp-core-library';


import { override } from '@microsoft/decorators';
import {
BaseFieldCustomizer,
IFieldCustomizerCellEventParameters
} from '@microsoft/sp-listview-extensibility';

The logic for your Field Customizer is contained in the OnInit(), onRenderCell(), and onDisposeCell() methods.
onInit() is where you should perform any setup needed for your extension. This event occurs after this.context and this.properties are assigned, but before the page DOM is ready.
As with web parts, onInit() returns a promise that you can use to perform asynchronous operations; onRenderCell() is not called until your promise has resolved. If you don’t need that,
simply return Promise.resolve<void>(); .
onRenderCell() occurs when each cell is rendered. It provides an event.domElement HTML element where your code can write its content.
onDisposeCell() occurs immediately before the event.cellDiv is deleted. It can be used to free any resources that were allocated during field rendering. For example, if onRenderCell()
mounted a React element, onDisposeCell() must be used to free it; otherwise, a resource leak would occur. 
The following are the contents of onRenderCell() and onDisposeCell() in the default solution:

@override
public onRenderCell(event: IFieldCustomizerCellEventParameters): void {
// Use this method to perform your custom cell rendering.
const text: string = `${this.properties.sampleText}: ${event.fieldValue}`;

event.domElement.innerText = text;

event.domElement.classList.add(styles.cell);
}

@override
public onDisposeCell(event: IFieldCustomizerCellEventParameters): void {
// This method should be used to free any resources that were allocated during rendering.
// For example, if your onRenderCell() called ReactDOM.render(), then you should
// call ReactDOM.unmountComponentAtNode() here.
super.onDisposeCell(event);
}

Debug your Field Customizer


You cannot currently use the local Workbench to test SharePoint Framework Extensions. You need to test and develop them directly against a live SharePoint Online site. You don't have to
deploy your customization to the app catalog to do this, which makes the debugging experience simple and efficient.
1. Compile your code and host the compiled files from the local machine by running this command:

gulp serve --nobrowser

You use the --nobrowser option because you don't need to launch the local Workbench, since you can't debug extensions locally.
When the code compiles without errors, it serves the resulting manifest from https://localhost:4321.
2. To test your extension, go to a site in your SharePoint Online tenant.
3. Move to the Site Contents page.
4. On the toolbar, select New, and then select List.

5. Create a new list named Orders, and then select Create.

6. Select the plus sign, and then select Number to create a new Number field for the list.

7. Set the name of the field to Percent, and then select Save.
8. Add a few items with different numbers in the percent field. We'll modify the rendering later in this tutorial, so the different numbers will be presented differently based on your
custom implementation.

Because our Field Customizer is still hosted in localhost and is running, we can use specific debug query parameters to execute the code in the newly created list.
9. Append the following query string parameters to the URL. Notice that you need to update the ID to match your own extension identifier available from the
HelloWorldFieldCustomizer.manifest.json file. For more information, see More details about the URL query parameters.

?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&fieldCustomizers={"Percent":{"id":"45a1d299-990d-4917-ba62-7cb67158be16","properties":{"sampleText":"Hello!"}}}

The full URL should look similar to the following, depending on your tenant URL and the location of the newly created list:

contoso.sharepoint.com/Lists/Orders/AllItems.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&fieldCustomizers={"Percent":{"id":"45a1d299-990d-4917-ba62-7cb67158

Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages

1. Accept the loading of debug manifests by selecting Load debug scripts when prompted.

Notice how the Percent values are now presented with an additional prefix string as Hello!: , which is provided as a property for the Field Customizer.
More details about the URL query parameters
loadSPFX=true ensures that the SharePoint Framework is loaded on the page. For performance reasons, the framework is not normally loaded unless at least one extension is
registered. Because no components are registered yet, we must explicitly load the framework.
debugManifestsFile specifies that you want to load SPFx components that are locally served. The loader only looks for components in the app catalog (for your deployed solution) and
the SharePoint manifest server (for the system libraries).
fieldCustomizers indicates which fields in your list should have their rendering controlled by the Field Customizer. The ID parameter specifies the GUID of the extension that should be
used to control the rendering of the field. The properties parameter is an optional text string containing a JSON object that is deserialized into this.properties for your extension.
Key: Use the internal name of the field as the key.
Id: The GUID of the Field Customizer extension associated with this field.
Properties: The property values defined in the extension. In this example, sampleText is a property defined by the extension.

Enhance the Field Customizer rendering


Now that we have successfully tested the out-of-the-box starting point of the Field Customizer, let's modify the logic slightly to have a more polished rendering of the field value.
1. Open the HelloWorld.module.scss file in the src\extensions\helloWorld folder, and update the styling definition as follows.

.HelloWorld {
.cell {
display: inline-block;
}
.full {
background-color: #e5e5e5;
width: 100px;
}
}

2. Open the HelloWorldFieldCustomizer.ts file in the src\extensions\helloWorld folder, and update the onRenderCell method as follows.

@override
public onRenderCell(event: IFieldCustomizerCellEventParameters): void {

event.domElement.classList.add(styles.cell);
event.domElement.innerHTML = `
<div class='${styles.HelloWorld}'>
<div class='${styles.full}'>
<div style='width: ${event.fieldValue}px; background:#0094ff; color:#c0c0c0'>
&nbsp; ${event.fieldValue}
</div>
</div>
</div>`;
}

3. In your console window, ensure that you do not have any exceptions. If you do not have the solution running in localhost, execute the following command:

gulp serve --nobrowser

4. In your previously created list, use the same query parameter as used previously, with the field being Percent and the ID being updated to your extension identifier available from
the HelloWorldFieldCustomizer.manifest.json file.
5. Accept the loading of debug manifests by selecting Load debug scripts when prompted.
Note how we changed the field rendering style completely. The field value is indicated by using a graphical representation of the value.

Add the field definition to the solution package for deployment


Now that we have tested our solution properly in debug mode, we can package this to be deployed automatically as part of the solution package deployed to the sites.
1. Install the solution package to the site where it should be installed, so that the extension manifest is white listed for execution.
2. Associate the Field Customizer to an existing field in the site. You can do this programmatically (CSOM/REST) or by using the feature framework inside of the SharePoint Framework
solution package. You need to associate the following properties in the SPField object at the site or list level.
ClientSiteComponentId is the identifier (GUID) of the Field Customizer, which has been installed in the app catalog.
ClientSideComponentProperties is an optional parameter, which can be used to provide properties for the Field Customizer instance.
Note that you can control the requirement to add a solution containing your extension to the site by using the skipFeatureDeployment setting in package-solution.json. Even
though you would not require the solution to be installed on the site, you'd need to associate ClientSideComponentId to specific objects for the extension to be visible.
In the following steps, we review the default field definition, which was automatically created and will then be used to automatically deploy needed configurations when the
solution package is installed on a site.
3. Return to your solution in Visual Studio Code (or to your preferred editor).
4. Extend the sharepoint folder and assets subfolder in the root of the solution to see the existing elements.xml file.

Review the elements.xml file


Open the elements.xml file inside the sharepoint\assets folder.
Note the following XML structure in elements.xml. The ClientSideComponentId property has been automatically updated to the unique ID of your Field Customizer available in the
HelloWorldFieldCustomizer.manifest.json file in the src\extensions\helloWorld folder.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<Field ID="{060E50AC-E9C1-3D3C-B1F9-DE0BCAC200F6}"
Name="SPFxPercentage"
DisplayName="Percentage"
Type="Number"
Min="0"
Required="FALSE"
Group="SPFx Columns"
ClientSideComponentId="7e7a4262-d02b-49bf-bfcb-e6ef1716aaef">
</Field>

</Elements>

Ensure that definitions are taken into account within the build pipeline
Open package-solution.json from the config folder. The package-solution.json file defines the package metadata as shown in the following code. To ensure that the element.xml file is
taken into account while the solution is being packaged, default scaffolding added needed configuration to define a feature framework feature definition for the solution package.

{
"solution": {
"name": "field-extension-client-side-solution",
"id": "11cd343e-1ce6-462c-8acb-929804d0c3b2",
"version": "1.0.0.0",
"skipFeatureDeployment": false,
"features": [{
"title": "Field Extension - Deployment of custom field.",
"description": "Deploys a custom field with ClientSideComponentId association",
"id": "123fe847-ced2-3036-b564-8dad5c6c6e83",
"version": "1.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
]
}
}]
},
"paths": {
"zippedPackage": "solution/field-extension.sppkg"
}
}

Deploy the field to SharePoint Online and host JavaScript from local host
Now you are ready to deploy the solution to a SharePoint site and get the field association automatically included in a field.
1. In the console window, enter the following command to package your client-side solution that contains the extension so that we get the basic structure ready for packaging:

gulp bundle

2. Execute the following command so that the solution package is created:

gulp package-solution

The command creates the package in the sharepoint/solution folder:

field-extension.sppkg

3. You now need to deploy the package that was generated to the app catalog. To do this, go to your tenant's app catalog and open the Apps for SharePoint library.
4. Upload or drag-and-drop the field-extension.sppkg located in the sharepoint/solution folder to the app catalog. SharePoint displays a dialog and asks you to trust the client-side
solution.
Note that we did not update the URLs for hosting the solution for this deployment, so the URL is still pointing to https://localhost:4321 .
5. Select the Deploy button.

6. Go to the site where you want to test SharePoint asset provisioning. This could be any site collection in the tenant where you deployed this solution package.
7. Select the gears icon on the top navigation bar on the right, and then select Add an app to go to your Apps page.
8. In the Search box, enter field, and then select Enter to filter your apps.
9. Select the field-extension-client-side-solution app to install the solution on the site. After the installation is complete, refresh the page by selecting F5.
10. When the solution has been installed, select New from the toolbar on the Site Contents page, and then select List.

11. Create a list named Invoices.


12. When the new list is created, on the Site Contents page, select Settings from the menu of the newly created list.

13. Under Columns, select Add from existing site columns.


14. Under the SPFx Columns group, select the Percentage field that was provisioned from the solution package, and then select OK.

15. On your console, ensure that the solution is running. If it's not running, execute the following command in the solution folder:

gulp serve --nobrowser

16. Go to the newly created Invoices list. Add a few items to the list with different values in the Percentage column to determine how the field is rendering without the debug query
parameters.
In this case, we continued to host the JavaScript from the localhost, but you could just as well relocate the assets to any CDN and update the URL to enable the loading of the JavaScript
assets outside of the localhost as well.
The process for publishing your app is identical among the different extension types. You can use the following publishing steps to update the assets to be hosted from a CDN: Host
extension from Office 365 CDN.
NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.

See also
Build your first ListView Command Set extension
Overview of SharePoint Framework Extensions
Build your first ListView Command Set extension
7/9/2018 • 11 minutes to read Edit Online

Extensions are client-side components that run inside the context of a SharePoint page. Extensions can be deployed to SharePoint Online, and you can use modern JavaScript tools and
libraries to build them.
You can follow these steps by watching the video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/JBhgdSgWgdM

Create an extension project


1. Create a new project directory in your favorite location.

md command-extension

2. Go to the project directory.

cd command-extension

3. Create a new HelloWorld extension by running the Yeoman SharePoint Generator.

yo @microsoft/sharepoint

4. When prompted:
Accept the default value of command-extension as your solution name, and then select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder, and select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select ListView Command Set as the extension type to be created.
5. The next set of prompts ask for specific information about your extension:
Accept the default value of HelloWorld as your extension name, and then select Enter.
Accept the default value of HelloWorld description as your extension description, and select Enter.
At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the HelloWorld extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:

For information about troubleshooting any errors, see Known issues.


6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

7. Next, type the following into the console to start Visual Studio Code.

code .

NOTE

Because the SharePoint client-side solution is HTML/TypeScript based, you can use any code editor that supports client-side development to build your extension.
Note how the default solution structure looks like the solution structure of client-side web parts. This is the basic SharePoint Framework solution structure, with similar configuration
options across all solution types.

8. Open HelloWorldCommandSet.manifest.json in the src\extensions\helloWorld folder.


This file defines your extension type and a unique identifier id for your extension. You need this unique identifier later when debugging and deploying your extension to SharePoint.
Note the actual command definitions in the manifest file. These are the actual buttons that are exposed based on the registration target. In the default template, you find two different
buttons: Command One and Command Two.

Currently, images are not properly referenced unless you are referring to them from absolute locations in a CDN within your manifest. This will be improved in future releases.

Code your ListView Command Set


Open the HelloWorldCommandSet.ts file in the src\extensions\helloWorld folder.
Notice that the base class for the ListView Command Set is imported from the sp-listview-extensibility package, which contains SharePoint Framework code required by the ListView
Command Set.

import { override } from '@microsoft/decorators';


import { Log } from '@microsoft/sp-core-library';
import {
BaseListViewCommandSet,
Command,
IListViewCommandSetListViewUpdatedParameters,
IListViewCommandSetExecuteEventParameters
} from '@microsoft/sp-listview-extensibility';
import { Dialog } from '@microsoft/sp-dialog';

The behavior for your custom buttons is contained in the onListViewUpdated() and OnExecute() methods.
The onListViewUpdated() event occurs separately for each command (for example, a menu item) whenever a change happens in the ListView, and the UI needs to be re-rendered. The
event function parameter represents information about the command being rendered. The handler can use this information to customize the title or adjust the visibility, for example, if a
command should only be shown when a certain number of items are selected in the list view. This is the default implementation.
When using the method tryGetCommand , you get a Command object, which is a representation of the command that shows in the UI. You can modify its values, such as title , or visible , to
modify the UI element. SPFx uses this information when re-rendering the commands. These objects keep the state from the last render, so if a command is set to visible = false , it remains
invisible until it is set back to visible = true .

@override
public onListViewUpdated(event: IListViewCommandSetListViewUpdatedParameters): void {
const compareOneCommand: Command = this.tryGetCommand('COMMAND_1');
if (compareOneCommand) {
// This command should be hidden unless exactly one row is selected.
compareOneCommand.visible = event.selectedRows.length === 1;
}
}

The OnExecute() method defines what happens when a command is executed (for example, the menu item is selected). In the default implementation, different messages are shown based
on which button was selected.
@override
public onExecute(event: IListViewCommandSetExecuteEventParameters): void {
switch (event.itemId) {
case 'COMMAND_1':
Dialog.alert(`${this.properties.sampleTextOne}`);
break;
case 'COMMAND_2':
Dialog.alert(`${this.properties.sampleTextTwo}`);
break;
default:
throw new Error('Unknown command');
}
}

Debug your ListView Command Set


You cannot currently use the local Workbench to test SharePoint Framework Extensions. You'll need to test and develop them directly against a live SharePoint Online site. You don't have to
deploy your customization to the app catalog to do this, which makes the debugging experience simple and efficient.
1. Compile your code and host the compiled files from the local machine by running this command:

gulp serve --nobrowser

You use the --nobrowser option because you don't need to launch the local Workbench, since you can't debug extensions locally.
When the code compiles without errors, it serves the resulting manifest from https://localhost:4321.
2. Go to any SharePoint list in your SharePoint Online site by using the modern experience.
Because our ListView Command Set is hosted from localhost and is running, we can use specific debug query parameters to execute the code in the list view.
3. Append the following query string parameters to the URL. Notice that you need to update the GUID to match the ID of your ListView Command Set Extension available in the
HelloWorldCommandSet.manifest.json file. For more information, see More details about the URL query parameters.

?loadSpfx=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"a8047e2f-30d5-40fc-b880-b2890c7c16d6":{"location":"ClientSideExtension.ListViewCommandSet.CommandBar

The full URL should look similar to the following, depending on your tenant URL and the location of the list.

contoso.sharepoint.com/Lists/Orders/AllItems.aspx?loadSpfx=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"a8047e2f-30d5-40fc-b880-b2890c7c16d6":{"location":"

Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages

1. Accept the loading of debug manifests by selecting Load debug scripts when prompted.

2. Notice the new Command Two button available in the toolbar. Select that button to see the text provided as property for the sampleTextTwo property.

3. The Command One button is not visible based on the code, until one row is selected in the document library. Upload or create a document to the library and confirm that the second
button is visible.
4. Select Command Two to see how the dialog control works, which is used in the default output from the solution scaffolding when the ListView Command Set is selected as the
extension type.

More details about the URL query parameters


loadSPFX=true ensures that the SharePoint Framework is loaded on the page. For performance reasons, the framework is not normally loaded unless at least one extension is
registered. Because no components are registered yet, we must explicitly load the framework.
debugManifestsFile specifies that we want to load SPFx components that are being locally served. The loader only looks for components in the app catalog (for your deployed solution)
and the SharePoint manifest server (for the system libraries).
customActions simulates a custom action. You can set many properties on this CustomAction object that affect the look, feel, and location of your button; we’ll cover them all later.
Key: GUID of the extension.
Location: Where the commands are displayed. The possible values are:
ClientSideExtension.ListViewCommandSet.ContextMenu: The context menu of the item(s).
ClientSideExtension.ListViewCommandSet.CommandBar: The top command set menu in a list or library.
ClientSideExtension.ListViewCommandSet: Both the context menu and the command bar (corresponds to SPUserCustomAction.Location="CommandUI.Ribbon").
Properties: An optional JSON object containing properties that are available via the this.properties member.

Enhance the ListView Command Set rendering


The default solution takes advantage of a new Dialog API, which can be used to show modal dialogs easily from your code. In the following steps, we'll slightly modify the default experience
to demonstrate Dialog API use cases.
1. Return to the console, and execute the following command to include the Dialog API in our solution.
2. Return to Visual Studio Code (or your preferred editor).
3. Open HelloWorldCommandSet.ts from the src\extensions\helloWorld folder.
4. Ensure at the top of the file the following import statement is present for the Dialog class from @microsoft/sp-dialog . It should already be there, if not, add it.

import { Dialog } from '@microsoft/sp-dialog';

1. Update the onExecute method as follows:


@override
public onExecute(event: IListViewCommandSetExecuteEventParameters): void {
switch (event.itemId) {
case 'COMMAND_1':
Dialog.alert(`Clicked ${strings.Command1}`);
break;
case 'COMMAND_2':
Dialog.prompt(`Clicked ${strings.Command2}. Enter something to alert:`).then((value: string) => {
Dialog.alert(value);
});
break;
default:
throw new Error('Unknown command');
}
}

2. In your console window, ensure that you do not have any exceptions. If you do not already have the solution running in localhost, execute the following command:

gulp serve --nobrowser

3. In the list view, use the same query parameters used previously with the ID matching your extension identifier available in the HelloWorldCommandSet.manifest.json file.
4. Accept the loading of debug manifests by selecting Load debug scripts when prompted.

We still have the same buttons in the toolbar, but you'll notice they behave differently if you select them one-by-one. Now we are using the new Dialog API, which can be easily used
with your solutions, even for complex scenarios.

Add a ListView Command Set to a solution package for deployment


1. Return to your solution in Visual Studio Code (or to your preferred editor).
2. Extend the sharepoint folder and assets subfolder in the root of the solution to see the existing elements.xml file.
Review the elements.xml file
Open the elements.xml file inside the sharepoint\assets folder.
Note the following XML structure in elements.xml. The ClientSideComponentId property has been automatically updated to the unique ID of your ListView Command Set available in
the HelloWorldCommandSet.manifest.json file in the src\extensions\helloWorld folder.
Notice that we use a specific location value of ClientSideExtension.ListViewCommandSet.CommandBar to define that this is a ListView Command Set and it should be displayed in the command
bar. We also define the RegistrationId as 100 and the RegistrationType as List to associate this custom action automatically with generic lists. ClientSideComponentProperties can be used
to provide instance specific configurations. In this case, we are using default properties called sampleTextOne and sampleTextTwo.

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<CustomAction
Title="SPFxListViewCommandSet"
RegistrationId="100"
RegistrationType="List"
Location="ClientSideExtension.ListViewCommandSet.CommandBar"
ClientSideComponentId="5fc73e12-8085-4a4b-8743-f6d02ffe1240"
ClientSideComponentProperties="{&quot;sampleTextOne&quot;:&quot;One item is selected in the list.&quot;, &quot;sampleTextTwo&quot;:&quot;This command is always visible.&quot;}">
</CustomAction>

</Elements>

NOTE

While running from localhost the custom action will work on both lists and document libraries, but will not once deployed unless the elements.xml is updated. RegistrationId=100 will only
associate the custom action with lists and NOT document libraries. In order to associate the custom action with document libraries, the RegistrationId must be set to 101. If you would like
the action to work on both lists and document libraries, another CustomAction must be added to the elements.xml file

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<CustomAction
Title="SPFxListViewCommandSet"
RegistrationId="100"
RegistrationType="List"
Location="ClientSideExtension.ListViewCommandSet.CommandBar"
ClientSideComponentId="5fc73e12-8085-4a4b-8743-f6d02ffe1240"
ClientSideComponentProperties="{&quot;sampleTextOne&quot;:&quot;One item is selected in the list.&quot;, &quot;sampleTextTwo&quot;:&quot;This command is always visible.&quot;}">
</CustomAction>

<CustomAction
Title="SPFxListViewCommandSet"
RegistrationId="101"
RegistrationType="List"
Location="ClientSideExtension.ListViewCommandSet.CommandBar"
ClientSideComponentId="5fc73e12-8085-4a4b-8743-f6d02ffe1240"
ClientSideComponentProperties="{&quot;sampleTextOne&quot;:&quot;One item is selected in the list.&quot;, &quot;sampleTextTwo&quot;:&quot;This command is always visible.&quot;}">
</CustomAction>

</Elements>

Possible location values that can be used with a ListView Command Set:
ClientSideExtension.ListViewCommandSet.CommandBar - Toolbar of the list or library
ClientSideExtension.ListViewCommandSet.ContextMenu - Context menu for list or library items
ClientSideExtension.ListViewCommandSet - Register commands to both the toolbar and to the context menu

Ensure that definitions are taken into account within the build pipeline
Open package-solution.json from the config folder. The package-solution.json file defines the package metadata as shown in the following code. To ensure that the element.xml file is
taken into account while the solution is being packaged, default scaffolding added needed configuration to define a feature framework feature definition for the solution package.
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "command-extension-client-side-solution",
"id": "690ae189-a4fc-4b98-8f28-d4ec17448b7a",
"version": "1.0.0.0",
"features": [
{
"title": "Application Extension - Deployment of custom action.",
"description": "Deploys a custom action with ClientSideComponentId association",
"id": "e91d5532-3519-4b50-b55e-b142fc74cd8a",
"version": "1.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
]
}
}
]
},
"paths": {
"zippedPackage": "solution/command-extension.sppkg"
}
}

Deploy the extension to SharePoint Online and host JavaScript from local host
Now you are ready to deploy the solution to a SharePoint site and have the CustomAction automatically associated on the site level.
1. In the console window, enter the following command to package your client-side solution that contains the extension so that we get the basic structure ready for packaging:

gulp bundle

2. Execute the following command so that the solution package is created:

gulp package-solution

The command creates the package in the sharepoint/solution folder:

command-extension.sppkg

3. Deploy the package that was generated to the app catalog. To do this, go to your tenant's app catalog and open the Apps for SharePoint library.
4. Upload or drag-and-drop the command-extension.sppkg located in the sharepoint/solution folder to the app catalog. SharePoint displays a dialog and asks you to trust the client-side
solution.
Note that we did not update the URLs for hosting the solution for this deployment, so the URL is still pointing to https://localhost:4321 .
5. Select the Deploy button.

6. In your console, ensure that the solution is running. If it's not running, execute the following command in the solution folder:

gulp serve --nobrowser

7. Go to the site where you want to test SharePoint asset provisioning. This could be any site collection in the tenant where you deployed this solution package.
8. Select the gears icon on the top navigation bar on the right, and then select Add an app to go to your Apps page.
9. In the Search box, enter extension, and then select Enter to filter your apps.
10. Select the command-extension-client-side-solution app to install the solution on the site. When the installation is complete, refresh the page by selecting F5.
11. When the application has been successfully installed, select New from the toolbar on the Site Contents page, and then select List.

12. Provide the name as Sample, and then select Create.


Notice how Command One and Command Two are rendering in the toolbar based on your ListView Command Set customizations.

NOTE

If you find an issue in the documentation or in the SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input
in advance.

See also
Build your first Field Customizer extension
Overview of SharePoint Framework Extensions
Configure extension icon
3/26/2018 • 2 minutes to read Edit Online

Selecting an icon that illustrates the purpose of your custom command in SharePoint Framework makes it easier for users to find your command among other options visible in the toolbar
or in the context menu. Specifying an icon for a command is optional. If you don't specify an icon, only the command title is displayed in the command bar.
SharePoint Framework supports building the following types of extensions:
Application Customizer
Field Customizer
Command Set
The Command Set is the only type of SharePoint Framework Extension for which you can configure icons.
When deploying Command Sets, you can choose whether their commands should be visible on:
The command bar ( location: ClientSideExtension.ListViewCommandSet.CommandBar )
The context menu ( location: ClientSideExtension.ListViewCommandSet.ContextMenu )
Both ( location: ClientSideExtension.ListViewCommandSet )

Icons defined for the different commands are displayed only for commands displayed in the command bar.
SharePoint Framework offers you two ways to define the icon for your extension:
Use an external icon image
Use a base64-encoded image

Use an external icon image


When building SharePoint Framework command sets, you can specify an icon for each command by providing an absolute URL pointing to the icon image in the extension manifest, in the
iconImageUrl property.

{
"$schema": "https://dev.office.com/json-schemas/spfx/command-set-extension-manifest.schema.json",

"id": "6cdfbff6-714f-4c26-a60c-0b18afe60837",
"alias": "WeatherCommandSet",
"componentType": "Extension",
"extensionType": "ListViewCommandSet",

// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,

// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,

"items": {
"WEATHER": {
"title": { "default": "Weather" },
"iconImageUrl": "https://localhost:4321/temp/sun.png",
"type": "command"
}
}
}

The command icon displayed in the command bar is 16x16 px. If your image is bigger, it is sized proportionally to match these dimensions.
While using custom images gives you flexibility to choose an icon for your command, it requires you to deploy them along with your other extension assets. Additionally, your image might
lose quality when displayed in higher DPI or specific accessibility settings. To avoid quality loss, you can use vector-based SVG images, which are also supported by the SharePoint
Framework.

Use a base64-encoded image


When using a custom image, rather than specifying an absolute URL to the image file hosted together with other extension assets, you can have your image base64-encoded and use the
base64 string instead of the URL.
A number of services are available online that you can use to base64-encode your image, such as Convert your images to Base64.
After encoding the image, copy the base64 string and use it as the value for the iconImageUrl property in the web part manifest.

{
"$schema": "https://dev.office.com/json-schemas/spfx/command-set-extension-manifest.schema.json",

"id": "6cdfbff6-714f-4c26-a60c-0b18afe60837",
"alias": "WeatherCommandSet",
"componentType": "Extension",
"extensionType": "ListViewCommandSet",

// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,

// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,

"items": {
"WEATHER": {
"title": { "default": "Weather" },
"iconImageUrl": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAAAXNSR0IB2cksfwAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAB/hUlEQVR42u29ebwkWVUn/j03Ip
"type": "command"
}
}
}

Base64 encoding works for both bitmap images, such as PNG, as well as vector SVG images. The big benefit of using base64-encoded images is that you don't need to deploy the web part
icon image separately.
See also
Overview of SharePoint Framework Extensions
Migrating JSLink customizations to SharePoint Framework Field Customizers
3/26/2018 • 10 minutes to read Edit Online

SharePoint Framework is a new model for building SharePoint customizations. If you customized SharePoint fields and list views with JSLink, you might be wondering what the advantages
of migrating them to the new SharePoint Framework are.
First, let's introduce the available options when developing SharePoint Framework Extensions:
Application Customizer. Extend the native "modern" UI of SharePoint Online by adding custom HTML elements and client-side code to pre-defined placeholders of "modern" pages. At
the time of this writing, the available placeholders are the header and the footer of every "modern" page.
Command Set. Add custom ECB menu items or custom buttons to the command bar of a list view for a list or a library. You can associate any JavaScript (TypeScript) action to these
commands.
Field Customizer. Customize the rendering of a field in a list view by using custom HTML elements and client-side code.
Depending on what is the target of your customization, you can leverage any of the above flavors. For example, the Field Customizers are a good replacement for the JSLink customizations
of fields.

Benefits of migrating existing JSLink customizations to the SharePoint Framework


SharePoint Framework was built thinking about the new SharePoint "modern" experience, which is available on the "modern" team sites and "modern" communication sites, and which
targets any device and any platform.

The only supported way of customizing "modern" lists and libraries


One of the main benefits of migrating old-school JSLink customizations to the SharePoint Framework is that it is the only supported technique that you have on modern sites for
customizing the UI of "modern" lists and libraries. In fact, the "modern" lists and libraries, because of their rendering infrastructure and because of the no-script flag enabled on the "modern"
sites, can't rely on old-school JSLink customizations. Thus, if you really want to extend the "modern" UI, you need to upgrade to the SharePoint Framework.

Easier access to information in SharePoint and Office 365


Another fundamental topic to consider is that in the old-school JSLink customizations it was not easy to consume SharePoint content and data. The only way of doing that was by using
JSOM (the JavaScript client-side object model of SharePoint) or low-level REST APIs. Moreover, it was almost impossible to consume the full set of services of Office 365 unless you
autonomously leveraged ADAL.JS (Azure Active Directory Authentication Library for JavaScript) and custom JavaScript code.
Now, with the SharePoint Framework and the SharePoint Framework Extensions, it is easy and straightforward to consume both the SharePoint REST API and Microsoft Graph. You can
now create more powerful solutions, which can consume and interact with the full ecosystem of services provided by Microsoft Office 365.

Similarities between SharePoint Framework solutions and SharePoint Feature Framework customizations
Nevertheless, both the JSLink customizations and the SharePoint Feature Framework customizations share some similarities.

Provisioning model
Both SharePoint Framework Extensions and user custom actions or the Edit Control Block (ECB) menu item solutions leverage an XML manifest file, which is written with the SharePoint
Feature Framework syntax. Thus, the deployment is based on the same techniques. However, with the new Field Customizers, you can customize the rendering of a field, and not the
rendering of a single view of a list or library. Of course, the custom field can be used in as many lists and libraries as you like.

Run as a part of the page


Similar to user custom actions and ECB of SharePoint Feature Framework, SharePoint Framework Extensions are a part of the page. This gives these solutions access to the page's DOM and
allows them to communicate with other components on the same page. Also, it allows developers to more easily make their solutions responsive to adapt to the different form factors on
which a SharePoint page could be displayed, including the SharePoint mobile app.
Because SharePoint Framework Extensions run as part of the page, whatever resources the customization has access to, other elements on the page can access as well. This is important to
keep in mind when building solutions that rely on OAuth implicit flow with bearer access tokens or use cookies or browser storage for storing sensitive information. Because SharePoint
Framework Extensions run as a part of the page, other elements on that page can access all these resources as well.

Use any library to build your extensions


When building page customizations by using user custom actions, you might have used libraries such as jQuery or Knockout to make your customization dynamic and better respond to user
interaction. When building SharePoint Framework Extensions, you can use any client-side library to enrich your solution, the same way you would have done in the past.
An additional benefit that the SharePoint Framework offers you is isolation of your script. Even though the web part is executed as a part of the page, its script is packaged as a module
allowing, for example, different extensions on the same page to use a different version of jQuery without colliding with each other. This is a powerful feature that allows you to focus on
delivering business value instead of technical migrations and compromising on functionality.

Run as the current user


In customizations built by using JSLink, whenever you needed to communicate with SharePoint, all you had to do was to call its API. The client-side solution was running in the browser in
the context of the current user, and by automatically sending the authentication cookie along with the request, your solution could directly connect to SharePoint. No additional
authentication, such as when using SharePoint Add-ins, was necessary to communicate with SharePoint.
The same mechanism applies to customizations built on the SharePoint Framework that also run under the context of the currently authenticated user and don't require any additional
authentication steps to communicate with SharePoint. Of course, the security context is that of the currently connected user, which implies that from a security perspective, you need to be
careful when installing any SharePoint Framework Extension in any target site collection.

Use only client-side code


Both SharePoint Framework Extensions and JSLink customizations run in the browser and can contain only client-side JavaScript code. Client-side solutions have several limitations, such as
not being able to elevate permissions in SharePoint, or reach out to external APIs that don't support cross-origin communication (CORS), or authentication using OAuth implicit flow. In such
cases, the client-side solution could leverage a remote server-side API to perform the necessary operation and return the results to the client.

Hosting model self-consistent and based on Office 365


Both SharePoint Framework Extensions and JavaScript files for JSLink customizations can be hosted on SharePoint Online, and eventually in the Office 365 CDN service, avoiding any need
for external services or hosting environments.
While hosting SharePoint Framework solutions on a CDN offers many advantages, it is not required, and you could choose to host the code in a SharePoint document library. SharePoint
Framework packages (.sppkg files) deployed to the app catalog specify the URL at which SharePoint Framework can find the solution's code. If the user browsing the page with the extension
can download the script from the specified location, there are no restrictions with regards to what that URL must be.
Office 365 offers the public CDN capability that allows you to publish files from a specific SharePoint document library to a CDN. Office 365 public CDN strikes a nice balance between the
benefits of using a CDN and the simplicity of hosting code files in a SharePoint document library. If your organization doesn't mind their code files being publicly available, using the Office
365 public CDN is an option worth considering.

Differences between SharePoint Framework solutions and JSLink customizations


However, between the two development models there are also some significant differences, which you should consider when designing the architecture of your solutions.

Run in no-script sites and in "modern" lists and libraries


Because SharePoint Framework solutions, including Extensions, are deployed through the app catalog with a prior approval, they are not subject to the no-script restrictions and work on all
"modern" sites. Moreover, as we already saw previously, the Field Customizers of SharePoint Framework work in "modern" lists and libraries, while the old-school JSLink doesn't.

Field Customizers support view only scenarios


A JSLink customization can be used to customize not only the view of a field in a list or library, but also the display and edit views of a field while showing a single item.
On the contrary, at the time of this writing, a Field Customizer of SharePoint Framework can customize the rendering of a field only in the list view rendering mode, while in the display and
edit views of a single item you are not able to leverage the customization.

Use TypeScript for building more robust and easier to maintain solutions
When building customizations using JSLink, developers often used plain JavaScript. Often such solutions didn't contain any automated tests, and refactoring the code was error-prone.
SharePoint Framework allows developers to benefit from the TypeScript type system when building solutions. Thanks to the type system, errors are caught during development rather than
at runtime. Also, refactoring code can be done more easily because changes to the code are safeguarded by TypeScript. Because all JavaScript is valid TypeScript, the entry barrier is low, and
you can migrate your plain JavaScript to TypeScript gradually over time, increasing the maintainability of your solutions.

No access to SharePoint JavaScript Object Model by default


When building client-side customizations for the classic SharePoint user experience, many developers used the JavaScript Object Model (JSOM) to communicate with SharePoint. JSOM
offered them IntelliSense and easy access to the SharePoint API in a way similar to the Client-Side Object Model (CSOM). In classic SharePoint pages, the core piece of JSOM was by default
present on the page, and developers could load additional pieces to communicate with SharePoint Search, for example.
The modern SharePoint user experience doesn't include SharePoint JSOM by default. While developers can load it themselves, the recommendation is to use the REST API instead, or the
SharePoint Patterns and Practices JavaScript Core Library (PnP JS Library), which internally uses the SharePoint REST API. Using REST is more universal and interchangeable between the
different client-side libraries such as jQuery, Angular, or React.
Microsoft is not actively investing in JSOM anymore. If you prefer working with an API, you could alternatively use the PnP JS Library, which offers you a fluent API and TypeScript typings.

Migrate existing customization to the SharePoint Framework Extensions


Migrating existing customizations to the SharePoint Framework Extensions offers both end-users and developers many benefits. When considering migrating existing customizations to the
SharePoint Framework, you can either choose to reuse as much of the existing JavaScript scripts as possible, or to completely rewrite the customization by using TypeScript.

Reuse existing scripts


When migrating existing customizations to the SharePoint Framework Extensions, you can choose to reuse your existing scripts. Even though the SharePoint Framework encourages using
TypeScript, you can use plain JavaScript and gradually transform it to TypeScript. If you need to support a solution for a limited period or have a limited budget, this approach might be good
enough for you.
However, reusing existing scripts in a SharePoint Framework solution is not always possible. For example, given the variety of JavaScript libraries, there is no easy way to tell upfront if your
existing scripts can be reused in a SharePoint Framework solution or if you need to rewrite them after all. The only way to determine this is by trying to move the different pieces to a
SharePoint Framework solution and see if they work as expected.

Rewrite the customization


If you need to support your solution for a longer period or would like to make better use of the SharePoint Framework, or if it turns out that your existing scripts cannot be reused with the
SharePoint Framework, you might need to completely rewrite your customization. While it's costlier than reusing existing scripts, it offers you better results over a longer period: a solution
that is better performing and easier to maintain and to use.
When rewriting an existing customization to a SharePoint Framework solution, you should start with the desired functionality in mind. For implementing the user experience, you should
consider using the Office UI Fabric so that your solution looks like an integral part of SharePoint.

See also
Tutorial: Migrating from JSLink to SharePoint Framework Extensions
Overview of SharePoint Framework Extensions
Migrating user custom actions and ECB menu items to SharePoint Framework Extensions
3/26/2018 • 10 minutes to read Edit Online

SharePoint Framework is a new model for building SharePoint customizations. If you customized SharePoint with user custom actions and custom Edit Control Block (ECB) menu items by
using the SharePoint Feature Framework, you might be wondering what the possible advantages of migrating them to the new SharePoint Framework are.
First, let's introduce the available options when developing SharePoint Framework Extensions:
Application Customizer. Extend the native "modern" UI of SharePoint Online by adding custom HTML elements and client-side code to pre-defined placeholders of "modern" pages. At
the time of this writing, the available placeholders are the header and the footer of every "modern" page.
Command Set. Add custom ECB menu items or custom buttons to the command bar of a list view for a list or a library. You can associate any JavaScript (TypeScript) action to these
commands.
Field Customizer. Customize the rendering of a field in a list view by using custom HTML elements and client-side code.
Depending on the target of your customization, you can leverage any of the above flavors. For example, the Application Customizers are a great replacement for the user custom actions.
Moreover, the Command Sets are an appropriate replacement for the ECB menu items.

Benefits of migrating existing SharePoint Feature Framework customizations to the SharePoint Framework
SharePoint Framework was built thinking about the new SharePoint "modern" experience, which is available on the "modern" team sites and "modern" communication sites, and which
targets any device and any platform.

The only supported way of customizing no-script "modern" sites


One of the main benefits of migrating old-school SharePoint Feature Framework customizations to the SharePoint Framework is that it is the only supported technique that you have on
modern sites for customizing the UI.
In fact, the "modern" sites have the no-script flag enabled, which avoids executing any scripting embedded into the page, as well as any user custom action, which refers to external JavaScript
or to embedded JavaScript.
Thus, the old-school user custom actions simply don't work in the "modern" UI. Moreover, the ECB customizations built by using the Feature Framework are very limited. For example, you
can only define ECB items that do not refer to external JavaScript files, or that do not use embedded JavaScript calls. Thus, if you really want to extend the "modern" UI, you need to upgrade
to the SharePoint Framework.

Easier access to information in SharePoint and Office 365


Another fundamental topic to consider is that in the old-school model of user custom actions and ECB customizations, it was not easy to consume SharePoint content and data. The only way
of doing that was by using JSOM (the JavaScript client-side object model of SharePoint) or low-level REST APIs. Moreover, it was almost impossible to consume the full set of services of
Office 365, unless you autonomously leveraged ADAL.JS (Azure Active Directory Authentication Library for JavaScript) and custom JavaScript code.
Now, with the SharePoint Framework and the SharePoint Framework Extensions, it is easy and straightforward to consume both the SharePoint REST API and Microsoft Graph. You can
now create more powerful solutions, which can consume and interact with the full ecosystem of services provided by Microsoft Office 365.

Similarities between SharePoint Framework solutions and SharePoint Feature Framework customizations
Nevertheless, both the SharePoint Feature Framework user custom actions and ECB items and the SharePoint Feature Framework customizations share some similarities.

Provisioning model
Both SharePoint Framework Extensions and user custom actions or ECB menu item solutions leverage an XML manifest file, which is written with the SharePoint Feature Framework syntax.
Thus, the deployment is based on the same techniques.

Run as a part of the page


Similar to user custom actions and ECB of SharePoint Feature Framework, SharePoint Framework Extensions are a part of the page. This gives these solutions access to the page's DOM and
allows them to communicate with other components on the same page. Also, it allows developers to more easily make their solutions responsive to adapt to the different form factors on
which a SharePoint page could be displayed, including the SharePoint mobile app.
Because SharePoint Framework Extensions run as part of the page, whatever resources the customization has access to, other elements on the page can access as well. This is important to
keep in mind when building solutions that rely on OAuth implicit flow with bearer access tokens or use cookies or browser storage for storing sensitive information. Because SharePoint
Framework Extensions run as a part of the page, other elements on that page can access all these resources as well.

Use any library to build your extensions


When building page customizations by using user custom actions, you might have used libraries such as jQuery or Knockout to make your customization dynamic and better respond to user
interaction. When building SharePoint Framework Extensions, you can use any client-side library to enrich your solution, the same way you would have done in the past.
An additional benefit that the SharePoint Framework offers you is isolation of your script. Even though the web part is executed as a part of the page, its script is packaged as a module
allowing, for example, different extensions on the same page to use a different version of jQuery without colliding with each other. This is a powerful feature that allows you to focus on
delivering business value instead of technical migrations and compromising on functionality.

Run as the current user


In customizations built by using user custom actions and ECB menu items, whenever you needed to communicate with SharePoint, all you had to do was to call its API. The client-side
solution was running in the browser in the context of the current user, and by automatically sending the authentication cookie along with the request, your solution could directly connect to
SharePoint. No additional authentication, such as when using SharePoint Add-ins, was necessary to communicate with SharePoint.
The same mechanism applies to customizations built on the SharePoint Framework that also run under the context of the currently authenticated user and don't require any additional
authentication steps to communicate with SharePoint. Of course, the security context is that of the currently connected user, which implies that from a security perspective, you need to be
careful when installing any SharePoint Framework Extension in any target site collection.

Use only client-side code


Both SharePoint Framework Extensions and user custom action or ECB menu item solutions run in the browser and can contain only client-side JavaScript code. Client-side solutions have
several limitations, such as not being able to elevate permissions in SharePoint, or reach out to external APIs that don't support cross-origin communication (CORS), or authentication using
OAuth implicit flow. In such cases, the client-side solution could leverage a remote server-side API to perform the necessary operation and return the results to the client.

Hosting model self-consistent and based on Office 365


Both SharePoint Framework Extensions and user custom action or ECB menu item solutions can be hosted on SharePoint Online, and eventually in the Office 365 CDN service, avoiding any
need for external services or hosting environments.
While hosting SharePoint Framework solutions on a CDN offers many advantages, it is not required, and you could choose to host the code in a SharePoint document library. SharePoint
Framework packages (.sppkg files) deployed to the app catalog specify the URL at which SharePoint Framework can find the solution's code. If the user browsing the page with the extension
can download the script from the specified location, there are no restrictions with regards to what that URL must be.
Office 365 offers the public CDN capability that allows you to publish files from a specific SharePoint document library to a CDN. Office 365 public CDN strikes a nice balance between the
benefits of using a CDN and the simplicity of hosting code files in a SharePoint document library. If your organization doesn't mind their code files being publicly available, using the Office
365 public CDN is an option worth considering.

Differences between SharePoint Framework solutions and SharePoint Feature Framework customizations
However, between the two development models there are also some significant differences, which you should consider when designing the architecture of your solutions.

Run in no-script sites


Because SharePoint Framework solutions, including Extensions, are deployed through the app catalog with a prior approval, they are not subject to the no-script restrictions and work on all
"modern" sites.

Pre-defined set of extensibility points


While a user custom action can embed JavaScript code that can update or literally change the DOM of any part of thhe page, a SharePoint Framework Extension such as an Application
Customizer can only customize, at the time of this writing, the header and/or the footer of any "modern" page.
Theoretically, you could create an Application Customizer that uses DOM to completely change the structure of a page, like with user custom actions. Nevertheless, SharePoint Framework
encourages a more structured and reliable approach to customizing SharePoint. Rather than using specific DOM elements to customize SharePoint, SharePoint Framework provides
developers with specific hooks and placeholders for customizations, and you should use them only.

Use TypeScript for building more robust and easier to maintain solutions
When building customizations using the user custom actions or the ECB menu items, developers often used plain JavaScript. Often such solutions didn't contain any automated tests, and
refactoring the code was error-prone.
SharePoint Framework allows developers to benefit from the TypeScript type system when building solutions. Thanks to the type system, errors are caught during development rather than
at runtime. Also, refactoring code can be done more easily because changes to the code are safeguarded by TypeScript. Because all JavaScript is valid TypeScript, the entry barrier is low, and
you can migrate your plain JavaScript to TypeScript gradually over time, increasing the maintainability of your solutions.

No access to SharePoint JavaScript Object Model by default


When building client-side customizations for the classic SharePoint user experience, many developers used the JavaScript Object Model (JSOM) to communicate with SharePoint. JSOM
offered them IntelliSense and easy access to the SharePoint API in a way similar to the Client-Side Object Model (CSOM). In classic SharePoint pages, the core piece of JSOM was by default
present on the page, and developers could load additional pieces to communicate with SharePoint Search, for example.
The modern SharePoint user experience doesn't include SharePoint JSOM by default. While developers can load it themselves, the recommendation is to use the REST API instead, or the
SharePoint Patterns and Practices JavaScript Core Library (PnP JS Library), which internally uses the SharePoint REST API. Using REST is more universal and interchangeable between the
different client-side libraries such as jQuery, Angular, or React.
Microsoft is not actively investing in JSOM anymore. If you prefer working with an API, you could alternatively use the PnP JS Library, which offers you a fluent API and TypeScript typings.

Migrate existing customization to the SharePoint Framework Extensions


Migrating existing customizations to the SharePoint Framework Extensions offers both end-users and developers many benefits. When considering migrating existing customizations to the
SharePoint Framework, you can either choose to reuse as much of the existing JavaScript scripts as possible, or to completely rewrite the customization by using TypeScript.

Reuse existing scripts


When migrating existing customizations to the SharePoint Framework Extensions, you can choose to reuse your existing scripts. Even though the SharePoint Framework encourages using
TypeScript, you can use plain JavaScript and gradually transform it to TypeScript. If you need to support a solution for a limited period or have a limited budget, this approach might be good
enough for you.
However, reusing existing scripts in a SharePoint Framework solution is not always possible. For example, given the variety of JavaScript libraries, there is no easy way to tell upfront if your
existing scripts can be reused in a SharePoint Framework solution or if you need to rewrite them after all. The only way to determine this is by trying to move the different pieces to a
SharePoint Framework solution and see if they work as expected.

Rewrite the customization


If you need to support your solution for a longer period or would like to make better use of the SharePoint Framework, or if it turns out that your existing scripts cannot be reused with the
SharePoint Framework, you might need to completely rewrite your customization. While it's costlier than reusing existing scripts, it offers you better results over a longer period: a solution
that is better performing and easier to maintain and to use.
When rewriting an existing customization to a SharePoint Framework solution, you should start with the desired functionality in mind. For implementing the user experience, you should
consider using the Office UI Fabric so that your solution looks like an integral part of SharePoint.

See also
Tutorial: Migrating from UserCustomAction to SharePoint Framework Extensions
Tutorial: Migrating from Edit Control Block (ECB) menu item to SharePoint Framework Extensions
Overview of SharePoint Framework Extensions
Migrating from Edit Control Block (ECB) menu item to SharePoint Framework Extensions
7/9/2018 • 11 minutes to read Edit Online

During the last few years, most of the enterprise solutions built on top of Office 365 and SharePoint Online leveraged the site CustomAction capability of the SharePoint Feature Framework
to extend the UI of pages. However, within the new "modern" UI of SharePoint Online, most of those customizations are no longer available. Fortunately, with the new SharePoint
Framework Extensions, you can provide similar functionality in the "modern" UI.
In this tutorial, you learn how to migrate from the old "classic" customizations to the new model based on SharePoint Framework Extensions.
NOTE

For more information about how to build SharePoint Framework Extensions, see Overview of SharePoint Framework Extensions.
First, let's introduce the available options when developing SharePoint Framework Extensions:
Application Customizer. Extend the native "modern" UI of SharePoint Online by adding custom HTML elements and client-side code to pre-defined placeholders of "modern" pages. At
the time of this writing, the available placeholders are the header and the footer of every "modern" page.
Command Set. Add custom ECB menu items or custom buttons to the command bar of a list view for a list or a library. You can associate any JavaScript (TypeScript) action to these
commands.
Field Customizer. Customize the rendering of a field in a list view by using custom HTML elements and client-side code.
The most useful option in our context is the Command Set extension.
Assume that you have a CustomAction in SharePoint Online in order to have a custom ECB menu item for documents in a library. The scope of the ECB menu item is to open a custom page,
providing the list ID and the list item ID of the currently selected item in the query string of the target page.
In the following code snippet, you can see the XML code defining that CustomAction by using the SharePoint Feature Framework.

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction Id="OpenDetailsPageWithItemReference"
Title="Show Details"
Description="Opens a new page with further details about the currently selected item"
Sequence="1001"
RegistrationType="List"
RegistrationId="101"
Location="EditControlBlock">
<UrlAction Url="ShowDetails.aspx?ID={ItemId}&amp;List={ListId}" />
</CustomAction>
</Elements>

As you can see, the feature elements file defines an element of type CustomAction to add a new item in the EditControlBlock location (that is, ECB) for any document in any library
(RegistrationType is List and RegistrationId is 101).
In the following figure, you can see the output of the previous custom action within the list view of a library.

Notice that the SharePoint Feature Framework ECB custom item works in a "modern" list. In fact, as long as you don't use JavaScript code, a list custom action still works in "modern" lists.
To migrate the previous solution to the SharePoint Framework, see the following steps.
NOTE

Before following the steps in this article, be sure to Set up your development environment.

Create a new SharePoint Framework solution


1. Open the command-line tool of your choice (for example, PowerShell, CMD.EXE, Cmder). Create a new folder for the solution named spfx-ecb-extension, and create a new
SharePoint Framework solution by running the Yeoman generator with the following command:
2. When prompted by the tool, provide the following answers:
Accept the default name spfx-ecb-extension for your solution, and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder, and select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select ListView Command Set as the extension type to be created.
Provide CustomECB as the name for your Command Set.

At this point, Yeoman installs the required dependencies and scaffolds the solution files and folders along with the CustomFooter extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:

3. To lock down the version of the project dependencies, run the following command:

npm shrinkwrap

4. Start Visual Studio Code (or the code editor of your choice) and start developing the solution. To start Visual Studio Code, you can execute the following statement.

code .

Define the new ECB item


To reproduce the same behavior of the ECB menu item built by using the SharePoint Feature Framework, you need to implement the same logic by using client-side code within the new
SharePoint Framework solution. To accomplish this task, complete the following steps.
1. Open the CustomEcbCommandSet.manifest.json file in the src/extensions/customEcb folder. Copy the value of the id property and store it in a safe place because you need it
later.
2. Within the same file, edit the array of items in the lower part of the file to define a single command for the Command Set. Call the command ShowDetails, and then provide a title
and a command type. In the following screenshot, you can see how the manifest file should look.
3. Open the CustomEcbCommandSet.ts file in the src/extensions/customEcb folder and edit the content according to the following code snippet:

import { Guid } from '@microsoft/sp-core-library';


import { override } from '@microsoft/decorators';
import {
BaseListViewCommandSet,
Command,
IListViewCommandSetListViewUpdatedParameters,
IListViewCommandSetExecuteEventParameters
} from '@microsoft/sp-listview-extensibility';
import { Dialog } from '@microsoft/sp-dialog';

import * as strings from 'CustomEcbCommandSetStrings';

export interface ICustomEcbCommandSetProperties {


targetUrl: string;
}

export default class CustomEcbCommandSet extends BaseListViewCommandSet<ICustomEcbCommandSetProperties> {

@override
public onInit(): Promise<void> {
return Promise.resolve();
}

@override
public onListViewUpdated(event: IListViewCommandSetListViewUpdatedParameters): void {
const compareOneCommand: Command = this.tryGetCommand('ShowDetails');
if (compareOneCommand) {
// This command should be hidden unless exactly one row is selected.
compareOneCommand.visible = event.selectedRows.length === 1;
}
}

@override
public onExecute(event: IListViewCommandSetExecuteEventParameters): void {
switch (event.itemId) {
case 'ShowDetails':

const itemId: number = event.selectedRows[0].getValueByName("ID");


const listId: Guid = this.context.pageContext.list.id;

window.location.replace(`${this.properties.targetUrl}?ID=${itemId}&List=${listId}`);

break;
default:
throw new Error('Unknown command');
}
}
}

Notice the import statement at the very beginning of the file that references the Guid type, which is used to hold the ID of the current list.
Moreover, the interface ICustomEcbCommandSetProperties declares a single property called targetUrl that can be used to provide the URL of the target page to open when selecting the
ECB menu item.
Furthermore, the override of the onExecute method handles the execution of the custom action. Notice the code excerpt that reads the ID of the currently selected item, from the
event argument, and the ID of the source list from the pageContext object.

Lastly, notice the override of the onListViewUpdated method, which by default enabled the 'ShowDetails' command only if a single item is selected.
The redirection to the target URL is handled by using classic JavaScript code and the window.location.replace function. Of course, you can write whatever kind of TypeScript code you
like inside the onExecute method. Just for the sake of making an example, you can leverage the SharePoint Framework Dialog Framework to open a new dialog window and interact
with users.
NOTE

For more information about the SharePoint Framework Dialog Framework, see Use custom dialog boxes with SharePoint Framework Extensions.
In the following figure you can see the resulting output.

Test the solution in debug mode


1. Go back to the console window and run the following command to build the solution and run the local Node.js server to host it.

gulp serve --nobrowser

2. Open your favorite browser and go to a "modern" library of any "modern" team site. Append the following query string parameters to the AllItems.aspx page URL.

?loadSpfx=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"6c5b8ee9-43ba-4cdf-a106-04857c8307be":{"location":"ClientSideExtension.ListViewCommandSet.ContextMen

In the previous query string, replace the GUID with the id value you saved from the CustomEcbCommandSet.manifest.json file.
Moreover, there is a location property that assumes the value of ClientSideExtension.ListViewCommandSet.ContextMenu, which instructs SPFx to render the Command Set
as an ECB menu item. Following are all the options for the location property:
ClientSideExtension.ListViewCommandSet.ContextMenu. The context menu of the item(s).
ClientSideExtension.ListViewCommandSet.CommandBar. The top command set menu in a list or library.
ClientSideExtension.ListViewCommandSet. Both the context menu and the command bar (corresponds to SPUserCustomAction.Location="CommandUI.Ribbon" ).
Still in the query string, there is a property called properties that represents the JSON serialization of an object of type ICustomEcbCommandSetProperties that is the type of the custom
properties requested by the custom Command Set for rendering.
Notice that when executing the page request, you are prompted with a warning message box with the title "Allow debug scripts?", which asks your consent to run code from localhost
for security reasons. Of course, if you want to locally debug and test the solution, you have to allow it to "Load debug scripts."

Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages

Package and host the solution


If you are happy with the result, you are now ready to package the solution and host it in a real hosting infrastructure. Before building the bundle and the package, you need to declare an
XML Feature Framework file to provision the extension.

Review Feature Framework elements


1. In the code editor, open the /sharepoint/assets sub-folder of the solution folder and edit the elements.xml file. In the following code excerpt, you can see how the file should look.

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction
Title="CustomEcb"
RegistrationId="101"
RegistrationType="List"
Location="ClientSideExtension.ListViewCommandSet.ContextMenu"
ClientSideComponentId="6c5b8ee9-43ba-4cdf-a106-04857c8307be"
ClientSideComponentProperties="{&quot;targetUrl&quot;:&quot;ShowDetails.aspx&quot;}">
</CustomAction>
</Elements>

As you can see, it reminds us of the SharePoint Feature Framework file that we saw in the "classic" model, but it uses the ClientSideComponentId attribute to reference the id of the
custom extension, and the ClientSideComponentProperties attribute to configure the custom configuration properties required by the extension.
2. Open the package-solution.json file in the /config folder of the solution. Within the file, you can see that there is a reference to the elements.xml file within the assets section.
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "spfx-ecb-extension-client-side-solution",
"id": "b8ff6fdf-16e9-4434-9fdb-eac6c5f948ee",
"version": "1.0.2.0",
"features": [
{
"title": "Custom ECB Menu Item.",
"description": "Deploys a custom ECB menu item sample extension",
"id": "f30a744c-6f30-4ccc-a428-125a290b5233",
"version": "1.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
]
}
}
]
},
"paths": {
"zippedPackage": "solution/spfx-ecb-extension.sppkg"
}
}

Enable the CDN in your Office 365 tenant


Now you need to host the extension in a hosting environment. Office 365 CDN is the easiest way to host SharePoint Framework solutions directly from your tenant while still taking
advantage of the Content Delivery Network (CDN) service for faster load times of your assets.
1. Download the SharePoint Online Management Shell to ensure that you have the latest version.
2. Connect to your SharePoint Online tenant by using PowerShell:

Connect-SPOService -Url https://[tenant]-admin.sharepoint.com

3. Get the current status of public CDN settings from the tenant level by executing the following commands one-by-one:

Get-SPOTenantCdnEnabled -CdnType Public


Get-SPOTenantCdnOrigins -CdnType Public
Get-SPOTenantCdnPolicies -CdnType Public

4. Enable public CDN in the tenant:

Set-SPOTenantCdnEnabled -CdnType Public

Public CDN has now been enabled in the tenant by using the default file type configuration allowed. This means that the following file type extensions are supported: CSS, EOT, GIF,
ICO, JPEG, JPG, JS, MAP, PNG, SVG, TTF, and WOFF.
5. Open up a browser and move to a site collection where you'd like to host your CDN library. This could be any site collection in your tenant. In this tutorial, we create a specific library
to act as your CDN library, but you can also use a specific folder in any existing document library as the CDN endpoint.
6. Create a new document library on your site collection called CDN and add a folder named customecb to it.
7. In the PowerShell console, add a new CDN origin. In this case, we are setting the origin as */cdn , which means that any relative folder with the name of cdn acts as a CDN origin.

Add-SPOTenantCdnOrigin -CdnType Public -OriginUrl */cdn

8. Execute the following command to get the list of CDN origins from your tenant:

Get-SPOTenantCdnOrigins -CdnType Public

Note that your newly added origin is listed as a valid CDN origin. Final configuration of the origin takes approximately 15 minutes, so we can continue provisioning the extension,
which is hosted from the origin after deployment is completed.

When the origin is listed without the (configuration pending) text, it is ready to be used in your tenant. This indicates an on-going configuration between SharePoint Online and the
CDN system.

Update the solution settings and publish it on the CDN


Next, you need to update the solution to use the just created CDN as the hosting enviroment, and you need to publish the solution bundle to the CDN. To accomplish this task, follow these
steps.
1. Return to the previously created solution to perform the needed URL updates.
2. Update the write-manifests.json file (in the config folder) as follows to point to your CDN endpoint. Use publiccdn.sharepointonline.com as the prefix, and then extend the URL
with the actual path of your tenant. The format of the CDN URL is as follows:

https://publiccdn.sharepointonline.com/[tenant host name]/sites/[site]/[library]/[folder]


3. Save your changes.
4. Execute the following task to bundle your solution. This executes a release build of your project by using the CDN URL specified in thewrite-manifests.json file. The output of this
command is located in the ./temp/deploy folder. These are the files that you need to upload to the SharePoint folder acting as your CDN endpoint.

gulp bundle --ship

5. Execute the following task to package your solution. This command creates an spfx-ecb-extension.sppkg package in the sharepoint/solution folder and prepares the assets in the
temp/deploy folder to be deployed to the CDN.

gulp package-solution --ship

6. Upload or drag-and-drop the newly created client-side solution package to the app catalog in your tenant, and then select the Deploy button.

7. Upload or drag-and-drop the files in the temp/deploy folder to the CDN/customfooter folder created earlier.

Install and run the solution


1. Open the browser and navigate to any target "modern" site.
2. Go to the Site Contents page and select to add a new App.
3. Select to install a new app From Your Organization to browse the solutions available in the app catalog.
4. Select the solution called spfx-ecb-extension-client-side-solution and install it on the target site.

5. After the application installation is completed, open the Documents library of the site and see the custom ECB menu item in action by selecting a single document.
Enjoy your new custom ECB menu item built by using the SharePoint Framework Extensions!

See also
Overview of SharePoint Framework Extensions
Migrating from JSLink to SharePoint Framework Extensions
7/9/2018 • 14 minutes to read Edit Online

Since Microsoft SharePoint 2013, most of the enterprise solutions built on top of Office 365 and SharePoint Online leveraged the JSLink property of fields and list views to customize the
rendering of fields. However, within the new "modern" UI of SharePoint Online, most of those customizations are no longer available. Fortunately, with the new SharePoint Framework
Extensions, you can now provide almost the same functionality in the "modern" UI.
In this tutorial you learn how to migrate from the old "classic" customizations to the new model based on SharePoint Framework Extensions.
NOTE

For more information about how to build SharePoint Framework Extensions, see Overview of SharePoint Framework Extensions.
First, let's introduce the available options when developing SharePoint Framework Extensions:
Application Customizer. Extend the native "modern" UI of SharePoint Online by adding custom HTML elements and client-side code to pre-defined placeholders of "modern" pages. At
the time of this writing, the available placeholders are the header and the footer of every "modern" page.
Command Set. Add custom ECB menu items or custom buttons to the command bar of a list view for a list or a library. You can associate any JavaScript (TypeScript) action to these
commands.
Field Customizer. Customize the rendering of a field in a list view by using custom HTML elements and client-side code.
The most useful option in our context is the Field Customizer extension.
Assume that you are in SharePoint Online, and you have a custom list with a custom field called "Color", which is of type Choice and which can assume the following values: Red, Green,
Blue, Yellow. Assume that you have a custom value for the JSLink property of the list view rendering web part of the custom list.
In the following code snippet, you can see the JavaScript code referenced by the JSLink property (customColorRendering.js).

// Define a namespace for the custom rendering code


var customJSLinkRendering = customJSLinkRendering || {};

// Define a function that declare the custom rendering rules for the target list view
customJSLinkRendering.CustomizeFieldRendering = function () {

// Define a custom object to configure the rendering template overrides


var customRenderingOverride = {};
customRenderingOverride.Templates = {};
customRenderingOverride.Templates.Fields =
{
// Declare the custom rendering function for the 'View' of field 'Color'
'Color':
{
'View': customJSLinkRendering.RenderColorField
}
};

// Register the custom rendering template


SPClientTemplates.TemplateManager.RegisterTemplateOverrides(customRenderingOverride);
};

// Declare the custom rendering function for the 'View' of field 'Color'
customJSLinkRendering.RenderColorField = function (context)
{
var colorField = context.CurrentItem.Color;

// Declare a local variable to hold the output color


var color = '';

// Evaluate the values of the 'Color' field and render it accordingly


switch (colorField)
{
case 'Red':
color = 'red';
break;
case 'Green':
color = 'green';
break;
case 'Blue':
color = 'blue';
break;
case 'Yellow':
color = 'yellow';
break;
default:
color = 'white';
break;
}

// Render the output for the 'Color' field


return "<div style='float: left; width: 20px; height: 20px; margin: 5px; border: 1px solid rgba(0,0,0,.2);background:" + color + "' />";
};

// Invoke the custom rendering function


customJSLinkRendering.CustomizeFieldRendering();

Moreover, in the following screenshot you can see how the JSLink property is configured in the list view web part.
If you uploaded the JavaScript file into the Site Assets library, the value for the JSLink property can be "~site/SiteAssets/customColorRendering.js" .
For the sake of completeness, you can see how the custom rendering of the list works.

As you can see, "Color" fields render a colored box filled with the color selected at the item level.
NOTE

To provision this kind of solution in a "classic" site you can eventually use a PnP provisioning template, which can provision both the list with the custom field, and the JSLink property at
once.
To migrate the previous solution to the SharePoint Framework, see the following steps.
NOTE

Before following the steps in this article, be sure to Set up your development environment.

Create a new SharePoint Framework solution


1. Open the command line tool of your choice (for example, PowerShell, CMD.EXE, Cmder). Create a new folder for the solution named spfx-custom-field-extension, and create a new
SharePoint Framework solution by running the Yeoman generator with the following command:

yo @microsoft/sharepoint

2. When prompted by the tool, provide the following answers:


Accept the default name spfx-custom-field-extension for your solution, and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder, and select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select Field Customizer as the extension type to be created.
Provide CustomColorField as the name for your Field Customizer.
Select to not use any specific JavaScript framework by selecting the No JavaScript framework option.

At this point, Yeoman installs the required dependencies and scaffolds the solution files and folders along with the CustomColorField extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:

3. To lock down the version of the project dependencies, run the following command:

npm shrinkwrap

4. Start Visual Studio Code (or the code editor of your choice) and start developing the solution. To start Visual Studio Code, you can execute the following statement.

code .

Define the new Field Customizer with JavaScript


To reproduce the same behavior of the JSLink custom field rendering, you need to implement the same logic by using client-side code within the new SharePoint Framework solution. To
accomplish this task, complete the following steps.
1. Open the file CustomColorFieldFieldCustomizer.manifest.json in the src/extensions/customColorField folder. Copy the value of the id property and store it in a safe place
because you need it later.
2. Open the CustomColorFieldFieldCustomizer.ts file in the src/extensions/customColorField folder, and edit the content according to the following code snippet:
import { Log } from '@microsoft/sp-core-library';
import { override } from '@microsoft/decorators';
import {
BaseFieldCustomizer,
IFieldCustomizerCellEventParameters
} from '@microsoft/sp-listview-extensibility';

import * as strings from 'CustomColorFieldFieldCustomizerStrings';


import styles from './CustomColorFieldFieldCustomizer.module.scss';

/**
* If your field customizer uses the ClientSideComponentProperties JSON input,
* it will be deserialized into the BaseExtension.properties object.
* You can define an interface to describe it.
*/
export interface ICustomColorFieldFieldCustomizerProperties {
// This is an example; replace with your own property
sampleText?: string;
}

const LOG_SOURCE: string = 'CustomColorFieldFieldCustomizer';

export default class CustomColorFieldFieldCustomizer


extends BaseFieldCustomizer<ICustomColorFieldFieldCustomizerProperties> {

@override
public onInit(): Promise<void> {
// Add your custom initialization to this method. The framework will wait
// for the returned promise to resolve before firing any BaseFieldCustomizer events.
Log.info(LOG_SOURCE, 'Activated CustomColorFieldFieldCustomizer with properties:');
Log.info(LOG_SOURCE, JSON.stringify(this.properties, undefined, 2));
Log.info(LOG_SOURCE, `The following string should be equal: "CustomColorFieldFieldCustomizer" and "${strings.Title}"`);
return Promise.resolve();
}

@override
public onRenderCell(event: IFieldCustomizerCellEventParameters): void {

var colorField = event.fieldValue;

// Declare a local variable to hold the output color


var color = '';

// Evaluate the values of the 'Color' field and render it accordingly


switch (colorField)
{
case 'Red':
color = 'red';
break;
case 'Green':
color = 'green';
break;
case 'Blue':
color = 'blue';
break;
case 'Yellow':
color = 'yellow';
break;
default:
color = 'white';
break;
}

// Render the output for the 'Color' field


event.domElement.innerHTML = "<div style='float: left; width: 20px; height: 20px; margin: 5px; border: 1px solid rgba(0,0,0,.2);background:" + color + "' />";
}

@override
public onDisposeCell(event: IFieldCustomizerCellEventParameters): void {
// This method should be used to free any resources that were allocated during rendering.
// For example, if your onRenderCell() called ReactDOM.render(), then you should
// call ReactDOM.unmountComponentAtNode() here.
super.onDisposeCell(event);
}
}

As you can see, the content of the method onRenderCell is almost the same as the previous RenderColorField method in the JSLink implementation. The only differences are:
To retrieve the current field value, you need to read the event.fieldValue property of the input argument of the onRenderCell method.
To return the custom HTML code to render the field, you need to assign a value to the innerHTML property of the event.domElement object, which represents the output HTML
container of the field rendering.
Aside from these small changes, you can reuse almost the same JavaScript code as before.
In the following figure, you can see the resulting output.
Test the solution in debug mode
1. Go back to the console window and run the following command to build the solution and run the local Node.js server to host it.

gulp serve --nobrowser

2. Open your favorite browser, and go to a "modern" list, which has a custom field with the name Color and the type Choice with the same value options as before (Red, Green, Blue,
Yellow). You can eventually use the list you created in the "classic" site, just viewing it with the new "modern" experience. Now, append the following query string parameters to the
AllItems.aspx page URL.

?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&fieldCustomizers={"Color":{"id":"c3070978-d85e-4298-8758-70b5b5933076"}}

In this query string, replace the GUID with the id value you saved from the CustomColorFieldFieldCustomizer.manifest.json file, and the Color object name refers to the name
of the field to customize. If you like, you can also provide a custom configuration object, serialized in JSON format, as an additional parameter for the field customizer construction.
Notice that when executing the page request, you are prompted with a warning message box with the title "Allow debug scripts?", which asks your consent to run code from localhost
for security reasons. Of course, if you want to locally debug and test the solution, you have to allow it to "Load debug scripts."

Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages

Define the new Field Customizer with TypeScript


You are now ready to replace the JavaScript code with TypeScript to benefit from the fully typed approach of TypeScript.
1. Open the file CustomColorFieldFieldCustomizer.module.scss in the src/extensions/customColorField folder. This file, which is a Sass CSS, represents the UI style for the field
customizer. Replace the content of the SCSS file with the following.

.CustomColorField {
.cell {
float: left;
width: 20px;
height: 20px;
margin: 5px;
border: 1px solid rgba(0,0,0,.2);
}

.cellRed {
background: red;
}

.cellGreen {
background: green;
}

.cellBlue {
background: blue;
}

.cellYellow {
background: yellow;
}

.cellWhite {
background: white;
}
}
2. Replace the implementation of the onRenderCell method with the following code excerpt.

@override
public onRenderCell(event: IFieldCustomizerCellEventParameters): void {

// Read the current field value


let colorField: String = event.fieldValue;

// Add the main style to the field container element


event.domElement.classList.add(styles.CustomColorField);

// Get a reference to the output HTML


let fieldHtml: HTMLDivElement = event.domElement.firstChild as HTMLDivElement;

// Add the standard style


fieldHtml.classList.add(styles.cell);

// Add the colored style


switch(colorField)
{
case "Red":
fieldHtml.classList.add(styles.cellRed);
break;
case "Green":
fieldHtml.classList.add(styles.cellGreen);
break;
case "Blue":
fieldHtml.classList.add(styles.cellBlue);
break;
case "Yellow":
fieldHtml.classList.add(styles.cellYellow);
break;
default:
fieldHtml.classList.add(styles.cellWhite);
break;
}
}

Notice that the new method implementation uses a fully typed approach, and assigns the cell CSS class to the DIV element child of the current field element, together with another
custom CSS class to define the target color of the DIV based on the currently selected value for the field.
3. Run the Field Customizer one more time in debug mode and view the results.

Package and host the solution


If you are happy with the result, you are now ready to package the solution and host it in a real hosting infrastructure. Before building the bundle and the package, you need to declare an
XML Feature Framework file to provision the extension.

Review Feature Framework elements


1. In the code editor, open the /sharepoint/assets sub-folder of the solution folder and edit the elements.xml file. In the following code excerpt, you can see how the file should look.

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field ID="{40475661-efaf-447a-a220-c992b20ec1c3}"
Name="SPFxColor"
DisplayName="Color"
Title="Color"
Type="Choice"
Required="FALSE"
Group="SPFx Columns"
ClientSideComponentId="c3070978-d85e-4298-8758-70b5b5933076">
</Field>
</Elements>

As you can see, it reminds us of a SharePoint Feature Framework file, but it defines a custom Field element with a field type Choice , which uses the ClientSideComponentId attribute
to reference the id of the Field Customizer, and there could be a ClientSideComponentProperties attribute to configure the custom configuration properties required by the extension.
2. Open the package-solution.json file in the /config folder of the solution. Within the file, you can see that there is a reference to the elements.xml file in the assets section.

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "spfx-custom-field-extension-client-side-solution",
"id": "ab0fbbf8-01ba-4633-8498-46cfd5652619",
"version": "1.0.0.0",
"features": [
{
"title": "Application Extension - Deployment of custom action.",
"description": "Deploys a custom action with ClientSideComponentId association",
"id": "090dc976-878d-44fe-8f8e-ac603d094aa1",
"version": "1.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
]
}
}
]
},
"paths": {
"zippedPackage": "solution/spfx-custom-field-extension.sppkg"
}
}

Enable the CDN in your Office 365 tenant


Now you need to host the extension in a hosting environment. Office 365 CDN is the easiest way to host SharePoint Framework solutions directly from your tenant while still taking
advantage of the Content Delivery Network (CDN) service for faster load times of your assets.
1. Download the SharePoint Online Management Shell to ensure that you have the latest version.
2. Connect to your SharePoint Online tenant by using PowerShell:

Connect-SPOService -Url https://[tenant]-admin.sharepoint.com

3. Get the current status of public CDN settings from the tenant level by executing the following commands one-by-one:

Get-SPOTenantCdnEnabled -CdnType Public


Get-SPOTenantCdnOrigins -CdnType Public
Get-SPOTenantCdnPolicies -CdnType Public

4. Enable public CDN in the tenant:

Set-SPOTenantCdnEnabled -CdnType Public

Public CDN has now been enabled in the tenant by using the default file type configuration allowed. This means that the following file type extensions are supported: CSS, EOT, GIF,
ICO, JPEG, JPG, JS, MAP, PNG, SVG, TTF, and WOFF.
5. Open up a browser and move to a site collection where you'd like to host your CDN library. This could be any site collection in your tenant. In this tutorial, we create a specific library
to act as your CDN library, but you can also use a specific folder in any existing document library as the CDN endpoint.
6. Create a new document library on your site collection called CDN, and add a folder named customcolorfield to it.
7. In the PowerShell console, add a new CDN origin. In this case, we are setting the origin as */cdn , which means that any relative folder with the name of cdn acts as a CDN origin.

Add-SPOTenantCdnOrigin -CdnType Public -OriginUrl */cdn

8. Execute the following command to get the list of CDN origins from your tenant:

Get-SPOTenantCdnOrigins -CdnType Public

Note that your newly added origin is listed as a valid CDN origin. Final configuration of the origin takes approximately 15 minutes, so we can continue provisioning the extension,
which is hosted from the origin after deployment is completed.

When the origin is listed without the (configuration pending) text, it is ready to be used in your tenant. This indicates an on-going configuration between SharePoint Online and the
CDN system.

Update the solution settings and publish it on the CDN


Next, you need to update the solution to use the just created CDN as the hosting enviroment, and you need to publish the solution bundle to the CDN. To accomplish this task, follow these
steps.
1. Return to the previously created solution to perform the needed URL updates.
2. Update the write-manifests.json file (under the config folder) as follows to point to your CDN endpoint. Use publiccdn.sharepointonline.com as the prefix, and then extend the URL
with the actual path of your tenant. The format of the CDN URL is as follows:

https://publiccdn.sharepointonline.com/[tenant host name]/sites/[site]/[library]/[folder]

3. Save your changes.


4. Execute the following task to bundle your solution. This executes a release build of your project using the CDN URL specified in the write-manifests.json file. The output of this
command is located in the ./temp/deploy folder. These are the files that you need to upload to the SharePoint folder acting as your CDN endpoint.

gulp bundle --ship

5. Execute the following task to package your solution. This command creates an spfx-custom-field-extension.sppkg package in the sharepoint/solution folder and also prepares
the assets in the temp/deploy folder to be deployed to the CDN.

gulp package-solution --ship

6. Upload or drag-and-drop the newly created client-side solution package to the app catalog in your tenant, and then select the Deploy button.
7. Upload or drag-and-drop the files in the temp/deploy folder to the CDN/customcolorfield folder created earlier.

Install and run the solution


1. Open the browser and navigate to any target "modern" site.
2. Go to the Site Contents page and select to add a new App.
3. Select to install a new app From Your Organization to browse the solutions available in the app catalog.
4. Select the solution called spfx-custom-field-extension-client-side-solution and install it on the target site.

5. After the application installation is completed, create a new custom list, edit the list settings, and add a new column from already existing site columns. Select the group of columns
called SPFx Columns and add the Color field.
6. Edit the just added field and configure some color values ( such as Red, Green, Blue, Yellow), and then save the field settings.
7. Add some items to the list and see the output in the list view. It should look like the one in the following screenshot.

Enjoy your new Field Customizer built by using the SharePoint Framework Extensions!

See also
Overview of SharePoint Framework Extensions
Migrating from UserCustomAction to SharePoint Framework Extensions
7/9/2018 • 13 minutes to read Edit Online

During the last few years, most of the enterprise solutions built on top of Office 365 and SharePoint Online leveraged the site CustomAction capability of the SharePoint Feature Framework
to extend the UI of pages. However, within the new "modern" UI of SharePoint Online, most of those customizations are no longer available. Fortunately, with the new SharePoint
Framework Extensions, you can provide similar functionality in the "modern" UI.
In this tutorial, you learn how to migrate from the old "classic" customizations to the new model based on SharePoint Framework Extensions.
NOTE

For more information about how to build SharePoint Framework Extensions, see Overview of SharePoint Framework Extensions.
First, let's introduce the available options when developing SharePoint Framework Extensions:
Application Customizer. Extend the native "modern" UI of SharePoint Online by adding custom HTML elements and client-side code to pre-defined placeholders of "modern" pages. At
the time of this writing, the available placeholders are the header and the footer of every "modern" page.
Command Set. Add custom ECB menu items or custom buttons to the command bar of a list view for a list or a library. You can associate any JavaScript (TypeScript) action to these
commands.
Field Customizer. Customize the rendering of a field in a list view by using custom HTML elements and client-side code.
The most useful option in our context is the Application Customizer extension.
Assume that you have a CustomAction in SharePoint Online in order to have a custom footer in all of the site's pages.
In the following code snippet, you can see the XML code defining that CustomAction by using the SharePoint Feature Framework.

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction Id="jQueryCDN"
Title="jQueryCDN"
Description="Loads jQuery from the public CDN"
ScriptSrc="https://code.jquery.com/jquery-3.2.1.slim.min.js"
Location="ScriptLink"
Sequence="100" />
<CustomAction Id="spoCustomBar"
Title="spoCustomBar"
Description="Loads a script to rendere a custom footer"
Location="ScriptLink"
ScriptSrc="SiteAssets/SPOCustomUI.js"
Sequence="200" />
</Elements>

As you can see, the feature elements file defines a few elements of type CustomAction to include in the pages of the target site: jQuery, loaded through the public CDN, and a custom
JavaScript file that renders the custom footer.
For the sake of completeness, you can see the JavaScript code that renders a custom footer, whose menu items are pre-defined in code for the sake of simplicity.
var SPOCustomUI = SPOCustomUI || {};

SPOCustomUI.setUpCustomFooter = function () {
if ($("#SPOCustomFooter").length)
return;

var footerContainer = $("<div>");


footerContainer.attr("id", "SPOCustomFooter");

footerContainer.append("<ul>");

$("#s4-workspace").append(footerContainer);
}

SPOCustomUI.addCustomFooterText = function (id, text) {


if ($("#" + id).length)
return;

var customElement = $("<div>");


customElement.attr("id", id);
customElement.html(text);

$("#SPOCustomFooter > ul").before(customElement);

return customElement;
}

SPOCustomUI.addCustomFooterLink = function (id, text, url) {


if ($("#" + id).length)
return;

var customElement = $("<a>");


customElement.attr("id", id);
customElement.attr("href", url);
customElement.html(text);

$("#SPOCustomFooter > ul").append($("<li>").append(customElement));

return customElement;
}

SPOCustomUI.loadCSS = function (url) {


var head = document.getElementsByTagName('head')[0];
var style = document.createElement('link');
style.type = 'text/css';
style.rel = 'stylesheet';
style.href = url;
head.appendChild(style);
}

SPOCustomUI.init = function (whenReadyDoFunc) {


// avoid executing inside iframes (used by Sharepoint for dialogs)
if (self !== top) return;

if (!window.jQuery) {
// jQuery is needed for Custom Bar to run
setTimeout(function () { SPOCustomUI.init(whenReadyDoFunc); }, 50);
} else {
$(function () {
SPOCustomUI.setUpCustomFooter();
whenReadyDoFunc();
});
}
}

// The following initializes the custom footer with some fake links
SPOCustomUI.init(function () {

var currentScriptUrl;

var currentScript = document.querySelectorAll("script[src*='SPOCustomUI']");


if (currentScript.length > 0) {
currentScriptUrl = currentScript[0].src;
}
if (currentScriptUrl != undefined) {
var currentScriptBaseUrl = currentScriptUrl.substring(0, currentScriptUrl.lastIndexOf('/') + 1);
SPOCustomUI.loadCSS(currentScriptBaseUrl + 'SPOCustomUI.css');
}

SPOCustomUI.addCustomFooterText('SPOFooterCopyright', '&copy; 2017, Contoso Inc.');


SPOCustomUI.addCustomFooterLink('SPOFooterCRMLink', 'CRM', 'CRM.aspx');
SPOCustomUI.addCustomFooterLink('SPOFooterSearchLink', 'Search Center', 'SearchCenter.aspx');
SPOCustomUI.addCustomFooterLink('SPOFooterPrivacyLink', 'Privacy Policy', 'Privacy.aspx');
});

In the following figure you can see the output of the previous custom action, within the home page of a classic site.
To migrate the previous solution to the "modern" UI, see the following steps.
NOTE

Before following the steps in this article, be sure to Set up your development environment.

Create a new SharePoint Framework solution


1. Open the command line tool of your choice (for example, PowerShell, CMD.EXE, Cmder). Create a new folder for the solution named spfx-react-custom-footer, and create a new
SharePoint Framework solution by running the Yeoman generator with the following command:

yo @microsoft/sharepoint

2. When prompted by the tool, provide the following answers:


Accept the default name spfx-react-custom-footer for your solution, and select Enter.
Select SharePoint Online only (latest), and select Enter.
Select Use the current folder, and select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select Application Customizer as the extension type to be created.
Provide CustomFooter as the name for your Application Customizer.

At this point, Yeoman installs the required dependencies and scaffolds the solution files and folders along with the CustomFooter extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:
3. To lock down the version of the project dependencies, run the following command:

npm shrinkwrap

4. Start Visual Studio Code (or the code editor of your choice) and start developing the solution. To start Visual Studio Code, you can execute the following statement.

code .

Define the new UI elements


The UI elements of the custom footer are rendered using React and a custom React component. Of course, you can create the UI elements of the sample footer with whatever technology you
like. In this tutorial, we use React to leverage the Office UI Fabric components for React.
NOTE

For more information about developing solutions with React, see Tutorial: Intro to React.
1. Open the file CustomFooterApplicationCustomizer.manifest.json in the src/extensions/customFooter folder. Copy the value of the id property and store it in a safe place
because you need it later.
2. Open the CustomFooterApplicationCustomizer.ts file in the src/extensions/customFooter folder, and import the types PlaceholderContent and PlaceholderName from the
package '@microsoft/sp-application-base' . At the very beginning of the file, add the import directives for React.
In the following code excerpt, you can see the imports section of the CustomFooterApplicationCustomizer.ts file.

import * as React from 'react';


import * as ReactDom from 'react-dom';

import { override } from '@microsoft/decorators';


import { Log } from '@microsoft/sp-core-library';
import {
BaseApplicationCustomizer,
PlaceholderContent,
PlaceholderName
} from '@microsoft/sp-application-base';
import { Dialog } from '@microsoft/sp-dialog';

import * as strings from 'CustomFooterApplicationCustomizerStrings';


import CustomFooter from './components/CustomFooter';

3. Locate the definition of the class CustomFooterApplicationCustomizer and declare a new private member called bottomPlaceholder of type PlaceholderContent | undefined .
4. Within the override of the onInit method, invoke a custom function called renderPlaceHolders , and define that function.
In the following code excerpt you can see the implementation of the custom footer Application Customizer class.
/** A Custom Action which can be run during execution of a Client Side Application */
export default class CustomFooterApplicationCustomizer
extends BaseApplicationCustomizer<ICustomFooterApplicationCustomizerProperties> {

// This private member holds a reference to the page's footer


private _bottomPlaceholder: PlaceholderContent | undefined;

@override
public onInit(): Promise<void> {
Log.info(LOG_SOURCE, `Initialized ${strings.Title}`);

let message: string = this.properties.testMessage;


if (!message) {
message = '(No properties were provided.)';
}

// Call render method for rendering the needed html elements


this._renderPlaceHolders();

return Promise.resolve();
}

private _renderPlaceHolders(): void {

// Handling the bottom placeholder


if (!this._bottomPlaceholder) {
this._bottomPlaceholder =
this.context.placeholderProvider.tryCreateContent(
PlaceholderName.Bottom);

// The extension should not assume that the expected placeholder is available.
if (!this._bottomPlaceholder) {
console.error('The expected placeholder (Bottom) was not found.');
return;
}

const element: React.ReactElement<{}> = React.createElement(CustomFooter);

ReactDom.render(element, this._bottomPlaceholder.domElement);
}
}
}

The renderPlaceHolders method searches for the placeholder of type Bottom , and if any, it renders its content. In fact, at the very end of the renderPlaceHolders method, the code
creates a new instance of a CustomFooter React component, and renders it within the placeholder of the pages' bottom (i.e. where the footer should be rendered).
NOTE

The React component is the replacement in the "modern" UI for the JavaScript file in the "classic" model. Of course, you can render the entire footer by using pure JavaScript code and
reusing most of the code that you already have. However, it is better to consider to upgrade the implementation not only from a technology perspective, but also from a code
perspective.
5. Add a new folder named components within the src/extensions/customFooter folder. Create a new file within the new folder, and name it CustomFooter.tsx.
In the following code excerpt, you can see the component source file.

import * as React from 'react';

import { CommandButton } from 'office-ui-fabric-react/lib/Button';

export default class CustomFooter extends React.Component<{}, {}> {

public render(): React.ReactElement<{}> {

return (
<div className={`ms-bgColor-neutralLighter ms-fontColor-white`}>
<div className={`ms-bgColor-neutralLighter ms-fontColor-white`}>
<div className={`ms-Grid`}>
<div className="ms-Grid-row">
<div className="ms-Grid-col ms-sm2 ms-md2 ms-lg2">
<CommandButton
data-automation="CopyRight"
href={`CRM.aspx`}>&copy; 2017, Contoso Inc.</CommandButton>
</div>
<div className="ms-Grid-col ms-sm2 ms-md2 ms-lg2">
<CommandButton
data-automation="CRM"
iconProps={ { iconName: 'People' } }
href={`CRM.aspx`}>CRM</CommandButton>
</div>
<div className="ms-Grid-col ms-sm2 ms-md2 ms-lg2">
<CommandButton
data-automation="SearchCenter"
iconProps={ { iconName: 'Search' } }
href={`SearchCenter.aspx`}>Search Center</CommandButton>
</div>
<div className="ms-Grid-col ms-sm2 ms-md2 ms-lg2">
<CommandButton
data-automation="Privacy"
iconProps={ { iconName: 'Lock' } }
href={`Privacy.aspx`}>Privacy Policy</CommandButton>
</div>
<div className="ms-Grid-col ms-sm4 ms-md4 ms-lg4">
</div>
</div>
</div>
</div>
</div>
);
}
}
Teaching you how to write a React component is out of scope for this document. Nevertheless, notice the import statements at the beginning, where the component imports React,
and the CommandButton React component from the Office UI Fabric components library.
In the render method of the component, it defined the output of the CustomFooter with few instances of the CommandButton component for the links in the footer. All the HTML output
is wrapped within a Grid layout of Office UI Fabric.
NOTE

For more information about the grid layout of Office UI Fabric, see Responsive Layout.
In the following figure, you can see the resulting output.

Test the solution in debug mode


1. Go back to the console window and run the following command to build the solution and run the local Node.js server to host it.

gulp serve --nobrowser

2. Now open your favorite browser and go to a "modern" page of any "modern" team site. Now, append the following query string parameters to the page's URL.

?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"82242bbb-f951-4c71-a978-80eb8f35e4c1":{"location":"ClientSideExtension.ApplicationCustomizer"}}

In this query string, replace the GUID with the id value you saved from the CustomFooterApplicationCustomizer.manifest.json file.
Notice that when executing the page request, you are prompted with a warning message box with the title "Allow debug scripts?", which asks your consent to run code from localhost
for security reasons. Of course, if you want to locally debug and test the solution, you have to allow it to "Load debug scripts."

Alternatively, you can create serve configuration entries in the config/serve.json file in your project to automate the creation of the debug query string parameters as outlined in this
document: Debug SharePoint Framework solutions on modern SharePoint pages

Package and host the solution


If you are happy with the result, you are now ready to package the solution and host it in a real hosting infrastructure. Before building the bundle and the package, you need to declare an
XML Feature Framework file to provision the extension.

Review Feature Framework elements


1. In the code editor, open the /sharepoint/assets sub-folder of the solution folder, and edit the elements.xml file. In the following code excerpt, you can see how the file should look.

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction
Title="CustomFooter"
Location="ClientSideExtension.ApplicationCustomizer"
ClientSideComponentId="82242bbb-f951-4c71-a978-80eb8f35e4c1">
</CustomAction>
</Elements>

As you can see, it reminds us of the SharePoint Feature Framework file that we saw in the "classic" model, but it uses the ClientSideComponentId attribute to reference the id of the
custom extension. You can also add a ClientSideComponentProperties attribute, if you need to provide custom settings to the extension, which is not the case in this tutorial.
2. Open the package-solution.json file under the /config folder of the solution. Within the file, you can see that there is a reference to the elements.xml file within the assets
section.
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "spfx-react-custom-footer-client-side-solution",
"id": "911728a5-7bde-4453-97b2-2eba59277ed3",
"version": "1.0.0.0",
"features": [
{
"title": "Application Extension - Deployment of custom action.",
"description": "Deploys a custom action with ClientSideComponentId association",
"id": "f16a2612-3163-46ad-9664-3d3daac68cff",
"version": "1.0.0.0",
"assets": {
"elementManifests": [
"elements.xml"
]
}
}
]
},
"paths": {
"zippedPackage": "solution/spfx-react-custom-footer.sppkg"
}
}

Enable the CDN in your Office 365 tenant


Now you need to host the extension in a hosting environment. Office 365 CDN is the easiest way to host SharePoint Framework solutions directly from your tenant while still taking
advantage of the Content Delivery Network (CDN) service for faster load times of your assets.
1. Download the SharePoint Online Management Shell to ensure that you have the latest version.
2. Connect to your SharePoint Online tenant by using PowerShell:

Connect-SPOService -Url https://[tenant]-admin.sharepoint.com

3. Get the current status of public CDN settings from the tenant level by executing the following commands one-by-one:

Get-SPOTenantCdnEnabled -CdnType Public


Get-SPOTenantCdnOrigins -CdnType Public
Get-SPOTenantCdnPolicies -CdnType Public

4. Enable public CDN in the tenant:

Set-SPOTenantCdnEnabled -CdnType Public

Public CDN has now been enabled in the tenant by using the default file type configuration allowed. This means that the following file type extensions are supported: CSS, EOT, GIF,
ICO, JPEG, JPG, JS, MAP, PNG, SVG, TTF, and WOFF.
5. Open up a browser and move to a site collection where you'd like to host your CDN library. This could be any site collection in your tenant. In this tutorial, we create a specific library
to act as your CDN library, but you can also use a specific folder in any existing document library as the CDN endpoint.
6. Create a new document library on your site collection called CDN and add a folder named customfooter to it.
7. In the PowerShell console, add a new CDN origin. In this case, we are setting the origin as */cdn , which means that any relative folder with the name of cdn acts as a CDN origin.

Add-SPOTenantCdnOrigin -CdnType Public -OriginUrl */cdn

8. Execute the following command to get the list of CDN origins from your tenant:

Get-SPOTenantCdnOrigins -CdnType Public

Note that your newly added origin is listed as a valid CDN origin. Final configuration of the origin takes approximately 15 minutes, so we can continue provisioning the extension,
which is hosted from the origin after deployment is completed.

When the origin is listed without the (configuration pending) text, it is ready to be used in your tenant. This indicates an on-going configuration between SharePoint Online and the
CDN system.

Update the solution settings and publish it on the CDN


Next, you need to update the solution to use the just created CDN as the hosting enviroment, and you need to publish the solution bundle to the CDN. To accomplish this task, follow these
steps.
1. Return to the previously created solution to perform the needed URL updates.
2. Update the write-manifests.json file (under the config folder) as follows to point to your CDN endpoint. Use publiccdn.sharepointonline.com as the prefix, and then extend the URL
with the actual path of your tenant. The format of the CDN URL is as follows:

https://publiccdn.sharepointonline.com/[tenant host name]/sites/[site]/[library]/[folder]


3. Save your changes.
4. Execute the following task to bundle your solution. This executes a release build of your project using the CDN URL specified in the write-manifests.json file. The output of this
command is located in the ./temp/deploy folder. These are the files that you need to upload to the SharePoint folder acting as your CDN endpoint.

gulp bundle --ship

5. Execute the following task to package your solution. This command creates an spfx-react-custom-footer.sppkg package in the sharepoint/solution folder and prepares the assets
in the temp/deploy folder to be deployed to the CDN.

gulp package-solution --ship

6. Upload or drag-and-drop the newly created client-side solution package to the app catalog in your tenant, and then select the Deploy button.

7. Upload or drag-and-drop the files in the temp/deploy folder to the CDN/customfooter folder created earlier.

Install and run the solution


1. Open the browser and navigate to any target "modern" site.
2. Go to the Site Contents page and select to add a new App.
3. Select to install a new app From Your Organization to browse the solutions available in the app catalog.
4. Select the solution called spfx-react-custom-footer-client-side-solution and install it on the target site.

5. After the application installation is completed, refresh the page or go to the home page of the site. You should be able to see the custom footer in action.
Enjoy your new custom footer built by using the SharePoint Framework Extensions!

See also
Overview of SharePoint Framework Extensions
SharePoint Framework (SPFx) enterprise guidance
7/9/2018 • 28 minutes to read Edit Online

The SharePoint Framework (or SPFx) is a new development model for SharePoint user interface extensibility. It is used by first and third parties, complementing already existing user
interface models such as the SharePoint Add-in model. The SharePoint Framework allows for a structured and supported approach to enrich and extend the user interface of SharePoint, by
using client-side frameworks with initial support for client-side web parts. Based on modern web technology standards, it offers a unique set of features to make SharePoint customizations
more broadly available for developers and enterprises, but at the same time aligns with previous models and patterns in SharePoint. In this document, we provide administrators with the
background, benefits, and knowledge they need to successfully manage SharePoint Framework-based components within their SharePoint environments.

Background
SharePoint has been used as an application and/or development platform for a long time and offered numerous sets of development and customization options ranging from full trust code
executing on the SharePoint servers, to sandboxed solutions, to add-ins, to interface customizations achieved by using out-of-the box features or JavaScript/CSS embedding.
Within multi-tenant SharePoint Online, full trust code has never been supported, and the sandboxed code service has been deprecated. The most common patterns for customizations of
SharePoint Online have been either through add-ins, remote-code execution (code executing elsewhere, such as in Azure) through the standard APIs, and JavaScript embedding. Although
JavaScript embedding has been a very powerful way of extending SharePoint, it has also proven difficult to keep up with the evergreen model of SharePoint Online. The SharePoint
Framework aims to solve these issues by providing a standardized framework on how to create custom user interface extensions as well as building applications on top of SharePoint Online
in a supported and future prepared way.
The SharePoint Framework will initially focus on extending the SharePoint user interface by using client-side web parts. The client-side web parts uses the well-known paradigm of web
parts, which has been one of the success factors of SharePoint over the years, that can be added to pages and independently customized by the end users. These client-side web parts work
on the new modern pages as well as in classic pages and even in the SharePoint mobile app.
This new model is built from the ground-up by using a modern web stack that uses TypeScript/JavaScript, HTML, and CSS, and all parts of the generated artifacts are executed in the end-
user's browser. The SharePoint Framework also comes with a completely new set of tooling. This new tooling is platform-agnostic and works on PC and Mac and is based on open source
technologies such as Node.js, Gulp, Webpack, and Yeoman. These frameworks and tools are used at build time to streamline the developer experience for building, packaging, and deploying;
they are not required for the actual execution of the SharePoint Framework code.

Current status of SharePoint Framework


The SharePoint Framework reached the General Available (GA) milestone, with version 1.0.0, in February 2017.

From a developer's point of view


SharePoint developers, new and seasoned, all have something to gain from the SharePoint Framework. While the current release is focused on the user interface extensibility story, it allows
the developer to, in a safe and structured way, extend the user interface capabilities of SharePoint by using, initially, client-side web parts. These web parts are executed client-side and can
work with data in SharePoint, in Office 365 via the Microsoft Graph, or even by using your own custom Web APIs that use standard OAuth and REST methods.
A seasoned SharePoint developer will be familiar with the concepts, such as web parts and the SharePoint data model. However, the tooling for building, packaging and deploying client-side
web parts will be new. Developers need to gain skills in specifically TypeScript, which is the primary language for developing SharePoint Framework artifacts. TypeScript adds several
benefits on top of JavaScript, important for enterprise development, such as strongly typed objects, object inheritance, classes and interfaces, concepts which all should be familiar to current
.NET, Java, and C/C++ developers. From a building and packaging point of view, developers no longer have Visual Studio as the only option to write SharePoint solutions; thanks to using
open source technologies and projects such as node.js, npm, and Gulp, SharePoint Framework development can be done on any platform with the developers preferred code editor or IDE,
for example Visual Studio Code, Sublime, or even Notepad.
For developers that have never built SharePoint solutions previously, but are familiar with modern web technologies, the threshold is not that high, and many developers have already moved
to the client-side of development, or a combination of it. Client-side development can provide a better, more dynamic and more responsive experience for users and even an easier experience
for developers. Thanks to the freedom of the code editor, the use of well-known and popular open source frameworks and technologies, many developers that might not have worked within
the Microsoft ecosystem can easily get up to speed on building SharePoint extensions.
One of the most common patterns in SharePoint Online extensibility has been the usage of JavaScript embedding (also known as JavaScript injection). This is a method where you use, for
example, the Script Editor web part to insert arbitrary JavaScript on the page, and then use web browser DOM (Document Object Model) manipulation to inject HTML, CSS, and JavaScript
to build a solution or application. This method has a lot of disadvantages, and in many cases, even prohibited customers from taking advantage of the new features in SharePoint Online, due
to its hard dependencies on how SharePoint built up the HTML and CSS structure. The SharePoint Framework allows a better way, although not yet a complete replacement, for these
JavaScript embed customizations. The SharePoint Framework, as said, uses TypeScript, which allows for a fairly easy transition of the JavaScript embeds to something standardized and
future proof. The OfficeDev PnP initiative also has example projects and guidelines on how to make this transition.

In perspective: SharePoint Framework in the broader SharePoint platform


The SharePoint Framework is a new model, an addition to already existing methods, but focused on leveraging more value to user interface customizations such as client-side web parts. This
framework is designed to work in conjunction with already existing working models and makes it easier to create new user interface customizations in a more supported and sustainable way.

Compared with add-ins


SharePoint Add-ins, previously known as SharePoint Apps and introduced in SharePoint 2013, have been one of the only available options of adding customizations to SharePoint Online in
a supported and governed way. However, SharePoint Add-ins require a lot more infrastructure than necessary in many cases where a simple user interface customization is needed.
SharePoint Add-ins come in two flavors: SharePoint-hosted and provider-hosted. SharePoint-hosted add-ins have been one of the ways of executing client-side code in SharePoint in a
supported way, but as said require a lot more effort than necessary to just include a simple client-side (JavaScript) web part. In many cases SharePoint-hosted add-ins were built just to
deploy artifacts, such as lists and web parts, onto a SharePoint site. These add-ins live in a "special" site called the App Web, which is a site with limited features.
Provider-hosted add-ins, on the other hand, are add-ins that are executed remotely from SharePoint (Online) and can leverage server-side code as well as client-side code. This has a benefit
for ISVs that want to protect their intellectual property/code/logic and for scenarios that can't be executed client-side by using JavaScript, such as long-running, calculation-heavy operations
or access to remote data that cannot be achieved by using client-side scripting.
The primary advantage of add-ins is isolation: because the actual code is not executed in the SharePoint site browser, cross-site scripting protections prevent the add-in from getting the
same access as the user has. Add-ins are limited to the permissions that the add-in was granted at install time. This makes add-ins a safer option for scenarios where an admin acquires an
add-in from a third party, and it also allows Microsoft to have a Store from where you can download add-ins.
The SharePoint Framework works side-by-side with both SharePoint-hosted and provider-hosted add-ins, but can also be used as an alternative in scenarios where only client-side scripting
is required. For example, add-ins can add app parts to the site where they are hosted. These app parts are similar to web parts, but instead of running in the context of the page, they run in
their own domain (App Web or provider-hosted web) within an Iframe on the page. This prevents the add-in from gaining the user context from the rest of the page.
The SharePoint Framework, on the other hand, does not run in an Iframe. Thanks to this, it can more seamlessly run in the context of the page with the full power of the user viewing the
part. This is the key to enabling it to run with rich functionality, but at the same time this means that it does not have the same level of security controls as add-ins. SharePoint Framework
solutions are due to this also being referred to as full trust client-side solutions. Iframes suffer from the problem that they are not responsive, which results in the rendered webpage not being
as fluent on a mobile phone or alternate screen size.
The SharePoint Framework solutions do not, at the time of writing, have a store where you can download and install solutions, due to the security aspect mentioned earlier. On the other
hand, in many scenarios, using the user's context is a wanted scenario where SharePoint Framework could be used instead.

JavaScript embeddings
One of the more popular approaches used by developers has been to use a method called JavaScript embeddings (also known as JavaScript injections). That means that arbitrary JavaScript
has been inserted to the sites and pages by using, for example, Custom Actions, master pages, or page layouts, and even Script Editor web parts. This method has proven simpler than
creating SharePoint-hosted add-ins, and allows the script code to run in the full context of the users, and therefore gained a lot of popularity. The downside with this approach is that many of
these embeddings relied on DOM manipulation and required developers' skills to do and maintain.
Due to the evergreen nature of SharePoint Online, these solutions built by using JavaScript embeddings could potentially break whenever SharePoint Online was updated, because the
developers might have taken dependencies (even accidentally) on how the SharePoint pages are structured or styled. When updates are done in SharePoint, even minor and subtle, it can
have huge impacts on these solutions and cause the embedded JavaScript to break completely.
Now with the SharePoint Framework, there is a Microsoft standardized and supported way to achieve many of these solutions previously built by using JavaScript embeddings.

Script Editor web parts


The most common way of inserting arbitrary HTML, JavaScript, or CSS customizations in SharePoint is to use the Script Editor web part or the Content Editor web part. Script Editor web
parts have gained popularity due to how easy it is to add custom scripts to any page. Any editor of a site can add a Script Editor web part to a page, copy and paste JavaScript into it, and
have that JavaScript perform the necessary customizations. Just as with JavaScript embeddings, it can be a challenging task for administrators to have control of Script Editor web parts.
The SharePoint Framework can in many cases be a direct replacement for these Script Editor web part configurations.

Control of scripting capabilities in SharePoint Online


SharePoint Online allows the admins to control the ability to add custom scripts to sites and pages to increase the security and integrity of the tenant. This is done by using the "Custom
Script" feature in the SharePoint Online admin site, or individually per site by using PowerShell. Custom scripts can be disabled on all sites or just on personal sites. By default, new tenants
have scripting disabled on personal sites, all self-service created sites, as well as the root site collection of the tenant. When custom scripts are disabled, editors of sites are not allowed to add
web parts such as the Script Editor web part. However, SharePoint Framework solutions are allowed because they are considered safe after being approved by an administrator in the app
catalog.

Differences in how SharePoint Framework solutions are created, and why it matters
The SharePoint Framework uses a new paradigm to SharePoint developers in how to design, build and deploy SharePoint customizations, by leveraging a modern web stack approach and
focusing on client-side/browser based customizations. This marks an important change in how SharePoint development is being treated.
By using technologies and frameworks such as TypeScript, Node.js, Yeoman, Gulp and more, the SharePoint Framework hopefully will attract developer audiences that traditionally have not
been in the SharePoint, or even Microsoft, eco-system, while at the same time, open the doors for existing SharePoint developers to build SharePoint customizations by using a more
modern and standardized approach.

Creating solutions
Because of the need for very specific and targeted tools provided via Visual Studio, SharePoint development was typically solely done via Visual Studio on a Windows machine with an
instance of SharePoint installed and running, which severely limited the hardware and user preferences, and increased development costs. The SharePoint Framework, on the other hand,
uses various common open source web tools available for many different platforms, like MacOS and Linux, to allow for more flexibility in development.
SharePoint Framework solutions are created by using a tool called Yeoman along with a specific SharePoint Framework generator, which is based on Node.js. Yeoman is a project scaffolding
tool that will create your project and generate the required artifacts, install the needed Node.js packages, and configure the build system. After the project is generated, it can be edited in any
editor on any operating system: Visual Studio, Visual Studio Code, Sublime, or Atom for example. This allows for a wider usage preference and style, in and between teams. The Yeoman
generator can be run multiple times on the same project to add additional artifacts, such as client-side web parts.

Developing and building solutions


The build system is based on Gulp, which is a task runner that builds, packages, and optionally deploys the SharePoint Framework artifacts. Like Yeoman, Gulp is also based on Node.js and
allows developers to build and deploy on any operating system.
One new part of the build toolset for SharePoint Framework is called the Workbench. The Workbench is a tool where the developer can host and test their SharePoint Framework solution.
The Workbench is reactive and will automatically reload your artifacts when the developer saves a file so that developers can see and test the solution quickly.
There are two versions of the Workbench, one outside of SharePoint, hosted locally on the development machine that runs offline without SharePoint access and SharePoint data. This allows
the team and designers to build and design solutions with mock or fake data to focus on the user interface. The second version is hosted inside SharePoint and is used when you need to test
and verify the SharePoint Framework solution by using real SharePoint data and context.

Deploying SharePoint Framework solutions


Deploying SharePoint Framework solutions is done in two steps: the first one being deploying the script artifacts packaged by the build process to a CDN (Content Delivery Network)
location. The second step is to add the solution package to the app catalog and approve it for usage in your tenant. The package added to the SharePoint app catalog contains a pointer to the
CDN location.
Developers of the SharePoint Framework solution can choose to use any CDN service, such as Azure Storage, Azure CDN, or even SharePoint itself, preferably by using the SharePoint CDN
features (see later in this document). Using a public CDN, where the assets deployed to the CDN are publicly available on the Internet, allows for usage of the SharePoint Framework
solution to be used by many tenants. In a SharePoint CDN-deployed SharePoint Framework solution, the deployed scripts and resources are only available for the tenant it is deployed into.
By default, there is a built-in task in the build tools to deploy the packaged solution to Azure Blob storage. This is something that is typically extended, by SIs or ISVs, to support custom CDN
locations or configurations.
After changing the code and building the solution, the SharePoint Framework toolchain produces a new solution package (.sppkg) and a set of script files. These script files include a unique
hash in their file name, which indicates that the contents of these files differ from their previously deployed versions. To use a new version of the solution, you must deploy the new set of
scripts to your CDN and update the solution package in the app catalog. While theoretically you could replace the contents of the existing script files and avoid upgrading the solution
package, it's unreliable and not recommended. Depending on the configuration of your CDN, it could be that the previously downloaded script files are cached for a long time on the client
computers, complicating the rollout of the solution to end-users.
The location of the CDN is important. The location where the SharePoint Framework assets are hosted must have high availability, so trusted CDN providers such as Azure, Akamai, or
similar, and SharePoint itself, are recommended. From a security standpoint, it is important to know what CDNs are in use by the SharePoint Framework solutions deployed. A broken CDN
can also break the SharePoint Framework solutions, and in the worst case scenario, a compromised CDN might lead to the data in the SharePoint (Online) tenant also being compromised.
When approving third-party SharePoint Framework solutions, a typical checklist item is to check the authority and trust of the CDN location and any third parties that might host them. This
is because after the application is installed and used within SharePoint site collections, these site collections have a dependency on the CDN location. As of this writing, there is no easy way
to control that end-point. The third-party provider of the CDN can update with both wanted and unwanted changes without the users' knowledge, opening an attack surface, given that the
SharePoint Framework is running under the users' context and can do whatever the users can do.
A recommendation is for IT administrators to keep track of what CDNs are used and what CDNs are approved by the organization, which should also be communicated to the enterprise
developers.

Office 365 Public CDN


The Office 365 Public CDN is a new capability in Office 365 and SharePoint Online that allows administrators to automatically host static assets such as JavaScript files, images, and CSS
styles in a CDN to provide better performance. The Office 365 Public CDN is a geo-distributed caching feature that keeps static assets as close to the end-users' browsers requesting them.
Administrators can enable the Office 365 Public CDN capability on one or more designated document libraries, which will serve as the origin for the static assets. Administration of the
libraries and the CDN are done by using the SharePoint Online PowerShell cmdlets. The assets in the document library will be replicated to the Office 365 CDN and be accessible through
the Office 365 Public CDN URLs generated and associated with the document library. Any updates to the assets will be reflected on the CDN end-points within 15 minutes. Note that any
assets within the document libraries will be available for anonymous users, through the CDN end-point.

SharePoint Framework in the enterprise


SharePoint is and has been one of the most successful enterprise collaboration platforms, and one of the reasons for its success has been the possibility to extend SharePoint and consider it
as a platform for applications and integrations. The SharePoint Framework will further expand this success by making SharePoint a more modern platform on which to build client-side
customizations in a supported and standardized way.

Enterprise developers
The SharePoint Framework allows Enterprise developers, typically developers that create applications for use within an organization, to extend SharePoint (Online) with new functionality
in a structured and supported way. The SharePoint Framework offers everything from the development framework and build pipeline to the actual deployment, and allows the developers in
a short time to reach out to all site collections with new solutions and features, all controlled by the app catalog. In an enterprise scenario, you also have full control of the CDN locations,
external or internal in SharePoint, and you can very easily deploy fixes and updates to your whole organization.
Within your enterprise, administrators and developers jointly should create a blue print for how SharePoint Framework solutions should be deployed. The blue print should contain details
on preferred client-side frameworks, CDN locations, etc. For more details, see the section later on Building a plan around SharePoint Framework customizations.

Citizen developers
Citizen developers have for a long time used SharePoint to build business applications by using many methods and techniques. SharePoint Framework will for certain scenarios, specifically
JavaScript embeddings and Script Editor web part solutions, be one good way forward. This to make these solutions more standardized and maintainable over time. For citizen developers,
there might be a little bit of a learning curve to adjust to this new structured way of building solutions, but will in the long run prove to be more stable, secure, and maintainable.
Given that the above mentioned Custom Script control methods are in place, the citizen developers will not be allowed to add arbitrary JavaScript code or Script Editor web parts. This can
potentially make your SharePoint environment more stable and maintainable, but at the same time you might prohibit innovation in your company, so you should make sure that your citizen
developers align with your enterprise developers on using SharePoint Framework going forward.

User experience designers and front-end developers


For web developers or user experience/interface designers, the SharePoint Framework will be very valuable. The Workbench allows front-end developers to work with a SharePoint
Framework solution on any operating system and by using their preferred editing tools without SharePoint, given that they use mock data, and focus on the user experience.
The SharePoint Framework is released in parallel with Office UI Fabric, which is the official front-end development framework for Office and Office 365, and allows the user experience
designers to create a seamless experience across Office, Office 365, and the custom-built solutions.

System Integrators (SI )


If you leverage System Integrators (SI) or consultancies to build your SharePoint and Office 365 solutions, you should place recommendations, or even requirements, on how they should
build SharePoint Framework solutions so that they are aligned with your enterprise plan for the SharePoint Framework.
Typically, System Integrators have a preferred way of building their solutions, which might not always be aligned with your governance, so this discussion with the System Integrators is
important and will in the end make it easier for all parties. A typical scenario with System Integrators is that they build the solution for your company, and after the project is complete, it is
up to you to maintain, upgrade, and update the solution, which only emphasizes that you need to align with the SI on how the SharePoint Framework solutions are built and hosted.

Independent software vendors (ISV)


Independent software vendors (ISV) are organizations building third-party solutions for the mass market, and they might not always fulfill your plan on SharePoint Framework solutions.
Also, ISVs typically own their own code and intellectual property, which makes it very hard for you to change the way they implement and host their solutions.
In the case of using SharePoint Framework solutions from third-party providers, you need to specifically consider how they manage updates and how their solutions are hosted. For
example: Do you allow the solution to be updated without your knowledge? Do you allow the static assets to be hosted on the ISV's CDN without your control? What is your trust
relationship with this ISV?
Remember that any client-side code in SharePoint Framework executes under the current users' context, and there is no possibility for you to put constraints on that, which you can do with
SharePoint Add-ins.

Building a plan around SharePoint Framework customizations


When introducing SharePoint Framework as one of the tools to extend your SharePoint (Online) instances, you need to plan for it. The plan should start with introducing the new technology
stack used when building SharePoint Framework solutions. Developers may need training on using TypeScript as the primary language for writing the SharePoint Framework code.
Another facet of the SharePoint Framework developers may need to learn is the actual toolchain for SharePoint Framework, including node.js, npm, and Gulp, and how you use the different
Gulp tasks to build, package, and deploy solutions. A very good starting resource for this is the official SharePoint Framework documentation or the SharePoint Github repositories.
Developers might want to standardize on one specific client-side framework for the organization or on different frameworks. Client-side frameworks include, but are not limited to, React,
Knockout, Angular, Handlebars, jQuery etc. There are advantages on standardizing on one framework, since that enables developers to build more reusable code and have better consistency
in how they build and maintain their solutions.
On the other hand, there are advantages of allowing more than one framework since each client-side framework has its pros and cons and use cases. But allowing any client-side framework
may cause fragmentation in your enterprise solutions, not to mention having multiple different frameworks might add to the page load time, since many frameworks require loading of more
external libraries.
Out-of-the-box, the SharePoint Framework Yeoman generator has templates for two client-side frameworks: React and Knockout. Over time, one can expect that the community adds more
generators or sub-generators to use other client-side frameworks. Choosing React as your preferred client-side framework has an advantage because Microsoft has created a React version
of the Office UI Fabric, so you will get the Office and Office 365 look and feel of your customization if that is something your organization prefers.
The fourth thing to plan for is how and where you deploy your solution artifacts, that is in what CDN are your generated script bundles and assets stored. Out-of-the-box, in the Gulp tasks
included in the toolchain, only Azure Blob storage and Azure CDN is supported. This might be a very good option if you can manage an Azure subscription and share your assets between
multiple tenants. Another very common scenario is to use SharePoint Online, and its CDN feature, as a host for the artifacts. Starting from the SharePoint Framework v1.4, static assets are
by default packaged inside of the SharePoint Framework package. When this package is deployed in the app catalog, they are automatically hosted either from Office 365 CDN (if enabled)
or from an app catalog URL.
Finally, developers will need to think about application life cycle management (ALM): the way you manage source code and versioning, automatic build, testing, and deployment etc. Most
common source code versioning systems can be used such as Git, GitHub, or Visual Studio Team Systems.
For continuous integration, there are no default tools, and you can use your tool of preference that supports node.js, such as Visual Studio Team Systems, Travis CI, or Jenkins. Using these
tools, you can automate the build and testing process and in the case of a successful and approved build, you can even automatically deploy the artifacts to the CDN location, and in such a
way automate everything from the developer checking in the code to deployment to production.

Management capabilities of SharePoint Framework solutions


All SharePoint Framework solutions deployed into a tenant must be approved by a tenant administrator. This is done by uploading the SharePoint Framework package, the .sppkg file into
the Apps for SharePoint library. When a new solution is added to the library, the administrator gets a dialog that asks for a consent to approve the solution for use in the tenancy. The dialog
explains that this is a full trust client-side code solution without any resource restrictions and that it executes under users' context. The dialog also shows from what domain it will primarily
get content, that is the CDN location of the SharePoint Framework scripts. Note that any SharePoint Framework application can load data from other locations, after the initial load from the
CDN. Once approved, the SharePoint Framework solution can be enabled on any site collection.

An administrator of the app catalog can at any time remove the package from the app catalog by removing the solution package from the Apps for SharePoint library. This will prohibit the
solution to be used in all site collections. The solution can also be disabled by modifying the Enabled property of the uploaded package. This will immediately disable the solution in all site
collections; existing pages that use client-side web parts will not render the web part, and the app will not be available on the site collections or available to add on existing site collections.
When removing a SharePoint Framework solution, it will not remove any data or information created by the actual client-side solution either in SharePoint or in any external data source
used by the solution.
The administrator can also modify other properties on the package in the app catalog to enhance the visibility of the solution in the site collections; for example, the icon, category,
description, and the featured status can be changed.
If there is a need to update the solution package, which is required if new SharePoint Framework artifacts or other package level changes are made, the administrator only needs to upload a
new version of the package to the library.
A tenant admin can also monitor the SharePoint Framework solutions, just as with SharePoint Add-ins. In the SharePoint Admin center under apps, the SharePoint admin can add the
SharePoint Framework solutions and then see how many installed locations there are of a specific solution, for both SharePoint Add-ins as well as SharePoint Framework solutions.
To enable a SharePoint Framework solution on a site collection, the site collection administrator must add it to the site collection. This is done in the same way as for SharePoint Add-ins, by
selecting to Add a new app on the site collection, and then choosing the solution from the list of apps. Once the app is added, it is available for use in the site collection. The site collection
administrator can also remove the SharePoint Framework from the site collection. This is done by going into Site Contents and then choosing Remove on the app.

SharePoint Framework deployment scopes


When building SharePoint Framework solutions, developers can choose whether their solution supports tenant-wide deployment or if it must be deployed on each site separately. The latter
is required when the solution needs to provision additional resources, such as lists, after being deployed to a site.
While the developers building the solution decide if the solution supports tenant-wide deployment or not, it's the administrators who make the final decision on how the solution is deployed.
Even if a solution could be deployed to all sites in the tenant, administrators can choose to deploy it only to the specific sites. If the solution doesn't support tenant-wide deployment,
administrators can deploy it only to specific sites.
IM P O R T A N T

Tenant-wide deployment is available only in SharePoint Online. In SharePoint hosted on-premises, SharePoint Framework solutions can be deployed only to specific sites.
The SharePoint Framework does not have a store, which SharePoint Add-ins have. For this reason, any deployments always must be initiated by the tenant admin by adding and approving a
solution package to the app catalog.

Backing up and restoring SharePoint Framework components


SharePoint Framework solutions do not have any specific backup and restore features. The only thing that is recommended from an administrative perspective is that it might be a good idea
to have a copy of all installed solution package files ( .sppkg ), if a solution package is by mistake removed from the app catalog. However, the app catalog is a SharePoint library and has the
same capabilities as any document library, with major versioning turned on and the recycle bin.
What you cannot back up is the actual solution artifacts such as script bundles and assets that are hosted in a CDN. However, if you have control of the CDN or the CDN is a SharePoint site,
you can back them up. On the other hand, if you are using SharePoint Framework solutions provided by a third party, there may be no way for your organization to back them up.
SharePoint Framework roadmap
The SharePoint Framework reached General Availability (GA) in February 2017. General Availability means that IT and developers can use SharePoint Framework in production in a
supported manner. Beyond General Availability, we would expect that the set of scenarios where we would see SharePoint Framework-based components built and used will expand beyond
web part scenarios, and into areas like list and site customizations. For more information about the SharePoint Framework, see the dedicated SharePoint Framework Roadmap article.
Major changes or introductions of new major features will be announced through the Office 365 Message Center, found in your tenant admin, something that an Office 365 administrator
already should have on their daily routine to check. Another important resource is the Office Developer blog where you will find even more details and updates.

Summary
The SharePoint Framework is a great new addition to and evolution of the SharePoint customization toolbox that allows developers to extend SharePoint in a supported and controllable
way. SharePoint Framework, based on open source and modern technologies, lets developers extend your SharePoint enterprise development story not only to the SharePoint team, but also
to a more diverse set of developers. As an administrator, providing proper governance and support for SharePoint Framework within your tenancy can empower your developers to build
more engaging solutions more quickly, resulting in better efficiency all around.
Since the SharePoint Framework is created for first- and third-party developers, and in growing use by Microsoft for future feature enhancements of SharePoint, it is also a safe bet for your
organization. We can expect to see incremental updates and additions to the SharePoint Framework over time to close the feature gap between the classic SharePoint and the modern
SharePoint experience.
Team-based development on the SharePoint Framework
3/26/2018 • 31 minutes to read Edit Online

SharePoint Framework is a new development model for building SharePoint customizations. Unlike other SharePoint development models available to date, the SharePoint Framework
focuses on client-side development and is built on top of popular open source tools such as gulp and webpack. One big benefit of this change is that developers on any platform can build
SharePoint customizations.
SharePoint Framework is a development model, and despite the differences in the underlying technology, the same concepts apply when using it for building solutions as to other
development models SharePoint developers used in the past. Developers use the SharePoint Framework toolchain to build and test their solutions and once ready, they hand over the
solution package to be deployed on the SharePoint tenant for further testing and release.
SharePoint Framework consists of a few different packages. These packages, each in its own specific version, make up a release of the SharePoint Framework. For example, the General
Availability release of the SharePoint Framework consists of the following package versions:
@microsoft/sp-client-base v1.0.0
@microsoft/sp-core-library v1.0.0
@microsoft/sp-webpart-base v1.0.0
@microsoft/sp-build-web v1.0.0
@microsoft/sp-module-interfaces v1.0.0
@microsoft/sp-webpart-workbench v1.0.0
For a project to target a specific release of the SharePoint Framework, it has to reference all the different packages in the correct versions. When scaffolding new projects, the SharePoint
Framework Yeoman generator automatically adds the necessary references to the package from the corresponding release of the SharePoint Framework. But when upgrading the project to
a newer version of the SharePoint Framework, developers have to pay extra attention to correctly update version numbers of the SharePoint Framework packages.

Preparing the development environment


In order to build SharePoint Framework solutions developers need specific tools on the development machines. Comparing to other SharePoint development models, the SharePoint
Framework is less restrictive and allows developers to use the tools that make them the most productive going even as far as choosing the operating system.
There are a few different ways in which developers can configure their development environment. Each of them has different advantages and it's important that developer teams have a good
understanding of the different options.

SharePoint Framework toolchain


Building SharePoint Framework solutions requires developers to use a certain set of tools. Following list covers the basic set of tools required on every SharePoint Framework development
environment.
Node.js
SharePoint Framework requires Node.js to be installed on the developer machine. Node.js is used as the runtime for design-time tools used to build and package the project. Node.js is
installed globally on the developer machine and there are solutions available to support running multiple versions of Node.js side-by-side if necessary.
For more information, see installing Node.js and the supported versions.
npm
npm is the equivalent of NuGet in .NET projects: it allows developers to acquire and install packages for use in SharePoint Framework projects. Npm is also used to install the SharePoint
Framework toolchain. Typically developers will use the latest version of npm and install it globally on their machine. Npm itself is a Node.js package so if you're running multiple versions of
Node.js side-by-side each will have its own version of npm installed.
gulp
gulp is the equivalent of MSBuild in .NET project and is responsible for running tasks such as building or packaging a SharePoint Framework project. gulp is distributed as a Node.js package
and is typically installed globally using npm.
Yeoman and SharePoint Framework Yeoman generator
Using Yeoman and the SharePoint Framework Yeoman generator developers create new SharePoint Framework projects. Both Yeoman and its generators are distributed as Node.js
packages and are typically installed using npm as global packages. The benefit of a global installation is that developers can install Yeoman and the generators once and use them to easily
create new projects.
The SharePoint Framework Yeoman generator is tied to a specific version of the SharePoint Framework. Projects scaffolded using the generator, reference the specific versions of the
SharePoint Framework packages and the generated web parts reference the specific pieces of the framework. The SharePoint Framework Yeoman generator is used for creating new
projects but also for adding web parts to existing projects. If you install it globally and would have to add a new web part to an existing project created in the past, the newly created web part
might be inconsistent with the rest of the project which might even lead to build errors. There are a number of ways in which you can work around this limitation which this article discusses
later on.
TypeScript
SharePoint Framework uses TypeScript to help developers be more productive by writing better code and catching errors already during development. SharePoint Framework projects ship
with their own version of TypeScript which is used in the build process and which doesn't require developers to install it separately.

Building a SharePoint Framework development environment


In the past SharePoint developers typically used virtual machines as their development environments. Virtual machines allowed them to ensure that the solution they were building would
work on the environment used by that particular organization. In their virtual machines developers would install SharePoint and patch it to the same level as the production environment
used by the particular organization. In some cases they would install additional software to match the target environment where the solution would run as closely as possible. This approach
allowed developers to catch any errors caused by the difference in environments earlier at the cost of complexity and managing the different environments.
Moving to developing solutions for the cloud solved these issues only partly. While developers no longer needed to run a SharePoint Farm on their development machines, they had to take
into account how their solution would be hosted and how it would communicate with SharePoint Online.
As SharePoint Framework focuses on client-side development it no longer requires SharePoint to be installed on the development machines. With a few exceptions, all dependencies to the
framework and other packages are specified in the project and contained in the project folder. As the SharePoint Framework has its origins in the cloud and evolves frequently, developers
must ensure that they are using the correct version of the toolchain corresponding to their SharePoint Framework project.
Shared or a personal development environment
SharePoint customizations range from simple scripts being added directly to the page to sophisticated solutions deployed as solution packages. SharePoint Framework is a development
model targeting the structured and repeatable deployment model of SharePoint customizations. When building SharePoint Framework solutions each developer on the team uses his own
development environment and shares the source code of the project with other developers on the team through a source control system. This way developers can work on the same project
simultaneously and test their solution without affecting each others productivity.
In the past it was challenging for many organizations to justify providing SharePoint developers with very powerful development machines and in some cases multiple developers had to
share the same machine at the cost of productivity. With SharePoint Framework developers can use market-standard developer machines to build SharePoint customizations.
Developing on the host
Probably the easiest option to setup a development environment for SharePoint Framework projects is to install all the tools directly on the host machine. If your team is working only on
SharePoint Framework projects, then they can install Node.js on their machines. If they work on other Node.js projects as well then they could use third party solutions such as nvm to run
multiple versions of Node.js side-by-side.
Following the tools required by the SharePoint Framework toolchain, developers would install Yeoman and the SharePoint Framework Yeoman generator. Typically both these tools are
installed globally. Given however, that the SharePoint Framework Yeoman generator is tied to a specific version of the SharePoint Framework and developers might need to work with
projects created using a different version, they would have to uninstall and install the version of the generator specific for the particular project they are working on at the moment. A more
viable approach would be to install Yeoman globally but the SharePoint Framework Yeoman generator locally in the given project. While it introduces some overhead, it helps developers
ensure that should they need to add new elements to the project in the future they would be compatible with the rest of the project.
Big benefit of developing on the host is that developers can configure their machine to their preferences once and use it across all projects. Also, as the software executes on the host, it has
direct access to the CPU, memory and disk I/O without a virtualization layer in between which leads to a better performance than when running the same software virtualized.
Developing in a virtual machine
In the past the most common approach amongst SharePoint developers was to use virtual machines as their primary development environment for building SharePoint solutions. Using
virtual machines developers could accommodate the different requirements for the different projects.
When building solutions on the SharePoint Framework organizations can use the same benefits as they used with building SharePoint solutions in the past. Using virtual machines they can
isolate the development software from the host operating system which is a common requirement particularly in large organizations. By creating a separate virtual machine for each project
developers can ensure that the toolchain they use is compatible with the project even if they need to pick up the particular project in the future.
Using virtual machines is not without drawbacks. Virtual machines are big and require developers to use computers powerful enough to run them with acceptable performance to be
productive. Additionally, particularly over longer periods of time, developers have to keep the operating system up-to-date and ensure they run all the necessary security updates. As
developers work in a virtual machine they either have to spend some time at the beginning of a new project to configure the standard virtual machine to their preferences or have to give in
to the standard setup at the cost of their productivity. Because virtual machines run a complete operating system with all its components it's much harder to ensure that all virtual machines
used by all developers on the team are consistent. Comparing to other types of development environments, using virtual machines for building SharePoint Framework solutions is expensive
both from the cost and time point of view.
Developing using Docker
An interesting middle ground between developing on the host and in a virtual machine is using Docker. Docker is a software virtualization technology similar to virtual machines with a few
big differences. The most important benefits of using Docker images over virtual machines are that Docker images are easier to create, maintain and distribute, they are more lightweight
(few hundred MBs comparing to tens of GBs disk space required for virtual machines) and they allow developers to use the tools and preferences they already have installed and configured
on their host machine.
Similarly to virtual machines, Docker containers run a virtualized instance of an operating system (most commonly based on Linux). All software installed in the image used to create the
container runs isolated inside that container and has only access to the portion of the host file system explicitly shared with the container. As all changes to the filesystem inside a Docker
container are discarded once the container is closed, developers share folders from their host to store the source code.
Read more about using Docker for building SharePoint Framework solutions.

Development workflow in SharePoint Framework projects


SharePoint Framework is based on open source toolchain and follows the general development workflow present in other projects built on the same stack. Following is a description of how
that workflow looks like in a typical SharePoint Framework project.

Create new SharePoint Framework project


When building SharePoint customizations using the SharePoint Framework the first step is to scaffold new SharePoint Framework project. This is done using the SharePoint Framework
Yeoman generator. The generator will prompt you to answer a few questions regarding the name of the project or its location. It will also allow you to create the first web part or extension.
Although you are free to choose a different JavaScript framework for each of your components, the general recommendation is to use a single framework per SharePoint Framework project.

Lock dependencies version


A new SharePoint Framework project scaffolded by the SharePoint Framework Yeoman generator has dependencies on the SharePoint Framework packages as well as other packages
required for it to run correctly. As you build your web parts you might want to include additional dependencies such as Angular or jQuery. In SharePoint Framework projects dependencies
are installed using npm. Each dependency is a Node.js package with a specific version. By default dependencies are referenced using a version range which is meant to help developers keep
their dependencies up-to-date more easily. A consequence of this approach is that restoring dependencies for the same project at two points in time might give different results which could
even lead to breaking the project.
A common solution to avoid the risk of dependencies changing during the project, in projects built on the open source toolchain, is to lock the version of all dependencies. When adding a
dependency to the project developers can choose to install the dependency with a specific version rather than a version range by calling the npm install command with the --save-exact
argument. This however doesn't affect the child dependencies of the particular package. To effectively lock the version of all dependencies and their children in the project, developers can use
the npm shrinkwrap command. Once executed, it will generate a list of all dependencies and their versions at the moment of execution and record it in the npm-shrinkwrap.json file which
should be included in the source control. When restoring dependencies npm will use the exact versions from this file rather than the latest version satisfying the particular version range.
NOTE

If you have any packages installed in the node_modules folder that are not listed as dependencies in the package.json file or are not a dependency of one of the packages, you will likely
see an error when generating the npm-shrinkwrap.json file. In this case, you can either see which packages are causing the error and add them to the package.json, or remove them from
the node_modules folder, or you can delete the node_modules folder altogether, restore all dependencies and generate the shrinkwrap file then.

Add the project to source control


To allow the rest of the team to work on the same project add it to the source control system that your team is using. The exact steps will differ depending on the system used by your team.
SharePoint Framework projects are scaffolded with the .gitignore file which describes which files should be excluded from the source control. If your team is using a source control system
other than Git (such as Visual Studio Team System with Team Foundation System repositories), you should ensure that you are including correct files from the project in the source control.
Also excluding the dependencies and autogenerated files during the build process allows you to ensure that your team will work efficiently.
One location developers should particularly pay attention not to include in the source control is the node_modules folder. This folder contains packages on which the project depends and
which are automatically installed when restoring dependencies using the npm install command. Some packages compile to binaries where the compilation process depends on the
operating system. If the team is working on different operating system then including the node_modules folder in the source control will likely break the build for some team members.
Get the project from source control
The first time you will get the project from source control, you will get the project's source code but none of the SharePoint Framework libraries required to build the project. Similarly to
when working with .NET projects and using NuGet packages, you have to restore the dependencies first. In SharePoint Framework projects, similarly to all other projects built on top of
Node.js, you do that by executing npm install in the command line. npm will use the information from the package.json file combined with the information from the npm-
shrinkwrap.json file and install all packages.
NOTE

Typically restoring dependencies using the npm install command requires internet connectivity as packages are downloaded from registry.npmjs.org. If you experience network connectivity
issues or the npmjs registry is unavailable your build will fail. There are a number of ways to mitigate this limitation. One of them is using shrinkpack to download tarballs of all dependencies
and have them stored in the source control. Shrinkpack automatically updates the npm-shrinkwrap.json file to use the local tarballs allowing for offline installation of the project's
dependencies.
Some of the packages are compiled into binaries during the installation process. This compilation process is specific to the architecture and operating system. If you would for example
restore dependencies in a Docker container running Linux and would then try to build the project on your Windows host you would get an error reporting the mismatch in the environment
type used to build and run the binaries.
As your team develops the solution, new or updated dependencies might be added to the project. If the package.json file has changed since you last got the project from the source control,
you will have to run npm install in the command line to install the missing dependencies. If you are unsure if the package.json file has changed, you can run npm install in the command
line just to be sure that you have the latest dependencies, without any harm to the project.

Add packages to your project


Using existing packages to accomplish specific tasks allows you to be more productive. npmjs.com is a public registry of packages that you can use in your project.
IM P O R T A N T

Since there is no formal verification process before a package is published to npmjs.com, you should carefully examine if you can use the particular package both from the contents and
license point of view.
To add a package to your SharePoint Framework project execute the npm install <package> --save or npm install <package> --save-dev command in the command line, eg.
npm install angular --save . Using the --save or --save-dev argument ensures that the package is added to the package.json file and other developers on your team will get it as well
when restoring dependencies. Without it building the project on a machine other than your own will fail. When adding packages that are required by your solution on runtime, such as
Angular or jQuery, you should use the --save argument. Packages that are required in the build process, such as additional gulp tasks, should be installed with the --save-dev argument.
When installing a package, if you don't specify a version, npm will install the latest version available in the package registry (npmjs.com by default), which usually is the version that you will
want to use. One specific case when you have to specify the version of the package is when you're using npm-shrinkwrap.json and want to upgrade an existing package to a newer version.
By default npm will install the version listed in the npm-shrinkwrap.json file. Specifying the version number in the npm install command, like npm install angular@1.5.9 --save , will
install that package and update the version number in the npm-shrinkwrap.json file.

Working with internal packages


As your team is developing client-side solutions, you will very likely build common libraries of code that you would like to reuse across all your project. In many cases such libraries contain
proprietary code not shared publicly outside the organization, beyond the bundles deployed to production. When working with SharePoint Framework projects, there are a number of ways
your team can leverage your internal libraries in their projects.

Hosting private package registry


In the past, many organizations building .NET solutions hosted private NuGet repositories to benefit of the NuGet package management system for their internal packages. As SharePoint
Framework uses npm for package management, organizations could similarly use a private registry for their internal packages. Packages developed internally would be published to the
private registry and be used in all projects within the organization.
When using private package registries organizations can choose between different offerings hosted in the cloud or they can host their own registry on their own infrastructure.
Using a private package registry allows organizations to centrally manage common code used across the different projects. By defining a separate governance plan around contributing
changes to the shared code base, organizations can ensure that the code library is of high quality and that it offers all developers benefits as intended rather than being a burden slowing
projects down.
Organizations using Visual Studio Team Services or the Team Foundation Server, can conveniently create a private npm registry directly in VSTS/TFS. Organizations using other source
control systems, can use other solutions for hosting their packages. A popular private registry hosted in the cloud is npm Enterprise. Organizations that are interested in hosting their registry
themselves can choose from a number of open source implementations such as Sinopia or its fork Verdaccio or Nexus.
NOTE

Different engines for hosting private package registries are in different development stages and you should carefully evaluate that the particular engine meets your requirements, both from
the functionality, license and support point of view.
To simplify the installation and management of a private package registry, most engines offer ready-to-use Docker images.

Linking packages using npm link


An alternative to using a private registry is linking packages. While it doesn't involve setting up a registry, it requires careful coordination on all developer machines and the build server.
First, every developer on the team must get a copy of the shared package on their development machine. In the command line they have to change the working directory to the one of the
shared package and then they must execute the npm link command. This command registers the particular package as a global package on that particular development machine. Next,
developers have to change the working directory to the directory of the project in which they would like to use the shared package. Then they install the package the same way they would
install any other package by executing the npm install <shared_package> --save command in the command line. As the shared package is installed globally, npm will use that version as the
source to install the package from. At this point, from the project point of view, the package is installed just like any other public package and developers can choose how they want to bundle
the package with the project.
Linking the package must be executed on all development machines as well as on the build server. If the shared package isn't linked using the npm link command, restoring project
dependencies will fail breaking the build.
Referencing linked packages is particularly helpful early in the project when you are developing the shared package and the project at the same time. Thanks to linking you don't need to
publish new version of the package to the registry in order to use the latest code in your project. A risk worth keeping in mind is that if developers would reference a version of the shared
library that they changed locally and which they haven't committed to the source control, it would break the build for the rest of the team.

Combining private package registry and linking packages


Linking packages can be combined with a private registry. You could for example work in a way where developers reference a linked package and the build server pulls the shared library
from a private registry. From the project perspective nothing changes: the package reference in the package.json file can be resolved both from a linked package as well as from a private
registry. The only thing your team has to keep in mind is to publish the latest changes to the shared library to the private registry before executing the build.
As the code of the shared library stabilizes over time and fewer changes are needed to accommodate the needs of the specific projects, developers would be more likely to just reference the
published package from the private registry rather than changing it.

Ensuring code consistency and quality


Software development teams often struggle with maintaining consistency and high quality of their projects. Different developers have different coding styles and preferences. In every team
there are more skilled individuals as well as developers who are less experienced in the particular domain. Also, many organizations or verticals have specific regulations with which the
software must comply. All these challenges make it harder for developers to stay on track. Particularly when the deadline is nearby developers tend to get things done at the cost of the
quality which in the long run is more harmful than not meeting the deadline.

Choose JavaScript library for your team and use coding standards
If your team has been building SharePoint customizations in the past, you very likely have coding standards that describe how you build customizations and which tools and libraries you use
in your projects. Using coding standards allows you to eliminate the personal preferences of the individual developers from the code which makes it significantly easier to be picked up by
other members of your team. Also your coding standards reflect the experience your team gathered over the years allowing you to build customizations more efficiently and of better quality.
Unlike other SharePoint customization models available to date, SharePoint Framework focuses on client-side development. While not strictly required, SharePoint Framework recommends
using TypeScript to help developers write better code and catch any inconsistencies already in the build process. There are also hundreds of client-side libraries available to accomplish the
same task. If your team has done client-side development in the past, you might already have preference for a particular library. If not, it would be highly beneficial for you to research a few
of the most popular libraries and pick one for your team or preferably the whole organization.
By using the same library in all your projects you make it easier to onboard new team members and exchange team members between projects. As you gain more experience with client-side
development, your organization will be able to benefit of it across all its projects. Standardizing your projects across the whole organization also shortens the time of delivery and lowers the
costs of maintenance of your projects. New libraries are published on the internet every day and if you keep switching between the latest libraries you will find yourself working inefficiently
delivering solutions of poor quality.
Standardizing which libraries are used across your organization additionally helps you optimize the performance of your solutions. Because the same library is used across the whole
organization, users only need to download it once, what significantly decreases the loading time of the solutions improving the user experience as the result.
Choosing one of the most popular libraries allows you to reuse the knowledge and experience of other developers who have been using that library for a longer period of time and have
already solved many of the issues you will likely experience yourself. Also for the most popular libraries there are coding standards available that your team could adopt. By using existing
market standards for the particular library you make it easier for your organization to grow your team by hiring developers and helping them become productive faster.
For example, for building first-party solutions on the SharePoint Framework, Microsoft chose React. Also many other teams at Microsoft such as OneDrive or Delve use React in their
projects. This doesn't mean that you should be using React in all your SharePoint Framework projects as well, but it proves the importance of choosing a client-side library that works for
your organization. If your team has for example experience with Angular or Knockout, there is no reason why you shouldn't benefit of that experience and stay productive when building
SharePoint Framework solutions.

Enforce coding standards and policies throughout the whole lifecycle of your solution
Using coding standards offers you clear advantages, but just having coding standards doesn't mean that they are being actively used throughout the whole development and testing process
of a SharePoint customization. The longer developers wait and the harder it is for your team to verify that your solution adheres to your team's coding standards and organizational policies,
the more costly it will be to fix any defects discovered in the project. Following are a few means that your team should use as a part of their development process to enforce the governance
plan for the SharePoint solution.
Linting
Linting is the process of verifying that the code meets specific rules. By default SharePoint Framework projects are built using TypeScript. On each build TSLint - the linter for TypeScript,
analyzes the project against the predefined set of rules and reports any inconsistencies. Developers can choose which rules they want to enable and if necessary can build their own rules that
reflect their team's or organization's guidelines.
Developers can use linting to verify not only the contents of TypeScript files. There are linters available for most popular languages such as CSS, JavaScript or Markdown, and if your team
has specific guidelines for these languages it would be beneficial to implement them in a linter so that they can be validated automatically every time a developer builds the project.
Automated testing
Using automated tests developers can easily verify that after applying the latest changes to the project, all elements continue working as expected. As the project grows so does the
importance of automated tests: with the code base expanding every change has bigger impact and risk of affecting some other pieces of code. Automated tests allow developers to verify that
the solution works correctly and catch any possible issues early on.
SharePoint Framework offers standard support for the Karma test runner and the Mocha framework that developers can use to write tests. If necessary developers can use additional
building blocks provided with the SharePoint Framework such as PhantomJS to further extend the coverage of their tests. All tests in the SharePoint Framework projects can be run using
the standard gulp test task.
Code analysis
Where linting is helpful to validate the syntax of the particular file, often developers need more support in order to verify that the project as a whole meets the guidelines. Generally linters
focus on the code itself but miss the context of what the particular code file represents. In SharePoint Framework solutions artifacts have specific requirements, for example a web part
should have a unique ID in the project. Also organizations might have other requirements such as not referencing scripts from CDN or only using a specific version of a particular library.
This is where linters generally fall short and developers need other tools.
SharePoint Code Analysis Framework (SPCAF) is a third party solution frequently used by SharePoint developers, administrators and employees in quality assurance and security roles to
verify that SharePoint customizations meet organizational quality guidelines. SPCAF integrates with the whole application lifecycle process helping organizations lower the total cost of
ownership of SharePoint customizations. SPCAF offers a set of rules that specifically target SharePoint Framework solutions.

Upgrading SharePoint Framework projects


Deploying a SharePoint customization to production usually doesn't mean the end of its lifecycle. Frequently the requirements change or new requirements are added in both cases leading
to changes in the solution. To properly update a customization previously deployed to production developers have to take a number of things into account.

Semantic versioning (SemVer)


With a few exceptions SharePoint Framework uses semantic versioning (SemVer) for tracking version numbers. Semantic versioning is a versioning pattern widely adopted by software
developers worldwide. A SemVer number consists of three numbers MAJOR.MINOR.PATCH and optional labels, eg. 1.0.1.
NOTE

Currently SharePoint Frameworks supports only the usage of the three numbers without labels.
Different parts of a SemVer number are increased depending on the type of change applied to the solution:
MAJOR, if the changes are not backwards-compatible
MINOR, if the changes introduce new functionality that is backwards-compatible
PATCH, if the changes are backwards-compatible bug fixes
It's important to keep in mind that SemVer is merely a contract. It's up to your team to follow it to make clear the changes in the latest release.
You can read more about semantic versioning at http://semver.org.

Increase version number


When updating a part of a SharePoint Framework solution, developers should increase version numbers of the affected pieces to clearly denote which elements have changed and what the
impact of the changes is.
Increase package version in package.json
SharePoint Framework package is structured like a Node.js package. Its dependencies and metadata are stored in the package.json file in the project folder. One of the properties in the
package.json file is the version property that denotes the version of the whole project. By default, all components in the current solution inherit this version number as their version.
Developers should increase the version number in the package.json file every time a new release of the project is planned following the SemVer convention.
Increase solution package version in package-solution.json
SharePoint Framework solutions are deployed using an .sppkg file installed in the app catalog on a SharePoint tenant. An .sppkg file is similar to a SharePoint add-in package and follows
the same versioning conventions. The current version of the .sppkg package is defined using a four-part (MAJOR.MINOR.REVISION.BUILD) number stored in the config/package-
solution.json file. For clarity, developers should keep this number in sync with the version number in the package.json file as both number refer to the version of the project as a whole.
NOTE

Increasing the version number in the package-solution.json file between releases is required in order for the new version of the package to be correctly deployed in SharePoint.

Update dependencies
One of the reasons for an update of a SharePoint Framework project might be a change to one of the underlying dependencies, for example a new release of Angular with bug fixes and
performance improvements. If your team follows the recommended approach of using npm shrinkwrap for locking dependencies' versions then you would use the
npm install <package>@<version> --save command to update your dependency to the specific version and test your project to verify that it works as expected with the latest updates.
Depending on how the changes to the underlying dependencies impact the project, the overall project update might vary from a patch to a full major release.
IM P O R T A N T

Don't modify the version numbers of dependencies in the package.json file manually. If you're using a lock file such as npm shrinkwrap, your manual changes to the package.json file will be
ignored and the version numbers recorded in the lock files will be used instead which will lead to hard to track errors in your project.
Mind project structure changes
Updating your project to a newer version of the SharePoint Framework, might require changes to your project structure and project configuration files. Before updating the versions of the
SharePoint Framework in your project dependencies, you should always create a new project using the version of the SharePoint Framework to which you want to upgrade and carefully
compare its structure and contents with your existing project. This will allow you to determine the impact of the upgrade on your project and help you avoid applying breaking changes to
your project.
Beware of using npm outdated
One of the ways to find out which dependencies in your project need updating, is to run the npm outdated command. This command will scan your dependency tree and will show you
which packages could be updated. While using this command is convenient, it has to be done with caution.
Starting from version 1.3, the SharePoint Framework Yeoman generator allows you to choose whether you want to scaffold a project that should work only in SharePoint Online or in both
SharePoint 2016 Feature Pack 2 and up and SharePoint Online. SharePoint hosted on-premises uses an older version of the SharePoint Framework than the latest version available in
SharePoint Online. If you would run the npm outdated command on a project compatible with SharePoint on-premises, it would suggest updating all core SharePoint Framework packages
to the latest versions published to Npm. Unfortunately, by updating these packages to their latest versions, your project wouldn't work with SharePoint on-premises anymore. Before
updating the versions of the SharePoint Framework packages, you should always verify if your project is meant to work with SharePoint hosted on-premises and if so, what version of the
SharePoint Framework you have to support.

Build and package project in release mode


Once you verified that the solution is working as expected, build the project in release mode using the gulp bundle --ship command. Then create a new package using the
gulp package-solution --ship command. Without running the gulp bundle --ship command first, the package will include previous version of your project.

Deploy new version of your solution


After building and packaging the project the next step is to deploy it. First deploy the updated web part bundles located in the ./temp/deploy folder in your project. Publish the files next to
web part bundles of the previous version of your solution.
NOTE

You shouldn't remove the previous versions of your solution as long as there are active instances of web parts using them. Each version of the bundle files has a unique name and removing
previous versions before updating web parts will break these web parts.
Next, deploy the new solution package to SharePoint app catalog. This is necessary to notify SharePoint of the new version of the solution which it should apply.
SharePoint Framework solutions governance considerations
3/26/2018 • 7 minutes to read Edit Online

With the SharePoint Framework, your organization can easily build solutions that easily integrate the capabilities available in SharePoint and Office 365. SharePoint Framework solutions
work across modern web technologies and different mobile devices so you can create productive experiences and apps that are responsive and mobile-ready from day one. To get the most
benefit from SharePoint Framework solutions, your organization should have an actionable governance plan covering the most important project management considerations.

Anatomy of SharePoint Framework solutions

SharePoint Framework solutions consist of two parts: code (often referred to as a web part bundle) deployed to a URL, and an .sppkg file that contains a web part manifest with a URL
pointing to the location where the web part code is deployed. There are no particular restrictions to where the code is deployed, as long as users working with the web part can access the
web part code. Organizations can choose, for example, to have their web parts deployed to the Office 365 public CDN, Azure storage, or a privately-owned web server.

Web part code-hosting location considerations


The most important thing that organizations should know before deploying SharePoint Framework solutions is where the code of the solution is deployed. SharePoint Framework solutions
are executed as a part of the page in the context of the current user. As a result, whatever the user can do, the web part's code can do as well. In contrast to SharePoint Add-ins, there is no
separate permission scope applied to SharePoint Framework solutions. This is why SharePoint administrators should treat SharePoint Framework solutions as high-trust solutions, the same
way they treat farm solutions on-premises. The location where the web part's code is deployed is important for a number of reasons.
Consider the following location issues.

Is the code-hosting location supported by the organization?


SharePoint Framework doesn't impose any restrictions regarding where the solution's code is deployed. As a result, developers and vendors can deploy the code to a range of locations
within or outside the organization's IT department. Different organizations may have different server requirements ranging from access policies to SL As. Before deploying a SharePoint
Framework solution package, organizations should ensure that the server used to host the code is a known server approved to be used by the organization.

Who manages the code-hosting location?


SharePoint Framework solutions execute as a part of the page in the context of the current user. While an organization could perform a code review before deploying a solution package, to
verify that the code can be trusted, it also should ensure the integrity of the code as long as it's deployed to the tenant. Organizations should have a clear understanding of who manages the
hosting location, who and under what circumstances they can modify the files, and what the update approval process looks like. Establishing this information upfront not only helps
organizations control the update process, but also lowers the risk of deploying malicious code.

What is the SLA for the hosting location?


When organizations use Office 365 and SharePoint Online, they rely on the SL A provided by Microsoft. SharePoint Framework solutions that extend the standard capabilities of SharePoint
and Office 365 should be deployed to servers that meet or exceed the SL A provided by Microsoft. That way, organizations can ensure that they are able to truly benefit from the added
values of their customizations.

Is the hosting location optimized for performance?


Loading existing libraries from a URL instead of embedding them in the web part bundle is the first step to speed up the loading time of SharePoint Framework solutions. To get the most
out of it, you want to ensure that the server hosting the different scripts is correctly configured for optimal performance. It should serve all files compressed, and the longer it allows proxies
and clients to cache the files, the longer users will be able to load these scripts from their local cache, significantly speeding up loading SharePoint pages containing web parts.

Tools and libraries


When building client-side solutions, developers can choose from a variety of libraries such as React, Angular, jQuery, or Knockout. Using an existing JavaScript library makes it easier for
developers to build rich solutions. There are big differences between how the different libraries work, and often specific knowledge is required to fully understand how to build a solution
using the particular library.
Once released to your production tenant, you should ensure that your support organization (either your own IT department or a contracted third party) is capable of supporting the solution.
To do this, the support organization should have at least a basic understanding of the library used to build that solution. Also, as you increase the number of libraries that you use across your
tenant, the harder it is to support the different solutions. Selecting one or two libraries to use in your organization helps you lower the operational costs. Before deploying a solution to your
production tenant, you should ensure that the solution is using only libraries supported in your organization.
Using external scripts
When using existing JavaScript libraries, developers can either choose to include them in the web part code bundle or load them from a URL. Loading libraries from URLs allows developers
to optimize SharePoint Framework solutions for performance. Because libraries are loaded from a URL, they don't need to be included in the web part bundle, which decreases its size
making it load faster. Additionally, by referencing the same libraries across the whole tenant, SharePoint Framework solutions load faster by reusing the previously downloaded scripts from
the local cache.
There are no restrictions to where the existing libraries can be loaded from, and it's important to know from which servers the external scripts are loaded. Together with the web part code,
these scripts run in the context of the current user and can do whatever the current user is capable of doing. Therefore, it's important that you trust these scripts and their integrity. Some
organizations have strict policies relating to resources sourced from public CDNs, and you should ensure that the solution and its resources meet your organizational policies.

Approving SharePoint Framework solutions for deployment


SharePoint Framework solutions are deployed to a tenant centrally through the app catalog. Your organization should have a plan in place describing who is allowed to deploy and approve
SharePoint Framework packages. This is important, because this plan should include who is responsible to verify that the packages that are deployed are secure and meet the organizational
policies. SharePoint Framework solutions run in the browser in the context of the current user and, unlike SharePoint Add-ins, always have the same permissions as the currently signed-in
user. Before deploying and approving a SharePoint Framework solution for use in your organization, its origin and other criteria mentioned previously in this article should be carefully
examined.
To verify that your SharePoint Framework solution meets your organization's policies, you should review the contents of the .sppkg package that you want to deploy and closely examine the
contents of the referenced scripts and the location where they are hosted. This step can be performed manually, or it can be automated by using third-party tooling. SharePoint
Customization Analysis Framework (SPCAF) is an example of a third-party solution that significantly simplifies the process of analyzing the contents of SharePoint Framework solutions and
verifying that they meet your organizational security and governance requirements.

SharePoint Framework solutions and no-script sites


In Office 365, organizations can use the no-script setting to disable script-based customizations in SharePoint Online. Organizations can configure the no-script setting either for the whole
tenant or for a particular site collection. Based on the criteria from the organizational policies, administrators can use the no-script setting to disable customizations built, for example, by
using the Script Editor web part or a user custom action.
The no-script setting is meant for organizations to apply an additional layer of control and security to either the whole tenant or specific site collections. Customizing SharePoint using script
embedding and injecting is not without risks, and particularly on sites containing sensitive information, should be thoroughly evaluated.
In the past, developers used script embedding and injecting techniques for building powerful SharePoint customizations. In some cases, these customizations relied on specific page
structure, and when the particular customization changed, it would stop working correctly. To guide developers to build more robust solutions, the SharePoint engineering team decided that
all modern sites should have the no-script setting enabled. This means that embedding and injecting scripts on these sites is not possible, and using the SharePoint Framework is currently
the only option to customize these sites. In the future, all modern sites will use the no-script setting, and alternatives to script embedding and injecting will become available for developers to
support the different scenarios.
Connect SharePoint Framework components using dynamic data
6/5/2018 • 7 minutes to read Edit Online

Using the dynamic data capability, you can connect SharePoint Framework client-side web parts and extensions to each other and exchange information between the components. This
allows you to build rich experiences and compelling end-user solutions.
IM P O R T A N T

The dynamic data capability is currently in preview and using it in production solutions is not supported.

Expose data using dynamic data source


Dynamic data in the SharePoint Framework is based on the source-notification model. Component designated as a dynamic data source, provides data and notifies about its changes. Other
components on the page can subscribe to notifications issued by a dynamic data source. When handling notifications, dynamic data consumers can retrieve the current value of the dynamic
data set exposed by the data source.
Each data source implements the IDynamicDataController interface. Following, is an example of a web part that displays a list of upcoming events. For each event, it includes some
information such as its name, description and location. The events web part exposes information about the selected event to other components on the page in two ways: the complete event
information and the location address.

export default class EventsWebPart extends BaseClientSideWebPart<IEventsWebPartProps> implements IDynamicDataController {


private _selectedEvent: IEvent;

private _eventSelected = (event: IEvent): void => {


this._selectedEvent = event;
this.context.dynamicDataSourceManager.notifyPropertyChanged('event');
this.context.dynamicDataSourceManager.notifyPropertyChanged('location');
}

protected onInit(): Promise<void> {


this.context.dynamicDataSourceManager.initializeSource(this);

return Promise.resolve();
}

public getPropertyDefinitions(): ReadonlyArray<IDynamicDataPropertyDefinition> {


return [
{
id: 'event',
title: 'Event'
},
{
id: 'location',
title: 'Location'
}
];
}

public getPropertyValue(propertyId: string): IEvent | ILocation {


switch (propertyId) {
case 'event':
return this._selectedEvent;
case 'location':
return this._selectedEvent ? { city: this._selectedEvent.city, address: this._selectedEvent.address } : undefined;
}

throw new Error('Bad property id');


}

public render(): void {


const element: React.ReactElement<IEventsProps> = React.createElement(
Events,
{
displayMode: this.displayMode,
onEventSelected: this._eventSelected,
title: this.properties.title,
updateProperty: (value: string): void => {
this.properties.title = value;
},
siteUrl: this.context.pageContext.web.serverRelativeUrl
}
);

ReactDom.render(element, this.domElement);
}

// ... omitted for brevity


}

IM P O R T A N T

The IDynamicDataController interface can be implemented by any class, not just web parts and extensions. If the dynamic data source requires complex logic, you should consider moving it
into a separate class rather than implementing it directly inside a web part or extension.
The class implementing the IDynamicDataController interface must define two methods: getPropertyDefinitions and getPropertyValue . The getPropertyDefinitions method returns an
array of types of data that the particular dynamic data source returns. In the previous example, the web part exposes detailed information about an event and its location. Even though the
information comes from a single object ( _selectedEvent ), by exposing it in two different shapes, the web part is more reusable and could be used in combination with other web parts that
aren't specific to events, such as a map web part that can show a map for the specified address. The list of the data types exposed by the data source is displayed to end-users when
connecting web parts to the data source.
IM P O R T A N T

The object returned by the getPropertyValue method should be flat, for example:
{
"date": "2018-06-01T11:21:59.446Z",
"name": "Tampa Home Show",
"organizerEmail": "Grady Archie",
"organizerName": "GradyA@contoso.onmicrosoft.com"
}

Object with a nested structure will be flattened during serialization, which could lead to undesired effects. For example, object like:

{
"date": "2018-06-01T11:21:59.446Z",
"name": "Tampa Home Show",
"organizer": {
"email": "Grady Archie",
"name": "GradyA@contoso.onmicrosoft.com"
}
}

would after serialization become:

{
"date": "2018-06-01T11:21:59.446Z",
"name": "Tampa Home Show",
"organizer.email": "Grady Archie",
"organizer.name": "GradyA@contoso.onmicrosoft.com"
}

The getPropertyValue method returns the value for the particular type of data. The value of the propertyId argument corresponds to the id of the definition specified in the
getPropertyDefinitions method.
To register a component as a dynamic data source, call the this.context.dynamicDataSourceManager.initializeSource() method, passing the instance of the dynamic data source as a
parameter. In the previous example, the web part itself implements the IDynamicDataController interface, which is why the initializeSource method is called with this as its argument.
In the example code, the web part displays upcoming events in a list. Each time, the user selects an event from the list, the web part calls the _eventSelected method. In that method, the web
part assigns the selected event to the _selectedEvent class variable and issues a notification that the information about the selected event and location has changed by calling the
this.context.dynamicDataSourceManager.notifyPropertyChanged() method passing the id of the definition that represents the changed data set.

Consume dynamic data


Components on the page can subscribe to data notifications exposed by dynamic data sources. The subscription is recorded using the ID of the data source and the ID of the data set it
exposes.
Following is the code of a web part showing detailed information about the event selected in the events list web part showed previously. The displayed data is retrieved from the events data
source configured in web part properties.

export default class EventDetailsWebPart extends BaseClientSideWebPart<IEventDetailsWebPartProps> {


protected onInit(): Promise<void> {
this.render = this.render.bind(this);

return Promise.resolve();
}

public render(): void {


let event: IEvent = undefined;
const needsConfiguration: boolean = !this.properties.sourceId || !this.properties.propertyId;

if (this.renderedOnce === false && !needsConfiguration) {


try {
this.context.dynamicDataProvider.registerPropertyChanged(this.properties.sourceId, this.properties.propertyId, this.render);
this._lastSourceId = this.properties.sourceId;
this._lastPropertyId = this.properties.propertyId;
}
catch (e) {
this.context.statusRenderer.renderError(this.domElement, `An error has occurred while connecting to the data source. Details: ${e}`);
return;
}
}

if (!needsConfiguration) {
const source: IDynamicDataSource = this.context.dynamicDataProvider.tryGetSource(this.properties.sourceId);
event = source ? source.getPropertyValue(this.properties.propertyId) : undefined;
}

const element: React.ReactElement<IEventDetailsProps> = React.createElement(


EventDetails,
{
needsConfiguration: needsConfiguration,
event: event,
onConfigure: this._onConfigure,
displayMode: this.displayMode,
title: this.properties.title,
updateProperty: (value: string): void => {
this.properties.title = value;
}
}
);

ReactDom.render(element, this.domElement);
}

// ... omitted for brevity


}

Dynamic data consumer subscribes to notifications issues by the dynamic data source by calling the
this.context.dynamicDataProvider.registerPropertyChanged(sourceId, propertyId, handler); method. The first argument, sourceId refers to the ID of the dynamic data source which issues
notifications. The second argument, propertyId refers to the ID of the data set exposed by the data source. The last arguments points to the handler method which is called whenever the
data source issued a notification.
When the data source notifies the data consumer that its data is changed, the specified handler method is called. In that method, you should retrieve the latest data from the data source. You
do this, by first retrieving the source using the this.context.dynamicDataProvider.tryGetSource(sourceId) method. Once you have the reference to the data source, you can retrieve the data by
calling the source.getPropertyValue(propertyId) method, specifying the id of the data set.

const source: IDynamicDataSource = this.context.dynamicDataProvider.tryGetSource(this.properties.sourceId);


event = source ? source.getPropertyValue(this.properties.propertyId) : undefined;

IM P O R T A N T

Depending on the order in which components on the page are loaded, it could happen that the particular dynamic data source is not available when retrieving it using the tryGetSource
method. Before calling the getPropertyValue method to retrieve the current value for the dynamic data, you should first check if the source is available to avoid runtime errors.

Connect to a dynamic data source


Dynamic data consumers subscribe to notifications issued by dynamic data sources by specifying the unique ID of the dynamic data source. Because these IDs are generated on runtime, the
easiest way to allow users to connect components is by using the web part property pane enumerating all available dynamic data sources and their data sets. Following code shows how to
provide configuration interface for end-users to connect web part to a dynamic data source on the page:
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
IPropertyPaneDropdownOption,
PropertyPaneDropdown
} from '@microsoft/sp-webpart-base';

import * as strings from 'EventDetailsWebPartStrings';


import { EventDetails, IEventDetailsProps } from './components';
import { IDynamicDataSource } from '@microsoft/sp-dynamic-data';
import { IEvent } from '../../data';

export interface IEventDetailsWebPartProps {


propertyId: string;
sourceId: string;
title: string;
}

export default class EventDetailsWebPart extends BaseClientSideWebPart<IEventDetailsWebPartProps> {


private _lastSourceId: string = undefined;
private _lastPropertyId: string = undefined;

// ... omitted for brevity

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


const sourceOptions: IPropertyPaneDropdownOption[] =
this.context.dynamicDataProvider.getAvailableSources().map(source => {
return {
key: source.id,
text: source.metadata.title
};
});
const selectedSource: string = this.properties.sourceId;

let propertyOptions: IPropertyPaneDropdownOption[] = [];


if (selectedSource) {
const source: IDynamicDataSource = this.context.dynamicDataProvider.tryGetSource(selectedSource);
if (source) {
propertyOptions = source.getPropertyDefinitions().map(prop => {
return {
key: prop.id,
text: prop.title
};
});
}
}

return {
pages: [
{
groups: [
{
groupFields: [
PropertyPaneDropdown('sourceId', {
label: strings.SourceIdFieldLabel,
options: sourceOptions,
selectedKey: this.properties.sourceId
}),
PropertyPaneDropdown('propertyId', {
label: strings.PropertyIdFieldLabel,
options: propertyOptions,
selectedKey: this.properties.propertyId
})
]
}
]
}
]
};
}

protected onPropertyPaneFieldChanged(propertyPath: string): void {


if (propertyPath === 'sourceId') {
this.properties.propertyId =
this.context.dynamicDataProvider.tryGetSource(this.properties.sourceId).getPropertyDefinitions()[0].id;
}

if (this._lastSourceId && this._lastPropertyId) {


this.context.dynamicDataProvider.unregisterPropertyChanged(this._lastSourceId, this._lastPropertyId, this.render);
}

this.context.dynamicDataProvider.registerPropertyChanged(this.properties.sourceId, this.properties.propertyId, this.render);


this._lastSourceId = this.properties.sourceId;
this._lastPropertyId = this.properties.propertyId;
}
}

The this.context.dynamicDataProvider.getAvailableSources() method returns information about all dynamic data source available on the current page. For each dynamic data source you get
the information about its unique ID as well as other information included in its component manifest. Additionally, for each data source you can call the
IDynamicDataSource.getPropertyDefinitions() method to get information about all data sets it exposes.

When using the web part property pane to allow users to connect components, it's important that you remove the previously configured event handler, before registering the new handler by
calling the this.context.dynamicDataProvider.unregisterPropertyChanged(sourceId, propertyId, handler) method.

Considerations
each page can have multiple dynamic data sources and consumers
each component can both provide dynamic data to other components and consume dynamic data from other components
components can consume data from multiple dynamic data sources
to persist subscriptions to dynamic data sources, store the subscription information in web part properties

See also
Dynamic Data sample code
Add an external library to your SharePoint client-side web part
3/26/2018 • 7 minutes to read Edit Online

You might want to include one or more JavaScript libraries in your web part. This article shows you how to bundle an external library and share libraries.

Bundle a script
By default, the web part bundler automatically includes any library that is a dependency of the web part module. This means that the library is deployed in the same JavaScript bundle file as
your web part. This is more useful for smaller libraries that are not used in multiple web parts.

Example
1. Include the string validating library validator package into a web part.
2. Download the validator package from npm:

npm install validator --save

NOTE

Because you're using TypeScript, you need typings for the package you add. This is essential when you are writing code because TypeScript is just a superset of JavaScript. All the
TypeScript code is still converted to JavaScript code when you compile. You can search for and find typings by using npm, for example: npm install @types/{package} --save
3. Create a file in the your web part's folder called validator.d.ts and add the following:

declare module "validator" {


export function isEmail(email: string): boolean;
export function isAscii(text: string): boolean;
}

NOTE

Some libraries do not have typings. While the validator library does have a community provided typings file, for this scenario let's assume it does not. In this case, you would want to
define your own typings definition .d.ts file for the library. The previous code shows an example.
4. In your web part file, import the typings:

import * as validator from 'validator';

5. Use the validator library in your web part code:

validator.isEmail('someone@example.com');

Share a library among multiple web parts


Your client-side solution might include multiple web parts. These web parts might need to import or share the same library. In such cases, instead of bundling the library, you should include
it in a separate JavaScript file to improve performance and caching. This is especially true of larger libraries.

Example
In this example, you will share the marked package (a markdown compiler) in a separate bundle.
1. Download the marked package from npm:

npm install marked --save

2. Download the typings:

npm install @types/marked --save

3. Edit the config/config.json, and add an entry to the externals map. This is what tells the bundler to put this in a separate file. This prevents the bundler from bundling this library:

"marked": "node_modules/marked/marked.min.js"

4. Add the statement to import the marked library in your web part now that we have added the package and typings for the library:

import * as marked from 'marked';

5. Use the library in your web part:

console.log(marked('I am using __markdown__.'));

Load a script from a CDN


Instead of loading the library from an npm package, you might want to load a script from a Content Delivery Network (CDN). To do so, edit the config.json file to load the library from its
CDN URL.

Example
In this example, you will load jQuery from CDN. You don't need to install the npm package. However, you still need to install the typings.
1. Install the typings for jQuery:
npm install --save @types/jquery

2. Update the config.json in the config folder to load jQuery from CDN. Add an entry to the externals field:

"jquery": "https://code.jquery.com/jquery-3.1.0.min.js"

3. Import jQuery in your web part:

import * as $ from 'jquery';

4. Use jQuery in your web part:

alert( $('#foo').val() );

Load a non-AMD module


Some scripts follow the legacy JavaScript pattern of storing the library on the global namespace. This pattern is now deprecated in favor of Universal Module Definitions (UMD) /
Asynchronous Module Definitions (AMD) or ES6 modules. However, you might need to load such libraries in your web part.
 T IP

It's difficult to determine manually whether the script that you're trying to load is an AMD or a non-AMD script. This is especially the case if the script that you're trying to load is minified. If
your script is hosted on a publicly accessible URL, you can use the free Rencore SharePoint Framework Script Check tool to determine the type of script for you. Additionally, this tool lets
you know whether the hosting location from which you're loading the script is properly configured.
To load a non-AMD module, you add an additional property to the entry in your config.json file.

Example
In this example, you will load a fictional non-AMD module from Contoso's CDN. These steps apply for any non-AMD script in your src/ or node_modules/ directory.
The script is called Contoso.js and is stored at https://contoso.com/contoso.js. Its contents are:

var ContosoJS = {
say: function(text) { alert(text); },
sayHello: function(name) { alert('Hello, ' + name + '!'); }
};

1. Create typings for the script in a file called contoso.d.ts in the web part folder.

declare module "contoso" {


interface IContoso {
say(text: string): void;
sayHello(name: string): void;
}
var contoso: IContoso;
export = contoso;
}

2. Update the config.json file to include this script. Add an entry to the externals map:

{
"contoso": {
"path": "https://contoso.com/contoso.js",
"globalName": "ContosoJS"
}
}

3. Add an import to your web part code:

import contoso from 'contoso';

4. Use the contoso library in your code:

contoso.sayHello(username);

Load a library that has a dependency on another library


Many libraries have dependencies on another library. You can specify such dependencies in the config.json file by using the globalDependencies property.
IM P O R T A N T

Note that you don't have to specify this field for AMD modules; they properly import each other. However, a non-AMD module cannot have an AMD module as a dependency. In some cases,
it is possible to load an AMD script as a non-AMD script. This is often required when working with jQuery, which by itself is an AMD script, and jQuery plug-ins, which most of the time are
distributed as non-AMD scripts and which depend on jQuery.
There are two examples of this.

Non-AMD module has a non-AMD module dependency


This example involves two fictional scripts. These are in the src/ folder, although they can also be loaded from a CDN.
ContosoUI.js
Contoso.EventList = {
alert: function() {
var events = Contoso.getEvents();
events.forEach( function(event) {
alert(event);
});
}
}

ContosoCore.js

var Contoso = {
getEvents: function() {
return ['A', 'B', 'C'];
}
};

1. Add or create typings for this class. In this case, you will create Contoso.d.ts , which contains typings for both JavaScript files.
contoso.d.ts

declare module "contoso" {


interface IEventList {
alert(): void;
}
interface IContoso {
getEvents(): string[];
EventList: IEventList;
}
var contoso: IContoso;
export = contoso;
}

2. Update the config.json file. Add two entries to externals:

{
"contoso": {
"path": "/src/ContosoCore.js",
"globalName": "Contoso"
},
"contoso-ui": {
"path": "/src/ContosoUI.js",
"globalName": "Contoso",
"globalDependencies": ["contoso"]
}
}

3. Add imports for Contoso and ContosoUI:

import contoso = require('contoso');


require('contoso-ui');

4. Use the libraries in your code:

contoso.EventList.alert();

Load SharePoint JSOM


Loading SharePoint JSOM is essentially the same scenario as loading non-AMD scripts that have dependencies. This means using both the globalName and globalDependency options.
IM P O R T A N T

Note that the following approach causes errors in classic SharePoint pages, where SharePoint JSOM is already loaded. If you require your web part to work with both classic and modern
pages, you should first check if SharePoint JSOM is already available, and if it isn't, load it dynamically by using the SPComponentLoader.

1. Install typings for Microsoft Ajax, which is a dependency for JSOM typings:

npm install @types/microsoft-ajax --save

2. Install typings for the JSOM:

npm install @types/sharepoint --save

3. Add entries to the config.json :


{
"sp-init": {
"path": "https://CONTOSO.sharepoint.com/_layouts/15/init.js",
"globalName": "$_global_init"
},
"microsoft-ajax": {
"path": "https://CONTOSO.sharepoint.com/_layouts/15/MicrosoftAjax.js",
"globalName": "Sys",
"globalDependencies": [ "sp-init" ]
},
"sp-runtime": {
"path": "https://CONTOSO.sharepoint.com/_layouts/15/SP.Runtime.js",
"globalName": "SP",
"globalDependencies": [ "microsoft-ajax" ]
},
"sharepoint": {
"path": "https://CONTOSO.sharepoint.com/_layouts/15/SP.js",
"globalName": "SP",
"globalDependencies": [ "sp-runtime" ]
}
}

4. In your web part, add the require statements:

require('sp-init');
require('microsoft-ajax');
require('sp-runtime');
require('sharepoint');

Load localized resources


You can use a map in config.json called localizedResources to describe how to load localized resources. Paths in this map are relative to the lib folder and must not contain a leading slash
(/).
In this example, you have a folder src/strings/. In this folder are several JavaScript files with names such as en-us.js, fr-fr.js, de-de.js. Because each of these files must be loadable by the
module loader, they must contain a CommonJS wrapper. For example, in en-us.js:

define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"DescriptionFieldLabel": "Description Field"
}
});

1. Edit the config.json file. Add an entry to localizedResources. {locale} is a placeholder token for the locale name:

{
"strings": "strings/{locale}.js"
}

2. Add typings for your strings. In this case, you have a file MyStrings.d.ts:

declare interface IStrings {


webpartTitle: string;
initialPrompt: string;
exitPrompt: string;
}

declare module 'mystrings' {


const strings: IStrings;
export = strings;
}

3. Add imports for the strings in your project:

import * as strings from 'mystrings';

4. Use the strings in your project:

alert(strings.initialPrompt);

See also
SharePoint Framework Overview
Use existing JavaScript libraries in SharePoint Framework client-side web parts
3/26/2018 • 11 minutes to read Edit Online

When building client-side web parts on the SharePoint Framework, you can benefit from using existing JavaScript libraries to build powerful solutions. There are, however, some
considerations that you should take into account to ensure that your web parts won't negatively impact the performance of SharePoint pages that they are being used on.

Reference existing libraries as packages


The most common way of referencing existing JavaScript libraries in SharePoint Framework client-side web parts is by installing them as a package in the project.
1. Taking Angular as an example, to use it in a client-side web part, you would first install Angular using npm:

npm install angular --save

2. To use Angular with TypeScript, you would install typings using npm:

npm install @types/angular --save

3. Reference Angular in your web part by using the import statement:

import { Version } from '@microsoft/sp-core-library';


import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import { escape } from '@microsoft/sp-lodash-subset';

import styles from './HelloWorld.module.scss';


import * as strings from 'helloWorldStrings';
import { IHelloWorldWebPartProps } from './IHelloWorldWebPartProps';

import * as angular from 'angular';

export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {


public render(): void {
this.domElement.innerHTML = `
<div class="${styles.helloWorld}">
<!-- omitted for brevity -->
</div>`;

angular.module('helloworld', []);

angular.bootstrap(this.domElement, ['helloworld']);
}

// omitted for brevity


}

Bundle web part resources


SharePoint Framework uses a build toolchain based on open-source tooling such as gulp and Webpack. When building SharePoint Framework projects, these build tools automatically
combine all referenced resources into a single JavaScript file in a process called bundling.
Bundling offers you a number of benefits. First of all, all resources required by your web part are available in one single JavaScript file. This simplifies the deployment because the
web part consists of a single file, and it's impossible to miss a dependency in the deployment process.
Because your web part uses different resources, it's important that they are loaded in the right order. Generated by Webpack during the build, the web part bundle manages loading the
different resources for you, including resolving any dependencies between these resources.
Bundling web parts also has benefits for end-users: generally speaking, it's faster to download a single, bigger file than a number of small files. By combining a number of smaller files into
one bigger bundle, your web part loads faster on the page.
However, bundling existing JavaScript libraries with SharePoint Framework client-side web parts isn't without drawbacks.
When bundling existing JavaScript frameworks in the SharePoint Framework, all referenced scripts are included in the generated bundle file. Following the Angular example, an optimized
web part bundle including Angular is over 170 KB.

If you add another web part to your project that also uses Angular and you build the project, you get two bundle files, one for each web part, each of them being over 170 KB.
If you add these web parts to a page, each user would download Angular multiple times, once with each web part on the page. This approach is inefficient and slows down page load time.

Reference existing libraries as external resources


A better approach to leveraging existing libraries in SharePoint Framework client-side web parts is by referencing them as external resources. That way, the only information about the
particular script that is included in the web part is the script's URL. When added to the page, the web part automatically tries to load all required resources from the specified URL.
Referencing existing JavaScript libraries in the SharePoint Framework is easy and doesn't require any specific changes in the code. Because the library is loaded on runtime from the
specified URL, it doesn't need to be installed as a package in the project.
Using Angular as an example, to reference it as an external resource in your client-side web part, you start by installing its TypeScript typings using npm:

npm install @types/angular --save

In the config/config.json file, to the externals property you add the following entry:

"angular": {
"path": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js",
"globalName": "angular"
}

The complete config/config.json file would then look similar to:

{
"entries": [
{
"entry": "./lib/webparts/helloWorld/HelloWorldWebPart.js",
"manifest": "./src/webparts/helloWorld/HelloWorldWebPart.manifest.json",
"outputPath": "./dist/hello-world.bundle.js"
}
],
"externals": {
"angular": {
"path": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js",
"globalName": "angular"
}
},
"localizedResources": {
"helloWorldStrings": "webparts/helloWorld/loc/{locale}.js"
}
}

Reference Angular in your web part, just like you did previously:

import { Version } from '@microsoft/sp-core-library';


import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import { escape } from '@microsoft/sp-lodash-subset';

import styles from './HelloWorld.module.scss';


import * as strings from 'helloWorldStrings';
import { IHelloWorldWebPartProps } from './IHelloWorldWebPartProps';

import * as angular from 'angular';

export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {


public render(): void {
this.domElement.innerHTML = `
<div class="${styles.helloWorld}">
<!-- omitted for brevity -->
</div>`;

angular.module('helloworld', []);

angular.bootstrap(this.domElement, ['helloworld']);
}

// omitted for brevity


}

If you build your project now and take a look at the size of the generated bundle file, you notice that it's only 6 KB.
If you add another web part to your project that also uses Angular, and you build the project again, both bundles would be 6 KB each.

It isn't correct to assume that you have just saved over 300 KB. Both web parts still need Angular and load it the first time the user visits the page where one of the web parts is placed.

Even if you add both Angular web parts to the page, SharePoint Framework still downloads Angular only once.
The real benefit of referencing existing JavaScript libraries as external resources is if your organization has a centralized location for all commonly-used scripts or you use a CDN. In such
cases, there is a chance that the particular JavaScript library is already present in the user's browser cache. As a result, the only thing that needs to be loaded is the web part bundle which
makes the page load significantly faster.
The previous example shows how to load Angular from a CDN, but using a public CDN is not required. In the configuration, you can point any location from a public CDN, a privately-
hosted repository, to a SharePoint Document Library. As long as users working with your web parts are able to access the specified URLs, your web parts will work as expected.
CDNs are optimized for fast resource delivery across the globe. The additional advantage of referencing scripts from public CDNs is that there is a chance that the same script has been used
on some other website the user has visited in the past. Because the script is already present in the local browser's cache, it wouldn't need to be downloaded specifically for your web part,
which would make the page with the web part on it load even faster.
Some organizations don't allow access to public CDNs from the corporate network. In such cases, using a privately-hosted storage location for commonly-used JavaScript frameworks is a
great alternative. Because your organization hosts the libraries, it could also control the cache headers, which could help you optimize your resources for performance even further.

JavaScript libraries formats


Different JavaScript libraries are built and packaged in different ways. Some are packaged as modules, while others are plain scripts that run in the global scope (these scripts are often
referred to as non-module scripts). When loading JavaScript libraries from a URL, how you register an external script in a SharePoint Framework project depends on the format of the script.
There are multiple module formats, such as AMD, UMD, or CommonJS, but the only thing that you have to know is if the particular script is a module or not.
When registering scripts packaged as modules, the only thing that you have to specify is the URL where the particular script should be downloaded from. Dependencies to other scripts are
handled inside the script's module construct.
On the other hand, non-module scripts require, at minimum, the URL from where the script should be downloaded and the name of the variable with which the script is registered in the
global scope. If the non-module script depends on other scripts, they can be listed as dependencies. To illustrate this, let's have a look at a few examples.
Angular v1.x is a non-module script. You register it as an external resource in a SharePoint Framework project by specifying its URL and the name of the global variable it should register
with:

"angular": {
"path": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js",
"globalName": "angular"
}

It's important that the name specified in the globalName property corresponds to the name used by the script. That way it can correctly expose itself to other scripts that might depend on
it.
ngOfficeUIFabric, the Angular directives for Office UI Fabric, is a UMD module that depends on Angular. The dependency on Angular is already handled inside the module, so to register it,
all you need to specify is its URL:

"ng-office-ui-fabric": "https://cdnjs.cloudflare.com/ajax/libs/ngOfficeUiFabric/0.12.3/ngOfficeUiFabric.js"
jQuery is an AMD script. To register it, you could simply use:

"jquery": "https://code.jquery.com/jquery-2.2.4.js"

Imagine now that you wanted to use jQuery with a jQuery plug-in that itself is distributed as a non-module script.
If you registered both scripts by using the following code, loading the web part would very likely result in an error. There is a chance that both scripts would be loaded in parallel, and the
plug-in wouldn't be able to register itself with jQuery.

"jquery": "https://code.jquery.com/jquery-2.2.4.js",
"simpleWeather": {
"path": "https://cdnjs.cloudflare.com/ajax/libs/jquery.simpleWeather/3.1.0/jquery.simpleWeather.min.js",
"globalName": "jQuery"
}

As mentioned previously, SharePoint Framework allows you to specify dependencies for non-module plug-ins. These dependencies are specified using the globalDependencies property:

"jquery": "https://code.jquery.com/jquery-2.2.4.js",
"simpleWeather": {
"path": "https://cdnjs.cloudflare.com/ajax/libs/jquery.simpleWeather/3.1.0/jquery.simpleWeather.min.js",
"globalName": "jQuery",
"globalDependencies": [ "jquery" ]
}

Each dependency specified in the globalDependencies property must point to another dependency in the externals section of the config/config.json file.
If you try to build the project now, you would get another error, this time stating that you can't specify a dependency to a non-module script.
To solve this problem, all you need to do is to register jQuery as a non-module script:

"jquery": {
"path": "https://code.jquery.com/jquery-2.1.1.min.js",
"globalName": "jQuery"
},
"simpleWeather": {
"path": "https://cdnjs.cloudflare.com/ajax/libs/jquery.simpleWeather/3.1.0/jquery.simpleWeather.min.js",
"globalName": "jQuery",
"globalDependencies": [ "jquery" ]
}

This way you specify that the simpleWeather script should be loaded after jQuery, and that jQuery should be available under a globally available variable jQuery , which is required by the
simpleWeather jQuery plug-in to register itself.
NOTE

Notice how the entry for registering jQuery uses jquery for the external resource name, but jQuery as the global variable name. The name of the external resource is the name that you use
in the import statements in your code. This is also the name that must match TypeScript typings. The global variable name, specified by using the globalName property, is the name known
to other scripts such as plug-ins built on top of the library. While for some libraries these names might be the same, it's not required, and you should carefully check that you are using
correct names to avoid any problems.
It's difficult to determine manually whether the script that you're trying to load is a module or a non-module script. This is especially the case if the script that you're trying to load is minified.
If your script is hosted on a publicly accessible URL, you can use the free Rencore SharePoint Framework Script Check tool to determine the type of script for you. Additionally, this tool lets
you know whether the hosting location from which you're loading the script is properly configured.

Non-module scripts considerations


Many JavaScript libraries and scripts developed in the past are distributed as non-module scripts. While the SharePoint Framework supports loading non-module scripts, you should strive
to avoid using them whenever possible.
Non-module scripts are registered in the global scope of the page: a script loaded by one web part is available to all other web parts on the page. If you had two web parts using different
versions of jQuery, both loaded as non-module scripts, the web part that loaded the last would overwrite all previously registered versions of jQuery.
As you can imagine, this could lead to unpredictable results, and it would be very hard to debug issues that would occur only in certain scenarios, such as only with other web parts by using
a different version of jQuery on the page and only when they load in a particular order. The module architecture solves this problem by isolating scripts and preventing them from affecting
each other.

When you should consider bundling


Bundling existing JavaScript libraries into your web part can lead to big web part files and can cause poor performance of pages using that web part. While you should generally avoid
bundling JavaScript libraries with your web parts, there are scenarios where bundling could work to your advantage.
If you are building a standard solution that should work on every intranet, bundling all your resources with your web part can help you ensure that your web part works as expected. Because
you don't know upfront where your solution will be installed, including all dependencies in your web part's bundle file allows it to work correctly, even if the organization doesn't allow
downloading resources from a CDN or other external location.
If your solution consists of many web parts that share some functionality with each other, it would be better to build the shared functionality as a separate library and reference it as an
external resource in all web parts. That way users need to download the common library only once and reuse it with all web parts.

Summary
When building client-side web parts on the SharePoint Framework, you can benefit from existing JavaScript libraries to build powerful solutions. SharePoint Framework allows you to either
bundle these libraries together with your web parts or load them as an external resource. While loading existing libraries from a URL is generally the recommended approach, there are
scenarios where bundling might be beneficial, and it's essential that you evaluate your requirements carefully to choose the approach that best meets your needs.

See also
SharePoint Framework Overview
Reference third-party CSS styles in SharePoint Framework web parts
3/26/2018 • 10 minutes to read Edit Online

To build rich SharePoint Framework client-side web parts, you can leverage many third-party libraries. In addition to scripts, these libraries often contain additional assets such as stylesheets.
This article describes two approaches to including third-party CSS styles in web parts, and how each approach affects the resulting web part bundle. The example web part discussed in this
article uses jQuery and jQuery UI to display an accordion.

NOTE

Before following the steps in this article, be sure to set up your SharePoint client-side web part development environment.

Prepare the project


Create a new project
1. Create a new folder for your project.

md js-thirdpartycss

2. Go to the project folder.

cd js-thirdpartycss

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project.

yo @microsoft/sharepoint

4. When prompted, enter the following values:


js-thirdpartycss as your solution name
Use the current folder for the location to place the files
no javaScript web framework as the starting point to build the web part
jQuery accordion as your web part name
Shows jQuery accordion as your web part description
5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer.

Add test content


In the code editor, open the ./src/webparts/jQueryAccordion/JQueryAccordionWebPart.ts file, and then change the render method to:
export default class JQueryAccordionWebPart extends BaseClientSideWebPart<IJQueryAccordionWebPartProps> {
// ...
public render(): void {
this.domElement.innerHTML = `
<div>
<div class="accordion">
<h3>Information</h3>
<div>
<p>
The Volcanoes, crags, and caves park is a scenic destination for
many visitors each year. To ensure everyone has a good
experience and to preserve the natural beauty, access is
restricted based on a permit system.
</p>
<p>
Activities include viewing active volcanoes, skiing on mountains,
walking across lava fields, and caving (spelunking) in caves
left behind by the lava.
</p>
</div>
<h3>Snow permit</h3>
<div>
<p>
The Northern region has snow in the mountains during winter.
Purchase a snow permit for access to approved ski areas.
</p>
</div>
<h3>Hiking permit</h3>
<div>
<p>
The entire region has hiking trails for your enjoyment.
Purchase a hiking permit for access to approved trails.
</p>
</div>
<h3>Volcano access</h3>
<div>
<p>
The volcanic region is beautiful but also dangerous. Each
area may have restrictions based on wind and volcanic
conditions. There are three type of permits based on activity.
</p>
<ul>
<li>Volcano drive car pass</li>
<li>Lava field access permit</li>
<li>Caving permit</li>
</ul>
</div>
</div>
</div>`;

($('.accordion', this.domElement) as any).accordion();


}
// ...
}

If you build the project now, you get an error stating that $ is undefined. This is because the project refers to jQuery without loading it first. There are two approaches to loading the libraries.
Neither approach impacts how you use the scripts in code.

Approach 1: Include third-party libraries in the bundle


The easiest way to reference a third-party library in SharePoint Framework projects is to include it in the generated bundle. The library is installed as a package and referenced in the project.
When bundling the project, Webpack picks up the reference to the library and includes it in the generated bundle.

Install libraries
1. Install jQuery and jQuery UI by running the following command:

npm install jquery jquery-ui --save

2. Because you are building your web part in TypeScript, you also need TypeScript typings for jQuery that you can install by running the following command:

npm install @types/jquery --save

Reference libraries in the web part


After installing libraries, the next step is to reference them in the project.
1. In the code editor, open the ./src/webparts/jQueryAccordion/JQueryAccordionWebPart.ts file. In its top section, just under the last import statement, add references to jQuery
and jQuery UI.

import * as $ from 'jquery';


require('../../../node_modules/jquery-ui/ui/widgets/accordion');

Because you installed the TypeScript typings for the jQuery package, you can reference it by using an import statement. However, the jQuery UI package is built differently. Unlike
how many modules are structured, there is no main entry point with a reference to all components that you can use. Instead, you refer directly to the specific component that you want
to use. The entry point of that component contains all references to dependencies that it needs to work correctly.
2. Confirm that the project is building by running the following command:

gulp serve

3. After adding the web part to the canvas, you should see the accordion working.
At this point, you have referenced only the jQuery UI scripts, which explains why the accordion is not styled. Next, you add the missing CSS stylesheets to brand the accordion.

Reference third-party CSS stylesheets in the web part


Adding references to third-party CSS stylesheets that are a part of the packages installed in the project is as simple as adding references to the packages themselves. The SharePoint
Framework offers standard support for loading CSS files through Webpack.
1. In the code editor, open the ./src/webparts/jQueryAccordion/JQueryAccordionWebPart.ts file. Just under the last require statement, add references to jQuery UI accordion CSS
files.

require('../../../node_modules/jquery-ui/themes/base/core.css');
require('../../../node_modules/jquery-ui/themes/base/accordion.css');
require('../../../node_modules/jquery-ui/themes/base/theme.css');

Referencing CSS files that are part of a package in the project is similar to adding references to JavaScript files. All you need to do is specify the relative path to the CSS file that you
want to load, including the .css extension. When bundling the project, Webpack processes these references and includes the files in the generated web part bundle.
2. Confirm that the project is building by running the following command:

gulp serve

The accordion should be displayed correctly and branded by using the standard jQuery UI theme.

Analyze the contents of the generated web part bundle


The easiest way to use third-party libraries and their resources is by including them in the generated web part bundle. In this approach Webpack automatically resolves all dependencies
between the different libraries and ensures that all scripts are loaded in the correct order. The downside of this approach is that all referenced resources are loaded separately with every web
part. So if you have multiple web parts in your project, all using jQuery UI, each web part loads its own copy of jQuery UI and slows down the page.
To see the impact of the libraries on the size of the generated web part bundle, after bundling the project, open the ./temp/stats/js-thirdpartycss.stats.html file in the web browser. Move
your mouse over the chart and you will see, for example, that the jQuery UI CSS files referenced by the web part make up over 6% of the total web part bundle size.
As mentioned in the disclaimer following the chart, the sizes are indicative and reflect the size of the debug version of the bundle. The release version of the bundle is significantly smaller.
Still, it's good to realize which different pieces compose the web part bundle and their relative size compared to other elements in the bundle.

Approach 2: Load third-party libraries from a URL


Another way to reference third-party libraries in the SharePoint Framework is by referencing them from a URL such as a public CDN or a privately managed location. The biggest benefit is
that if you're loading a frequently used library from a public location, there is a chance that users might already have that particular library downloaded on their computer. In that case, the
SharePoint Framework reuses the cached library, loading your web part faster.
Even if you cannot use a public CDN to load libraries from a central location, it is a good practice from the performance point of view. Pointing to a URL allows your users to download the
script only once and reuse it across the whole portal, significantly speeding up loading pages and improving the user experience.
When loading third-party libraries from public URLs, keep in mind that there is a risk involved in using those libraries. Because you don't manage the hosting location of any particular script,
you can't be sure of its contents. Scripts loaded by the SharePoint Framework run under the context of the current user and are allowed to do whatever that user can do. Also, if the hosting
location is offline, your web part won't work.

Install typings for libraries


When you reference third-party libraries from a URL, you don't need to install them as packages in your project. You do have to install their TypeScript typings if you want the benefit of type
safety checks during development.
Assuming you start with an empty project created as described previously in this article, install TypeScript typings for jQuery by running the following command:

npm install @types/jquery --save

Specify URLs of libraries


To load third-party libraries from a URL, you have to specify the URL where they are located in the configuration of your project. In the code editor, open the ./config/config.json file. In the
externals section, add the following JSON:

{
//...
"externals": {
//...
"jquery": "https://code.jquery.com/jquery-3.1.1.min.js",
"jquery-ui": "https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
//...
}
//...
}

Reference libraries from the URL in the web part


Having specified the URL that the SharePoint Framework should use to load jQuery and jQuery UI, the next step is to reference them in the project.
1. In the code editor, open the ./src/webparts/jQueryAccordion/JQueryAccordionWebPart.ts file. In its top section, just under the last import statement, add the following
references to jQuery and jQuery UI:

import * as $ from 'jquery';


require('jquery-ui');

Compared to how you were referencing both libraries when they were installed as packages in your project, referencing them from the URL is very similar. Because jQuery has its
TypeScript typings installed, it can be referenced by using an import statement. For jQuery UI all you want is to load the script on the page.
Because you registered jquery and jquery-ui in the project configuration as external resources, when you reference any of these libraries, the SharePoint Framework uses the
specified URLs to load them at runtime. When bundling the project, these resources are marked as externals and are therefore excluded from the bundle.
One difference to keep in mind is that previously you specified to load the accordion from the jQuery UI package, but now you're referring to jQuery UI from the CDN that contains
all jQuery UI components.
2. Confirm that the project is building by running the following command:

gulp serve

After adding the web part to the canvas, you should see the accordion working.

3. In your web browser, open the developer tools, switch to the tab showing the network requests, and reload the page. You should see how both jQuery and jQuery UI are loaded from
the CDN.

At this point you have referenced only the jQuery UI scripts, which explains why the accordion is not styled. Next, you add the missing CSS stylesheets to brand the accordion.

Reference third-party CSS stylesheets from URL in the web part


Adding references to third-party CSS stylesheets from a URL is different from referencing resources from project packages. While the project configuration in the config.json file allows
you to specify external resources, it applies only to scripts. To reference CSS stylesheets from a URL, you must use the SPComponentLoader instead.
Load CSS from the URL using the SPComponentLoader
1. In the code editor, open the ./src/webparts/jQueryAccordion/JQueryAccordionWebPart.ts file. In the top section of the file, just after the last import statement, add the
following code:

import { SPComponentLoader } from '@microsoft/sp-loader';

2. In the same file, override the onInit() method as follows:

export default class JQueryAccordionWebPart extends BaseClientSideWebPart<IJQueryAccordionWebPartProps> {


protected onInit(): Promise<void> {
SPComponentLoader.loadCss('https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.min.css');
return super.onInit();
}

// ...
}

When the web part is instantiated on the page, it loads the jQuery UI CSS from the specified URL. This CSS stylesheet is the combined and optimized version of the jQuery UI CSS
that contains the basic styles, theme, and styling for all components.
3. Confirm that the project is building by running the following command:

gulp serve

The accordion should be displayed correctly and branded by using the standard jQuery UI Theme.

Analyze the contents of the generated web part bundle loading resources from URL
After building the project in the web browser, open the ./temp/stats/js-thirdpartycss.stats.html file.
Notice how the overall bundle is significantly smaller (7 KB compared to over 300 KB when including jQuery and jQuery UI in the bundle), and how jQuery and jQuery UI are not listed in
the chart because they are loaded at runtime.

See also
SharePoint Framework Overview
Use sp-pnp-js with SharePoint Framework web parts
3/26/2018 • 9 minutes to read Edit Online

You may choose to use the sp-pnp-js library when building your SharePoint Framework (SPFx) web parts. This library provides a fluent API to make building your REST queries intuitive
and supports batching and caching. For more information, see the project's homepage, which has links to documentation, samples, and other resources to help you get started.
You can download the full source for this article from the samples site.
NOTE

Before following the steps in this article, be sure to set up your SharePoint client-side web part development environment.

Create a new project


1. Create a new folder for the project by using your console of choice:

md spfx-sp-pnp-js-example

2. Enter that folder:

cd spfx-sp-pnp-js-example

3. Run the Yeoman generator for SPFx:

yo @microsoft/sharepoint

4. Enter the following values when prompted during the setup of the new project:
spfx-sp-pnp-js-example as the solution name (keep default)
SharePoint Online only (latest) as the baseline packages version
Current Folder as the solution location
Y as allow tenant admin to deploy solution to all sites
WebPart as the component to create
SPPnPJSExample as the name of the web part
Example of using sp-pnp-js within SPFx as the description
Knockout as the framework

5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open the project in the code editor of your choosing. The screenshots shown here demonstrate Visual Studio Code. To open the directory within Visual Studio Code, enter the
following in the console:

code .
Install and set up sp-pnp-js
After your project is created, you must install and set up sp-pnp-js, starting with installing the package. These steps are common for any project type (React, etc).

npm install sp-pnp-js --save

Because the sp-pnp-js library constructs REST requests, it needs to know the URL to send these requests. When operating within classic sites and pages, we can make use of the global
_spPageContextInfo variable. Within SPFx, this is not available, or if it is, it may not be correct. So we need to rely on the context object supplied by the framework.

There are two ways to ensure that you have correctly set up your requests; we use the onInit method in this example.

Update onInit in SpPnPjsExampleWebPart.ts


1. Open the src\webparts\spPnPjsExample\SpPnPjsExampleWebPart.ts file, and add an import statement for the pnp root object:

import pnp from "sp-pnp-js";

2. In the onInit method, update the code to appear as follows. Add the block after the super.onInit() call. We do this after the super.onInit to ensure that the framework has a
chance to initialize anything required, and that we are setting up the library after those steps are completed.

/**
* Initialize the web part.
*/
protected onInit(): Promise<void> {
this._id = _instance++;

const tagName: string = `ComponentElement-${this._id}`;


this._componentElement = this._createComponentElement(tagName);
this._registerComponent(tagName);

// When the web part description is changed, notify the view model to update.
this._koDescription.subscribe((newValue: string) => {
this._shouter.notifySubscribers(newValue, 'description');
});

const bindings: ISpPnPjsExampleBindingContext = {


description: this.properties.description,
shouter: this._shouter
};

ko.applyBindings(bindings, this._componentElement);

return super.onInit().then(_ => {


pnp.setup({
spfxContext: this.context
});
});
}

Update the ViewModel


Next, replace the contents of the SpPnPjsExampleViewModel.ts file with the following code. We added an import statement for the pnp items, an interface to define our list item's fields,
some observables to track both our list of items and the new item form, and methods to support getting, adding, and deleting items.
We also added an ensureList method, which uses the sp-pnp-js lists.ensure method to always ensure that we have the list (and to create it if necessary). There are many ways to
provision resources, but this method was chosen to demonstrate creating a list, field, and items by using batching within a single method.
The takeaway is that by using sp-pnp-js, we write much less code to handle requests and can focus on our business logic.

import * as ko from 'knockout';


import * as ko from 'knockout';
import styles from './SpPnPjsExample.module.scss';
import { ISpPnPjsExampleWebPartProps } from './SpPnPjsExampleWebPart';
import pnp, { List, ListEnsureResult, ItemAddResult, FieldAddResult } from "sp-pnp-js";

export interface ISpPnPjsExampleBindingContext extends ISpPnPjsExampleWebPartProps {


shouter: KnockoutSubscribable<{}>;
}

/**
* Interface which defines the fields in our list items
*/
export interface OrderListItem {
Id: number;
Title: string;
OrderNumber: string;
}

const LIST_EXISTS: string = 'List exists';

export default class SpPnPjsExampleViewModel {


public description: KnockoutObservable<string> = ko.observable('');
public newItemTitle: KnockoutObservable<string> = ko.observable('');
public newItemNumber: KnockoutObservable<string> = ko.observable('');
public items: KnockoutObservableArray<OrderListItem> = ko.observableArray([]);

public labelClass: string = styles.label;


public spPnPjsExampleClass: string = styles.spPnPjsExample;
public containerClass: string = styles.container;
public rowClass: string = `ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`;
public buttonClass: string = `ms-Button ${styles.button}`;

constructor(bindings: ISpPnPjsExampleBindingContext) {
this.description(bindings.description);

// When the web part description is updated, change this view model's description.
bindings.shouter.subscribe((value: string) => {
this.description(value);
}, this, 'description');

// Load the items


this.getItems().then((items: OrderListItem[]): void => {
this.items(items);
});
}

/**
* Gets the items from the list
*/
private getItems(): Promise<OrderListItem[]> {
return this.ensureList().then((list: List): Promise<OrderListItem[]> => {
// Here we are using the getAs operator so that our returned value will be typed
return list.items.select("Id", "Title", "OrderNumber").getAs<OrderListItem[]>();
});
}

/**
* Adds an item to the list
*/
public addItem(): void {
if (this.newItemTitle() !== "" && this.newItemNumber() !== "") {
this.ensureList().then((list: List): Promise<ItemAddResult> => {
// Add the new item to the SharePoint list
return list.items.add({
Title: this.newItemTitle(),
OrderNumber: this.newItemNumber(),
});
}).then((iar: ItemAddResult) => {
// Add the new item to the display
this.items.push({
Id: iar.data.Id,
OrderNumber: iar.data.OrderNumber,
Title: iar.data.Title,
});

// Clear the form


this.newItemTitle("");
this.newItemNumber("");
});
}
}

/**
* Deletes an item from the list
*/
public deleteItem(data): void {
if (!confirm("Are you sure you want to delete this item?")) {
return;
}

this.ensureList().then((list: List): Promise<void> => {


return list.items.getById(data.Id).delete();
}).then(_ => {
this.items.remove(data);
}).catch((e: Error) => {
alert(`There was an error deleting the item: ${e.message}`);
});
}

/**
* Ensures the list exists. If not, it creates it and adds some default example data
*/
private ensureList(): Promise<List> {
return new Promise<List>((resolve: (list: List) => void, reject: (err: string) => void): void => {
let listEnsureResults: ListEnsureResult;
// Use lists.ensure to always have the list available
// Use lists.ensure to always have the list available
pnp.sp.web.lists.ensure("SPPnPJSExampleList")
.then((ler: ListEnsureResult): Promise<FieldAddResult> => {
listEnsureResults = ler;

if (!ler.created) {
// resolve main promise
resolve(ler.list);
// break promise chain
return Promise.reject(LIST_EXISTS);
}

// We created the list on this call, so let's add a column


return ler.list.fields.addText("OrderNumber");
}).then((): Promise<string> => {
console.warn('Adding items...');
// And we will also add a few items so we can see some example data
// Here we use batching
return listEnsureResults.list.getListItemEntityTypeFullName();
}).then((typeName: string): Promise<void> => {
// Create a batch
const batch = pnp.sp.web.createBatch();
listEnsureResults.list.items.inBatch(batch).add({
Title: "Title 1",
OrderNumber: "4826492"
}, typeName);

listEnsureResults.list.items.inBatch(batch).add({
Title: "Title 2",
OrderNumber: "828475"
}, typeName);

listEnsureResults.list.items.inBatch(batch).add({
Title: "Title 3",
OrderNumber: "75638923"
}, typeName);

// Execute the batched operations


return batch.execute();
}).then((): void => {
// All of the items have been added within the batch
resolve(listEnsureResults.list);
}).catch((e: any): void => {
if (e !== LIST_EXISTS) {
reject(e);
}
});
});
}
}

Update the template


Finally, we need to update the template to match the functionality that we added into the ViewModel. Copy the following code into the SpPnPjsExample.template.html file. We added a
title row, a foreach repeater for the items collection, and a form allowing you to add new items to the list.
<div data-bind="attr: {class:spPnPjsExampleClass}">
<div data-bind="attr: {class:containerClass}">

<div data-bind="attr: {class:rowClass}">


<div class="ms-Grid-col ms-u-sm12">
<span class="ms-font-xl ms-fontColor-white ms-fontWeight-semibold" data-bind="text: description"></span>
</div>
</div>

<div data-bind="attr: {class:rowClass}">


<div class="ms-Grid-col ms-u-sm6">
<span class="ms-font-l ms-fontColor-white ms-fontWeight-semibold">Title</span>
</div>
<div class="ms-Grid-col ms-u-sm6">
<span class="ms-font-l ms-fontColor-white ms-fontWeight-semibold">Order Number</span>
</div>
</div>

<!-- ko foreach: items -->


<div data-bind="attr: {class:$parent.rowClass}">
<div class="ms-Grid-col ms-u-sm6">
<span class="ms-font-l ms-fontColor-white" data-bind="text: Title"></span>
</div>
<div class="ms-Grid-col ms-u-sm5">
<span class="ms-font-l ms-fontColor-white" data-bind="text: OrderNumber"></span>
</div>
<div class="ms-Grid-col ms-u-sm1">
<i class="ms-Icon ms-Icon--Delete" aria-hidden="true" data-bind="click: $parent.deleteItem.bind($parent, $data)"></i>
</div>
</div>
<!-- /ko -->

<div data-bind="attr: {class:rowClass}">


<div class="ms-Grid-col ms-u-sm12">
<span class="ms-font-l ms-fontColor-white ms-fontWeight-semibold">Add New</span>
</div>
</div>

<div data-bind="attr: {class:rowClass}">


<form data-bind="submit: addItem">
<div class="ms-Grid-col ms-u-sm5">
<input class="ms-TextField-field" placeholder="Title" data-bind='value: newItemTitle, valueUpdate: "afterkeydown"' />
</div>
<div class="ms-Grid-col ms-u-sm5">
<input class="ms-TextField-field" placeholder="Order Number" data-bind='value: newItemNumber, valueUpdate: "afterkeydown"'
/>
</div>
<div class="ms-Grid-col ms-u-sm2">
<button class="ms-Button--default ms-Button" type="submit" data-bind="enable: newItemTitle().length > 0 && newItemNumber().length > 0"><span class="ms-Button-label">Add</span></button>
</div>
</form>
</div>

</div>
</div>

Run the example


Start the sample, and add the web part to your SharePoint-hosted Workbench (/_layouts/workbench.aspx) to see it in action.

gulp serve --nobrowser

You can delete existing items by selecting the trashcan icon, or you can add new items by putting values in both fields and selecting Add.
Next steps
The sp-pnp-js library contains a great range of functionality and extensibility. For samples, guidance, and hints about using and configuring the library, see the Developer Guide.

Deploy to production
When you are ready to deploy your solution and want to build by using the --ship flag, you need to mark sp-pnp-js as an external library in the configuration. This is done by updating the
SPFx config/config.js file to include this line in the externals section:

"sp-pnp-js": "https://cdnjs.cloudflare.com/ajax/libs/sp-pnp-js/2.0.1/pnp.min.js"

In this configuration, we use the public CDN, but the URL can be an internal path or any other location you would like to use. Be sure, however, to update the version number in the URL to
match the version you are targeting.

Improve the mock data example


Ideally, the sample should work within both the local Workbench as well as the SharePoint-hosted Workbench. To enable this, we need to mock our ViewModel and make an update to the
web part code as outlined in the following sections.

Add mock ViewModel file


Add a new file named MockSpPnPjsExampleViewModel.ts alongside the other web part files. Update the content of this file using the following code. This provides the same set of
functionality and works in the local environment, but does not rely on SharePoint being available.
import * as ko from 'knockout';
import styles from './SpPnPjsExample.module.scss';
import { ISpPnPjsExampleWebPartProps } from './SpPnPjsExampleWebPart';
import pnp, { List, ListEnsureResult, ItemAddResult } from "sp-pnp-js";
import { ISpPnPjsExampleBindingContext, OrderListItem } from './SpPnPjsExampleViewModel';

export default class MockSpPnPjsExampleViewModel {

public description: KnockoutObservable<string> = ko.observable('');


public newItemTitle: KnockoutObservable<string> = ko.observable('');
public newItemNumber: KnockoutObservable<string> = ko.observable('');
public items: KnockoutObservableArray<OrderListItem> = ko.observableArray([]);

public labelClass: string = styles.label;


public spPnPjsExampleClass: string = styles.spPnPjsExample;
public containerClass: string = styles.container;
public rowClass: string = `ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`;
public buttonClass: string = `ms-Button ${styles.button}`;

constructor(bindings: ISpPnPjsExampleBindingContext) {
this.description(bindings.description);

// When the web part description is updated, change this view model's description.
bindings.shouter.subscribe((value: string): void => {
this.description(value);
}, this, 'description');

// Load the items


this.getItems().then((items: OrderListItem[]): void => {
this.items(items);
});
}

/**
* Simulates getting the items from the list
*/
private getItems(): Promise<OrderListItem[]> {
return Promise.resolve([{
Id: 1,
Title: "Mock Item 1",
OrderNumber: "12345"
},
{
Id: 2,
Title: "Mock Item 2",
OrderNumber: "12345"
},
{
Id: 3,
Title: "Mock Item 3",
OrderNumber: "12345"
}]);
}

/**
* Simulates adding an item to the list
*/
public addItem(): void {
if (this.newItemTitle() !== "" && this.newItemNumber() !== "") {
// Add the new item to the display
this.items.push({
Id: this.items.length,
OrderNumber: this.newItemNumber(),
Title: this.newItemTitle(),
});

// Clear the form


this.newItemTitle("");
this.newItemNumber("");
}
}

/**
* Simulates deleting an item from the list
*/
public deleteItem(data): void {
if (confirm("Are you sure you want to delete this item?")) {
this.items.remove(data);
}
}
}

Update web part


Finally, we need to update the web part to use the mock data when appropriate.
1. Open the SpPnPjsExampleWebPart.ts file, and import the mock ViewModel web just created:

import MockSpPnPjsExampleViewModel from './MockSpPnPjsExampleViewModel';

2. Import the Environment and EnvironmentType types that you use to detect the type of environment the web part is running in:

import { Environment, EnvironmentType } from '@microsoft/sp-core-library';

3. Locate the _registerComponent method and update it as shown:


private _registerComponent(tagName: string): void {
ko.components.register(
tagName,
{
viewModel: Environment.type === EnvironmentType.Local ?
MockSpPnPjsExampleViewModel :
SpPnPjsExampleViewModel,
template: require('./SpPnPjsExample.template.html'),
synchronous: false
}
);
}

4. Type gulp serve in the console to bring up the local Workbench, which now works with the mock data. (If you already have the server running, stop it by selecting Ctrl+C, and then
restart it):

gulp serve

See also
Download the full sample
Provide feedback or report issues
SharePoint Framework Overview
Build SharePoint Framework client-side web parts with AngularJS
4/14/2018 • 14 minutes to read Edit Online

If you are familiar with AngularJS, you can also use this extremely popular framework to build client-side web parts. Thanks to its modularity, it can be used for anything ranging from
complex multi-view Single Page Applications to smaller components such as web parts. Many organizations have been using AngularJS for building SharePoint solutions in the past. This
article shows how to use AngularJS to build a SharePoint Framework client-side web part and have it styled using Office UI Fabric.
During this tutorial, you build a simple web part that manages To Do items.

The source of the working web part is available on GitHub at samples/angular-todo/.


NOTE

Before following the steps in this article, be sure to set up your development environment for building SharePoint Framework solutions.

Create a new project


1. Create a new folder for your project

md angular-todo

2. Navigate to the project folder:

cd angular-todo

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project:

yo @microsoft/sharepoint

4. When prompted, define values as follows:


angular-todo as your solution name
Use the current folder for the location to place the files
No JavaScript web framework as the starting point to build the web part
To do as your web part name
Simple management of to do tasks as your web part description
5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. In this tutorial, you use Visual Studio Code.

Add AngularJS
In this tutorial, you load AngularJS from a CDN.
In the code editor, open the config/config.json file, and in the externals property, add the following lines:

"angular": {
"path": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.6/angular.min.js",
"globalName": "angular"
}
Add AngularJS typings for TypeScript
Because you are referencing AngularJS in your web part's code, you also need AngularJS typings for TypeScript.
To install them, run the following in the command line:

npm install @types/angular --save-dev

Implement AngularJS application


With all the prerequisites in place, you can start implementing the sample AngularJS application. Because it consists of several files, create a separate folder for it called app.

Implement To Do data service


In the newly created app folder, create a new file called DataService.ts. In the file, paste the following code:

export interface ITodo {


id: number;
title: string;
done: boolean;
}

export interface IDataService {


getTodos(hideFinishedTasks: boolean): angular.IPromise<ITodo[]>;
addTodo(todo: string): angular.IPromise<{}>;
deleteTodo(todo: ITodo): angular.IPromise<{}>;
setTodoStatus(todo: ITodo, done: boolean): angular.IPromise<{}>;
}

export default class DataService implements IDataService {


public static $inject: string[] = ['$q'];

private items: ITodo[] = [


{
id: 1,
title: 'Prepare demo Web Part',
done: true
},
{
id: 2,
title: 'Show demo',
done: false
},
{
id: 3,
title: 'Share code',
done: false
}
];
private nextId: number = 4;

constructor(private $q: angular.IQService) {


}

public getTodos(hideFinishedTasks: boolean): angular.IPromise<ITodo[]> {


const deferred: angular.IDeferred<ITodo[]> = this.$q.defer();

const todos: ITodo[] = [];


for (let i: number = 0; i < this.items.length; i++) {
if (hideFinishedTasks && this.items[i].done) {
continue;
}

todos.push(this.items[i]);
}

deferred.resolve(todos);

return deferred.promise;
}

public addTodo(todo: string): angular.IPromise<{}> {


const deferred: angular.IDeferred<{}> = this.$q.defer();

this.items.push({
id: this.nextId++,
title: todo,
done: false
});

deferred.resolve();

return deferred.promise;
}

public deleteTodo(todo: ITodo): angular.IPromise<{}> {


const deferred: angular.IDeferred<{}> = this.$q.defer();

let pos: number = -1;


for (let i: number = 0; i < this.items.length; i++) {
if (this.items[i].id === todo.id) {
pos = i;
break;
}
}

if (pos > -1) {


this.items.splice(pos, 1);
deferred.resolve();
}
else {
deferred.reject();
}

return deferred.promise;
}

public setTodoStatus(todo: ITodo, done: boolean): angular.IPromise<{}> {


const deferred: angular.IDeferred<{}> = this.$q.defer();

for (let i: number = 0; i < this.items.length; i++) {


if (this.items[i].id === todo.id) {
this.items[i].done = done;
}
}

deferred.resolve();

return deferred.promise;
}
}
In the previous code snippet, you implement three types:
The ITodo interface, which represents a To Do item in your application.
The IDataService interface, which defines the signature of the data service.
The DataService class, which is responsible for retrieving and manipulating To Do items.
The data service implements simple methods for adding and modifying To Do items. Even though the operations are instantaneous, for consistency, each CRUD function returns a promise.
In this tutorial, To Do items are stored in memory. You could, however, easily extend the solution to store items in a SharePoint list and use the data service to communicate with SharePoint
by using its REST API.

Implement the controller


Next, implement the controller that facilitates communication between the view and the data service.
In the app folder, create a new file named HomeController.ts, and paste the following code:

import { IDataService, ITodo } from './DataService';

export default class HomeController {


public isLoading: boolean = false;
public newItem: string = null;
public newToDoActive: boolean = false;
public todoCollection: any[] = [];
private hideFinishedTasks: boolean = false;

public static $inject: string[] = ['DataService', '$window', '$rootScope'];

constructor(private dataService: IDataService, private $window: angular.IWindowService, private $rootScope: angular.IRootScopeService) {


const vm: HomeController = this;
this.init();
}

private init(hideFinishedTasks?: boolean): void {


this.hideFinishedTasks = hideFinishedTasks;
this.loadTodos();
}

private loadTodos(): void {


const vm: HomeController = this;
this.isLoading = true;
this.dataService.getTodos(vm.hideFinishedTasks)
.then((todos: ITodo[]): void => {
vm.todoCollection = todos;
})
.finally((): void => {
vm.isLoading = false;
});
}

public todoKeyDown($event: any): void {


if ($event.keyCode === 13 && this.newItem.length > 0) {
$event.preventDefault();

this.todoCollection.unshift({ id: -1, title: this.newItem, done: false });


const vm: HomeController = this;

this.dataService.addTodo(this.newItem)
.then((): void => {
this.newItem = null;
this.newItem = null;
this.dataService.getTodos(vm.hideFinishedTasks)
.then((todos: any[]): void => {
this.todoCollection = todos;
});
});
}
}

public deleteTodo(todo: ITodo): void {


if (this.$window.confirm('Are you sure you want to delete this todo item?')) {
let index: number = -1;
for (let i: number = 0; i < this.todoCollection.length; i++) {
if (this.todoCollection[i].id === todo.id) {
index = i;
break;
}
}

if (index > -1) {


this.todoCollection.splice(index, 1);
}

const vm: HomeController = this;

this.dataService.deleteTodo(todo)
.then((): void => {
this.dataService.getTodos(vm.hideFinishedTasks)
.then((todos: any[]): void => {
this.todoCollection = todos;
});
});
}
}

public completeTodo(todo: ITodo): void {


todo.done = true;

const vm: HomeController = this;

this.dataService.setTodoStatus(todo, true)
.then((): void => {
this.dataService.getTodos(vm.hideFinishedTasks)
.then((todos: any[]): void => {
this.todoCollection = todos;
});
});
}

public undoTodo(todo: ITodo): void {


todo.done = false;

const vm: HomeController = this;

this.dataService.setTodoStatus(todo, false)
.then((): void => {
this.dataService.getTodos(vm.hideFinishedTasks)
.then((todos: any[]): void => {
this.todoCollection = todos;
});
});
}
}
You start by loading the previously implemented data service. The controller needs it to get the list of items and modify items as requested by the user. Using AngularJS's dependency
injection, the service is injected into the controller. The controller implements a number of functions that are exposed to the view model and called from the template. Using these functions,
users are able to add new items, mark items as finished or To Do, or delete items.

Implement the main module


With the data service and the controller ready, define the main module of your application and register the data service and controller with it.
In the app folder, create a new file called app-module.ts, and paste the following contents:

import * as angular from 'angular';


import HomeController from './HomeController';
import DataService from './DataService';

const todoapp: angular.IModule = angular.module('todoapp', []);

todoapp
.controller('HomeController', HomeController)
.service('DataService', DataService);

You start by referencing AngularJS and by loading the previously implemented controller and data service. Next, you define the module for your application. Finally, you register the
controller and data service with your application.
Now you've built an AngularJS application for your web part. In the following steps, you register the AngularJS application with the web part and make it configurable by using web part
properties.

Register AngularJS application with web part


The next step is to add the AngularJS application to the web part.
1. In the code editor, open the ToDoWebPart.ts file.
2. Just before the class declaration, add the following lines:

import * as angular from 'angular';


import './app/app-module';

This allows us to load a reference to AngularJS and your application, both of which you need to bootstrap your AngularJS application.
3. Change the web part's render function to:
public render(): void {
if (this.renderedOnce === false) {
this.domElement.innerHTML = `
<div class="${styles.toDo}">
<div data-ng-controller="HomeController as vm">
<div class="${styles.loading}" ng-show="vm.isLoading">
<div class="${styles.spinner}">
<div class="${styles.spinnerCircle} ${styles.spinnerLarge}"></div>
<div class="${styles.spinnerLabel}">Loading...</div>
</div>
</div>
<div ng-show="vm.isLoading === false">
<div class="${styles.textField} ${styles.underlined}" ng-class="{'${styles.isActive}': vm.newToDoActive}">
<label for="newToDo" class="${styles.label}">New to do:</label>
<input type="text" label="New to do:" id="newToDo" value="" class="${styles.field}" aria-invalid="false" ng-model="vm.newItem" ng-keydown="vm.todoKeyDown($event)" ng-focus="vm.newToDoA
</div>
</div>
<div class="list" ng-show="vm.isLoading === false">
<div class="listSurface">
<div class="listPage">
<div class="listCell" ng-repeat="todo in vm.todoCollection" uif-item="todo" ng-class="{'${styles.done}': todo.done}">
<div class="${styles.listItem}">
<span class="${styles.listItemPrimaryText}">{{todo.title}}</span>
<div class="${styles.listItemActions}">
<div class="${styles.listItemAction}" ng-click="vm.completeTodo(todo)" ng-show="todo.done === false">
<i class="${styles.icon} ${styles.iconCheckMark}"></i>
</div>
<div class="${styles.listItemAction}" ng-click="vm.undoTodo(todo)" ng-show="todo.done">
<i class="${styles.icon} ${styles.iconUndo}"></i>
</div>
<div class="${styles.listItemAction}" ng-click="vm.deleteTodo(todo)">
<i class="${styles.icon} ${styles.iconRecycleBin}"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>`;

angular.bootstrap(this.domElement, ['todoapp']);
}
}

4. The code first assigns the template of your application directly to the web part's DOM element. On the root element, you specify the name of the controller that handles events and
data binding in the template.
5. Bootstrap your application by using the todoapp name you used previously when declaring the main module.
6. Using the renderedOnce web part property, ensure that your AngularJS application is bootstrapped only once. Without it, if you changed one of the web part's properties, the
render function is invoked again, bootstrapping the AngularJS application again, which leads to an error.
7. Implement CSS styles that you are using in the template. In the code editor, open the ToDo.module.scss file, and replace its contents with:

.toDo {
.loading {
margin: 0 auto;
width: 6em;

.spinner {
display: inline-block;
margin: 10px 0;

@-webkit-keyframes spinnerSpin {
0% {
-webkit-transform:rotate(0);
transform:rotate(0);
}
100% {
-webkit-transform:rotate(360deg);
transform:rotate(360deg);
}
}
@keyframes spinnerSpin {
0% {
-webkit-transform:rotate(0);
transform:rotate(0);
}
100% {
-webkit-transform:rotate(360deg);
transform:rotate(360deg);
}
}

.spinnerCircle {
margin: auto;
box-sizing: border-box;
border-radius: 50%;
width: 100%;
height: 100%;
border: 1.5px solid #c7e0f4;
border-top-color: #0078d7;
-webkit-animation: spinnerSpin 1.3s infinite cubic-bezier(.53, .21, .29, .67);
animation: spinnerSpin 1.3s infinite cubic-bezier(.53, .21, .29, .67);

&.spinnerLarge {
width: 28px;
height: 28px;
}
}

.spinnerLabel {
color: #0078d7;
margin-top: 10px;
text-align: center;
}
}
}

.label {
font-family: "Segoe UI WestEuropean", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
font-weight: 400;
box-sizing: border-box;
margin: 0;
padding: 0;
box-shadow: none;
color: #333333;
box-sizing: border-box;
display: block;
padding: 5px 0
}

.textField {
font-family: "Segoe UI WestEuropean", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
box-sizing: border-box;
margin: 0;
padding: 0;
box-shadow: none;
color: #333333;
font-size: 14px;
font-weight: 400;
margin-bottom: 8px;

&.underlined {
border-bottom: 1px solid #c8c8c8;
display: table;
width: 100%;

&:hover {
border-color: #767676;
}

&.isActive, &:active {
border-color: #0078d7;
}

.field {
border: 0;
display: table-cell;
padding-top: 8px;
padding-bottom: 3px
}
}
.label {
padding-right: 0;
padding-left: 12px;
margin-right: 8px;
font-size: 14px;
display: table-cell;
vertical-align: top;
padding-top: 9px;
height: 32px;
width: 1%;
white-space: nowrap;
font-weight: 400;
}

.field {
text-align: left;
float: left;
box-sizing: border-box;
margin: 0;
padding: 0;
box-shadow: none;
font-family: "Segoe UI WestEuropean", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
border: 1px solid #c8c8c8;
border-radius: 0;
font-weight: 400;
font-size: 14px;
color: #333333;
height: 32px;
padding: 0 12px 0 12px;
width: 100%;
outline: 0;
text-overflow: ellipsis;
}

.field:hover {
border-color: #767676;
}
}

.listItem {
font-family: "Segoe UI WestEuropean", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
font-weight: 400;
box-sizing: border-box;
margin: 0;
padding: 0;
box-shadow: none;
padding: 9px 28px 3px;
position: relative;
display: block;

&::before {
display: table;
content: "";
line-height: 0;
}

&::after {
display: table;
content: "";
line-height: 0;
clear: both;
}

.listItemPrimaryText {
font-family: "Segoe UI WestEuropean", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 21px;
font-weight: 100;
padding-right: 80px;
position: relative;
top: -4px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
}

.listItemActions {
max-width: 80px;
position: absolute;
right: 30px;
text-align: right;
top: 10px;

.listItemAction {
color: #a6a6a6;
display: inline-block;
font-size: 15px;
position: relative;
text-align: center;
top: 3px;
cursor: pointer;
height: 16px;
width: 16px;

&:hover {
color: #666666;
outline: 1px solid transparent;
}

.icon {
vertical-align: top;
vertical-align: top;
}
}
}
}

.done {
text-decoration: line-through;
}

.icon {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
display: inline-block;
font-family: FabricMDL2Icons;
font-style: normal;
font-weight: 400;
speak: none;

&.iconCheckMark::before {
content: "\E73E";
}

&.iconUndo::before {
content: "\E7A7";
}

&.iconRecycleBin::before {
content: "\EF87";
}
}
}

8. Run the following command to confirm that everything is working as expected:

gulp serve

9. In the browser, you should see your To Do web part showing To Do items.
Make web part configurable
At this point, the To Do web part shows a fixed list of To Do items. Next, you extend it with a configuration option to allow users to choose whether they want to see items that are marked as
done or not.

Add property in the web part manifest


Start by adding a configuration property in the web part manifest.
In the code editor, open the ToDoWebPart.manifest.json file. In the preconfiguredEntries section, navigate to the properties array, and replace the existing description property with
the following line:

"hideFinishedTasks": false

Update the signature of the web part properties interface


Next, update the signature of the web part properties interface.
In the code editor, open the ToDoWebPart.ts file, and update the IToDoWebPartProps interface to the following:

export interface IToDoWebPartProps {


hideFinishedTasks: boolean;
}
Add the property to the web part property pane
To allow users to configure the value of your newly added property, you have to expose it through the web part property pane.
1. In the code editor, open the ToDoWebPart.ts file.
2. In the first import statement, replace PropertyPaneTextField with PropertyPaneToggle :

import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneToggle
} from '@microsoft/sp-webpart-base';

3. Change the implementation of the propertyPaneSettings function to:


protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.ViewGroupName,
groupFields: [
PropertyPaneToggle('hideFinishedTasks', {
label: strings.HideFinishedTasksFieldLabel
})
]
}
]
}
]
};
}

4. To fix the missing string references, you first need to change the signature of your strings. In the code editor, open the loc/mystrings.d.ts file, and change its contents to:

declare interface IToDoWebPartStrings {


PropertyPaneDescription: string;
ViewGroupName: string;
HideFinishedTasksFieldLabel: string;
}

declare module 'ToDoWebPartStrings' {


const strings: IToDoWebPartStrings;
export = strings;
}

5. Provide the actual values for the newly defined strings. In the code editor, open the loc/en-us.js file, and change its contents to:

define([], function() {
return {
"PropertyPaneDescription": "Manage configuration of the To do web part",
"ViewGroupName": "View",
"HideFinishedTasksFieldLabel": "Hide finished tasks"
}
});
6. Run the following command to confirm that everything is working as expected:

gulp serve

7. In the web part property pane, you should see a toggle button for your newly defined property.

At this point, selecting the toggle button doesn't have any effect on your web part because it hasn't been connected to AngularJS. You do that in the next step.

Make the AngularJS application configurable using web part properties


In the previous step, you defined a web part property that allows users to choose whether to show completed tasks or not. Next you pass the value selected by the user into the AngularJS
application so that it can load items accordingly.
Broadcast AngularJS event on web part property change
1. In the code editor, open the ToDoWebPart.ts file. Right before the web part's constructor, add the following line:

private $injector: angular.auto.IInjectorService;


2. Change the web part's render function to the following:

public render(): void {


if (this.renderedOnce === false) {
this.domElement.innerHTML = `
<div class="${styles.toDo}">
<div data-ng-controller="HomeController as vm">
<div class="${styles.loading}" ng-show="vm.isLoading">
<div class="${styles.spinner}">
<div class="${styles.spinnerCircle} ${styles.spinnerLarge}"></div>
<div class="${styles.spinnerLabel}">Loading...</div>
</div>
</div>
<div ng-show="vm.isLoading === false">
<div class="${styles.textField} ${styles.underlined}" ng-class="{'${styles.isActive}': vm.newToDoActive}">
<label for="newToDo" class="${styles.label}">New to do:</label>
<input type="text" label="New to do:" id="newToDo" value="" class="${styles.field}" aria-invalid="false" ng-model="vm.newItem" ng-keydown="vm.todoKeyDown($event)" ng-focus="vm.newToDoA
</div>
</div>
<div class="list" ng-show="vm.isLoading === false">
<div class="listSurface">
<div class="listPage">
<div class="listCell" ng-repeat="todo in vm.todoCollection" uif-item="todo" ng-class="{'${styles.done}': todo.done}">
<div class="${styles.listItem}">
<span class="${styles.listItemPrimaryText}">{{todo.title}}</span>
<div class="${styles.listItemActions}">
<div class="${styles.listItemAction}" ng-click="vm.completeTodo(todo)" ng-show="todo.done === false">
<i class="${styles.icon} ${styles.iconCheckMark}"></i>
</div>
<div class="${styles.listItemAction}" ng-click="vm.undoTodo(todo)" ng-show="todo.done">
<i class="${styles.icon} ${styles.iconUndo}"></i>
</div>
<div class="${styles.listItemAction}" ng-click="vm.deleteTodo(todo)">
<i class="${styles.icon} ${styles.iconRecycleBin}"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>`;

this.$injector = angular.bootstrap(this.domElement, ['todoapp']);


}

this.$injector.get('$rootScope').$broadcast('configurationChanged', {
hideFinishedTasks: this.properties.hideFinishedTasks
});
}

In the previous code sample, every time the web part property is changed, it broadcasts an AngularJS event to which the AngularJS application subscribes it. When the event is received by
the AngularJS application, it handles that accordingly.
Subscribe to web part property change event in AngularJS
1. In the code editor, open the app/HomeController.ts file. Extend the constructor as follows:
constructor(private dataService: IDataService, private $window: angular.IWindowService, private $rootScope: angular.IRootScopeService) {
const vm: HomeController = this;
this.init();

$rootScope.$on('configurationChanged', (event: angular.IAngularEvent, args: { hideFinishedTasks: boolean }): void => {


vm.init(args.hideFinishedTasks);
});
}

2. Verify that the AngularJS application is working as expected and correctly responding to the changed property by running the following in the command line:

gulp serve

3. If you toggle the value of the Hide finished tasks property, the web part should show or hide finished tasks accordingly.

See also
SharePoint Framework Overview
Connect to API secured with Azure Active Directory
5/11/2018 • 30 minutes to read Edit Online

When building SharePoint Framework solutions, you might need to connect to your custom API to retrieve some data or to communicate with line of business applications. Securing custom
APIs with Microsoft Azure Active Directory (Azure AD) offers you many benefits and can be done in a number of ways. After you have built the API, there are several ways in which you can
access it. These ways vary in complexity and each have their specific considerations.
This article discusses the different approaches and describes the step-by-step process of building and connecting to an API secured with Azure AD.
IM P O R T A N T

When connecting to Azure AD-secured APIs, we recommend that you use the GraphHttpClient or AadHttpClient classes. These are new capabilities that are currently in preview and
planned to be generally released during spring 2018. For more information about recommended models, see Use the MSGraphClient to connect to Microsoft Graph.

Secure an API with Azure AD


If you're using Office 365, securing custom APIs using Azure AD is an architectural option that you should definitely consider. First and foremost, it allows you to secure the access to the API
using existing organizational credentials that are already managed through Office 365 and Azure AD. Users with an active account can seamlessly work with applications that leverage APIs
secured with Azure AD. Azure AD administrators can centrally manage access to the API, the same way they manage access to all other applications registered with Azure AD.
As the API developer, using Azure AD to secure your API frees you from managing a proprietary set of user credentials and implementing a custom security layer for your API. Additionally,
Azure AD supports the OAuth protocol, which allows you to connect to the API from a range of application types varying from mobile apps to client-side solutions.
When building custom APIs, there are two main ways in which you can secure your API with Azure AD. If you host the API in Microsoft Azure App Service, you can benefit from the App
Service Authentication option. If you look for more hosting flexibility for your API, such as hosting it on your own infrastructure or in Docker containers, you need to secure it in code. In such
cases, the implementation depends on your programming language and framework.
In this article, when discussing this option, you will use C# and the ASP.NET Web API as the framework.

Secure the API using Azure App Service Authentication


When deploying custom APIs to Azure App Service, you can benefit from the App Service Authentication option to secure the API with Azure AD. The biggest benefit of using App Service
Authentication is its simplicity: by following the configuration steps available in the Azure portal, you can have the wizard set up the authentication configuration for you. If you choose the
basic setup, the wizard creates a new Azure AD application in Azure AD associated with the current subscription. In the advanced configuration, you can choose which Azure AD application
should be used to secure the access to the App Service hosting the API.

After App Service Authentication has been configured, users trying to access your API are prompted to sign in with their organizational account that belongs to the same Azure AD as the
Azure AD application used to secure the API. After signing in, you are able to access the information about the current user through the HttpContext.Current.User property. When using
Azure App Service Authentication, there is no additional configuration required in your application.
Azure App Service Authentication is a feature available only in Azure App Service. While this capability significantly simplifies implementing authentication in your API, it ties it to running
inside Azure App Service. If you want to host the API with another cloud provider or inside a Docker container, you need to implement the authentication layer first.

Secure the API using ASP.NET authentication


If you want to have the maximum flexibility with regards to where your API is hosted and how it is deployed, you should consider implementing the support for Azure AD authentication in
ASP.NET. Visual Studio simplifies the implementation process significantly, and after completing the authentication setup wizard, your API requires users to sign in by using their
organizational account.
During the configuration process, Visual Studio adds all the necessary references and settings to your ASP.NET Web API project, including registering a new Azure AD application to secure
your API.

Access an API secured with Azure AD from SharePoint Framework solutions


SharePoint Framework solutions are fully client-side and as such are incapable of securely storing secrets required to connect to secured APIs. To support secure communication with client-
side solutions, Azure AD supports a number of mechanisms such as authentication cookies or the OAuth implicit flow.

Access the API using ADAL JS


A commonly used approach for communicating with APIs secured with Azure AD from client-side solutions is using the ADAL JS library. ADAL JS simplifies implementing authentication
against Azure AD in client-side applications as well as retrieving access tokens for specific resources. For applications built using AngularJS, ADAL JS offers an HTTP request interceptor that
automatically adds required access tokens to headers of outgoing web requests. By using this requestor, developers don't need to modify web requests to APIs secured with Azure AD and
can focus on building the application instead.
Benefits of using ADAL JS to communicate with APIs secured with Azure AD
When using ADAL JS, client-side applications have full access to the identity information of the currently signed-in user. This is convenient for requirements such as displaying a user name
or profile picture in the application. When building solutions hosted in SharePoint, developers can retrieve extended profile information by using the SharePoint API, but for standalone
applications this isn't possible.
Besides facilitating authentication against Azure AD, ADAL JS is capable of retrieving access tokens to specific resources. With these access tokens, applications can securely access APIs
secured with Azure AD such as Microsoft Graph or other custom APIs. Before a client-side application can use ADAL JS, it has to be registered as an application in Azure AD. In the
registration process, developers specify a number of parameters such as the URL where the application is hosted and the resources to which the application requires access, either by itself or
on behalf of the currently signed-in user.

The first time the application is used, it prompts the user to grant it the necessary permissions. This is often referred to as consent flow. After it's approved, the application can then request
access tokens for the specific resources and communicate with them securely.
Considerations when using ADAL JS to communicate with APIs secured with Azure AD
ADAL JS has been designed to be used with single-page applications. As such, by default it doesn't work correctly when used with SharePoint Framework solutions. By applying a patch
however, it can be successfully used in SharePoint Framework projects.
When using ADAL JS and OAuth to access APIs secured with Azure AD, the authentication flow is facilitated by Azure. Any errors are handled by the Azure sign-in page. After the user has
signed-in with her organizational account, the application tries to retrieve a valid access token. All errors that occur at this stage have to be explicitly handled by the developer of the
application because retrieving access tokens is non-interactive and doesn't present any UI to the user.
Every client-side application that wants to use ADAL JS needs to be registered as an Azure AD application. A part of the registration information is the URL where the application is located.
Because the application is fully client-side and is not capable of securely storing a secret, the URL is a part of the contract between the application and Azure AD to establish security. This
requirement is problematic for SharePoint Framework solutions because developers cannot simply know upfront all URLs where a particular web part will be used. Additionally, at this
moment, Azure AD supports specifying up to 10 reply URLs, which might not be sufficient in some scenarios.
Before a client-side application can retrieve an access token to a specific resource, it needs to authenticate the user to obtain the ID token which can then be exchanged for an access token.
Even though SharePoint Framework solutions are hosted in SharePoint, where users are already signed in using their organizational accounts, the authentication information for the current
user isn't available to SharePoint Framework solutions. Instead, each solution must explicitly request the user to sign in. This can be done either by redirecting the user to the Azure sign-in
page or by showing a pop-up window with the sign-in page. The latter is less intrusive in the case of a web part, which is one of the many elements on a page. If there are multiple
SharePoint Framework client-side web parts on the page, each of them manages its state separately and requires the user to explicitly sign in to that particular web part.
Retrieving access tokens required to communicate with APIs secured with Azure AD is facilitated by hidden iframes that handle redirects to Azure AD endpoints. There is a known limitation
in Microsoft Internet Explorer where obtaining access tokens in OAuth implicit flow fails, if the Azure AD sign-in endpoints and the SharePoint Online URL are not in the same security zone.
If your organization is using Internet Explorer, ensure that the Azure AD endpoint and SharePoint Online URLs are configured in the same security zone. To maintain consistency, some
organizations choose to push these settings to end-users using group policies.
APIs secured with Azure AD cannot be accessed anonymously. Instead they require a valid credential to be presented by the application calling them. When using the OAuth implicit flow
with client-side applications, this credential is the bearer access token obtained using ADAL JS. If you have built your SharePoint Framework solution using AngularJS, ADAL JS
automatically ensures that you have a valid access token for the particular resource, and adds it to all outgoing requests executed by using the AngularJS $http service. When using other
JavaScript libraries, you have to obtain a valid access token, and if necessary refresh it, and attach it to the outgoing web requests yourself.

Access the API by leveraging SharePoint Online authentication cookie


An alternative approach to using ADAL JS for connecting to APIs secured with Azure AD is leveraging the existing authentication cookie for seamless authentication to the custom API.
How it works
When you sign in with your organizational account to SharePoint Online, an authentication cookie is set in your browser. This cookie is sent with every request to SharePoint allowing to
work sites and documents. To use this cookie, to connect to a custom API secured with Azure AD, you place a hidden iframe on the page pointing to a URL where the API is hosted and which
is also secured with Azure AD. After the browser tries to load this URL, it gets redirected to the Azure AD sign-in page because anonymous access is not allowed. Because you are already
signed in with your organization account to access SharePoint, the authentication completed automatically, redirecting you back to the original URL. At this point, your browser has the Azure
AD authentication cookie for accessing the custom API secured with Azure AD.
After placing the iframe on the page, you attach an onload event listener to it, which is triggered after the authentication flow completed. In this event listener, you set a flag indicating that
authentication completed and you can now securely call the custom API. All web requests to your custom APIs should be delayed until this flag is set or they will fail.

// ...

export default class LatestOrdersWebPart extends BaseClientSideWebPart<ILatestOrdersWebPartProps> {


private remotePartyLoaded: boolean = false;
private orders: IOrder[];

public render(): void {


this.domElement.innerHTML = `
<div class="${styles.latestOrders}">
<iframe src="https://contoso.azurewebsites.net/"
style="display:none;"></iframe>
<div class="ms-font-xxl">Recent orders</div>
<div class="loading"></div>
<table class="data" style="display:none;">
<thead>
<tr>
<th>ID</th>
<th>Date</th>
<th>Region</th>
<th>Rep</th>
<th>Item</th>
<th>Units</th>
<th>Unit cost</th>
<th>Total</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>`;

this.context.statusRenderer.displayLoadingIndicator(
this.domElement.querySelector(".loading"), "orders");

this.domElement.querySelector("iframe").addEventListener("load", (): void => {


this.remotePartyLoaded = true;
});

this.executeOrDelayUntilRemotePartyLoaded((): void => {


// retrieve and render data
});
}

private executeOrDelayUntilRemotePartyLoaded(func: Function): void {


if (this.remotePartyLoaded) {
func();
} else {
setTimeout((): void => { this.executeOrDelayUntilRemotePartyLoaded(func); }, 100);
}
}

// ...
}
When executing AJAX requests in your web parts, you have to specify that the authentication cookie should be sent cross-domain. You can enable this by setting the credentials property of
the web request to include. Without this, the request is blocked in the browser and you are not able to call the API.

// ...

export default class LatestOrdersWebPart extends BaseClientSideWebPart<ILatestOrdersWebPartProps> {


// ...

private retrieveAndRenderData(): void {


this.context.httpClient.get("https://contoso.azurewebsites.net/api/orders",
HttpClient.configurations.v1, {
credentials: "include"
})
.then((response: HttpClientResponse): Promise<IOrder[]> => {
// ...
});
}

// ...
}

To support this method, the custom API requires some specific configurations as well. First, it requires support for receiving credentials from cross-domain calls. This is done by setting the
Access-Control-Allow-Credentials response header to true.
IM P O R T A N T

When using Access-Control-Allow-Credentials, you are allowed to specify only one origin.
Next, it needs to specify what origin is allowed to call the API. This is configured in the Access-Control-Allow-Origin response header.
How these headers should be configured exactly depends on the implementation of your API. If you use an Azure Function to build the API using Node.js for example, you would set these
headers on the response object:

context.res = {
body: "response",
headers: {
"Access-Control-Allow-Credentials" : "true",
"Access-Control-Allow-Origin" : "https://contoso.sharepoint.com"
}
};

When using ASP.NET Web API, you would install the Microsoft.AspNet.WebApi.Cors NuGet package, call the config.EnableCors() method, and use the EnableCors attribute to set the
header values:

[EnableCors("origins": "*", "headers": "*", "methods": "*", SupportsCredentials = true)]


public string Get() {
return "response";
}

Benefits of using the SharePoint Online authentication cookie for seamless authentication
The most important benefit for using the SharePoint Online authentication cookie to connect to custom APIs secured with Azure AD is the fact that in this approach you don't need to
register an Azure AD application for every web part. This frees you from having to manage reply URLs of pages where each web part is used and doesn't have the limitation of maximum 10
reply URLs per Azure AD application.
The authentication flow is handled seamlessly, and there is no user interaction required to complete. In comparison, when using ADAL JS, each web part is based on a different Azure AD
application and requires the user to explicitly sign in to it.
Considerations when using the SharePoint Online authentication cookie for seamless authentication
From the functional point of view, using both ADAL JS and the SharePoint Online authentication cookie allows you to connect to APIs secured with Azure AD. There are, however, a few
important differences between the two approaches that you should be aware of.
When using ADAL JS, before the client-side application retrieves an access token, it retrieves the identity token for the current user. This token contains information about the current user
retrieved from Azure AD such as the user name or password. When using the authentication cookie, there is no identity token. Because you're working with SharePoint, this isn't really a
limitation, since you can retrieve the same information about the current user from SharePoint.
ADAL JS allows you to connect to any API secured with Azure AD. When using the authentication cookie, the API must explicitly support receiving credentials from cross-domain calls.
When designing APIs, you should take this requirement into account to ensure that you are able to use these APIs in SharePoint Framework solutions.
With both ADAL JS and the SharePoint Online authentication cookie, you can access APIs secured with Azure AD. But not all APIs support use of both methods. For example, to access
Microsoft Graph, you need to have a valid OAuth access token with specific Microsoft Graph permissions. You can obtain this token by using ADAL JS but not by using a SharePoint Online
authentication cookie.
When using the SharePoint Online authentication cookie to access APIs secured with Azure AD, no additional authorization information is being sent along with the request. This means, that
by default, every user with a valid organizational account in Azure AD associated with the API can access the API. When building the API, you must take care of authorization to ensure that
all API operations are performed by users with sufficient privileges.
Custom APIs are hosted outside of SharePoint Online and can be accessed by using cross-domain web requests. By default, web browsers don't include credentials when performing cross-
domain AJAX requests. To connect to these secured APIs, you have to enable sending credentials with cross-domains explicitly for each outgoing web request.

General considerations
Both ADAL JS and the method that uses the SharePoint Online authentication cookie use iframes for communicating with Azure AD. The reason for that are the redirects that are a part of
the OAuth flow, and which cannot be automatically followed by AJAX requests. Microsoft Internet Explorer uses security zones to apply security policies to websites depending on the
associated zone. For the scripts to be able to access information from an iframe, the resource in the iframe and the page hosting the iframe must be located in the same security zone. To
ensure correct configuration, organizations can use group policies to distribute the settings consistently to their users.

Build an API secured with Azure AD


Securing the access to an API with Azure AD isn't complex and requires just a few steps. The exact process varies depending on the implementation of your API. If you choose to use Azure
Functions, you are able to configure the security through the Azure portal. If you built your API by using the ASP.NET Web API and want to host it somewhere else than in Azure App
Service, you need to extend the Web API's code to add authentication to it. Following is a step-by-step description of how you would build and configure an API secured with Azure AD by
using both Azure Functions and ASP.NET Web API.
Build the API using an Azure Function
Building APIs using Azure Functions offers you a number of benefits. First and foremost, it significantly simplifies the development and deployment process of the API. Azure Functions offer
a rich set of configuration options. The only thing that you need to take care of is the actual API code. For everything else, from authentication to supporting Cross-Origin Resource Sharing
(CORS) and documenting the API, you can use the Azure portal.
Azure Functions are hosted in Azure App Service and benefit from many capabilities available in the underlying service. On top of securing the API by using a function or admin key, you can
choose to enable Azure App Service security and protect your API by using Azure AD or one of the other available authentication providers. App Service Authentication can be configured
via the Azure portal and doesn't require any changes in the API code.
Following is how you would use Azure Functions to create an API secured with Azure AD and capable of being called from a cross-domain origin in a secured way.
Create a new Azure Function
1. In the Azure portal, go to your Resource Group and add a Function App.

2. After the Function App has been provisioned, open the newly created Function App and add a new function by selecting the plus icon next to the Functions label.

3. On the quick start screen, scroll to the Get started on your own section, and select the Custom function option.
4. From the list of templates, select HttpTrigger-JavaScript.
5. For the function name, enter Orders, and set the function authorization level to Anonymous because you will use Azure AD to secure access to the Azure Function. Confirm your
selection by selecting Create.

Implement API code


1. Replace the function's code with the following snippet:
module.exports = function (context, req) {
context.res = {
body: [
{
id: 1,
orderDate: new Date(2016, 0, 6),
region: "east",
rep: "Jones",
item: "Pencil",
units: 95,
unitCost: 1.99,
total: 189.05
},
{
id: 2,
orderDate: new Date(2016, 0, 23),
region: "central",
rep: "Kivell",
item: "Binder",
units: 50,
unitCost: 19.99,
total: 999.50
},
{
id: 3,
orderDate: new Date(2016, 1, 9),
region: "central",
rep: "Jardine",
item: "Pencil",
units: 36,
unitCost: 4.99,
total: 179.64
},
{
id: 4,
orderDate: new Date(2016, 1, 26),
region: "central",
rep: "Gill",
item: "Pen",
units: 27,
unitCost: 19.99,
total: 539.73
},
{
id: 5,
orderDate: new Date(2016, 2, 15),
region: "west",
rep: "Sorvino",
item: "Pencil",
units: 56,
unitCost: 2.99,
total: 167.44
}],
headers: {
"Access-Control-Allow-Credentials" : "true",
"Access-Control-Allow-Origin" : "https://contoso.sharepoint.com"
}
};
context.done();
};

2. Change the URL specified in the Access-Control-Allow-Origin header to match the URL of your SharePoint Online tenant from which you are calling this API.
3. Save the changes to the function's code by selecting Save.

Change CORS settings


Azure Functions are hosted in Azure App Service, which allows you to configure its Cross-Origin Resource Sharing (CORS) settings through the Azure portal. While this is convenient, if
configured through the portal, it cannot be used in combination with the Access-Control-Allow-Credentials header, which is required by the API to accept authentication cookies coming
from another origin. For the client-side authentication to work correctly, CORS settings of the Azure App Service must be cleared.
IM P O R T A N T

If you're authenticating with the API using the SharePoint Online cookie you have to clear all CORS settings or the authentication process will fail. If you're however authenticating using
OAuth, you can use the Azure portal, to configure CORS settings for your API.
1. In the Function App, select your Azure Function, and navigate to the Platform features blade.

2. In the API section, select the CORS option.

3. On the CORS settings blade, delete all entries so that the CORS configuration is empty.

4. Confirm the deletion by selecting Save.


Enable App Service Authentication
1. In the Function App settings, go back to the Platform features blade.
2. In the Networking section, select the Authentication / Authorization option.

3. Enable App Service Authentication by setting the App Service Authentication toggle to On.
4. To disallow anonymous access to the API and force authentication using Azure AD, set the value of the Action to take when request is not authenticated list to Log in with
Azure Active Directory.

5. In the list of authentication providers, select Azure Active Directory to configure it.

6. On the Active Directory Authentication blade, set the Management mode to Express, and create a new Azure AD app.
IM P O R T A N T

When using the Express configuration mode, the Azure portal creates a new Azure AD application from the same directory where the Function App is located. If the Function App is
hosted in a different Azure subscription with a different directory, you should use the advanced mode instead, and specify the ID of the directory and application that should be used
to secure access to the API.
When using existing Azure AD applications, configure the application to accept credentials from a single tenant only. Configuring the application as multi-tenant allows any user with a
valid organization or personal account to connect to your API.
Using an Azure AD application to secure the access to your API only accounts for authentication. When building your API, you should also authorize requests in your API's code to
ensure that only users with sufficient privileges are using the API.
7. Because the app is only meant to secure access to the Azure Function, it doesn't require any additional permissions. Confirm the selection by selecting OK.
8. When the Azure Active Directory blade closes, back on the Authentication / Authorization blade, select Save to confirm all changes to authentication settings.

9. If you try to navigate to your API URL in a new private window, you should be prompted to sign in by using your Azure AD account.
At this point, the API is ready to be called securely from a SharePoint Framework client-side web part by using the authentication cookie.

Build the API by using ASP.NET Web API


Another way to implement the API is by using the ASP.NET Web API. Compared to using Azure Functions to build the API, the ASP.NET Web API requires significantly more work. Not only
do you have to set up a complete project for it, but you also have to think about where the API will be deployed. On the other hand, using the ASP.NET Web API offers you more flexibility
and allows you to deploy the API to different platforms such as Azure App Service, Docker containers, other cloud providers, or even on your infrastructure.
Following are steps to build an API using the ASP.NET Web API, deploy it to Azure App Service, and secure it by using Azure App Service Authentication. Later, you will extend the API to
perform the authentication by itself so that it can be deployed to other platforms as well.
Create a new ASP.NET Web API project
1. In Visual Studio, on the File menu, select the New / Project option.
2. In the New Project dialog box, select the Visual C# Web templates, and from the list of available templates, select the ASP.NET Web Application template.

3. As the type of ASP.NET Web Application project, select Web API.


4. Because you will use Azure App Service Authentication to secure the access to the API, select the Change Authentication button, and then select the No Authentication option.

5. Confirm your choice by selecting OK.


6. Visual Studio allows you to easily deploy your Web API to Azure App Service. To benefit from this capability, in the New ASP.NET Web Application dialog box, in the Microsoft
Azure section, select the Host in the cloud check box, and in the list, select the App Service option.
7. In the Create App Service dialog box, specify the name for the web app to be created, and select the Azure Subscription, Resource Group, and App Service Plan that you want to
use for this application.

8. Confirm your choice by selecting Create. At this point, Visual Studio creates a new Azure Web App to host your web application.
Add support for CORS
By default, APIs created using the ASP.NET Web Application project template don't support CORS and cannot be called by client-applications hosted on different domains.
1. To add support for CORS to your Web API, right-click the project, and from the context menu, select the Manage NuGet Packages option.
2. On the Manage NuGet Packages tab, search for a package named Microsoft.AspNet.WebApi.Cors and install it in your project.

Add data model


In the project, define a model that represents the data returned by the API. In the Models folder, add a new class and name it Order. Paste the following code into the newly created file:
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;

namespace PnP.Aad.Api.Models {
public class Order {
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
[JsonProperty(PropertyName = "orderDate")]
public DateTime OrderDate { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty(PropertyName = "region")]
public Region Region { get; set; }
[JsonProperty(PropertyName = "rep")]
public string Rep { get; set; }
[JsonProperty(PropertyName = "item")]
public string Item { get; set; }
[JsonProperty(PropertyName = "units")]
public uint Units { get; set; }
[JsonProperty(PropertyName = "unitCost")]
public double UnitCost { get; set; }
[JsonProperty(PropertyName = "total")]
public double Total { get; set; }
}

public enum Region {


East,
Central,
West
}
}

Add Orders API


Add an API that returns the information about the latest orders. In the Controllers folder, create a new class and name it OrdersController. Paste the following code into the newly created
file:

using PnP.Aad.Api.Models;
using System;
using System.Collections.Generic;
using System.Web.Http;

namespace PnP.Aad.Api.Controllers {
public class OrdersController : ApiController {
private List<Order> orders = new List<Order> {
new Order {
Id = 1,
OrderDate = new DateTime(2016, 1, 6),
Region = Region.East,
Rep = "Jones",
Item = "Pencil",
Units = 95,
UnitCost = 1.99,
Total = 189.05
},
new Order {
Id = 2,
OrderDate = new DateTime(2016, 1, 23),
Region = Region.Central,
Rep = "Kivell",
Item = "Binder",
Units = 50,
UnitCost = 19.99,
Total = 999.50
},
new Order {
Id = 3,
OrderDate = new DateTime(2016, 2, 9),
Region = Region.Central,
Rep = "Jardine",
Item = "Pencil",
Units = 36,
UnitCost = 4.99,
Total = 179.64
},
new Order {
Id = 4,
OrderDate = new DateTime(2016, 2, 26),
Region = Region.Central,
Rep = "Gill",
Item = "Pen",
Units = 27,
UnitCost = 19.99,
Total = 539.73
},
new Order {
Id = 5,
OrderDate = new DateTime(2016, 3, 15),
Region = Region.West,
Rep = "Sorvino",
Item = "Pencil",
Units = 56,
UnitCost = 2.99,
Total = 167.44
}
};

public IEnumerable<Order> Get() {


return orders;
}
}
}
Extend the API with support for CORS
Even though you have installed support for CORS in your project, it's not being actively used yet. If you call the newly created Orders API from a client application hosted on another
domain, you get a CORS error and the request fails.
1. For an API to support CORS, it has to be decorated with the EnableCors attribute.

using PnP.Aad.Api.Models;
using System;
using System.Collections.Generic;
using System.Web.Http;
using System.Web.Http.Cors;

namespace PnP.Aad.Api.Controllers {
public class OrdersController : ApiController {
private List<Order> orders = new List<Order> {
// ...
};

[EnableCors("*", "*", "GET", SupportsCredentials = true)]


public IEnumerable<Order> Get() {
return orders;
}
}
}

2. Open the .\App_Start\WebApiConfig.cs file, and paste the following code:

using System.Web.Http;

namespace PnP.Aad.Api {
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Web API configuration and services

// Web API routes


config.MapHttpAttributeRoutes();

config.EnableCors();

config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}

At this point, the API is code complete and can be published to the Azure Web App.
Publish the API to Azure Web App
1. In Visual Studio, right-click the project, and from the context menu, select the Publish option.

2. In the Publish dialog box, verify that all the information is correct, and select Publish to start the publishing process.
3. After the publishing process completes, navigate in your web browser to the API URL, for example, http://pnp-aad-api.azurewebsites.net/api/orders . At this point, the API is not
secured and can be accessed by anonymous users.

Secure the API using Azure App Service


1. To secure the API using Azure AD, go to the Azure portal and open the Web App hosting your API.
2. From the Settings group, select the Authentication / Authorization option.

3. To enable authentication for your Web App, set the App Service Authentication toggle to On.
4. To disallow anonymous access to the API, in the Action to take when request is not authenticated listn, select the Log in with Azure Active Directory option.

5. Configure Azure Active Directory authentication from the list of authentication providers by selecting Azure Active Directory.
6. On the Active Directory Authentication blade, set the Management mode to Express and create a new Azure AD app.
IM P O R T A N T

When using the Express configuration mode, the Azure portal creates a new Azure AD application from the same directory where the Function App is located. If the Function App is
hosted in a different Azure subscription with a different directory, you should use the advanced mode instead, and specify the ID of the directory and application that should be used
to secure access to the API.
When using existing Azure AD applications, configure the application to accept credentials from a single tenant only. Configuring the application as multi-tenant allows any user with a
valid organization or personal account to connect to your API.
Using an Azure AD application to secure the access to your API only accounts for authentication. When building your API, you should also authorize requests in your API's code to
ensure that only users with sufficient privileges are using the API.
7. Because the app is only meant to secure access to the Azure Function, it doesn't require any additional permissions. Confirm the selection by selecting OK.
8. When the Azure Active Directory blade closes, back on the Authentication / Authorization blade, select Save to confirm all changes to authentication settings.

9. If you try to navigate to your API URL in a new private window, you should be prompted to sign in by using your Azure AD account.
At this point, the API is ready to be called securely from a SharePoint Framework client-side web part by using the authentication cookie.
Secure the API using OpenID
If you want to deploy your ASP.NET Web API project to other location than Azure App Service and want it to be secured with Azure AD, you can't rely on App Service Authentication.
Instead, you have to extend the web application to require its users to authenticate before they can use the API.
D IS A B LE A N O N Y M O U S A C C E S S T O A LL R E S O U R C E S

1. Assuming you want all resources secured, open the .\App_Start\FilterConfig.cs file, and paste the following code:

using System.Web.Mvc;

namespace PnP.Aad.Api {
public class FilterConfig {
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new HandleErrorAttribute());
filters.Add(new AuthorizeAttribute());
}
}
}

2. To require authentication for all APIs, open the .\App_Start\WebApiConfig.cs file, and paste the following code:

using System.Web.Http;

namespace PnP.Aad.Api {
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Web API configuration and services

// Web API routes


config.MapHttpAttributeRoutes();

config.EnableCors();
config.Filters.Add(new AuthorizeAttribute());

config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}

3. If you try to access either the API or any other resource in your web application, you get a 401 Unauthorized response.
At this point, the web application requires that all requests to its resources are authenticated, but it doesn't start the Azure AD sign-in flow.
In the following steps, you extend the web application so that it redirects users to the Azure AD sign-in page, if they weren't previously authenticated.
R E G IS T E R A Z U R E A D A P P LIC A T IO N

To secure an API with Azure AD, you need to register an Azure AD application. This application is then referenced in the web application project and used by the OWIN middleware to secure
the access to your API with Azure AD.
1. If you don't have an existing Azure AD application yet, you can create one in the Azure portal, by navigating to the Azure Active Directory blade.
IM P O R T A N T

The Azure AD application used to secure the API should be created in the same Azure Active Directory that is used by your organization to access Office 365.

2. On the Azure Active Directory blade, navigate to the App registrations blade.
3. On the App registrations blade, select the New application registration button to register a new Azure AD application.

4. On the Create blade, provide the information about your application, and confirm the creation by selecting Create.
5. After the application registration is successfully created, select it in the list to view its details.

6. From the application registration information, copy the Application ID and store it because you will need it when you configure Azure AD authentication for your web application.
R E D IR E C T A N O N Y M O U S R E Q U E S T S T O A Z U R E A D S IG N -IN P A G E

1. In Visual Studio, rightclick the project, and from the context menu, select the Manage NuGet Packages option.
2. In the Manage NuGet Packages window, add the following packages to your project:
Microsoft.Owin.Host.SystemWeb
Microsoft.Owin.Security.Cookies
Microsoft.Owin.Security.OpenIdConnect
3. In the root directory of your project, add a new class named Startup, and paste the following code:

using Owin;

namespace PnP.Aad.Api {
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
}

4. In the App_Start folder, create a new class named Startup.Auth, and paste the following code:
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using System.Configuration;

namespace PnP.Aad.Api {
public partial class Startup {
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app) {
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

app.UseCookieAuthentication(new CookieAuthenticationOptions());

app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions {
ClientId = ConfigurationManager.AppSettings["ida:ClientId"],
Authority = $"https://login.microsoftonline.com/{(ConfigurationManager.AppSettings["ida:Tenant"])}",
PostLogoutRedirectUri = ConfigurationManager.AppSettings["ida:PostLogoutRedirectUri"],
});
}
}
}

5. In Visual Studio, open the Web.config file, and in the appSettings section, add the following elements:

<add key="ida:Tenant" value="contoso.onmicrosoft.com" />


<add key="ida:ClientId" value="eeb40f1f-c5fa-4096-896b-71c77d459e21" />
<add key="ida:PostLogoutRedirectUri" value="https://localhost:44320/" />

The value of the ida:Tenant key is the name of the Azure AD where the Azure AD app used to secure the API is defined.
ida:ClientId specifies the ID of the Azure AD application used to secure the API.
The URL specified in the ida:PostLogoutRedirectUri property is where Azure AD would redirect to after signing out of your application, which isn't used in this case.
This concludes the configuration process. If you start your web application, before you are able to access any of its resources, you are prompted to sign in with your Azure AD account. To
ensure that only authorized users are accessing the particular API, you should implement authorization in your custom APIs. You can do that by retrieving the user name from the
RequestContext.Principal.Identity property, and verifying it against your security matrix.

See also
Call custom APIs secured with Azure Active Directory without ADAL JS (code sample)
Call the Microsoft Graph API using OAuth from your web part
3/26/2018 • 13 minutes to read Edit Online

You can add a lot of great functionality such as email, documents, and a calendar to your web part by integrating with Microsoft Graph. To call APIs on Microsoft Graph, you need to use the
Active Directory Authentication Library (ADAL) for JavaScript library and authenticate by using the OAuth flow.
To use ADAL JS and call Microsoft Graph APIs correctly and securely, consider your design and any potential code modifications that you need to make for your web part.

Azure AD authorization flows


Office 365 uses Azure Active Directory (Azure AD) to secure its APIs, which are accessed through Microsoft Graph. Azure AD uses OAuth as the authorization protocol. When an application
completes the OAuth authorization flow, it gets a temporary access token. The token provides access to specific resources on behalf of the user by using permissions granted to the
application by that user.
There are different types of OAuth flows depending on the kind of application. Web applications use an OAuth flow where Azure AD redirects to the URL where the application is hosted.
The redirect is an additional security measure to verify the authenticity of that application.
Client applications, such as Android and iOS apps, do not have a URL and cannot use a redirect. So they complete the OAuth flow without the redirect. Both web applications and client
applications use a publicly known client ID and a privately held client secret known only to Azure AD and the application.
Client-side web applications are similar to web applications but are implemented using JavaScript and run in the context of a browser. These applications are incapable of using a client secret
without revealing it to users. Therefore these applications use an authorization flow called OAuth implicit flow to access resources secured with Azure AD. In this flow, the contract between
the application and Azure AD is established based on the publicly-known client ID and the URL where the application is hosted. This is the flow that SharePoint Framework client-side web
parts must use in order to connect to resources secured with Azure AD.
To implement Azure AD-based authentication and authorization in your web part, you can use the Active Directory Authentication Library (ADAL) for JavaScript provided by Microsoft.

Client-side applications versus SharePoint Framework web parts


A typical client-side web application owns the whole page and is the only resource available at the application's URL. All elements of the page are determined during development, and users
working with the application cannot dynamically add new elements. Even though a client-side web application might consist of several views, work with external data, and offer a certain
degree of configuration, these aspects are considered by developers while building the application.
When working with SharePoint, users compose pages by adding and configuring web parts. A single web part is only a small part of the whole page. Developers building a web part cannot
know up front if other web parts will be placed on the same page, and if so, which resources those web parts will use. Unlike SharePoint Add-ins, web parts are a part of the page. All web
parts can access the page's DOM, and resources loaded by one web part are available to other web parts.

Limitations when using ADAL JS with client-side web parts


The ADAL JS library significantly simplifies implementing the OAuth flow for Azure AD in client-side web applications. But it has a number of limitations when used with SharePoint
Framework client-side web parts. These limitations are due to the fact that ADAL JS is designed to be used by client-side web applications that own the whole page and do not share the
page with other applications.

Shared storage
Depending on how you configured the ADAL JS library in your project, it stores its data either in the browser's local storage or in the session storage. Either way, the information stored by
ADAL JS is accessible to any component on the same page. For example, if one web part retrieves an access token for Microsoft Graph, any other web part on the same page can reuse that
token and call Microsoft Graph.

ADAL JS as a singleton
ADAL JS is designed to work as a singleton service registered in the global scope of the page. When processing OAuth flow callbacks in IFrames, ADAL JS code uses the registered
singleton reference from the main window to resolve the token flow. Because each web part is registered with a different Azure AD application, reusing the same instance of ADAL JS leads
to undesirable results where every web part uses the same configuration as the one registered by the first web part loaded on the page.

Resource-based storage
By default, the ADAL JS library stores information such as the current access token or its expiration time in a set of keys associated with the particular resource, for example Microsoft Graph
or SharePoint. If there are multiple components on one page accessing the same resource with different permissions, the first retrieved token is served by ADAL JS to all components. If
different components require access to the same resource, they might fail. To illustrate this limitation, consider the following example.
Imagine that there are two web parts on the page: one that lists upcoming meetings, and one that creates a new meeting. To get upcoming meetings, the upcoming meetings web part uses a
Microsoft Graph access token with permissions to read users' calendars. The web part that creates new meetings, on the other hand, requires a Microsoft Graph access token with
permissions to write to users' calendars.
If the upcoming meetings web part loads first, ADAL JS retrieves its token with only the read permission. The same token is then served by ADAL JS to the web part creating new meetings.
As you can see, when the web part attempts to create a new meeting, the web part fails with an access denied error. Because of the resource-based storage, ADAL JS wouldn't retrieve a new
token for Microsoft Graph until the previously retrieved token expired.

Processing authorization callbacks


OAuth implicit flow is based on redirects between Azure AD and the application participating in the flow. When the authentication process starts, the application redirects you to the Azure
AD sign-in page. After the authentication completes, Azure AD redirects you back to the application, and sends the identity token in the URL hash for the application to process. From the
perspective of a web part placed on a SharePoint page, this behavior has two drawbacks.
Even though you are signed in to SharePoint, you need to separately authenticate with Azure AD in order for your web part to be able to access resources secured with Azure AD. The web
part is a small part of the overall page, but to complete the authentication process, you need to leave the whole page, which is a poor user experience.
After the authentication completes, Azure AD redirects you back to your application. In the URL hash, it includes the identity token that your application needs to process. Unfortunately,
because the identity token doesn't contain any information about its origin, if you had multiple web parts on one page, all of them would try to process the identity token from the URL.

Use ADAL JS with client-side web parts


You can overcome the limitations in ADAL JS to implement OAuth successfully in your SharePoint Framework client-side web part.
IM P O R T A N T

The following guidance is based on ADAL JS v1.0.12. When adding ADAL JS to your SharePoint Framework projects, ensure that you're installing ADAL JS v1.0.12, or the guidance
mentioned in this article will not work as expected.

Load ADAL JS in your web part


Web parts are built using TypeScript and distributed as AMD modules. Their modular architecture allows you to isolate the different resources used by the web part. ADAL JS is designed to
register itself in the global scope, but you can load it in a web part by using the following code:

import * as AuthenticationContext from 'adal-angular';

This statement imports the AuthenticationContext class that exposes the ADAL JS functionality for use in web parts. Despite the name of the module, the AuthenticationContext class works
with every JavaScript library.

Make ADAL JS suitable for use with SharePoint Framework web parts
The current ADAL JS functionality is unsuitable for use in web parts. Use the following patch to make ADAL JS work in your web part.
WebPartAuthenticationContext.js
const AuthenticationContext = require('adal-angular');

AuthenticationContext.prototype._getItemSuper = AuthenticationContext.prototype._getItem;
AuthenticationContext.prototype._saveItemSuper = AuthenticationContext.prototype._saveItem;
AuthenticationContext.prototype.handleWindowCallbackSuper = AuthenticationContext.prototype.handleWindowCallback;
AuthenticationContext.prototype._renewTokenSuper = AuthenticationContext.prototype._renewToken;
AuthenticationContext.prototype.getRequestInfoSuper = AuthenticationContext.prototype.getRequestInfo;
AuthenticationContext.prototype._addAdalFrameSuper = AuthenticationContext.prototype._addAdalFrame;

AuthenticationContext.prototype._getItem = function (key) {


if (this.config.webPartId) {
key = this.config.webPartId + '_' + key;
}

return this._getItemSuper(key);
};

AuthenticationContext.prototype._saveItem = function (key, object) {


if (this.config.webPartId) {
key = this.config.webPartId + '_' + key;
}

return this._saveItemSuper(key, object);


};

AuthenticationContext.prototype.handleWindowCallback = function (hash) {


if (hash == null) {
hash = window.location.hash;
}

if (!this.isCallback(hash)) {
return;
}

var requestInfo = this.getRequestInfo(hash);


if (requestInfo.requestType === this.REQUEST_TYPE.LOGIN) {
return this.handleWindowCallbackSuper(hash);
}

var resource = this._getResourceFromState(requestInfo.stateResponse);


if (!resource || resource.length === 0) {
return;
}

if (this._getItem(this.CONSTANTS.STORAGE.RENEW_STATUS + resource) === this.CONSTANTS.TOKEN_RENEW_STATUS_IN_PROGRESS) {


return this.handleWindowCallbackSuper(hash);
}
}

AuthenticationContext.prototype._renewToken = function (resource, callback) {


this._renewTokenSuper(resource, callback);
var _renewStates = this._getItem('renewStates');
if (_renewStates) {
_renewStates = _renewStates.split(',');
}
else {
_renewStates = [];
}
_renewStates.push(this.config.state);
this._saveItem('renewStates', _renewStates);
}

AuthenticationContext.prototype.getRequestInfo = function (hash) {


var requestInfo = this.getRequestInfoSuper(hash);
var _renewStates = this._getItem('renewStates');
if (!_renewStates) {
return requestInfo;
}

_renewStates = _renewStates.split(';');
for (var i = 0; i < _renewStates.length; i++) {
if (_renewStates[i] === requestInfo.stateResponse) {
requestInfo.requestType = this.REQUEST_TYPE.RENEW_TOKEN;
requestInfo.stateMatch = true;
break;
}
}

return requestInfo;
}

AuthenticationContext.prototype._addAdalFrame = function (iframeId) {


var adalFrame = this._addAdalFrameSuper(iframeId);
adalFrame.style.width = adalFrame.style.height = '106px';
return adalFrame;
}

window.AuthenticationContext = function() {
return undefined;
}

The patch applies the following changes to ADAL JS:


All information is stored in a key specific to the web part (see the override of the _getItem and _saveItem functions).
Callbacks are processed only by web parts that initiated them (see the override of the handleWindowCallback function).
When verifying data from callbacks, the instance of the AuthenticationContext class of the specific web part is used instead of the globally registered singleton (see _renewToken ,
getRequestInfo and the empty registration of the window.AuthenticationContext function).

Use the ADAL JS patch in SharePoint Framework web parts


For ADAL JS to work correctly in SharePoint Framework web parts, you have to configure it in a specific way.
1. Define a custom interface that extends the standard ADAL JS Config interface to expose additional properties on the configuration object.

export interface IAdalConfig extends adal.Config {


popUp?: boolean;
callback?: (error: any, token: string) => void;
webPartId?: string;
}

The popUp property and the callback function are both already implemented in ADAL JS but are not exposed in the TypeScript typings of the standard Config interface. You need
them in order to allow users to sign in to your web parts by using a pop-up window instead of redirecting them to the Azure AD sign-in page.
2. Load the ADAL JS patch, the custom configuration interface, and your configuration object into the main component of your web part.

import * as AuthenticationContext from 'adal-angular';


import adalConfig from '../AdalConfig';
import { IAdalConfig } from '../../IAdalConfig';
import '../../WebPartAuthenticationContext';

3. In the constructor of your component, extend the ADAL JS configuration with additional properties and use it to create a new instance of the AuthenticationContext class.

export default class UpcomingMeetings extends React.Component<IUpcomingMeetingsProps, IUpcomingMeetingsState> {


private authCtx: adal.AuthenticationContext;

constructor(props: IUpcomingMeetingsProps, state: IUpcomingMeetingsState) {


super(props);

this.state = {
loading: false,
error: null,
upcomingMeetings: [],
signedIn: false
};

const config: IAdalConfig = adalConfig;


config.webPartId = this.props.webPartId;
config.popUp = true;
config.callback = (error: any, token: string): void => {
this.setState((previousState: IUpcomingMeetingsState, currentProps: IUpcomingMeetingsProps): IUpcomingMeetingsState => {
previousState.error = error;
previousState.signedIn = !(!this.authCtx.getCachedUser());
return previousState;
});
};

this.authCtx = new AuthenticationContext(config);


AuthenticationContext.prototype._singletonInstance = undefined;
}
}

The code first retrieves the standard ADAL JS configuration object and casts it to the type of the newly defined configuration interface.
It then passes the ID of the web part instance so that all ADAL JS values can be stored in a way that they won't collide with other web parts on the page.
Next, it enables the pop-up-based authentication and defines a callback function that runs when authentication completes to update the component.
Finally, it creates a new instance of the AuthenticationContext class and resets the _singletonInstance set in the constructor of the AuthenticationContext class. This is required in order to
allow every web part to use its own version of the ADAL JS authentication context.

Considerations when using OAuth implicit flow in client-side web parts


Before you build SharePoint Framework client-side web parts that communicate with resources secured by Azure AD, there are some constraints that you should consider. The following
information helps you determine when OAuth authorization in web parts is the right choice for your solution and organization.

SharePoint Framework web parts are highly trusted


Unlike SharePoint Add-ins, web parts run with the same permissions as the current user. Whatever the user can do, the web part can do as well. This is why web parts can be installed and
deployed only by tenant administrators. The tenant administrator should verify that web parts they are deploying come from a trusted source and were approved for use in the tenant.
Web parts are a part of the page and, unlike SharePoint Add-ins, share DOM and resources with other elements on the page. Access tokens that grant access to resources secured with
Azure AD, are retrieved through a callback to the same page where the web part is located. That callback can be processed by any element on the page. Also, after access tokens are
processed from callbacks, they are stored in the browser's local storage or session storage from where they can be retrieved by any component on the page. A malicious web part could read
the token and either expose the token or the data it retrieved using that token to an external service.

URL is a part of the OAuth implicit flow contract


Client-side applications are incapable of storing a client secret without revealing it to users. To verify the authenticity of the particular application, the URL where the application is hosted is
used as a part of the trust contract between Azure AD and the application. The consequences of this are that the URL of every page with web parts using OAuth implicit flow must be
registered with Azure AD. If a page is not registered, the OAuth flow fails, and the web part is denied access to the secured resource.
This necessary security measure is a significant limitation for organizations that allow users to add web parts to pages. We recommend that you limit the number of locations where web
parts using OAuth implicit flow are used. Use a few well known locations such as the home page or specific landing pages, and have these locations registered with Azure AD.

Internet Explorer security zones


Internet Explorer uses security zones to apply security policies to websites you visit. Websites assigned to different security zones run isolated and cannot cooperate. When using OAuth
implicit flow in SharePoint Framework client-side web parts, the page with web parts that use OAuth and the Azure AD sign-in page (located at https://login.microsoftonline.com) must be in
the same security zone. Without such configuration, the authentication process fails, and web parts won't be able to communicate with Azure AD-secured resources.

User must sign in frequently


When using regular OAuth flow, web applications and client applications get a short-lived access token and a refresh token that is valid for a longer period of time. When the access token
expires, the refresh token is used to get a new access token. This approach reduces how often users need to sign in to Azure AD.
Because client-side applications are incapable of securely storing secrets, and disclosing a refresh token is a serious security threat, they only receive the access token as part of the OAuth
implicit flow. After that token expires, the application must start a new OAuth flow, which could require the user to sign in again.

See also
Authentication Scenarios for Azure AD
Connect to Azure AD-secured APIs in SharePoint Framework solutions
5/11/2018 • 17 minutes to read Edit Online

When building SharePoint Framework solutions, you might need to connect to an API secured by using Azure Active Directory (Azure AD). SharePoint Framework allows you to specify
which Azure AD applications and permissions your solution requires, and a tenant administrator can grant the necessary permissions if they haven't yet been granted. By using the
AadHttpClient, you can easily connect to APIs secured by using Azure AD without having to implement the OAuth flow yourself.
IM P O R T A N T

AadHttpClient and MSGraphClientclient objects are currently in preview and are subject to change. Do not use them in a production environment. Also note that the
webApiPermissionRequests properties in package-solution.json are not supported in production tenants.

Web API permissions overview


Azure AD secures a number of resources, from Office 365 to custom line-of-business applications built by the organization. To connect to these resources, applications must obtain a valid
access token that grants them access to a particular resource. Applications can obtain an access token as part of the OAuth authorization flow.
Client-side applications that are incapable of storing a secret, such as SharePoint Framework solutions, use a specific type of OAuth flow named OAuth implicit flow.
Developers building client-side solutions are responsible for implementing authorization by using the OAuth implicit flow in their application. In SharePoint Framework solutions, that's
already done as part of the framework through MSGraphClient and AadHttpClient, both of which are introduced in SharePoint Framework v1.4.1.
NOTE

If you build solutions on a version of the SharePoint Framework earlier than v1.4.1, you can still connect to resources secured with Azure AD. In this case, you need to implement the OAuth
implicit flow by using ADAL JS. For more information, see Connect to API secured with Azure Active Directory.
As part of the SharePoint Framework, a specific process is defined for how developers can request permissions and tenant administrators can manage permissions to resources secured with
Azure AD. The following schema illustrates this process.

Developers building a SharePoint Framework solution that requires access to specific resources secured with Azure AD list these resources along with the required permission scopes in the
solution manifest. When deploying the solution package to the app catalog, SharePoint creates permission requests and prompts the administrator to manage the requested permissions. For
each requested permission, tenant administrators can decide whether they want to grant or deny the specific permission.
All permissions are granted to the whole tenant and not to a specific application that has requested them. When the tenant administrator grants a specific permission, it is added to the
SharePoint Online Client Extensibility Azure AD application, which is provisioned by Microsoft in every Azure AD and which is used by the SharePoint Framework in the OAuth flow to
provide solutions with valid access tokens.

Discover available applications and permissions


The target Azure AD that secures your Office 365 tenant determines which applications you can request permissions for in your solution. The list of available applications might depend on
the Office 365 license that the organization is using and which line-of-business applications they registered in Azure AD. If you have sufficient permissions, there are several ways that you
can see which applications and permission scopes are available in your tenant.

Use Azure portal or Azure AD admin center


One way to see the available applications in Azure AD is by navigating to the Azure portal or to the Azure AD admin center.
1. In the Azure AD admin center, in the left navigation, choose the Enterprise applications link.
2. On the Enterprise applications blade, in the Manage group, choose the All applications link.

3. To quickly find the application to which you want to connect, you can filter the overview either by application type (Microsoft Applications or Enterprise Applications), or you can
search for it by using its name or ID.
For example, if you want to request additional permissions to the Microsoft Graph, in the search box you would search for graph .

4. After you find the application, choose it to get additional information. On the application's blade, in the Manage group, choose Properties to open the application's properties.
5. From the list of properties, copy the value of the Object ID property, which you need to request additional permission scopes to the Microsoft Graph. Alternatively, you can copy the
application's Name and use it in the permission request instead.

NOTE

While the Object ID is unique for each tenant, the application's Name is the same across all tenants. If you want to build your solution once and deploy it to different tenants, you
should use the application's Name when requesting additional permissions in your solution.

Use Azure PowerShell


NOTE

Before you can execute the following steps, you must install Azure PowerShell. Alternatively, you can execute the cmdlets mentioned in this section in the Azure Cloud Shell PowerShell.
1. Sign in to your Azure subscription by executing in PowerShell (this is not necessary if you're using the Azure Cloud Shell):

Login-AzureRmAccount

2. Enter the following to list the applications available in your tenant:

Get-AzureRmADServicePrincipal | sort DisplayName | ft DisplayName, Id

Running this cmdlet lists all applications available in your tenant. For each application, its display name and object ID are displayed, which you can use in your SharePoint Framework
solution to request application permissions.

Use Azure CLI


NOTE

Before you can execute the following steps, you must install the Azure CLI. Alternatively, you can run the Azure CLI through the Azure Cloud Shell or as a Docker container.
1. If you're running the CLI on your machine or in a Docker container, start by connecting to your Azure subscription by executing:

azure login

2. After you're connected, execute the following command to list all available Azure AD applications:
azure ad sp list --query "sort_by([*].{displayName: displayName, objectId: objectId}, &displayName)" -o table

Running this command lists all Azure AD applications available in your tenant, sorted by displayName. For each application, the command displays its displayName and objectId.
Additionally, the output is formatted as a table.

Get the list of permission scopes exposed by the application


Each Azure AD application exposes a number of permission scopes. These permission scopes often relate to specific resources or operations inside the application. To get the list of
permissions available for the application you would like to connect to, consult its documentation. For the list of permission scopes available in the Microsoft Graph, see Microsoft Graph
permissions reference.

Request permissions to an Azure AD application


If your SharePoint Framework solution requires permissions to specific resources secured with Azure AD, such as Microsoft Graph or enterprise applications, you can specify these resources
along with the necessary permissions in the configuration of your solution.
1. In your SharePoint Framework project, open the config/package-solution.json file.
2. To the solution property, add the webApiPermissionRequests property that lists all the resources and corresponding permissions that your solution needs.
Following is an example of a SharePoint Framework solution requesting access to read user calendars by using the Microsoft Graph:

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "spfx-graph-client-side-solution",
"id": "5d16587c-5e87-44d7-b658-1148988f212a",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "Calendars.Read"
}
]
},
"paths": {
"zippedPackage": "solution/spfx-graph.sppkg"
}
}

NOTE

For the value of the resource property, you can specify either the displayName or the objectId of the application to which you want to request permissions. Using the displayName
not only is more readable but also allows you to build your solution once and reuse it across multiple tenants. While the objectId of an Azure AD application is different on each
tenant, the displayName stays the same.
3. If you want to request multiple permission scopes for the given resource, specify each scope in a separate entry, for example:

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "spfx-graph-client-side-solution",
"id": "5d16587c-5e87-44d7-b658-1148988f212a",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "Calendars.Read"
},
{
"resource": "Microsoft Graph",
"scope": "User.ReadBasic.All"
}
]
},
"paths": {
"zippedPackage": "solution/spfx-graph.sppkg"
}
}

4. When this solution is deployed to the SharePoint app catalog, it prompts the administrator to verify the requested permissions and either grant or deny them.
NOTE

No matter if the administrator denies or approves the requested permissions, the solution can be deployed and used on sites. When building solutions that require additional
permissions, you should never assume that the requested permissions have been granted.

Manage permission requests


When deploying SharePoint Framework solutions that request permissions to Azure AD applications, administrators are prompted to manage the permission request provided with the
solution. Permission requests can be managed in several ways.

Manage permissions in the Office 365 Admin portal


NOTE

Screenshots included in this section are based on the prerelease version of this capability and will change when it becomes generally available. One of the limitations of the prerelease
version of the administration UI is that it doesn't report errors. If you perform an action and the UI doesn't seem to respond to it, it is possible that an error has occurred. You can verify that
by opening the developer tools in your web browser and examining the console and the issued web requests.
Office 365 tenant administrators can manage permission grants and requests through the web UI from the modern SharePoint admin center.
1. Open the modern SharePoint admin center by navigating to the Office 365 portal landing page. Sign in with your organizational account.
2. From the list of apps, choose Admin.
3. In the Office 365 Admin center, in the Admin centers group, choose SharePoint.
4. In the SharePoint admin center, choose the Try the new SharePoint admin center link.

Following are some ways that Office 365 tenant administrators can manage permission grants and requests through the web UI from the modern SharePoint admin center.
To view pending permission requests, in the modern SharePoint admin center, in the left pane, choose WebApiPermission management (API management in the screenshot).

All pending permissions requests will be highlighted in the list of web API permissions.

To approve a pending permission request, select the request in the list of permissions, and on the toolbar, choose Approve or reject. In the Approve or reject access pane,
choose Approve.

After the request has been approved, the permission changes in the list, indicating that it has been granted.
NOTE

If you try to approve a permission request for a resource that already has some permissions granted (for example, granting additional permissions to the Microsoft Graph), the
requested scopes are added to the previously granted permissions.
To reject a pending permission request, select the request in the list of permissions, and on the toolbar, choose Approve or reject. In the Approve or reject access pane, choose
Reject.

After the request has been rejected, it is no longer visible in the list of web API permissions.
NOTE

Rejecting a permission request issued by a solution deployed in the app catalog doesn't affect that solution, and it remains deployed in the app catalog. Because the requested
permissions have been denied, the solution won't be working as expected and you should remove it from the app catalog immediately after rejecting the permission request.
To revoke a previously granted set of permissions, select the grant in the list of permissions, and on the toolbar, choose Remove access. In the Remove access pane, choose
Remove.

After the grant has been removed, it is no longer visible in the list of web API permissions.
NOTE

Removing a previously granted set of permissions yields errors in all solutions used in your tenant that rely on those permissions. Before removing the specific permission grant, you
should closely examine the impact that it will have on your tenant. If you accidentally removed a permission grant, you can restore it by issuing a new permission request with the
same resource and scope.
Revoking granted permissions doesn't invalidate previously issued access tokens. Instead, they remain valid until they expire.
To view all previously granted permissions, in the modern SharePoint admin center, in the left pane, choose API management. All granted permissions are displayed in the
Approved section.
Manage permissions with PowerShell
SharePoint tenant administrators can use the SharePoint Online Management Shell to manage permissions and permission requests in SharePoint Online.
To view all pending permission requests, use the Get-SPOTenantServicePrincipalPermissionRequests cmdlet. For each permission request, the cmdlet lists its ID (required to either
approve or deny the request), the resource for which permissions have been requested, and the requested permissions.
NOTE

SharePoint doesn't verify if the requested permissions have already been granted or not, so before approving or rejecting a permission request, check which permissions have already
been granted in your tenant.
To approve the specific permission request, use the Approve-SPOTenantServicePrincipalPermissionRequest -RequestId <Guid> cmdlet, specifying the ID of the permission request that
you want to approve.
NOTE

If you try to approve a request for a permission that has already been granted, you get an error.
To deny a permission request (if the requested permission has already been granted, or the request is against your organizational policies), use the
Deny-SPOTenantServicePrincipalPermissionRequest -RequestId <Guid> cmdlet, specifying the ID of the permission request that you want to deny.

NOTE

Denying a permission request issued by a SharePoint Framework application doesn't prevent that application from being deployed in the app catalog and installed on sites.
To view which permissions have been granted in your tenant, use the Get-SPOTenantServicePrincipalPermissionGrants cmdlet. For each grant, the cmdlet displays the following
information:
ClientId: The objectId of the service principal granted consent to impersonate the user when accessing the resource (represented by the resourceId).
ConsentType: Whether consent was provided by the administrator on behalf of the organization or whether consent was provided by an individual. The possible values are
"AllPrincipals" or "Principal".
ObjectId: The unique identifier for the permission grant.
Resource: The resource to which access has been granted.
ResourceId: The objectId of the resource service principal to which access has been granted.
Scope: The value of the scope claim that the resource application should expect in the OAuth 2.0 access token.
To revoke a previously granted permission, use the Revoke-SPOTenantServicePrincipalPermission -ObjectId <String> cmdlet. In the ObjectId parameter, you should specify the
objectId of the grant that you want to revoke, which you can obtain by using the Get-SPOTenantServicePrincipalPermissionGrants cmdlet.
NOTE

Revoking a permission doesn't trigger any changes to the app catalog or any of the deployed applications. The only consequence of revoking a permission is that any application used
in the tenant will not be able to connect to the resources for which the permission has been revoked.

Manage permissions using the Office 365 CLI


SharePoint tenant administrators can use the Office 365 CLI to manage permissions and permission requests in SharePoint Online.
To view all pending permission requests, use the spo serviceprincipal permissionrequest list command. For each permission request, the command lists its ID (required to either
approve or deny the request), the resource for which permissions have been requested, and the requested permissions.
NOTE

SharePoint doesn't verify if the requested permissions have already been granted or not, so before approving or rejecting a permission request, check which permissions have already
been granted in your tenant.
To approve a specific permission request, use the spo serviceprincipal permissionrequest approve command, specifying the ID of the permission request that you want to approve.
NOTE

If you try to approve a request for a permission that has already been granted, you get an error.
To deny a permission request (if the requested permission has already been granted, or the request is against your organizational policies), use the spo serviceprincipal
permissionrequest deny command, specifying the ID of the permission request that you want to deny.
NOTE

Denying a permission request issued by a SharePoint Framework application doesn't prevent that application from being deployed in the app catalog and installed on sites.
To view which permissions have been granted in your tenant, use the spo serviceprincipal grant list command. For each grant, the command displays the following information:
ObjectId: The unique identifier for the permission grant.
Resource: The resource to which access has been granted.
ResourceId: The objectId of the resource service principal to which access has been granted.
Scope: The value of the scope claim that the resource application should expect in the OAuth 2.0 access token.
To revoke a previously granted permission, use the spo serviceprincipal grant revoke command. In the grantId parameter, specify the objectId of the grant that you want to
revoke, which you can obtain by using the spo serviceprincipal grant list command.
NOTE

Revoking a permission doesn't trigger any changes to the app catalog or any of the deployed applications. The only consequence of revoking a permission is that any application used
in the tenant will not be able to connect to the resources for which the permission has been revoked.

Connect to Azure AD applications using the AadHttpClient


Starting from version 1.4.1, SharePoint Framework simplifies connecting to APIs secured with Azure AD. Using the new AadHttpClient, you can easily connect to APIs secured with Azure
AD without having to implement authentication and authorization yourself.
Internally, the AadHttpClient implements the Azure AD OAuth flow using ADAL JS by using the SharePoint Online Client Extensibility service principal to obtain a valid access token.
The SharePoint Online Client Extensibility service principal is provisioned by Microsoft and is available in the Azure AD of all Office 365 tenants.
1. To use the AadHttpClient in your SharePoint Framework solution, add the following import clause in your main web part file:

import { AadHttpClient, HttpClientResponse } from '@microsoft/sp-http';

2. Create a new instance of the AadHttpClient, passing the current service scope and the resource to which you want to connect as parameters:
export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {
public render(): void {
// ...

const contosoApiClient: AadHttpClient = new AadHttpClient(this.context.serviceScope, 'https://contoso.onmicrosoft.com/orders');


}

// ...
}

NOTE

Each instance of the AadHttpClient is linked to the specific resource, which is why you need to create a new instance of the client for each resource that you want to connect to.
3. After you instantiate the AadHttpClient for your resource, you can issue a web request to communicate with your API; in this example, the API returns a list of orders represented by
the custom Order interface defined elsewhere in the project:

export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {


public render(): void {
// ...

const contosoApiClient: AadHttpClient = new AadHttpClient(this.context.serviceScope, 'https://contoso.onmicrosoft.com/orders');


contosoApiClient
.get('https://contoso.azurewebsites.net/api/orders', AadHttpClient.configurations.v1)
.then((response: HttpClientResponse): Promise<Order[]> => {
return response.json();
})
.then((orders: Order[]): void => {
// process data
});
}

// ...
}

Considerations
Following are some considerations that you should take into account when working with web API permissions.

Request permissions via SharePoint Framework solutions


At this moment, it's only possible to request additional permissions through a SharePoint Framework solution. The request is initiated when the solution package (.sppkg) containing a
permissions request is deployed in the app catalog. After the request is initiated, it can be approved or denied by the tenant administrator.

Granted permissions apply to all solutions


Although permissions to Azure AD resources are being requested by a SharePoint Framework solution, once granted, they apply to the whole tenant and can be leveraged by any solution in
that tenant.

Removing solution doesn't revoke permissions


Removing the solution that initially requested the particular permission doesn't revoke the granted permission. Tenant administrators have to manually revoke permissions granted through
SharePoint Framework application requests.

Revoking previously granted permissions doesn't invalidate issued access tokens


Revoking previously granted permissions doesn't invalidate access tokens issued to users. Instead, these access tokens remain valid until they expire.

Permission request doesn't affect solution deployment


No matter if the administrator denies or approves permissions requested by the solution, the solution can be deployed and used on sites. When building solutions that require additional
permissions, you should never assume that the requested permissions have been granted.

Control the SharePoint Online Client service principal


All permissions granted through web API requests are stored with the SharePoint Online Client Extensibility Azure AD application. If tenant administrators don't want developers to use
the web API request model and the MSGraphClient and AadHttpClient in their solutions, they can disable the SharePoint Online Client Extensibility service principal through
PowerShell by using the Disable-SPOTenantServicePrincipal cmdlet.
The service principal can be re-enabled by using the Enable-SPOTenantServicePrincipal cmdlet. Alternatively, it's also possible to enable and disable the SharePoint Online Client
Extensibility service principal through the Office 365 CLI by using the spo serviceprincipal set command.

Access to the Microsoft Graph


Even if you don't explicitly grant access to the Microsoft Graph, solutions are able to request an access token for it. The SharePoint Online Client Extensibility service principal issues an
access token with the user_impersonation scope, which allows scripts to access basic information about the current user.
Consume enterprise APIs secured with Azure AD in SharePoint Framework
5/11/2018 • 11 minutes to read Edit Online

IM P O R T A N T

The AadHttpClient class is currently in preview and is subject to change. Do not use it in a production environment. Also note that the webApiPermissionRequests properties in
package-solution.json are not supported in production tenants.
This article illustrates how you would connect to an enterprise API secured with Azure Active Directory from a SharePoint Framework solution. It covers both creating and securing the API
as well as building the SharePoint Framework solution.

Create an enterprise API secured with Azure AD


Start with creating an enterprise API secured with Azure Active Directory. While there are no restrictions on how the API should be implemented from the SharePoint Framework point of
view, in this tutorial, you will build the API using Azure Functions and secure it using Azure App Service Authentication.

While your organization most likely already has specific APIs exposing their applications, this section is meant to give you a complete overview of the implementation and configuration
steps.

Create an Azure function


In the Azure portal, create a new Function App.

For more information on creating Function Apps in Azure see the Create a function app from the Azure portal help article.

In the Function App, you will create a new HTTP-triggered function. In this example, you will build the function using C#, but, in general, there is no restriction on which programming
language you must use.
In the Function App, press the Create new button:

Next, click the Custom function link to create a custom HTTP-triggered function:
From the list of templates, choose HTTP trigger:

In the New Function panel, choose C# as the language, specify the function name, set the Authorization level to Anonymous, and click the Create button:
Azure functions can be secured in a number of ways. Because you want to secure the function using Azure AD, rather than securing the function itself, you will secure the underlying
Function App. This is why, at this stage, you chose not to secure the function itself. Authentication settings applied to the Function App, apply to all functions inside that app.

Once the function is created, replace its contents with the following snippet:

using System.Net;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)


{
log.Info("C# HTTP trigger function processed a request.");

return req.CreateResponse(HttpStatusCode.OK, new List<object> {


new {
Id = 1,
OrderDate = new DateTime(2016, 1, 6),
Region = "east",
Rep = "Jones",
Item = "Pencil",
Units = 95,
UnitCost = 1.99,
Total = 189.05
},
new {
Id = 2,
OrderDate = new DateTime(2016, 1, 23),
Region = "central",
Rep = "Kivell",
Item = "Binder",
Units = 50,
UnitCost = 19.99,
Total = 999.50
},
new {
Id = 3,
OrderDate = new DateTime(2016, 2, 9),
Region = "central",
Rep = "Jardine",
Item = "Pencil",
Units = 36,
UnitCost = 4.99,
Total = 179.64
},
new {
Id = 4,
OrderDate = new DateTime(2016, 2, 26),
Region = "central",
Rep = "Gill",
Item = "Pen",
Units = 27,
UnitCost = 19.99,
Total = 539.73
},
new {
Id = 5,
OrderDate = new DateTime(2016, 3, 15),
Region = "west",
Rep = "Sorvino",
Item = "Pencil",
Units = 56,
UnitCost = 2.99,
Total = 167.44
}
});
}

Verify that the function is working correctly, by pressing the Save and run button:
If the function executed correctly, you will see a Status: 200 OK label and the list orders displayed in the test pane.

Secure the Azure function


Now that the Azure function is working, the next step is to secure it with Azure Active Directory so that you will need to sign in with your organizational account to access it.
On the Function App blade in the side panel select the function app:

In the top section, switch to the Platform features tab:


Next, from the Networking group, select the Authentication / Authorization link:

On the Authentication / Authorization blade, enable App Service Authentication by switching the App Service Authentication toggle button to On:

In the Action to take when request not authenticated drop down, change the value to Login with Azure Active Directory. This setting ensures that anonymous requests to the API are
not allowed:

Next, in the list of authentication providers, select Azure Active Directory:


In the Azure Active Directory Settings blade, set the Management mode option to Express. Set the second Management mode option to Create new AD App:

IM P O R T A N T

Before you continue, note the value in the Create App field. This value represents the name of the Azure AD application that you will use to secure the API, and which you will need later to
request permissions to access the API from the SharePoint Framework project.
Confirm your selection by pressing the OK button.
Back in the Authentication / Authorization blade, update the Function App's authentication and authorization settings by pressing the Save button:

Confirm that the API is correctly secured by opening a new browser window in private mode and navigating to the API. The URL for your Function App can be found in the Overview
section of the Function App blade. If the authentication settings have been applied correctly, you should be redirected to the Azure AD login page:
Get an Azure AD application ID
To be able to request an access token to connect to the API, you will need the application ID of the Azure AD application used to secure that API.
In the Function App, navigate to the Authentication settings. If the Authentication link is not available under the Configured features header, press the Refresh button next to the
Function App in the left panel:

From the list of authentication providers, select Azure Active Directory:


On the Azure Active Directory Settings blade, press the Manage Application button:

On the Azure AD application blade, copy the value of the Application ID property:

Enable CORS
The Function App will be called from JavaScript running on a SharePoint page. Because the API is hosted on a different domain than the SharePoint portal, cross-domain security constraints
will apply to the API call. By default, APIs implemented using Azure Function Apps cannot be called from other domains. You can change this by adjusting the Function App's CORS settings.
IM P O R T A N T

If you're authenticating with the API using the SharePoint Online cookie instead of OAuth, you cannot configure CORS settings through the Azure portal. For the authentication to work, you
have to clear all CORS settings in the Azure portal and specify them in your API instead.
In the Function App, switch to the Platform features tab.
From the API group, select the CORS link:

In the list of allowed origins, add the URL of your SharePoint tenant, eg. https://contoso.sharepoint.com :

Confirm your changes by pressing the Save button.

Consume the enterprise API secured with Azure AD from the SharePoint Framework
With the API configured and working, the next step is to build the SharePoint Framework solution that will consume the API.

Before you proceed, ensure that you have installed version 1.4.1 or higher of the SharePoint Framework Yeoman generator. If you have installed the generator globally, you can check the
installed version by executing in the command line: npm ls -g --depth=0 .

Create a new SharePoint Framework project


Next, you'll create a new SharePoint Framework project to consume the API.
In the command line create a new folder for your project:

md contoso-api

Change the working directory:

cd contoso-api
To create a new project, launch the SharePoint Framework Yeoman generator:

yo @microsoft/sharepoint

When prompted, use the following values:


contoso-api as the solution name
SharePoint Online only (latest) as the baseline packages
Use the current folder as the location to place files
Y as the choice for enabling tenant-wide deployment
WebPart as the type of component to create
Orders as the name of the web part to create
Shows recent orders as the web part description
No JavaScript framework as the framework to use

After the project is created, open it in a code editor. In this tutorial, you will use Visual Studio Code:

Request permissions to the enterprise API


By default, SharePoint Framework has no access to enterprise APIs even though they are registered in the same Azure Active Directory as Office 365. This is by design and allows
organizations to consciously choose which APIs should be exposed to scripts and client-side solutions deployed to SharePoint. To get access to your enterprise APIs, you need to issue a
permission request from the SharePoint Framework project that you're building.
In the code editor, open the config/package-solution.json file:

In the solution property, add a new property named webApiPermissionRequests with a reference to the Azure AD application used to secure your API:

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "contoso-api-client-side-solution",
"id": "8cbc01fb-bab6-48fc-afec-2c2053759771",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"webApiPermissionRequests": [
{
"resource": "contoso-api",
"scope": "user_impersonation"
}
]
},
"paths": {
"zippedPackage": "solution/contoso-api.sppkg"
}
}

The value of the resource property refers to either the name or the ID of the Azure AD application used to secure the API. Using the name is more readable and easier to maintain over time.
The value of the scope property specifies the permission scope that your solution needs in order to communicate with the API. In this tutorial, Azure AD is used only to secure the API, so
user_impersonation is the scope that you will use.

NOTE

If you want to connect to an enterprise API that has been created previously, contact your administrator to provide you with details for the Azure AD application used to secure it. You will
need information such as the application ID, permissions the application exposes, and the audience it's configured to.

Connect to the enterprise API


The last part left is to implement the actual connection to the enterprise API.
In the code editor, open the src\webparts\orders\OrdersWebPart.ts file:
In the top section of the file, reference the AadHttpClient and HttpClientResponse classes, by adding the following code snippet:

import { AadHttpClient, HttpClientResponse } from '@microsoft/sp-http';

To the OrdersWebPart class, add a new class variable named ordersClient :

export default class OrdersWebPart extends BaseClientSideWebPart<IOrdersWebPartProps> {


private ordersClient: AadHttpClient;

// shortened for brevity


}

Next, in the OrdersWebPart class, override the onInit method to create an instance of the AadHttpClient:

export default class OrdersWebPart extends BaseClientSideWebPart<IOrdersWebPartProps> {


private ordersClient: AadHttpClient;

protected onInit(): Promise<void> {


this.ordersClient = new AadHttpClient(this.context.serviceScope, '594e83da-9618-438f-a40a-4a977c03bc16');

return Promise.resolve();
}

// shortened for brevity


}

The GUID passed as the second parameter of the AadHttpClient constructor, is the application ID of the Azure AD application used to secure the enterprise API.
Finally, extend the render method to load and display orders retrieved from the enterprise API:
export default class OrdersWebPart extends BaseClientSideWebPart<IOrdersWebPartProps> {
private ordersClient: AadHttpClient;

protected onInit(): Promise<void> {


this.ordersClient = new AadHttpClient(this.context.serviceScope, '594e83da-9618-438f-a40a-4a977c03bc16');

return Promise.resolve();
}

public render(): void {


this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'orders');

this.ordersClient
.get('https://contoso-apis.azurewebsites.net/api/Orders', AadHttpClient.configurations.v1)
.then((res: HttpClientResponse): Promise<any> => {
return res.json();
})
.then((orders: any): void => {
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
this.domElement.innerHTML = `
<div class="${ styles.orders}">
<div class="${ styles.container}">
<div class="${ styles.row}">
<div class="${ styles.column}">
<span class="${ styles.title}">Orders</span>
<p class="${ styles.description}">
<ul>
${orders.map(o => `<li>${o.Rep} $${o.Total}</li>`).join('')}
</ul>
</p>
<a href="https://aka.ms/spfx" class="${ styles.button}">
<span class="${ styles.label}">Learn more</span>
</a>
</div>
</div>
</div>
</div>`;
}, (err: any): void => {
this.context.statusRenderer.renderError(this.domElement, err);
});
}

// shortened for brevity


}

Deploy the solution to the SharePoint app catalog


After completing the implementation of the SharePoint Framework solution, the next step is to deploy it to SharePoint.
First, build and package the project using the command line:

gulp bundle --ship && gulp package-solution --ship

Next, in file explorer, open the project folder and navigate to the sharepoint/solution folder:

In your web browser, navigate to the tenant app catalog in your Office 365 tenant:
Add the newly generated .sppkg file by dragging and dropping it from explorer to the tenant app catalog:

When prompted, select the Make this solution available to all sites in the organization checkbox. Also, take note of the remark that you should go to the Service Principal
Permissions Management Page to approve pending permission requests. Confirm the deployment by pressing the Deploy button:
Grant access to the enterprise API
In the web browser, navigate to the tenant admin site by choosing the Admin option in the Office 365 app launcher:

In the menu, from the Admin centers group choose SharePoint:


In the SharePoint admin center, navigate to the new SharePoint admin center preview using the Try the new SharePoint admin center preview link:

In the new admin center, from the menu, choose the API management option:
On the API management page, in the Pending approval group, select the newly added permission request to access the contoso-api API (Your API name will be displayed):

Next, from the toolbar, press the Approve or reject button:

In the side panel, grant the access to the API by pressing the Approve button:
Add the Orders web part to the page
To verify that everything is working as expected, add the previously created Orders web part to a page.
In the web browser, navigate to a site in your tenant. From the toolbar, select the Edit option:

In the canvas, select a section to add the web part to:


Select the + option to open the toolbox. In the search box type Orders to quickly find the Orders web part:

Select the Orders web part to add it to the page. You should see the list of orders retrieved from the enterprise API:

If you receive an error with the technical details of "Failed to open pop-up window", you have a pop-up blocker enabled. You will need to disable the browser's pop-up blocker for your
site in order to show the page correctly.
Consume multi-tenant enterprise APIs secured with Azure AD in SharePoint Framework
5/11/2018 • 13 minutes to read Edit Online

IM P O R T A N T

The AadHttpClient class is currently in preview and is subject to change. Do not use it in a production environment. Also note that the webApiPermissionRequests properties in
package-solution.json are not supported in production tenants.
This article illustrates how you would connect to a multi-tenant enterprise API secured with Azure Active Directory from a SharePoint Framework solution. It covers both creating and
securing the API as well building the SharePoint Framework solution.

Create a multi-tenant enterprise API secured with Azure AD


Start with creating a multi-tenant enterprise API secured with Azure Active Directory. While there are no restrictions how the API should be implemented from the SharePoint Framework
point of view, in this tutorial, you will build the API using Azure Functions and secure it using Azure App Service Authentication.

While your organization most likely already has specific APIs exposing their applications, this section is meant to give you a complete overview of the implementation and configuration
steps.

Create Azure function


In the Azure portal, create a new Function App.

For more information on creating Function Apps in Azure see the Create a function app from the Azure portal help article.

In the Function App, create new HTTP-triggered function. In this example, you will build it using C#, but there is no restriction with regards to which programming language you can use.
In the Function App, select the Create new button.

Next, select on the Custom function link, to create a custom HTTP-triggered function.
From the list of available function types, choose HTTP trigger.

In the settings of the function, choose C# as the language, specify the function name and set the Authorization level to Anonymous.
Azure functions can be secured in a number of ways. Because you want to secure the function using Azure AD, rather than securing the function itself, you will secure the underlying Function
App. This is why, at this stage, you set not to secure the function itself. Authentication settings applied to the Function App, apply to all functions inside that app.
To confirm your settings and create the function, select the Create button.
Once the function is created, replace its contents with the following snippet:

using System.Net;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)


{
log.Info("C# HTTP trigger function processed a request.");

return req.CreateResponse(HttpStatusCode.OK, new List<object> {


new {
Id = 1,
OrderDate = new DateTime(2016, 1, 6),
Region = "east",
Rep = "Jones",
Item = "Pencil",
Units = 95,
UnitCost = 1.99,
Total = 189.05
},
new {
Id = 2,
OrderDate = new DateTime(2016, 1, 23),
Region = "central",
Rep = "Kivell",
Item = "Binder",
Units = 50,
UnitCost = 19.99,
Total = 999.50
},
new {
Id = 3,
OrderDate = new DateTime(2016, 2, 9),
Region = "central",
Rep = "Jardine",
Item = "Pencil",
Units = 36,
UnitCost = 4.99,
Total = 179.64
},
new {
Id = 4,
OrderDate = new DateTime(2016, 2, 26),
Region = "central",
Rep = "Gill",
Item = "Pen",
Units = 27,
UnitCost = 19.99,
Total = 539.73
},
new {
Id = 5,
OrderDate = new DateTime(2016, 3, 15),
Region = "west",
Rep = "Sorvino",
Item = "Pencil",
Units = 56,
UnitCost = 2.99,
Total = 167.44
}
});
}
Verify, that the function is working correctly, by selecting the Save and run button.

If the function executed correctly, you should see a Status: 200 OK label and the list orders displayed in the test pane.

Secure Azure function


Now that the Azure function is working, the next step is for you to secure it with Azure Active Directory so that in order to access it, you need to sign in with your organizational account.
On the Function App blade, from the side panel, select the function app.

In the top section, switch to the Platform features tab.


Next, from the Networking group, select the Authentication / Authorization link.

On the Authentication / Authorization blade, enable App Service Authentication by switching the App Service Authentication toggle button to On.

In the Action to take when request not authenticated drop down, change the value to Login with Azure Active Directory.
This setting ensures that anonymous requests to the API are not allowed.
Next, in the list of authentication providers select Azure Active Directory.

On the Azure Active Directory Settings blade, for the first Management mode option, choose Express. For the second Management mode option, choose Create new AD App.

IM P O R T A N T

Before you continue, note the value in the Create App field. This value represents the name of the Azure AD application that you will use to secure the API, and which you will need later, to
request permissions to access the API from the SharePoint Framework project.
Confirm your selection, by selecting the OK button.
Update Function App authentication and authorization settings, by selecting the Save button.
Confirm, that the API is correctly secured, by opening a new browser window in private mode and navigating to the API. If the authentication settings have been applied correctly, you should
be redirected to the Azure AD login page.

Make the Azure AD application multi-tenant


By default, when you secure an Azure Function using an Azure AD application, that Azure Function can be used only by users from the same Azure AD as where the application is located. If
you would like to use the API in different tenants, you have to change the Azure AD application to multi-tenant.
Change the application to be multi-tenant
In the Function App, navigate to the Authentication settings.
From the list of authentication providers, select Azure Active Directory.

On the Azure Active Directory Settings blade, choose the Manage Application button.
On the Azure AD application blade, from the toolbar, select the Settings button.

On the Settings blade, from the General group, select the Properties option.

On the Properties blade, in the App ID URI field, change the ID of your Azure AD app, so that it begins with https://yourtenant.onmicrosoft.com, eg.
https://contoso.onmicrosoft.com/contoso-api . This change is required, because your Azure AD app will be used by other tenants, and it will be necessary to ensure its uniqueness across all
Azure Active Directories.
Next, switch the value of the Multi-tenanted field to Yes
Finally, confirm your changes by from the toolbar selecting the Save button.
Allows users from other Azure ADs to use your applications
Because you secured your API using the Azure AD express settings, only users from the same Azure AD, as where the application is located, are allowed to use it. Because you want the API
to be used by users from other tenants as well, you have to adjust the security settings.
Close all open blades, until you are back on the Authentication / Authorization blade. From the list of authentication providers, choose Azure Active Directory.

On the Azure Active Directory Settings blade, switch the value of the Management mode option to Advanced.
Next, clear the value in the Issuer Url field. This will allow users from other Azure Active Directories to authenticate against your API.

Before confirming your changes, copy the value from the Client ID field. You will need it when building your web part, to request an access token for the API.
Confirm your changes using the OK button.

Enable CORS
The Function App will be called from JavaScript running on a SharePoint page. Because the API is hosted on a different domain than the SharePoint portal, cross-domain security constraints
will apply to the API call. By default, APIs implemented using Azure Function Apps cannot be called from other domains. You can change it, by adjusting the Function App's CORS settings.
In the Function App, switch to the Platform features tab.
From the API group, select the CORS link.
To the list of allowed origins, add the URL of your SharePoint tenant, eg. https://contoso.sharepoint.com .

Confirm your changes using the Save button.

Consent the use of the API in your tenant


Before users in your tenant will be able to use the API from another tenant, the API has to be approved. The approval, also known as consent, can be done on two levels: user and admin
(organization). In this scenario, you will use the admin consent to approve the API for use by the whole organization.
NOTE

Usually, the site exposing the API takes your through the process of consenting the API in your tenant. In this example, you will perform the necessary steps manually to better understand
how the process works.
On the Function App blade, select your function.
To get the function's URL, from the toolbar, select the Get function URL option.

In the Get function URL dialog, copy the URL of the function using the Copy button.

In a new browser window, navigate to the function URL you have just copied. When prompted to sign in, use the admin account from the Office 365 tenant, where you want to use the API.
After signing in, you will be prompted to consent with the use of this API.
This is however the user consent. To switch to the admin consent and approve the API for use by the whole organization, append to the URL &prompt=admin_consent . Once again, you will be
prompted with a consent dialog, but notice, that this time, the dialog states that the app will have access to the specified resources for all users in your organization and that no one else will
be prompted.

Confirm that you want users in your organization to use the API, by selecting the Accept button.

Consume enterprise API secured with Azure AD from the SharePoint Framework
With the API configured and working, the next step is to build the SharePoint Framework solution that will consume this API.

Before you proceed, ensure that you have installed version 1.4.1 or higher of the SharePoint Framework Yeoman generator. If you have installed the generator globally, you can check the
installed version by executing in the command line: npm ls -g --depth=0 .

Create new SharePoint Framework project


Start with creating a new SharePoint Framework project. In the command line create new folder for your project:
md contoso-api

Change the working directory by executing in the command line:

cd contoso-api

To create new project, execute the SharePoint Framework Yeoman generator:

yo @microsoft/sharepoint

When prompted, use the following values:


contoso-api as the solution name
SharePoint Online only (latest) as the baseline packages
Use the current folder as the location to place files
Y as the choice for enabling tenant-wide deployment
WebPart as the type of component to create
Orders as the name of the web part to create
Shows recent orders as the web part description
No JavaScript framework as the framework to use

After the project is created, open it in the code editor. In this tutorial you will use Visual Studio Code.
Request permissions to the enterprise API
By default, SharePoint Framework has no access to enterprise APIs, even though they are registered in the same Azure Active Directory as Office 365. This is by design and allows
organizations to consciously choose which APIs should be exposed to scripts and client-side solutions deployed to SharePoint. To get access to your enterprise APIs, you need to issue a
permission request from the SharePoint Framework project that you're building.
In the code editor, open the config/package-solution.json file.

To the solution property, add a new section named webApiPermissionRequests with a reference to the Azure AD application used to secure your API:
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "contoso-api-client-side-solution",
"id": "8cbc01fb-bab6-48fc-afec-2c2053759771",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"webApiPermissionRequests": [
{
"resource": "contoso-api",
"scope": "user_impersonation"
}
]
},
"paths": {
"zippedPackage": "solution/contoso-api.sppkg"
}
}

The value of the resource property refers to either the name or the ID of the Azure AD application used to secure the API. Using the name is more readable and easier to maintain over time.
The value of the scope property specifies the permission scope that your solution needs in order to communicate with the API. In this tutorial, Azure AD is used only to secure the API, so
user_impersonation is the scope that you will use.

NOTE

If you want to connect to an enterprise API that has been created previously, contact your administrator to provide you with details for the Azure AD application used to secure it. You will
need information such as the application ID, permissions the application exposes and the audience it's configured to.

Connect to the enterprise API


The last part left is to implement the actual connection to the enterprise API.
In the code editor, open the src\webparts\orders\OrdersWebPart.ts file.

In the top section of the file, reference the AadHttpClient and HttpClientResponse classes, by adding the following code snippet:

import { AadHttpClient, HttpClientResponse } from '@microsoft/sp-http';

To the OrdersWebPart class, add a new class variable named ordersClient :

export default class OrdersWebPart extends BaseClientSideWebPart<IOrdersWebPartProps> {


private ordersClient: AadHttpClient;

// shortened for brevity


}

Next, in the OrdersWebPart class, override the onInit method to create an instance of the AadHttpClient:
export default class OrdersWebPart extends BaseClientSideWebPart<IOrdersWebPartProps> {
private ordersClient: AadHttpClient;

protected onInit(): Promise<void> {


this.ordersClient = new AadHttpClient(this.context.serviceScope, '594e83da-9618-438f-a40a-4a977c03bc16');

return Promise.resolve();
}

// shortened for brevity


}

The GUID passed as the second parameter of the AadHttpClient constructor, is the application ID of the Azure AD application used to secure the enterprise API.
Finally, extend the render method to load and display orders retrieved from the enterprise API:

export default class OrdersWebPart extends BaseClientSideWebPart<IOrdersWebPartProps> {


private ordersClient: AadHttpClient;

protected onInit(): Promise<void> {


this.ordersClient = new AadHttpClient(this.context.serviceScope, '594e83da-9618-438f-a40a-4a977c03bc16');

return Promise.resolve();
}

public render(): void {


this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'orders');

this.ordersClient
.get('https://contoso-apis.azurewebsites.net/api/Orders', AadHttpClient.configurations.v1)
.then((res: HttpClientResponse): Promise<any> => {
return res.json();
})
.then((orders: any): void => {
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
this.domElement.innerHTML = `
<div class="${ styles.orders}">
<div class="${ styles.container}">
<div class="${ styles.row}">
<div class="${ styles.column}">
<span class="${ styles.title}">Orders</span>
<p class="${ styles.description}">
<ul>
${orders.map(o => `<li>${o.Rep} $${o.Total}</li>`).join('')}
</ul>
</p>
<a href="https://aka.ms/spfx" class="${ styles.button}">
<span class="${ styles.label}">Learn more</span>
</a>
</div>
</div>
</div>
</div>`;
}, (err: any): void => {
this.context.statusRenderer.renderError(this.domElement, err);
});
}

// shortened for brevity


}

Deploy the solution to SharePoint app catalog


After completing the implementation of the SharePoint Framework solution, the next step is to deploy it to SharePoint.
First, build and package the project, by executing in the command line:

gulp bundle --ship && gulp package-solution --ship

Next, in the explorer, open the project folder and navigate to the sharepoint/solution folder.

In your web browser, navigate to the tenant app catalog in your Office 365 tenant.
Add the newly generated .sppkg file by dragging and dropping it from explorer to the tenant app catalog.

When prompted, select the Make this solution available to all sites in the organization checkbox. Also, take note of the remark, that you should go to the Service Principal
Permissions Management Page to approve pending permission requests. Confirm the deployment by selecting the Deploy button.
Grant access to the enterprise API
In the web browser, navigate to the tenant admin site by choosing from the Office 365 app launcher, the Admin option.

In the menu, from the Admin centers group, choose SharePoint.


In the SharePoint admin center, navigating to the new SharePoint admin center preview using the Try the new SharePoint admin center preview link.

In the new admin center, from the menu, choose the API management option.
On the API management page, in the Pending approval group, select the newly added permission request to access the contoso-api API.

Next, from the toolbar, select the Approve or reject option.

In the side panel, grant the access to the API by selecting the Approve button.
Add the Orders web part to the page
To verify that everything is working as expected, add the previously created Orders web part to the page.
In the web browser, navigate to a site in your tenant. From the toolbar, select the Edit option.

In the canvas, select a section to add the web part to.


Select the + option to open the toolbox. In the search box type Orders to quickly find the Orders web part.

Select the Orders web part to add it to the page. You should see the list of orders retrieved from the enterprise API.
Use the MSGraphClient to connect to Microsoft Graph
3/26/2018 • 2 minutes to read Edit Online

When building SharePoint Framework solutions, you can easily connect to the Microsoft Graph by using the MSGraphClient.
IM P O R T A N T

AadHttpClient and MSGraphClientclient objects are currently in preview and are subject to change. Do not use them in a production environment. Also note that the
webApiPermissionRequests properties in package-solution.json are not supported in production tenants.

MSGraphClient overview
MSGraphClient is a new HTTP client introduced in SharePoint Framework v1.4.1 that simplifies connecting to the Microsoft Graph inside SharePoint Framework solutions.
MSGraphClient wraps the existing Microsoft Graph JavaScript Client Library, offering developers the same capabilities as when using the client library in other client-side solutions.
While you could use the Microsoft Graph JavaScript Client Library in your solution directly, MSGraphClient handles authenticating against the Microsoft Graph for you, which allows you
to focus on building your solution.

Use the MSGraphClient in your solution


NOTE

The MSGraphClient is available only in projects built using SharePoint Framework v1.4.1 and later. While the MSGraphClient is explained in this article by using a client-side web part,
you can also use it in SharePoint Framework Extensions.
1. To use the MSGraphClient in your SharePoint Framework solution, add the following import clause in your main web part file:

import { MSGraphClient } from '@microsoft/sp-client-preview';

2. MSGraphClient is provided as a service, which you have to consume from the service scope to get a reference. To do that, in your code add:

export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {


public render(): void {
// ...

const client: MSGraphClient = this.context.serviceScope.consume(MSGraphClient.serviceKey);


}

// ...
}

3. After you have the reference to the MSGraphClient instance, start communicating with the Microsoft Graph by using its JavaScript Client Library syntax:

export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {


public render(): void {
// ...

const client: MSGraphClient = this.context.serviceScope.consume(MSGraphClient.serviceKey);


// get information about the current user from the Microsoft Graph
client
.api('/me')
.get((error, response: any, rawResponse?: any) => {
// handle the response
});
}

// ...
}

Use the Microsoft Graph TypeScript types


When working with the Microsoft Graph and TypeScript, you can use the Microsoft Graph TypeScript types to help you catch errors in your code faster. The Microsoft Graph TypeScript
types are provided as a separate package.
1. Install the Microsoft Graph TypeScript types:

npm install @microsoft/microsoft-graph-types --save-dev

2. After installing the package in your project, import it to your web part file:

import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';

3. Enter the objects retrieved from the Microsoft Graph, for example:

export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {


public render(): void {
// ...

const client: MSGraphClient = this.context.serviceScope.consume(MSGraphClient.serviceKey);


// get information about the current user from the Microsoft Graph
client
.api('/me')
.get((error, user: MicrosoftGraph.User, rawResponse?: any) => {
// handle the response
});
}

// ...
}
Available permission scopes
By default, the service principal has no explicit permissions granted to access the Microsoft Graph. However, if you request an access token for the Microsoft Graph, you get a token with the
user_impersonation permission scope that can be used for reading information about the users (that is, User.Read.All ).

Additional permission scopes can be requested by developers and granted by tenant administrators. For more information, see Connect to Azure AD-secured APIs in SharePoint Framework
solutions.
IM P O R T A N T

The behavior that uses user_impersonation is subject to change before general availability of this capability. We recommend that you not take dependency on these default permissions.

See also
Microsoft Graph
Microsoft Graph JavaScript Client Library samples
Consume the Microsoft Graph in the SharePoint Framework
6/5/2018 • 15 minutes to read Edit Online

IM P O R T A N T

AadHttpClient and MSGraphClientclient objects are currently in preview and are subject to change. Do not use them in a production environment. Also note that the
webApiPermissionRequests properties in package-solution.json are not supported in production tenants.
Consuming REST APIs secured with Azure Active Directory (Azure AD) and Open Authorization (OAuth 2.0) from within a SharePoint Framework client-side web part or extension is a
common enterprise-level business scenario.
You can use the SharePoint Framework (starting from v.1.4.1) to consume Microsoft Graph REST APIs, or any other REST API that's registered in Azure AD.
In this article, you'll learn how to create a SharePoint Framework solution that uses the Microsoft Graph API with a custom set of permissions. For a conceptual overview of this technology,
see Connect to Azure AD-secured APIs in SharePoint Framework solutions.
IM P O R T A N T

You can consume the Microsoft Graph API with versions of SharePoint Framework earlier than v.1.4.1, either via the native graphHttpClient, or via a manual ADAL JS implicit OAuth flow.
However, the former approach is bound to a predefined set of permissions, which presents some limitations, and the latter is complex from a development perspective. For details about how
to implement an implicit OAuth flow, see Connect to APIs secured with Azure Active Directory.

Solution overview
The steps in this article show you how to build a client-side web part that enables searching for users in the current tenant, as shown in the following screenshot. The search is based on
Microsoft Graph and requires at least the User.ReadBasic.All permission.

The client-side web part enables searching for users based on their name, and provides all the matching users through a DetailsList Office UI Fabric component. The web part has an option
in the property pane to choose how to access Microsoft Graph. In versions of the SharePoint Framework starting with v.1.4.1, you can access Microsoft Graph by using either the native
graph client (MSGraphClient), or the low-level type used to access any Azure AD-secured REST API (AadHttpClient).
NOTE

To get the source code for this solution, see the api-scopes GitHub repo.
If you're already familiar with how to create SharePoint Framework solutions, you can proceed to Configure the API permissions requests.

Create the initial solution


If you have an old version of the SharePoint Framework generator, you need to update it to version 1.4.1 or later. To do that, run the following command to globally install the latest version
of the package.

npm install -g @microsoft/generator-sharepoint

Next, create a new SharePoint Framework solution:


1. Create a folder in your file system. You will store the solution source code and move the current path into this folder.
2. Run the Yeoman generator to scaffold a new solution.

yo @microsoft/sharepoint

3. In your solution, do the following:


Provide a name for the solution (for example spfx-api-scopes-tutorial).
Target the solution for SharePoint Online only (latest).
Use the current folder.
Decide whether you want to globally deploy the solution to the target tenant.
Choose to create a web part.
Call the web part GraphConsumer.
Provide a description.
Choose to use React as the development framework.

4. Start Visual Studio Code (or your favorite code editor) within the context of the current folder.

code .

Configure the base web part elements


Next, configure the initial elements of the client-side web part.

Configure the custom properties


1. Create a new source code file under the src/webparts/graphConsumer/components folder of the solution. Call the new file ClientMode.ts and use it to declare a TypeScript enum
with the available options for the ClientMode property of the web part.

export enum ClientMode {


aad,
graph,
}

2. Open the GraphConsumerWebPart.ts file in the src/webparts/graphConsumer folder of the solution. Change the definition of the IGraphConsumerWebPartProps interface to
accept a value of type ClientMode.

export interface IGraphConsumerWebPartProps {


clientMode: ClientMode;
}

3. Update the getPropertyPaneConfiguration() method of the client-side web part to support the choice selection in the property pane. The following example shows the new
implementation of the method.

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneChoiceGroup('clientMode', {
label: strings.ClientModeLabel,
options: [
{ key: ClientMode.aad, text: "AadHttpClient"},
{ key: ClientMode.graph, text: "MSGraphClient"},
]
}),
]
}
]
}
]
};
}

4. In addition, you need to update the render method of the client-side web part to create a properly configured instance of the React component for rendering. The following code
shows the updated method definition.
public render(): void {
const element: React.ReactElement<IGraphConsumerProps > = React.createElement(
GraphConsumer,
{
clientMode: this.properties.clientMode,
context: this.context,
}
);

ReactDom.render(element, this.domElement);
}

5. For this code to work, you need to add some import statements at the beginning of the GraphConsumerWebPart.ts file, as shown in the following example. Note the import for the
PropertyPaneChoiceGroup control, as well as the import of the ClientMode enum.

import * as React from 'react';


import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneChoiceGroup
} from '@microsoft/sp-webpart-base';

import * as strings from 'GraphConsumerWebPartStrings';


import GraphConsumer from './components/GraphConsumer';
import { IGraphConsumerProps } from './components/IGraphConsumerProps';
import { ClientMode } from './components/ClientMode';

Update the resource strings


To compile the solution, you need to update the mystrings.d.ts file under the src/webparts/graphConsumer/loc folder of the solution.
1. Rewrite the interface that defines the resource strings with the following code.

declare interface IGraphConsumerWebPartStrings {


PropertyPaneDescription: string;
BasicGroupName: string;
ClientModeLabel: string;
SearchFor: string;
SearchForValidationErrorMessage: string;
}

2. Configure proper values for the newly created resource strings by updating the en-us.js file within the same folder.

define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ClientModeLabel": "Client Mode",
"SearchFor": "Search for",
"SearchForValidationErrorMessage": "Invalid value for 'Search for' field"
}
});

Update the style for the client-side web part


You also need to update the SCSS style file.
Open the GraphConsumer.module.scss under the src/webparts/graphConsumer/components folder of the solution. Add the following style classes, right after the .title class:

.form {
@include ms-font-l;
@include ms-fontColor-white;
}

label {
@include ms-fontColor-white;
}

Update the React component rendering the web part


Now you can update the GraphConsumer React component under the src/webparts/graphConsumer/components folder of the solution.
1. Update the IGraphConsumerProps.ts file to accept the custom properties required by the web part implementation. The following example shows the updated content of the
IGraphConsumerProps.ts file. Notice the import of the ClientMode enum definition, as well as the import of the WebPartContext type. You will use that later.

import { WebPartContext } from '@microsoft/sp-webpart-base';


import { ClientMode } from './ClientMode';

export interface IGraphConsumerProps {


clientMode: ClientMode;
context: WebPartContext;
}

2. Create a new interface to hold the React component state. Create a new file in the src/webparts/graphConsumer/components folder, and call it IGraphConsumerState.ts. The following
is the interface definition.
import { IUserItem } from './IUserItem';

export interface IGraphConsumerState {


users: Array<IUserItem>;
searchFor: string;
}

3. Define the IUserItem interface (within a file called IUserItem.ts stored in the src/webparts/graphConsumer/components folder). That interface is imported in the state file. The
interface is used to define the outline of the users retrieved from the current tenant and bound to the DetailsList in the UI.

export interface IUserItem {


displayName: string;
mail: string;
userPrincipalName: string;
}

4. Update the GraphConsumer.tsx file. First, add some import statements to import the types you defined earlier. Notice the import for IGraphConsumerProps,
IGraphConsumerState, ClientMode, and IUserItem. There are also some imports for the Office UI Fabric components used to render the UI of the React component.

import * as React from 'react';


import styles from './GraphConsumer.module.scss';
import * as strings from 'GraphConsumerWebPartStrings';
import { IGraphConsumerProps } from './IGraphConsumerProps';
import { IGraphConsumerState } from './IGraphConsumerState';
import { ClientMode } from './ClientMode';
import { IUserItem } from './IUserItem';
import { escape } from '@microsoft/sp-lodash-subset';

import {
autobind,
PrimaryButton,
TextField,
Label,
DetailsList,
DetailsListLayoutMode,
CheckboxVisibility,
SelectionMode
} from 'office-ui-fabric-react';

import { AadHttpClient } from "@microsoft/sp-http";


import { MSGraphClient } from "@microsoft/sp-client-preview";

5. After the imports, define the outline of the columns for the DetailsList component of Office UI Fabric.

// Configure the columns for the DetailsList component


let _usersListColumns = [
{
key: 'displayName',
name: 'Display name',
fieldName: 'displayName',
minWidth: 50,
maxWidth: 100,
isResizable: true
},
{
key: 'mail',
name: 'Mail',
fieldName: 'mail',
minWidth: 50,
maxWidth: 100,
isResizable: true
},
{
key: 'userPrincipalName',
name: 'User Principal Name',
fieldName: 'userPrincipalName',
minWidth: 100,
maxWidth: 200,
isResizable: true
},
];

This array is used in the settings of the DetailsList component, as you can see in the render() method of the React component.
6. Replace this component with the following code.
public render(): React.ReactElement<IGraphConsumerProps> {
return (
<div className={ styles.graphConsumer }>
<div className={ styles.container }>
<div className={ styles.row }>
<div className={ styles.column }>
<span className={ styles.title }>Search for a user!</span>
<p className={ styles.form }>
<TextField
label={ strings.SearchFor }
required={ true }
value={ this.state.searchFor }
onChanged={ this._onSearchForChanged }
onGetErrorMessage={ this._getSearchForErrorMessage }
/>
</p>
<p className={ styles.form }>
<PrimaryButton
text='Search'
title='Search'
onClick={ this._search }
/>
</p>
{
(this.state.users != null && this.state.users.length > 0) ?
<p className={ styles.form }>
<DetailsList
items={ this.state.users }
columns={ _usersListColumns }
setKey='set'
checkboxVisibility={ CheckboxVisibility.hidden }
selectionMode={ SelectionMode.none }
layoutMode={ DetailsListLayoutMode.fixedColumns }
compact={ true }
/>
</p>
: null
}
</div>
</div>
</div>
</div>
);
}

7. Update the React component type declaration and add a constructor, as shown in the following example.

export default class GraphConsumer extends React.Component<IGraphConsumerProps, IGraphConsumerState> {

constructor(props: IGraphConsumerProps, state: IGraphConsumerState) {


super(props);

// Initialize the state of the component


this.state = {
users: [],
searchFor: ""
};
}

There are some validation rules and handling events for the TextField component to collect the search criteria. The following are the method implementations.

@autobind
private _onSearchForChanged(newValue: string): void {

// Update the component state accordingly to the current user's input


this.setState({
searchFor: newValue,
});
}

private _getSearchForErrorMessage(value: string): string {


// The search for text cannot contain spaces
return (value == null || value.length == 0 || value.indexOf(" ") < 0)
? ''
: `${strings.SearchForValidationErrorMessage}`;
}

The PrimaryButton fires a _search() function, which determines what client technology to use to consume Microsoft Graph.

@autobind
private _search(): void {

console.log(this.props.clientMode);

// Based on the clientMode value search users


switch (this.props.clientMode)
{
case ClientMode.aad:
this._searchWithAad();
break;
case ClientMode.graph:
this._searchWithGraph();
break;
}
}
The DetailsList component instance is rendered in the render() method, in case there are items in the users property of the component's state.

Configure the API permissions requests


To consume Microsoft Graph or any other third-party REST API, you need to explicitly declare the permission requirements from an OAuth perspective in the manifest of your solution.
In the SharePoint Framework v.1.4.1 or later, you can do that by configuring the webApiPermissionRequests property in the package-solution.json under the config folder of the solution.
The following example shows an excerpt of that file for the current solution.
Copy the declaration of the webApiPermissionRequests property.

{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "spfx-api-scopes-tutorial-client-side-solution",
"id": "841cd609-d821-468d-a6e4-2d207b966cd8",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "User.ReadBasic.All"
}
]
},
"paths": {
"zippedPackage": "solution/spfx-api-scopes-tutorial.sppkg"
}
}

Notice the webApiPermissionRequests, which is an array of webApiPermissionRequest items. Each item defines the resource and the scope of the permission request.
The resource can be the name or the ObjectId (in Azure AD) of the resource for which you want to configure the permission request. For Microsoft Graph, the name is Microsoft Graph. The
ObjectId is not unique and varies on a per tenant basis.
The scope can be the name of the permission, or the unique ID of that permission. You can get the permission name from the API documentation. You can get the permission ID from the
API manifest file.
NOTE

For a list of the permissions that are available in Microsoft Graph, see Microsoft Graph permissions reference.
By default, the service principal has no explicit permissions granted to access Microsoft Graph. However, if you request an access token for Microsoft Graph, you get a token with the
user_impersonation permission that you can use to read information about the users (User.Read.All). You can request additional permissions to be granted by tenant administrators. For
more information, see Connect to Azure AD-secured APIs in SharePoint Framework solutions.
The User.ReadBasic.All permission is sufficient for searching for users and getting their displayName, mail, and userPrincipalName.
When you package and deploy your solution, you (or an admin) will have to grant the requested permissions to your solution. For details, see Deploy the solution and grant permissions.

Consume Microsoft Graph


You can now implement the methods to consume the Microsoft Graph. You have two options:
Use the AadHttpClient client object
Use the MSGraphClient client object
The AadHttpClient client object is useful for consuming any REST API. You can use it to consume Microsoft Graph or any other third-party (or first-party) REST API.
The MSGraphClient client object can consume the Microsoft Graph only. Internally it uses the AadHttpClient client object and supports the fluent syntax of the Microsoft Graph SDK.

Using AadHttpClient
To consume any REST API using the AadHttpClient client object, create a new instance of the AadHttpClient type, and provide the serviceScope of the current context and the URI of the
target service.
The object created provides methods to make the following requests:
get: makes an HTTP GET request
post: makes an HTTP POST request
fetch: makes any other kind of HTTP request, based on the HttpClientConfiguration and IHttpClientOptions arguments provided.
Because all these methods support the asynchronous development model of JavaScript/TypeScript, you can handle their result with promises.
The following example shows the _searchWithAad() method of the sample solution.
private _searchWithAad(): void {

// Log the current operation


console.log("Using _searchWithAad() method");

// Using Graph here, but any 1st or 3rd party REST API that requires Azure AD auth can be used here.
const aadClient: AadHttpClient = new AadHttpClient(
this.props.context.serviceScope,
"https://graph.microsoft.com"
);

// Search for the users with givenName, surname, or displayName equal to the searchFor value
aadClient
.get(
`https://graph.microsoft.com/v1.0/users?$select=displayName,mail,userPrincipalName&$filter=(givenName%20eq%20'${escape(this.state.searchFor)}')%20or%20(surname%20eq%20'${escape(this.state
AadHttpClient.configurations.v1
)
.then(response => {
return response.json();
})
.then(json => {

// Prepare the output array


var users: Array<IUserItem> = new Array<IUserItem>();

// Log the result in the console for testing purposes


console.log(json);

// Map the JSON response to the output array


json.value.map((item: any) => {
users.push( {
displayName: item.displayName,
mail: item.mail,
userPrincipalName: item.userPrincipalName,
});
});

// Update the component state accordingly to the result


this.setState(
{
users: users,
}
);
})
.catch(error => {
console.error(error);
});
}

The get() method gets the URL of the OData request as the input argument. A successful request returns a JSON object with the response.

Using MSGraphClient
If you are targeting Microsoft Graph, you can use the MSGraphClient client object, which provides a more fluent syntax.
The following example shows the implementation of the _searchWithGraph() method of the sample solution.

private _searchWithGraph(): void {

// Log the current operation


console.log("Using _searchWithGraph() method");

const graphClient: MSGraphClient = this.props.context.serviceScope.consume(


MSGraphClient.serviceKey
);

// From https://github.com/microsoftgraph/msgraph-sdk-javascript sample


graphClient
.api("users")
.version("v1.0")
.select("displayName,mail,userPrincipalName")
.filter(`(givenName eq '${escape(this.state.searchFor)}') or (surname eq '${escape(this.state.searchFor)}') or (displayName eq '${escape(this.state.searchFor)}')`)
.get((err, res) => {

if (err) {
console.error(err);
return;
}

// Prepare the output array


var users: Array<IUserItem> = new Array<IUserItem>();

// Map the JSON response to the output array


res.value.map((item: any) => {
users.push( {
displayName: item.displayName,
mail: item.mail,
userPrincipalName: item.userPrincipalName,
});
});

// Update the component state accordingly to the result


this.setState(
{
users: users,
}
);
});
}
You create an instance of the MSGraphClient type by providing its service key to the consume() method of the current context's serviceScope.
You then use the fluent API of the Microsoft Graph SDK to define the OData query that runs against the target Microsoft Graph endpoint.
The result is a JSON response that you have to decode and map to the typed result.
NOTE

You can use a fully typed approach by using the Microsoft Graph TypeScript types.

Deploy the solution and grant permissions


You're now ready to build, bundle, package, and deploy the solution.
1. Run the gulp commands to verify that the solution builds correctly.

gulp build

2. Use the following command to bundle and package the solution.

gulp bundle
gulp package-solution

3. Browse to the app catalog of your target tenant and upload the solution package. You can find the solution package under the sharepoint/solution folder of your solution. It is the
.sppkg file. After you upload the solution package, the app catalog prompts you with a dialog box, similar to the one shown in the following screenshot.

A message in the lower part of the screen tells you that the solution package requires permissions approval. This is because of the webApiPermissionRequests property in the
package-solution.json file.
4. Open the SharePoint Admin Center of your tenant, and in the upper-right corner of the screen, choose Try the new SharePoint admin center.

5. In the new Admin Center, in the left quick launch menu, choose the WebApiPermission management menu item (API management). You will see a page similar to the following.
NOTE

Asterisks in the UI of the new Admin Center indicate that the features are in preview.
Using this page, you (or any other admin of your SharePoint Online tenant) can approve or deny any pending permission request. Note that you don't see which solution package is
requesting which permission because the permissions are defined at the tenant level and for a unique application.
NOTE

For more information about how the tenant-level permission scopes work internally, see the articles in the See also section.
6. Choose the permission that you requested in the package-solution.json file of your solution, choose Approve or reject access, and then choose Approve. The following screenshot
shows the panel in the Admin UI.

7. You can also select the pending approval permission item, and choose Approve or reject on the toolbar.
And you're now ready to go.
W A R N IN G

If you are getting an unexpected exception when trying to approve the permission ( [HTTP]:400 - [CorrelationId] ), update the resource attribute in your package-solution.json to use the
value Microsoft.Azure.AgregatorService rather than Microsoft Graph , which was instructed earlier in this tutorial. Reject the existing request and update the solution package in the app
catalog with the update value.

Test the solution


1. Run your solution by using the following gulp command.

gulp serve --nobrowser

2. Open the browser and go to the following URL to go to the SharePoint Framework Workbench page:

https://<your-tenant>.sharepoint.com/_layouts/15/Workbench.aspx

3. Add the GraphConsumer client-side web part, configure the Client Mode, and search for users.
When you make your first request, you will see a pop-up window appear and disappear. That's the sign-in window used by ADAL JS, which is used internally by the SharePoint
Framework to get the access token from Azure AD by using an OAuth implicit flow.
And that's it! Now you can build enterprise-level solutions that use Azure AD-secured REST APIs.

See also
Connect to Azure AD-secured APIs in SharePoint Framework solutions
Use the MSGraphClient to connect to Microsoft Graph
Complete source code from this tutorial
Overview of the GraphHttpClient class (deprecated)
5/26/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The GraphHttpClient has been deprecated and should no longer be used. It has been replaced with MSGraphClient
You can use Microsoft Graph to build powerful solutions that access data from Office 365 and other Microsoft services. To connect SharePoint Framework (SPFx) solutions to Microsoft
Graph, you have to register an Azure Active Directory (Azure AD) application and complete the authorization flow. To make this easier, you can use the SPFx GraphHttpClient class to call
Microsoft Graph directly, without any additional setup.

What is the GraphHttpClient class?


The GraphHttpClient class is included as part of the SharePoint Framework. It works in a similar way to the HttpClient that you can use to communicate with third-party APIs. The
GraphHttpClient class automatically ensures that your request to Microsoft Graph has a valid bearer access token and the required headers.
When you issue a GET or a POST request, GraphHttpClient verifies that it has a valid access token, and if it doesn't, it automatically retrieves one from an internal API and stores it for
subsequent requests.
The following example shows a request to Microsoft Graph that uses the GraphHttpClient class.

// ...
import { GraphHttpClient, GraphHttpClientResponse } from '@microsoft/sp-http';

export default class MyApplicationCustomizer


extends BaseApplicationCustomizer<IMyApplicationCustomizerProperties> {

// ...

@override
public onRender(): void {
this.context.graphHttpClient.get("v1.0/groups?$select=displayName", GraphHttpClient.configurations.v1)
.then((response: GraphHttpClientResponse): Promise<any> => {
return response.json();
})
.then((data: any): void => {
// ...
});
}
}

To make a request to Microsoft Graph:


1. Import the GraphHttpClient and GraphHttpClientResponse modules from the @microsoft/sp-http package.
2. Use the instance of GraphHttpClient that's available on the this.context.graphHttpClient property to issue a GET or POST request to Microsoft Graph.
3. As parameters, specify the Microsoft Graph API that you want to call (start with the API version without a leading / - slash), followed by the GraphHttpClient configuration.
4. Optionally, you can specify additional request headers that will be merged with the default headers set by GraphHttpClient ( 'Accept': 'application/json' ,
'Authorization': 'Bearer [token]' and 'Content-Type': 'application/json; charset=utf-8' ).

Considerations for using the GraphHttpClient class


The GraphHttpClient class provides a convenient way to communicate with Microsoft Graph because it abstracts the authorization flow and management of access tokens. Because
GraphHttpClient is currently in developer preview, there are some considerations that you should take into account before using it.

Use for Microsoft Graph access only


Use the GraphHttpClient class only to access Microsoft Graph. The URL specified in the request must begin with the version of the Microsoft Graph API (either v1.0 or beta), followed by
the API operation. Any other URL returns an error.

Permissions
The GraphHttpClient uses the Office 365 SharePoint Online Azure AD application to retrieve a valid access token to Microsoft Graph on behalf of the current user. The retrieved access token
contains two permissions:
Read and write all groups (preview) ( Group.ReadWrite.All )
Read all usage reports ( Reports.Read.All )
These are the only permissions that are available when you use GraphHttpClient. If you need other permissions for your solution, you can use ADAL JS with implicit OAuth flow instead.

Tokens are retrieved using an internal API


To acquire a valid access token, GraphHttpClient issues a web request to the /_api/SP.OAuth.Token/Acquire endpoint. This API is intended for internal use. You should not communicate
with it directly in your solutions.

See also
Use GraphHttpClient to call Microsoft Graph
Application Customizer GraphClient from Modern Teamsite sample.
Microsoft Graph Dev Center
SharePoint Framework Overview
Use GraphHttpClient to call Microsoft Graph
5/3/2018 • 8 minutes to read Edit Online

IM P O R T A N T

The GraphHttpClient has been deprecated and should no longer be used. It has been replaced with MSGraphClient
Use the GraphHttpClient class to make calls to the Microsoft Graph REST API. You can make GET, POST, and PATCH requests by using the get(), post(), and fetch() methods. This article
shows how to build a web part that uses GraphHttpClient, but you can use GraphHttpClient in any SharePoint Framework client code.

Retrieve Office 365 groups using a GET call


You can use the get() method to make a REST call to Microsoft Graph. This example shows you how to retrieve a list of Office 365 groups.

Create a new web part project


1. Create a new project directory in your favorite location.

mkdir hellograph-webpart

2. Go to the project directory.

cd hellograph-webpart

3. Create a new web part by running the Yeoman SharePoint generator.

yo @microsoft/sharepoint

4. When prompted:
Enter a solution name of hellograph-webpart.
Select Use the current folder for where to place the files.
Enter y when prompted if you want to allow the tenant admin to deploy the solution to all sites immediately, without running any feature deployment or adding apps in sites.
Select Web Part as the type of client-side component to create.
Enter HelloGraph as your web part name.
Enter Calls the Microsoft Graph Groups API as the web part description.
Accept the default No javascript web framework as the framework, and select Enter.

5. The Yeoman generator builds the web part. When the scaffolding is finished, open your project folder in your code editor. This article uses Visual Studio Code in the steps and
screenshots, but you can use any editor that you prefer.
6. Run the gulp serve command and confirm that it runs in the local workbench correctly.

gulp serve

Add a button and placeholder for results


Next, you'll modify the HTML to provide a button to retrieve Office 365 groups. The HTML also needs a placeholder to display the groups.
1. In your code editor, open the /src/webparts/helloGraph/HelloGraphWebPart.ts file.
2. Modify the render() method so that it contains a button and a div where the code lists the Office 365 groups after they are retrieved.
Your code should look like the following TypeScript:
public render(): void {
this.domElement.innerHTML = `
<div class="${styles.helloGraph}">
<div class="${styles.container}">
<div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
<div class="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span class="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
<p class="ms-font-l ms-fontColor-white">Customize SharePoint experiences using web parts.</p>
<p class="ms-font-l ms-fontColor-white">${escape(this.properties.description)}</p>
<a href="https://aka.ms/spfx" class="${styles.button}">
<span class="${styles.label}">Learn more</span>
</a>
<p>
<input id="readGroups" type="button" value="Read Groups"/>
</p>
<div id="spTableContainer" ></div>
</div>
</div>
</div>
</div>`;
this.domElement.querySelector('#readGroups').addEventListener('click',() => {this._readGroups();});
}

You'll define the _readGroups() method later.


3. Define an interface to represent each Office 365 group. Add the following code just before the HelloGraphWebPart class but after the imports.

export interface IOffice365Group {


// Microsoft Graph has more group properties.
displayName: string;
mail: string;
description: string;
}

Use the GraphHttpClient.get method to retrieve Office 365 groups


Next, you'll call the GraphHttpClient.get() method to make a REST call to Microsoft Graph to retrieve a list of Office 365 groups.
1. Import the GraphHttpClient class and related types by adding the following import statement near the top of the HelloGraphWebPart.ts file.

import { GraphHttpClient, HttpClientResponse, IGraphHttpClientOptions } from '@microsoft/sp-http';

2. Create the _readGroups() method by adding the following code to the HelloGraphWebPart class.

protected _readGroups(){
// Query for all groups on the tenant using Microsoft Graph.
this.context.graphHttpClient.get(`v1.0/groups?$orderby=displayName`, GraphHttpClient.configurations.v1).then((response: HttpClientResponse) => {
if (response.ok) {
return response.json();
} else {
console.warn(response.statusText);
}
}).then((result: any) => {
// Transfer result values to the group variable
this._renderTable(result.value);
});
}

In the previous code, the context property has the GraphHttpClient instance. When you call the get() method, a REST call is made to Microsoft Graph that passes the specified URL. In
this case, the URL is v1.0/groups?orderby=displayName. This issues a GET request, and Microsoft Graph returns all Office 365 groups in the tenant in order by display name.
You can issue any GET request by using this technique and entering the correct URL values. To find the URL values, see the Microsoft Graph documentation. For example, you can use
the URL specified in the Groups GET request topic to get groups.
The get() method returns an HttpClientResponse, which you can use to determine whether the call was successful. The returned JSON is in the result.value. Because you expect
multiple groups to be returned, you pass the value to a _renderTable() method, which builds a table of rows for each group.
3. Create a _renderTable() method to render the returned groups in a table where each row represents a group. Add the following method to the HelloGraphWebPart class.

protected _renderTable(items: IOffice365Group[]): void {


let html: string = '';
if (items.length<=0){
html=`<p>There are no groups to list...</p>`;
}
else {
html += `
<table><tr>
<th>Display Name</th>
<th>Mail</th>
<th>Description</th></tr>`;
items.forEach((item: IOffice365Group) => {
html += `
<tr>
<td>${item.displayName}</td>
<td>${item.mail}</td>
<td>${item.description}</td>
</tr>`;
});
html += `</table>`;
}
const tableContainer: Element = this.domElement.querySelector('#spTableContainer');
tableContainer.innerHTML = html;
return;
}
Run the web part to call Microsoft Graph
The code needs to call the GraphHttpClient application that runs on SharePoint, so you can't run it on the local workbench. You have to package and deploy it to SharePoint.
1. Use gulp to package your solution.

gulp package-solution

2. Deploy the solution to your SharePoint tenant:


Go to your site's app catalog.
Upload or drag and drop the hellograph-webpart.sppkg to the app catalog.
When prompted, if you trust the hellograph-webpart-client-side-solution, select Make this solution available to all sites in the organization, and select Deploy.
3. Use gulp serve to host the web part.

gulp serve --nobrowser

4. Add the web part to a webpage, or use the SharePoint Workbench.


You should see the following on your page.

When you select Read Groups, you see a list of all the Office 365 groups on your tenant. If no groups are listed, you'll just see a message that indicates that there were no groups. You
will create a new group next.

Create a new Office 365 group using a POST call


You can issue POST calls to the Microsoft Graph API by using the GraphHttpClient.post() method. You'll use the post() method to create a new Office 365 group.

Add a button and placeholder for results


Again, you need to modify the HTML to add a button that creates a new group.
1. In your code editor, open the /src/webparts/helloGraph/HelloGraphWebPart.ts file.
2. Modify the render() method so that it contains a button and a div that indicates whether the creation was successful.
Your code should look like the following TypeScript:

public render(): void {


this.domElement.innerHTML = `
<div class="${styles.helloGraph}">
<div class="${styles.container}">
<div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
<div class="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span class="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
<p class="ms-font-l ms-fontColor-white">Customize SharePoint experiences using web parts.</p>
<p class="ms-font-l ms-fontColor-white">${escape(this.properties.description)}</p>
<a href="https://aka.ms/spfx" class="${styles.button}">
<span class="${styles.label}">Learn more</span>
</a>
<p>
<input id="readGroups" type="button" value="Read Groups"/>
<input id="createGroup" type="button" value="Create New Group"/>
</p>
<div id="spCreateGroupResults" ></div>
<div id="spTableContainer" ></div>
</div>
</div>
</div>
</div>`;
this.domElement.querySelector('#createGroup').addEventListener('click',() => {this._createGroup();});
this.domElement.querySelector('#readGroups').addEventListener('click',() => {this._readGroups();});
}

3. Add the _createGroup() method to call the Microsoft Graph API and create a new group.
protected _createGroup(){
// Use Microsoft Graph to create a sample group.
this.context.graphHttpClient.post(`v1.0/groups`,GraphHttpClient.configurations.v1,{
body: JSON.stringify({"description": "Self help community for library",
"displayName": "Library Assist",
"groupTypes": [
"Unified"
],
"mailEnabled": true,
"mailNickname": "library",
"securityEnabled": false
})
}).then((response: HttpClientResponse) => {
const resultContainer: Element = this.domElement.querySelector('#spCreateGroupResults');
if (response.ok) {
resultContainer.innerHTML = `<p>Sample group created</p>`;
} else {
resultContainer.innerHTML = `<p>Could not create group see console for details</p>`;
console.warn(response.status);
}
});
}

The previous code creates a simple group by using the code example from the Microsoft Graph Create group article.
The post() issues a POST REST API call to the v1.0/groups URL. The third parameter is an IGraphHttpClientOptions value in which the JSON body is specified to describe the
new group. The HttpClientResponse is used to determine whether the call was successful, and to display an appropriate result.
You can issue a POST call from the Microsoft Graph documentation by using this pattern and specifying the JSON in the body.

Run the web part to create a new group


1. Use gulp to package your solution.

gulp package-solution

2. Deploy the solution to your SharePoint tenant:


Go to your site's app catalog.
Upload or drag and drop the hellograph-webpart.sppkg to the app catalog.
Because your solution is already registered, you are prompted as to whether you want to replace it. Select Replace it.
When prompted as to whether you trust the solution, select Deploy.
3. Use gulp serve to host the web part.

gulp serve --nobrowser

4. Add the web part to a webpage, or use the SharePoint Workbench.


You should see the following on your page.

5. When you select Create New Group, the code creates a new Office 365 group.
NOTE

If you try to create the same group again, the code returns an error because the group already exists. The error is logged to the console, which you can view in the browser's developer
mode.

Update a group using a PATCH call


By now you should understand the pattern. If you need to call a Microsoft Graph REST API, use the get() or post() methods along with the URL for your request. The last method to show is
the fetch() method. This method allows you to issue a PATCH request to Microsoft Graph to update a resource.
The following code shows how to call the fetch() method to update an existing group.
this.context.graphHttpClient.fetch(`v1.0/groups/2dfead70-21e4-4f30-bb2b-94b1bbdefdfa`,GraphHttpClient.configurations.v1,{
method: "PATCH",
body: JSON.stringify(
{
"description": "This is the new description",
"displayName": "testtest"
})
}).then((response: HttpClientResponse) => {
const resultContainer: Element = this.domElement.querySelector('#spUpdateGroupResults');
if (response.ok) {
resultContainer.innerHTML = `<p>Group updated</p>`;
} else {
resultContainer.innerHTML = `<p>Could not update group see console for details</p>`;
console.warn(response.status);
}
});

The ID of the group is specified in the URL. Get the ID by using a GET call first. The method parameter is set to PATCH. The body specifies which group properties to modify.

See also
Overview of the GraphHttpClient class
SharePoint solution packaging
3/26/2018 • 3 minutes to read Edit Online

The package-solution gulp task looks at /config/package-solution.json for various configuration details, including some generic filepaths, as well as defining the relationship between
components (WebParts and Applications) in a package.
The schema for the configuration file is as follows:

interface IPackageSolutionTaskConfig {
paths?: {
packageDir?: string;
debugDir?: string;
zippedPackage?: string;
featureXmlDir?: string;
manifestsMatch?: string;
manifestDir?: string;
sharepointAssetDir?: string;
};
solution?: ISolution;
}

Each package configuration file has some optional settings to override the places where the task looks for various source files and manifests, as well as defining the location to write the
package. Additionally, it has a required solution definition, which instructs the packager on the relationships of various components.

Solution definition (ISolution)


interface ISolution {
name: string;
id: string;
title?: string;
supportedLocales?: string[];
version?: string;
features?: IFeature[];
iconPath?: string;
skipFeatureDeployment?: boolean;
}

Each solution file must have a name that identifies the package in the SharePoint UI. Additionally, each package must contain a globally unique identifier (id), which is used internally by
SharePoint. Optionally, you may also specify a version number in the format "X.X.X.X", which is used to identify various versions of the package when upgrading.
The solution definition also optionally contains a list of SharePoint Feature definitions.
NOTE

If this is omitted or empty, the task creates a single Feature for every component (a 1:1 mapping).

Feature definition (IFeature)


interface IFeature {
title: string;
description: string;
id: string;
version?: string;
componentIds?: string[];
components: IComponent[];
assets: ISharepointAssets<string>;
}

It's important to note that this is a definition for creating a SharePoint feature, and that some of these options are exposed in the UI. Similarly to the solution, each feature has a mandatory
title, description, id, and version number (in the X.X.X.X format). Note that the feature id should also be a globally unique identifier.
Each feature can also contain any number of components that are activated when the feature is activated. This is defined via a list of componentIds, which are globally unique identifiers that
must match the ID in the component's manifest file. If this list is undefined or empty, the packager includes every component in the feature.

File paths
interface IPackageSolutionTaskConfig {
paths?: {
packageDir?: string;
debugDir?: string;
zippedPackage?: string;
featureXmlDir?: string;
manifestsMatch?: string;
manifestDir?: string;
sharepointAssetDir?: string;
};
solution?: ISolution;
}

packageDir: Packaging root folder. Defaults to ./sharepoint . All other paths are relative to this folder.
debugDir: Folder to write the raw package to disk for debugging. Defaults to solution/debug
zippedPackage: Name of the sppkg file to create (including extension). Defaults to ClientSolution.sppkg
featureXmlDir: Folder containing the custom feature XML to import into the package. Defaults to feature_xml
IM P O R T A N T

Note that all files in this folder are included in the SPPKG; however, you must create a .rels file for your custom feature for it to be included in the package manifest.
manifestsMatch: Glob to match against to find manifest files. Looks in dist/ when running in normal, but in deploy/ for production.
manifestDir: Path to the folder where manifests are stored. Defaults to buildConfig.distFolder
sharepointAssetDir: Directory containing SharePoint assets (such as feature elements, element manifests, and upgrade actions), which are automatically included in the SharePoint
package. Defaults to assets

Examples
Default configuration
{
"solution": {
"name": "spfx-hello-world-client-side-solution",
"id": "77fd2eed-55b0-42bf-8b4d-f66730cb0c34",
"version": "1.0.0.0"
},
"paths": {
"zippedPackage": "solution/spfx-hello-world.sppkg"
}
}

Custom feature XML


To support provisioning of various SharePoint resources (such as List Templates, Pages, or Content Types), custom feature XML may also be injected into the package. This is used to
provision resources necessary for applications, but may also be used for web parts. The documentation for Feature XML is located at Feature.xml Files.
By default, the packaging task looks for the custom feature XML in ./sharepoint/feature_xml. Every file in this folder is included in the final application package. However, the task relies on
the contents of the _rels/ folder to determine which custom features are defined.
Essentially, it assumes that each .xml.rels file is related to a feature.xml of the same name at the top level of the feature_xml/, and adds a relationship to the AppManifest.xml.rels file that
includes that feature in the package.

See also
SharePoint Framework Overview
Integrate gulp tasks in SharePoint Framework toolchain
3/26/2018 • 3 minutes to read Edit Online

SharePoint client-side development tools use gulp as the build process task runner to:
Bundle and minify JavaScript and CSS files.
Run tools to call the bundling and minification tasks before each build.
Compile LESS or Sass files to CSS.
Compile TypeScript files to JavaScript.
One common task you can add to the SharePoint Framework toolchain is to integrate your custom gulp tasks in the build pipeline.

Gulp tasks
Normally gulp tasks are defined in the gulpfile.js as:

gulp.task('somename', function() {
// Do stuff
});

When working with the SharePoint Framework toolchain, it is necessary to define your tasks in the framework's build pipeline. After the task is defined and registered with the pipeline, it is
added to the toolchain.
SharePoint Framework uses a common build toolchain that consists of a set of npm packages that share common build tasks. Hence, the default tasks are defined in the common package as
opposed to your client-side project's gulpfile.js . To see the available tasks, you can execute the following command in a console within your project directory:

gulp --tasks

This command lists all the available tasks.

Custom gulp tasks


To add your custom tasks, define the custom tasks in the gulpfile.js .
Open the gulpfile.js in your code editor. The default code initializes the SharePoint Framework toolchain and the global gulp instance for the toolchain. Any custom tasks added should
be defined before initializing the global gulp instance.

Add your custom task


To add your custom gulp task, add a new subtask to the SharePoint Framework build pipeline by using the build.subTask function:

let helloWorldSubtask = build.subTask('log-hello-world-subtask', function(gulp, buildOptions, done) {


this.log('Hello, World!');
// use functions from gulp task here
});

In the case of a stream, you return the stream:

let helloWorldSubtask = build.subTask('log-hello-world-subtask', function(gulp, buildOptions, done) {


return gulp.src('images/*.png')
.pipe(gulp.dest('public'));
});

Register your task with gulp command line


After the custom task is defined, you can register this custom task with the gulp command line by using the build.task function:

// Register the task with gulp command line


let helloWorldTask = build.task('hello-world', helloWorldSubtask);

NOTE
Any custom tasks added should be defined before initializing the global gulp instance, that is, before the following line of code: build.initialize(gulp);

Now you can execute your custom command in the command line as follows:

gulp hello-world

NOTE

You cannot execute the subtask registered by using the build.subTask function directly from the command line. You can only execute the task registered by using the build.task function.

Execute your custom task before or after available tasks


You can also add this custom task to be executed before or after certain available gulp tasks. The following gulp tasks allow you to inject your custom task before or after the task:
Generic build task (that consists of all the available tasks)
TypeScript task
The SharePoint Framework tasks are available in the default build rig. The build rig is a collection of tasks defined for a specific purpose, in our case, building client-side packages. You can
access this default rig by using the build.rig object and then get access to the pre- and post-task functions:

// execute before the TypeScript subtask


build.rig.addPreBuildTask(helloWorldTask);

// execute after TypeScript subtask


build.rig.addPostTypescriptTask(helloWorldTask);

// execute after all tasks


build.rig.addPostBuildTask(helloWorldTask);

Example: Custom image resize task


As an example, let's use the image resize gulp task. It's a simple task that allows you to resize images.
You can download the completed sample at samples/js-extend-gulp/.
In the image resize task's documentation, it shows how to use this custom task:

var gulp = require('gulp');


var imageResize = require('gulp-image-resize');

gulp.task('default', function () {
gulp.src('test.png')
.pipe(imageResize({
width : 100,
height : 100,
crop : true,
upscale : false
}))
.pipe(gulp.dest('dist'));
});

We use this information to add this task in our project by using the build.subTask and build.task functions:

var imageResize = require('gulp-image-resize');

let imageResizeSubTask = build.subTask('image-resize-subtask', function(gulp, buildOptions, done){


return gulp.src('images/*.jpg')
.pipe(imageResize({
width: 100,
height: 100,
crop: false
}))
.pipe(gulp.dest(path.join(buildOptions.libFolder, 'images')))
});

let imageResizeTask = build.task('resize-images', imageResizeSubTask);

Because we are defining the stream, we return the stream in the build.subTask function to the build pipeline. The build pipeline then asynchronously executes this gulp stream.
Now, you can execute this task from the gulp command line as follows:

gulp resize-images
You also see this resize-images task in the available tasks for your project when you execute gulp --tasks :

See also
SharePoint Framework Overview
Extending Webpack in the SharePoint Framework toolchain
4/17/2018 • 5 minutes to read Edit Online

Webpack is a JavaScript module bundler that takes your JavaScript files and their dependencies and generates one or more JavaScript files, so you can load different pieces of code for
different scenarios.
The framework toolchain uses CommonJS for bundling. This enables you to define modules and where you want to use them. The toolchain also uses SystemJS, a universal module loader,
to load your modules. This helps you to scope your web parts by making sure that each web part is executed in its own namespace.
One common task you can add to the SharePoint Framework toolchain is to extend the Webpack configuration with custom loaders and plug-ins.

Using Webpack loaders


There are many cases where you might like to import and utilize a non-JavaScript resource during development, which is typically done with images or templates. A Webpack loader
converts the resource into something that can be utilized by your JavaScript application, or provides a simple reference that your JavaScript application can understand.
For example, a markdown template may be compiled and converted to a text string, while an image resource may be converted to an inlined Base64 image, or it may be referenced as a URL
and copied to your dist directory for deployment.
There are many useful loaders, several of which are already used by the standard SharePoint Framework Webpack configuration, such as:
html-loader
json-loader
loader-load-themed-styles
Extending the framework Webpack configuration with custom loaders is a straightforward process that is documented atWebpack Loaders.

Example: Using the markdown-loader package


As an example, let's use the markdown-loader package. It's a loader that allows you to reference an .md file and output it as an HTML string.
You can download the completed sample at samples/js-extend-webpack.

Step 1 - Install the package


Reference markdown-loader in our project:

npm i --save markdown-loader

Step 2 - Configure Webpack


Now that we have the package installed, let's configure the SharePoint Framework Webpack configuration to include markdown-loader .
In the documentation of markdown-loader, it shows how to extend the Webpack configuration to include the loader:

{
module: {
rules: [
{
test: /\.md$/,
use: [
{
loader: 'html-loader'
},
{
loader: 'markdown-loader',
options: {
/* options for markdown-loader here */
}
}
]
}
]
}
}

Let's take a look at what this configuration is doing:


The rules array in the Webpack configuration defines a set of file path tests and the loaders that should be used when a resource is found that matches the test. In this case, the test
property checks for file paths that end with .md .
The use array describes a list of loaders that are applied sequentially to the resource. They are applied from last to first. In this case, the first loader to be applied is markdown-loader ,
and the last loader to be applied is html-loader .
When multiple loaders are specified, the result of each loader is piped to the next.
We will use this information to configure it in our project.
To add this custom loader into the SharePoint Framework Webpack configuration, we need to instruct the build task to configure Webpack. The build tasks are defined in the gulpfile.js
that is located at the root of your project.
Edit the gulpfile.js and add the following code right before build.initialize(gulp); :
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
generatedConfiguration.module.rules.push(
{
test: /\.md$/,
use: [
{
loader: 'html-loader'
},
{
loader: 'markdown-loader'
}
]
}
);

return generatedConfiguration;
}
});

Let's walk through what this code snippet is doing:


As its name implies, the ConfigureWebpackTask (instantiated as build.configureWebpack ) configures Webpack for us. There is a lot of special configuration that happens to build SPFx
projects, so there is some nontrivial logic in this task.
The ConfigureWebpackTask takes an optional additionalConfiguration property. We want to set this property to a function that takes the generated configuration, makes our
modifications to it, and then returns the updated configuration. Note that this function must return a Webpack configuration to the toolchain, otherwise Webpack will not
be configured correctly.
Inside the body of the function that we set to additionalConfiguration , simply push a new rule onto the existing set of rules in the configuration. Notice that this new rule is very
similar to the example in the configuration snippet at the top of Step 2.
NOTE

While you are able to completely replace the toolchain's default Webpack configuration by using this approach, to get the maximum benefit with performance and optimization, it is not
recommended to do so unless stated otherwise in the documentation.

Step 3 - Update your code


Now that we have configured the loader, let's update our code and add a few files to test the scenario.
1. Create a file my-markdown.md in the src directory of your project folder with some markdown text in it.

#Hello Markdown

*Markdown* is a simple markup format to write content.

You can also format text as **bold** or *italics* or ***bold italics***

When you build the project, the Webpack markdown-loader converts this markdown text to an HTML string.
2. To use this HTML string in any of your source *.ts files, add the following require() line at the top of the file after your imports, for example:

const markdownString: string = require<string>('./../../../../src/readme.md');

Webpack by default looks in the lib folder for the file, but by default .md files don't get copied to the lib folder, meaning that we need to create a rather lengthy relative path. We
can control this setting by defining a config file to tell the toolchain to copy md files to the lib folder.
3. Create a file copy-static-assets.json in the config directory to tell the build system to copy some additional files from src to lib . By default, this build task copies files with
extensions that the default toolchain Webpack configuration understands (like png and json ), so we just need to tell it to also copy md files.

{
"includeExtensions": [
"md"
]
}

4. Now instead of using the relative path, you can use the file path in your require statement, for example:

const markdownString: string = require<string>('./../../readme.md');

5. You can then reference this string in your code, for example:

public render(): void {


this.domElement.innerHTML = markdownString;
}

Step 4 - Build and test your code


To build and test your code, execute the following command in a console in the root of your project directory:

gulp serve

See also
SharePoint Framework Overview
Update SharePoint Framework packages
3/26/2018 • 4 minutes to read Edit Online

SharePoint client-side development tools use the npm package manager to manage dependencies and other required JavaScript helpers. npm is typically included as part of Node.js setup.
When you create a new client-side solution, the Yeoman generator for SharePoint fetches the latest SharePoint Framework packages required for your client-side project. As you build your
project, your existing packages could be outdated because there could be new versions of one or more packages available.
Based on the release notes for a particular release or the latest package, you may decide to update your SharePoint Framework packages used in your project. SharePoint Framework
packages include both the npm packages you have installed in your project, for example: @microsoft/sp-core-library, and npm packages installed globally, for example:
@microsoft/generator-sharepoint.
 T IP

While it may not be required, we recommend that you update the SharePoint Framework packages often so that you can get the latest changes and fixes that have been released.

Find outdated packages


To find the outdated packages in your client-side project, including SharePoint Framework and other packages your project depends on, run the following command in a console in the same
directory as your project.

npm outdated

The command lists the following information about the packages your project depends on. This information is looked up from the package.json file located in the root of your project
directory and npm registry.
Current version installed in your project
Version requested by your project (available in package.json )
Latest version available

To identify the SharePoint Framework packages, look for the package names that start with the following npm scope and prefix:

@microsoft/sp-

Along with the framework packages, you may also need to update react and office-ui-fabric-react packages. Make sure you read the release notes for that specific release to infer which
packages require updates and plan accordingly.

Using the "npm outdated" command with a project


Starting from Feature Pack 2, SharePoint 2016 supports SharePoint Framework solutions. SharePoint 2016 uses an older version of the SharePoint Framework than the version available in
SharePoint Online.
When scaffolding new projects, the SharePoint Framework Yeoman generator prompts you to choose if your solution should be using the latest version of the SharePoint Framework and be
working only with SharePoint Online, or if it should use an older version of the SharePoint Framework and work with both SharePoint 2016 and SharePoint Online.
When you run the npm outdated command in a project that targets both SharePoint Online and SharePoint 2016, it shows you the latest versions of the SharePoint Framework packages.
These versions, however, work only with SharePoint Online. If you update your solution to use these latest packages, it no longer works with SharePoint 2016.
When working with SharePoint Framework solutions compatible with SharePoint hosted on-premises, you should always verify which patch level the target SharePoint farm has and which
version of the SharePoint Framework it supports.

Update packages
When updating packages to newer versions, you should always use your package manager (npm or Yarn). You should not edit the package.json file manually. If you follow the
recommended practice of using a lock file, your changes to the package.json file would be ignored.
Start with identifying which packages need updating and which newer version you want to use. Note that it might not always be possible for you to use the latest version of the given
package because it might be incompatible with other SharePoint Framework dependencies, such as TypeScript.
For each package that you want to update, run the following command:

npm install mypackage@newversion --save

For example, if you were using AngularJS version v1.5.9 and wanted to update to version 1.6.5, you would run:
npm install angular@1.6.5 --save

Updating the package by using npm installs the specified version of the package in your project and updates the version number in the package.json file dependencies and the lock file used
in your project.
After the packages are installed, execute the following command to clean up any old build artifacts:

gulp clean

Update your code


Depending on breaking API changes, you may have to update your existing project code and config files. For each release, the release notes highlight any such breaking changes and the
modifications required to your existing code. You must make sure you update your code with those fixes.
You can always build the project to see if you have any errors and warnings by running the command in a console in your project directory:

gulp build

Update Yeoman generator


If you have installed the SharePoint Framework Yeoman generator globally, you can find out if it requires updating by running the following command:

npm outdated -g

The command lists the following information about the packages installed globally on your machine. This information is looked up from the versions installed on your machine and the npm
registry.
Current version installed globally on your machine
Version requested by you when you installed
Latest version available

To identify the generator package, look for the following package name:

@microsoft/generator-sharepoint

Update generator package


Open your favorite console and execute the following command to update the generator to its latest published version:

npm install @microsoft/generator-sharepoint@latest -g

The command updates the Yeoman generator for SharePoint to the latest published version along with its dependencies. You can validate this by executing the following command in the
console:

npm ls @microsoft/generator-sharepoint -g --depth=0

See also
Upgrading SharePoint Framework projects (Team-based development guidance)
Upgrade SharePoint items (Provisioning SharePoint assets)
SharePoint Framework Overview
Tenant-scoped solution deployment for SharePoint Framework solutions
4/20/2018 • 2 minutes to read Edit Online

You can configure your SharePoint Framework components to be immediately available across the tenant when the solution package is installed to the tenant app catalog. This can be
configured by using the skipFeatureDeployment attribute in the package-solution.json file.
When the solution has this attribute enabled, the tenant administrator is provided the option to enable the solution to be available automatically across all site collections and sites in the
tenant when the solution package is installed to the tenant app catalog.
You can also see the tenant-wide deployment option demonstrated by watching the following video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/pemHOZCSwZI

NOTE

You have to update to the latest SharePoint Framework Yeoman template version to be able to use this capability. You can update your global installation by executing
npm install -g @microsoft/generator-sharepoint .

Solution-specific requirements
When this option is used, any feature framework definitions in the SharePoint Framework solution are ignored. If the solution contains feature framework definitions, for example, for
creating a custom list, you should not use this solution-specific option.
For more information, see Provision SharePoint assets with your solution package.
NOTE

Solutions that are configured to be automatically deployed across tenants are not visible in the add-an-app capability at the site level.

Configure solution to be available across the tenant


The SharePoint Framework Yeoman template asks a specific question related to this option. This question impacts directly on the skipFeatureDeployment attribute in the package-
solution.json file.
In following example configuration, skipFeatureDeployment is set to true, which indicates that the solution can be centrally deployed across the tenant.

{
"solution": {
"name": "tenant-deploy-client-side-solution",
"id": "dd4feca4-6f7e-47f1-a0e2-97de8890e3fa",
"version": "1.0.0.0",
"skipFeatureDeployment": true
},
"paths": {
"zippedPackage": "solution/tenant-deploy-true.sppkg"
}
}

Approving tenant-wide deployment in app catalog


When the solution with the skipFeatureDeployment attribute set to true is deployed to the tenant app catalog, the administrator is given an option to configure the solution to be deployed
centrally across the tenant.
By default, the Make this solution available to all sites in the organization check box is not selected. If the check box is selected by the administrator, components in the solutions are
automatically visible and available across the tenant.

Notice that because the solution and site-specific upgrade actions are only available when you use the feature framework, there's no specific upgrade option for the centrally deployed
solutions. These solutions can be updated by updating the solution-specific assets in the CDN and by updating the package in the app catalog. This automatically updates all existing
component instances across the tenant to use the latest component assets, such as JavaScript files and updated CSS files.

Client-side web part visibility on SharePoint sites


Web parts included in solutions that have been centrally deployed are immediately visible in the web part picker in both classic and modern pages.

Impact of skipFeatureDeployment setting with Extensions


SharePoint Framework Extensions are immediately available to be used on SharePoint sites. This means that they can be associated with ClientSideComponentId properties in the specific
SharePoint elements, such as fields and user custom actions.

See also
Overview of the SharePoint Framework
SharePoint Online tenant properties
3/26/2018 • 2 minutes to read Edit Online

Tenant properties allow tenant administrators to add properties in the app catalog that can be read by various SharePoint Framework components. The tenant properties are managed by
tenant administrators by using the Microsoft SharePoint Online Management Shell, which is a PowerShell module to manage your SharePoint Online subscription in Office 365.
Alternatively, the Office 365 CLI can be used to manage the tenant properties. The Office 365 CLI is a cross-platform command line interface that can be used on any platform, including
Windows, MacOS and Linux.

Manage tenant properties


Using the Microsoft SharePoint Online Management Shell, tenant administrators can use PowerShell to add and remove tenant properties.
The following PowerShell cmdlets are available to manage the tenant properties. Because tenant properties are stored in the tenant app catalog, you must provide the tenant app catalog site
collection URL in the following cmdlets.
Before running the following script, connect to your SharePoint Online tenant using the Connect-SPOService cmdlet when using the SharePoint Online PowerShell.

Get-SPOStorageEntity
Applies to Office 365, SharePoint Online
Syntax Get-SPOStorageEntity [-Site] [-Key]

Set-SPOStorageEntity
Applies to Office 365, SharePoint Online
Syntax Set-SPOStorageEntity [-Site] [-Key] [-Value] [-Description] [-Comments]

Remove-SPOStorageEntity
Applies to Office 365, SharePoint Online
Syntax Remove-SPOStorageEntity [-Site] [-Key]

Office 365 CLI commands to get, set, remove and list tenant properties cross-platform
Using the Office 365 CLI, tenant administrators can use shell commands to manage tenant properties.
Before using the commands, connect to a SharePoint Online site, using the spo connect command.

Get details for the specified tenant property


The spo storageentity get command can be used to get details for Office 365, SharePoint Online tenant property

spo storageentity get --key <key>

List tenant properties stored on the specified SharePoint Online app catalog
The spo storageentity list command can be used to list all the tenant properties.

spo storageentity list --appCatalogUrl <appCatalogUrl>

Set tenant property on a specified SharePoint Online app catalog


The spo storageentity set command can be used to set tenant property

spo storageentity set --appCatalogUrl <appCatalogUrl> --key <key> --value <value>

Remove tenant property stored on the specified SharePoint Online app catalog
The spo storageentity remove command can be used to remove tenant property

spo storageentity remove --appCatalogUrl <appCatalogUrl> --key <key>

Remarks when using the Office 365 CLI set and remove commands
To set or remove a tenant property, you have to first connect to a tenant admin site using the spo connect command, eg. spo connect https://contoso-admin.sharepoint.com. If you are
connected to a different site and will try to manage tenant properties, you will get an error.
Tenant properties are stored in the app catalog site associated with that tenant. To set or remove a property, you have to specify the absolute URL of the app catalog site. If you specify the
URL of a site different than the app catalog, you will get an access denied error.

Read tenant properties


Developers can read tenant properties by using the SharePoint REST APIs and use them in SharePoint Framework components such as web parts and extensions.

HTTP request
Get a tenant property
GET _api/web/GetStorageEntity('key')

Example
GET _api/web/GetStorageEntity('AnalyticsKey')
Request body
Do not supply a request body for this method.
Response
This returns the storage entity information for the given key.

HTTP/1.1 200 OK
Content-Type: application/json
{
"Comment":"Tenant property comment.",
"Description":"Tenant property description",
"Value":"Tenant property key value"
}

See also
Overview of the SharePoint Framework
Office 365 CLI
Provision SharePoint assets with your solution package
4/20/2018 • 9 minutes to read Edit Online

At times, you may need to provision a SharePoint list or a document library along with your client-side solution package so that the list or library is available for your client-side components,
such as web parts. SharePoint Framework toolchain allows you to package and deploy SharePoint items with your client-side solution package. These items are then provisioned when the
client-side solution is installed on a site.
You can also find details on the provisioning options in this SharePoint PnP webcast available on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/r-UdJhhHlEQ

Provision items using JavaScript code


While it is possible to create SharePoint items using JavaScript code in your component, such as web parts, it is limited to the context of the current user using that component. If the user
doesn't have sufficient permissions to create or modify SharePoint items, the JavaScript code does not provision those items. In such cases, when you want to provision SharePoint items in
an elevated context, you must package and deploy the items along with your solution package.

Provision SharePoint items in your solution


The following SharePoint assets can be provisioned along with your client-side solution package:
Fields
Content types
List instances
List instances with custom schema

Fields
A field or a site column represents an attribute, or piece of metadata, that the user wants to manage for the items in the list or content type to which they added the column. It is a reusable
column definition, or template, that you can assign to multiple lists across multiple SharePoint sites. Site columns decrease rework and help you ensure consistency of metadata across sites
and lists.
For example, suppose you define a site column named Customer. Users can add that column to their lists and reference it in their content types. This ensures that the column has the same
attributes—at least to start with—wherever it appears.
You can refer to the schema and attributes in the Field Element (Field) documentation to define a new field in your solution.
Following is an example of a new DateTime field:

<Field ID="{1511BF28-A787-4061-B2E1-71F64CC93FD5}"
Name="DateOpened"
DisplayName="Date Opened"
Type="DateTime"
Format="DateOnly"
Required="FALSE"
Group="Financial Columns">
<Default>[today]</Default>
</Field>

Content types
A content type is a reusable collection of metadata (columns), behavior, and other settings for a category of items or documents in a SharePoint list or document library. Content types enable
you to manage the settings for a category of information in a centralized, reusable way.
For example, imagine a business situation in which you have three different types of documents: expense reports, purchase orders, and invoices. All three types of documents have some
characteristics in common; for one thing, they are all financial documents and contain data with values in currency. Yet each type of document has its own data requirements, its own
document template, and its own workflow.
One solution to this business problem is to create four content types. The first content type, Financial Document, could encapsulate data requirements that are common to all financial
documents in the organization. The remaining three, Expense Report, Purchase Order, and Invoice, could inherit common elements from Financial Document. In addition, they could define
characteristics that are unique to each type, such as a particular set of metadata, a document template to be used in creating a new item, and a specific workflow for processing an item.
You can refer to the schema and attributes in the ContentType Element (ContentType) documentation to define a new content type in your solution.
Following is an example of a content type:

<ContentType ID="0x010042D0C1C200A14B6887742B6344675C8B"
Name="Cost Center"
Group="Financial Content Types"
Description="Financial Content Type">
<FieldRefs>
<FieldRef ID="{1511BF28-A787-4061-B2E1-71F64CC93FD5}" />
<FieldRef ID="{060E50AC-E9C1-4D3C-B1F9-DE0BCAC300F6}" />
</FieldRefs>
</ContentType>

List instances
Lists are a key, underlying feature of a SharePoint site. They enable teams to gather, track, and share information. Many applications rely on lists created at the site for data storage to
implement their behaviors. A list instance is a predefined SharePoint list that has a well-known identifier. You can customize and add items to these lists, create additional lists from the list
templates that are already available, and create custom lists with just the settings and columns that you choose.
SharePoint provides several list templates such as contact list, calendar, task list, and more. You can use these templates to create new list instances for your web parts or other components.
For example, you can define a list instance Finance Documents based on the Document Library template to store associated documents with your web part.
You can refer to the schema and attributes in the ListInstance Element (List Instance) documentation to define a list instance in your solution.
Following is an example of a list instance definition:

<ListInstance
FeatureId="00bfea71-e717-4e80-aa17-d0c71b360101"
Title="Finance Records"
Description="Finance documents"
TemplateType="101"
Url="Lists/FinanceRecords">
</ListInstance>

List instances with custom schema


You can use a custom list schema definition to define your fields, content types, and views used in your list instance. You use the CustomSchema attribute in the ListInstance element to
reference a custom schema for the list instance.
For example, you can define a list instance Finance Documents with a content type Financial Document that could encapsulate data requirements that are common to all financial
documents in the organization.
Following is an example of a list instance definition that uses a custom schema:

<ListInstance
CustomSchema="schema.xml"
FeatureId="00bfea71-de22-43b2-a848-c05709900100"
Title="Cost Centers"
Description="Cost Centers"
TemplateType="100"
Url="Lists/CostCenters">
</ListInstance>

This is the custom schema definition that defines a content type for the list instance defined previously:
<List xmlns:ows="Microsoft SharePoint" Title="Basic List" EnableContentTypes="TRUE" FolderCreation="FALSE" Direction="$Resources:Direction;" Url="Lists/Basic List" BaseType="0" xmlns="http://sche
<MetaData>
<ContentTypes>
<ContentTypeRef ID="0x010042D0C1C200A14B6887742B6344675C8B" />
</ContentTypes>
<Fields></Fields>
<Views>
<View BaseViewID="1" Type="HTML" WebPartZoneID="Main" DisplayName="$Resources:core,objectiv_schema_mwsidcamlidC24;" DefaultView="TRUE" MobileView="TRUE" MobileDefaultView="TRUE" SetupPath="
<XslLink Default="TRUE">main.xsl</XslLink>
<JSLink>clienttemplates.js</JSLink>
<RowLimit Paged="TRUE">30</RowLimit>
<Toolbar Type="Standard" />
<ViewFields>
<FieldRef Name="LinkTitle"></FieldRef>
<FieldRef Name="SPFxAmount"></FieldRef>
<FieldRef Name="SPFxCostCenter"></FieldRef>
</ViewFields>
<Query>
<OrderBy>
<FieldRef Name="ID" />
</OrderBy>
</Query>
</View>
</Views>
<Forms>
<Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
</Forms>
</MetaData>
</List>

Create SharePoint items in your solution


The solution package uses SharePoint Features to package and provision the SharePoint items. A feature is a container that includes one or more SharePoint items to provision. A feature
contains a Feature.xml file and one or more element manifest files. These XML files are also known as feature definitions.
Typically, a client-side solution package contains one feature. This feature is activated when the solution is installed on a site. It is important to note that the site administrators install your
solution package and not the feature.
A feature is primarily constructed by using the following XML files.

Element manifest file


The element manifest file contains the SharePoint item definitions and is executed when the feature is activated. For example, the XML definitions to create a new field, content type, or list
instance is in the element manifest.
Following is an example of an element manifest file that defines a new DateTime field.

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field ID="{1511BF28-A787-4061-B2E1-71F64CC93FD5}"
Name="DateOpened"
DisplayName="Date Opened"
Type="DateTime"
Format="DateOnly"
Required="FALSE"
Group="Financial Columns">
<Default>[today]</Default>
</Field>
</Elements>

Element file
Any supported files that accompany the element manifest are element files. For example, the list instance schema is an element file that is associated with a list instance that is defined in an
element manifest.
Following is an example of a custom list instance schema:

<List xmlns:ows="Microsoft SharePoint" Title="Basic List" EnableContentTypes="TRUE" FolderCreation="FALSE"


Direction="$Resources:Direction;" Url="Lists/Basic List" BaseType="0" xmlns="http://schemas.microsoft.com/sharepoint/">
<MetaData>
<ContentTypes>
<ContentTypeRef ID="0x010042D0C1C200A14B6887742B6344675C8B" />
</ContentTypes>
</MetaData>
</List>

Upgrade actions file


As its name suggests, this is the file that includes any upgrade actions when the solution is updated on the site. As part of the upgrade actions, the action could specify to include one or more
element manifests as well. For example, if the upgrade requires a new field to be added, the field definition is available as an element manifest and is associated in the upgrade actions file.
Following is an example of an upgrade actions file that applies an element manifest file during the upgrade:

<ApplyElementManifests>
<ElementManifest Location="9c0be970-a4d7-41bb-be21-4a683586db18\elements-v2.xml" />
</ApplyElementManifests>

Configure the SharePoint feature


To include the XML files, you must first define the feature configuration in the package-solution.json configuration file under the config folder in your project. The package-solution.json
contains the key metadata information about your client-side solution package and is referenced when you run the package-solution gulp task that packages your solution into an .sppkg
file.

{
"solution": {
"name": "hello-world-client-side-solution",
"id": "26364618-3056-4b45-98c1-39450adc5723",
"version": "1.1.0.0",
"features": [{
"title": "hello-world-client-side-solution",
"description": "hello-world-client-side-solution",
"id": "d46cd9d6-87fc-473b-a4c0-db9ad9162b64",
"version": "1.1.0.0",
"assets": {
"elementManifests": [
"elements.xml"
],
"elementFiles":[
"schema.xml"
],
"upgradeActions":[
"upgrade-actions-v1.xml"
]
}
}]
},
"paths": {
"zippedPackage": "solution/hello-world.sppkg"
}
}

The features JSON object contains the metadata about the feature, as shown in the following table.

PR O PER T Y D ES CR IPTIO N

id Unique identifier (GUID) of the feature

title Title of the feature

description Description of the feature

assets An array of XML files used in the feature

elementManifests Defined within the assets property, an array of element manifest files

elementFiles Defined within the assets property, an array of element files

upgradeActions Defined within the assets property, an array of upgrade action files

Create the feature XML files


The toolchain looks for the XML files as defined in the configuration under a special folder, sharepoint\assets, in your client-side solution project.

The configurations defined in the package-solution.json is what maps the XML files here to its appropriate feature XML file when the package-solution gulp task is executed.

Package SharePoint items


After you have defined your feature in the package-solution.json and created the respective feature XML files, you can use the following gulp task to package the SharePoint items along
with your .sppkg package.
gulp package-solution

This command packages one or more client-side component manifests, such as web parts, along with the feature XML files referenced in the package-solution.json configuration file.
NOTE

You can use the --ship flag to package minified versions of your components.

Upgrade SharePoint items


You may include new SharePoint items or update existing SharePoint items when you upgrade your client-side solution. Because provisioning SharePoint items uses features, you are using
the feature UpgradeActions XML file to define a list of upgrade actions.
The upgradeActions JSON object array in the package-solution.json references the feature XML file(s) associated with the upgrade actions for your feature. At the least, an upgrade action
file defines the element manifest XML file that is executed when upgrading the feature.
When you are upgrading a SharePoint Framework solution, you must also update version attributes for both the solution and the feature where the upgrade actions have been included. A
solution version increase indicates to SharePoint end users that there is a new version of the package available. A feature element version increase ensures that the tasks defined in the
upgrade actions are being processed as part of the solution upgrade.
Following is an example of an upgrade action file that applies an element manifest file during the upgrade:

<ApplyElementManifests>
<ElementManifest Location="9c0be970-a4d7-41bb-be21-4a683586db18\elements-v2.xml" />
</ApplyElementManifests>

This is the corresponding element-v2.xml that defines a new Currency field to be provisioned during the upgrade:

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field ID="{060E50AC-E9C1-4D3C-B1F9-DE0BCAC300F6}"
Name="Amount"
DisplayName="Amount"
Type="Currency"
Decimals="2"
Min="0"
Required="FALSE"
Group="Financial Columns" />
</Elements>

Sub-elements
Upgrade actions in client-side solutions support the following sub-elements.
AddContentTypeField
Adds a new field to an existing provisioned content type. Propagates the change from the site content type to all child lists and content types within the site. For example:

<AddContentTypeField
ContentTypeId="0x010100A6F9CE1AFE2A48f0A3E6CB5BB770B0F7"
FieldId="{B250DCFD-9310-4e2d-85F2-BE2DA37A57D2}"
PushDown="TRUE" />

ApplyElementManifests
Adds a new element to an existing feature. When a feature is upgraded, provisions all non-declarative elements that are referenced in the specified element manifests.
VersionRange
Specifies a version range to which specified upgrade actions apply.

See also
Tutorial - Provisioning SharePoint assets from your SharePoint client-side web part
SharePoint Framework Overview
Optimize SharePoint Framework builds for production
3/26/2018 • 6 minutes to read Edit Online

When deploying SharePoint Framework solutions to production you should always use a release build of your project that is optimized for performance. This article illustrates the main
differences between debug and release builds and shows how you can optimize your bundle for use in production environments.

Use release builds in production


When building a SharePoint Framework project, you can choose whether you want to build it in a debug or release mode. By default, SharePoint Framework projects are built in debug
mode, which makes it easier for you to debug code. But when your code is finished and is working as expected, you should build it in release mode to optimize it for running in the
production environment.
For more information about building your project in release mode, see SharePoint Framework toolchain.
The main difference between the output of a debug and release build is that the release version of the generated bundle is minified and significantly smaller in size than its debug equivalent.
To illustrate the difference, compare the size of the debug and release version of a SharePoint Framework project with a web part using Angular.

The debug version of the bundle is 1255 KB while its release equivalent is only 177 KB. The difference in size between the debug and release version of the generated bundle differs
depending on the libraries used in your project. Still, the release build is always significantly smaller than a debug build, which is why you should always deploy the output of release builds to
production.

Don't include third-party libraries in the bundle


When building SharePoint Framework solutions, you can benefit from many existing JavaScript libraries to solve common problems. Using existing libraries allows you to be more
productive and lets you focus on the added value for your organization, instead of on developing generic functionality.
By default, when referencing third-party libraries in your project, SharePoint Framework includes them in the generated bundle. As a result, users working with your solution end up
downloading the same library multiple times, once with each component. The total page size grows significantly, taking longer to load and leading to a poor user experience, particularly on
slower networks.
When working with third-party libraries, you should always consider loading them from an external location: either a public CDN or a hosting location owned by your organization. This
allows you to exclude the library from your bundle, significantly decreasing its size.
Additionally, if the hosting location from which you are loading the library is optimized for serving static assets, users working with your solution need to load the library only once. On
subsequent requests, or even when using your solution in the future, the web browser reuses the previously cached copy of the library rather than downloading it again. As a result, the page
with your solution loads significantly faster.

Verify the contents of your bundle


To better understand the size of the generated bundles, you can extend the Webpack configuration in your project and have the SharePoint Framework generate bundle statistics.
First, install the webpack-bundle-analyzer package in your project by executing the following in the command line:

npm install webpack-bundle-analyzer --save-dev

Next, change the contents of the gulpfile.js file in your project to:

'use strict';

const gulp = require('gulp');


const path = require('path');
const build = require('@microsoft/sp-build-web');
const bundleAnalyzer = require('webpack-bundle-analyzer');

build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
const lastDirName = path.basename(__dirname);
const dropPath = path.join(__dirname, 'temp', 'stats');
generatedConfiguration.plugins.push(new bundleAnalyzer.BundleAnalyzerPlugin({
openAnalyzer: false,
analyzerMode: 'static',
reportFilename: path.join(dropPath, `${lastDirName}.stats.html`),
generateStatsFile: true,
statsFilename: path.join(dropPath, `${lastDirName}.stats.json`),
logLevel: 'error'
}));

return generatedConfiguration;
}
});

build.initialize(gulp);
The next time you bundle your project by using the gulp bundle task, you'll see the bundle stats files generated in the temp/stats folder in your project. One of the generated stats files is a
treemap showing the different scripts included in the generated bundle. You can find this visualization in the ./temp/stats/[solution-name].stats.html file.

Using the Webpack bundle analyzer treemap is a convenient way for you to verify that the generated bundle doesn't contain any unnecessary scripts and understand how the included
scripts affect the total bundle size. Keep in mind that the displayed size reflects the debug build and is significantly smaller for a release build.
More detailed information used to generate the visualization is included in the ./dist/[solution-name].stats.json file. By using this file, you can find out why a specific script has been
included in the bundle or if a particular script is used in multiple bundles. With this information, you can optimize your bundles, improving the loading time of your solution.

Choose your primary client-side library


If there are multiple components on the same page, or even on different pages across the portal, and they all use the same library loaded from the same URL, the web browser also reuses
the copy it cached previously, which leads to the portal loading faster.
This is exactly why it is essential for organizations to rationalize which libraries and versions they use and where they load from, not only for a specific project but for the whole organization.
Such a policy allows users working with the different applications to be more productive by loading the applications faster. By reusing the previously downloaded assets, the load on the
network is limited, freeing its bandwidth for other purposes.
For more information about working with external libraries, see Use existing JavaScript libraries in SharePoint Framework client-side web parts.

Reference only the necessary components


Sometimes when working with external libraries, you might actually not need the whole library but only a small portion of it. Including the whole library unnecessarily adds to the size of
your bundle, increasing its load time. Instead, you should always consider loading only the specific parts of the particular library that you actually need.
To illustrate this, take the Lodash library as an example. Lodash is a collection of utilities helping you to perform certain operations in your code. The odds are high that when working with
Lodash, you only need a few specific methods rather than the complete library.
However, if you referenced the whole library by using the following code, it adds 527 KB to your unoptimized bundle:

import * as _ from 'lodash';

Instead, if you referenced only the specific Lodash method by using the following code, it adds 45 KB to your unoptimized bundle:

const at: any = require('lodash/at');


Specifically with regards to Lodash, but which could also be the case with other libraries, referencing specific methods instead of the whole library comes with a price.
Currently, Lodash doesn't support loading specific methods inside of SharePoint Framework projects by using the import notation. Instead, you have to use a require statement, which
doesn't offer you the typesafety capabilities that using the import statement does. Eventually, it is up to you to decide if loading significantly more code into your bundles is worth preserving
the typesafety capabilities.
NOTE

Some of the Lodash methods are provided with the SharePoint Framework in the @microsoft/sp-lodash-subset library. Before using Lodash, verify if the method that you want to use
isn't already available in the @microsoft/sp-lodash-subset library, which is already available as a part of the SharePoint Framework and does not need to be included in your bundle.

See also
SharePoint Framework Overview
Localize SharePoint Framework client-side web parts
5/3/2018 • 23 minutes to read Edit Online

You can broaden the appeal of your SharePoint Framework client-side web part by localizing it for different languages spoken by SharePoint users all over the world. In this article, you will
localize a web part to the Dutch (Netherlands) locale, and verify that the localized values are displayed correctly.
NOTE

Before following the steps in this article, be sure to set up your SharePoint client-side web part development environment.

Prepare the project


Create a new project
1. Create a new folder for your project.

md react-localization

2. Go to the project folder.

cd react-localization

3. In the project folder, run the SharePoint Framework Yeoman generator to scaffold a new SharePoint Framework project.

yo @microsoft/sharepoint

4. When prompted, enter the following values:


react-localization as your solution name.
SharePoint Online only (latest) as the baseline package set.
Use the current folder for the location to place the files.
y to allow tenant-wide deployment.
WebPart as the type of component to develop.
Greeting as your web part name.
Greets the user as your web part description.
React as the starting point to build the web part.

5. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

6. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer.
Replace the default code
1. In the code editor, open the ./src/webparts/greeting/GreetingWebPart.ts file, and update the definition of the IGreetingWebPartProps interface to the following code:

export interface IGreetingWebPartProps {


greeting: string;
}

2. In the same file, change the GreetingWebPart class to:

export default class GreetingWebPart extends BaseClientSideWebPart<IGreetingWebPartProps> {

public render(): void {


const element: React.ReactElement<IGreetingProps > = React.createElement(
Greeting,
{
greeting: this.properties.greeting
}
);

ReactDom.render(element, this.domElement);
}

protected get dataVersion(): Version {


return Version.parse('1.0');
}

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.DisplayGroupName,
groupFields: [
PropertyPaneTextField('greeting', {
label: strings.GreetingFieldLabel
})
]
}
]
}
]
};
}
}

3. Update the main React component by opening the ./src/webparts/greeting/components/Greeting.tsx file and changing its code to:
import * as React from 'react';
import styles from './Greeting.module.scss';
import { IGreetingProps } from './IGreetingProps';
import { escape } from '@microsoft/sp-lodash-subset';

export default class Greeting extends React.Component<IGreetingProps, {}> {


public render(): JSX.Element {
return (
<div className={styles.greeting}>
<div className={styles.container}>
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span className='ms-font-xl ms-fontColor-white'>
Welcome to SharePoint!
</span>
<p className='ms-font-l ms-fontColor-white'>
Customize SharePoint experiences using web parts.
</p>
<p className='ms-font-l ms-fontColor-white'>
{escape(this.props.greeting)}
</p>
<a href="https://aka.ms/spfx" className={styles.button}>
<span className={styles.label}>Learn more</span>
</a>
</div>
</div>
</div>
</div>
);
}
}

4. Update the main React component interface by opening the ./src/webparts/greeting/components/IGreetingProps.tsx file and changing its code to:

import { IGreetingWebPartProps } from '../GreetingWebPart';

export interface IGreetingProps extends IGreetingWebPartProps {


}

5. Update the localization TypeScript type definition file by opening the ./src/webparts/greeting/loc/mystrings.d.ts file and changing its code to:

declare interface IGreetingWebPartStrings {


PropertyPaneDescription: string;
DisplayGroupName: string;
GreetingFieldLabel: string;
}

declare module 'GreetingWebPartStrings' {


const strings: IGreetingWebPartStrings;
export = strings;
}

6. Update the US English locale file by opening the ./src/webparts/greeting/loc/en-us.js file and changing its code to:

define([], function() {
return {
"PropertyPaneDescription": "Greeting web part configuration",
"DisplayGroupName": "Display",
"GreetingFieldLabel": "Greeting to show in the web part"
}
});

7. In the web part manifest, update the default value of the greeting property by opening the ./src/webparts/greeting/GreetingWebPart.manifest.json file and changing the
properties section to:

{
// ...
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "Greeting" },
"description": { "default": "Greets the user" },
"officeFabricIconFontName": "Page",
"properties": {
"greeting": "Hello"
}
}]
}

8. Verify that you have applied all changes correctly by running the following command:

gulp serve

9. In the SharePoint Workbench, add the web part to the page, and open its configuration.
Localize the web part manifest
Every SharePoint Framework client-side web part consists of code and a manifest. The manifest provides information about the web part such as its title, description, and icon. When adding
a web part to the page, the information from the web part manifest is displayed to users.
Using this information, users decide if the web part is the one that they are looking for. Providing a title and description that correctly reflect the web part's functionality is essential if you
want your web part to be used. If your web part is used on non-English sites, localizing its metadata can improve the user experience even further.
Some properties defined in the web part manifest, such as title or description, support specifying localized values. For the complete list of all web part manifest properties that support
localization, see Simplify adding web parts with preconfigured entries.
Properties that support localization are of type ILocalizedString. Each localized string must specify at least the default value and optionally values for other locales.

Add localized values for title, description, and group name


1. In the code editor, open the ./src/webparts/greeting/GreetingWebPart.manifest.json file.
2. In the preconfiguredEntries array, add translations for the title, description, and group properties in Dutch (Netherlands), by changing the code to:

{
// ...
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other", "nl-nl": "Anders" },
"title": { "default": "Greeting", "nl-nl": "Begroeting" },
"description": { "default": "Greets the user", "nl-nl": "Begroet de gebruiker" },
"officeFabricIconFontName": "Page",
"properties": {
"greeting": "Hello"
}
}]
}

3. Run the following command to verify that the project is working:

gulp serve

NOTE

Unfortunately, the SharePoint Workbench doesn't currently support previewing the localized values from the web part manifest. It always uses the default translation.

Localize the web part property pane


When working with a web part, a user often needs to configure it for their specific needs. Providing descriptive labels for the different configuration settings improves the usability of the web
part and decreases the number of support requests from users for help configuring web parts.
The web part property pane consists of sections. Each section has a header and one or more controls that allow users to configure the web part. Each of these controls contains a label that
describes its purpose.
By default, web parts load the string labels from a JavaScript resource file. If you've built classic web parts with full-trust solutions, they resemble .resx resource files. It's not required to use
these resource files, and you could include the strings directly in code. However, it's highly recommended that you use resource files. The little additional overhead they add outweighs the
effort required to extract all labels afterwards should you need to translate the web part later on.
The localization files used by the web part are stored in the ./src/webparts/greeting/loc folder.
The loc folder contains a TypeScript type definition file (./src/webpart/greeting/loc/mystrings.d.ts) that informs TypeScript of the different strings included in the localized files. Using the
information from this file, your code editor can provide you with IntelliSense when working with strings in code. Additionally, while building your project, TypeScript can verify that you're not
referring to a string that hasn't been defined.

For each locale supported by your web part, there is also a plain JavaScript file (not TypeScript) named in lowercase after the locale (for example en-us.js) that contains the translated strings.
IM P O R T A N T

You should pay extra attention to verifying that all keys specified in the TypeScript type definition file for localization have translations in all localization JavaScript files.
The default locale used by the SharePoint Framework is en-US. If your web part is used on a site that uses a locale not supported by your web part, the SharePoint Framework uses en-US
as the default locale.
You can override this behavior by creating a locale file named default.js with the translations in your preferred language. While the name default.js doesn't follow the locale naming
convention, it signals to the SharePoint Framework build process to use that particular locale file as the fallback locale instead of the standard US English locale.

Add localized values for web part property pane strings


1. In the ./src/webparts/greetings/loc folder, create a new file named nl-nl.js, and enter the following code:

define([], function() {
return {
"PropertyPaneDescription": "Instellingen van het begroeting webonderdeel",
"DisplayGroupName": "Weergave",
"GreetingFieldLabel": "Begroeting die in het webonderdeel getoond wordt"
}
});

2. Verify that the keys in the TypeScript type definition file for localization match the contents of the locale files for US English and Dutch (Netherlands).

Verify the localized web part property pane strings


When testing web parts by using the hosted version of the SharePoint Workbench or team sites on a developer tenant, the locale of the context site expressed by the
spPageContextInfo.currentUICultureName property is used as the default locale.
When testing web parts by using the local SharePoint Workbench, the SharePoint Framework uses by default the en-US locale to display web part property pane strings. There are two ways
in which you can test the values from other locales supported by your web part.
Specify the locale to be tested in the project configuration
One way to specify the locale to be tested in the SharePoint Workbench is by editing the project configuration. This approach is useful if you and your team members are working with a
locale for a longer period of time, or if you're building a web part that doesn't support US English.
1. In the code editor, open the ./config/write-manifests.json file, and change its code to:

{
"cdnBasePath": "<!-- PATH TO CDN -->",
"debugLocale": "nl-nl"
}

2. Start the SharePoint Workbench by running the following command:

gulp serve

When you add the web part to the page and open its configuration, you'll see the strings in the web part property pane displayed in Dutch (Netherlands).

Specify the locale to be tested by using the command-line argument


Another way to specify the locale to be used by the local SharePoint Workbench is to specify it as an argument for the gulp task.
Start the SharePoint Workbench by running the following command:

gulp serve --locale=nl-nl

Once again, when you open your web part's configuration, you'll see that all property pane strings are displayed in Dutch (Netherlands) rather than the default US English.

Localize web part contents


The same way that you localize web part property pane strings, you should localize all strings displayed by the web part in its body. You can use the same approach that you use when
localizing web part property pane strings. For every string to be localized, add a key in the localization TypeScript definition file, and then translate the string to each of the supported locales
in the corresponding locale JavaScript file.

Globalize the web part strings


The default web part provided with the scaffolded SharePoint Framework project has its strings embedded in the code. Before you can localize these strings, you have to replace them with
references to the localized strings. This process is often referred to as globalization or internationalization (or i18n for short).
1. In the code editor, open the ./src/webparts/greeting/components/Greetings.tsx file.
2. In the top section of the file, directly after the last import statement, add a reference to the localized strings:

import * as strings from 'GreetingWebPartStrings';

3. Replace the contents of the Greeting class with the following code:

// ...
export default class Greeting extends React.Component<IGreetingProps, {}> {
public render(): JSX.Element {
return (
<div className={styles.greeting}>
<div className={styles.container}>
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span className='ms-font-xl ms-fontColor-white'>
Welcome to SharePoint!
</span>
<p className='ms-font-l ms-fontColor-white'>
Customize SharePoint experiences using web parts.
</p>
<p className='ms-font-l ms-fontColor-white'>
{escape(this.props.greeting)}
</p>
<a href="https://aka.ms/spfx" className={styles.button}>
<span className={styles.label}>{strings.LearnMoreButtonLabel}</span>
</a>
</div>
</div>
</div>
</div>
);
}
}

Add the new string to the localization TypeScript type definition file
Having replaced the string with a reference, the next step is to add that string to the localization files used by the web part.
In the code editor, open the ./src/webparts/greetings/loc/mystrings.d.ts file, and change its code to:

declare interface IGreetingWebPartStrings {


PropertyPaneDescription: string;
DisplayGroupName: string;
GreetingFieldLabel: string;
LearnMoreButtonLabel: string;
}

declare module 'greetingStrings' {


const strings: IGreetingWebPartStrings;
export = strings;
}

Add localized values for the new string


The last step is to provide localized versions for the new string in all locales supported by the web part.
1. In the code editor, open the ./src/webparts/greeting/loc/en-us.js file, and change its code to:

define([], function() {
return {
"PropertyPaneDescription": "Greeting web part configuration",
"DisplayGroupName": "Display",
"GreetingFieldLabel": "Greeting to show in the web part",
"LearnMoreButtonLabel": "Learn more"
}
});

2. Open the ./src/webparts/greeting/loc/nl-nl.js file, and change its code to:

define([], function() {
return {
"PropertyPaneDescription": "Instellingen van het begroeting webonderdeel",
"DisplayGroupName": "Weergave",
"GreetingFieldLabel": "Begroeting die in het webonderdeel getoond wordt",
"LearnMoreButtonLabel": "Meer informatie"
}
});

3. Confirm that the translated string is correctly displayed by running the following command:

gulp serve --locale=nl-nl


Improve globalizing and localizing web parts by using pseudo-locales
Using localization when building web parts offers clear benefits but is also something that developers overlook easily. Often, translations to other locales are provided later in the project and
it's difficult for testers to verify that all code properly supports the different locales.
The same words in different locales have different lengths. For example, the same sentence translated from English to German or Dutch can become 35% longer. Without all translations
available upfront, it's difficult for developers and designers to ensure that the user interface can properly accommodate longer strings.
Some languages use special characters beyond the standard ASCII character set. If designers use a non-standard font, it is possible that the font doesn't properly support some special
characters.
Finding out about all these issues late in the project will likely lead to delays and costly fixes. The SharePoint Framework allows developers to use pseudo-locales to address these issues
while building web parts.
 T IP

What are pseudo-locales? Pseudo-locales are locales designed to test software for proper support of the different aspects of the localization process, such as support for special characters,
right-to-left languages, or accommodating longer strings in the user interface.

Add the base pseudo-locale


1. In the ./src/webparts/greeting/loc folder, add a new file named qps-ploc.js, and paste the following code:

define([], function() {
return {
"PropertyPaneDescription": "[!!! Gřèèƭïñϱ ωèβ ƥářƭ çôñƒïϱúřáƭïôñ ℓôřè₥ ïƥƨú !!!]",
"DisplayGroupName": "[!!! Ðïƨƥℓᥠℓ !!!]",
"GreetingFieldLabel": "[!!! Gřèèƭïñϱ ƭô ƨλôω ïñ ƭλè ωèβ ƥářƭ ℓôřè₥ ïƥƨú !!!]",
"LearnMoreButtonLabel": "[!!! £èářñ ₥ôřè ℓôř !!!]"
}
});

 T IP

You can convert US English strings to their base pseudo-locale equivalent at Pseudolocalize!. By increasing the length of the generated string by 35%, you should be able to simulate
the length of strings translated to longer locales such as German or Dutch. Additionally, by surrounding the translations with brackets and exclamation marks you can more easily see
if the whole string is displayed on the screen.
2. Test the project using the base pseudo-locale by running the following command:

gulp serve --locale=qps-ploc

After adding the web part to the page, you can quickly see that there are two strings in the web part body that have not been internationalized and are still displayed in US English
rather than in the base pseudo-locale.
3. Open the web part property pane, and confirm that all strings and their special characters are displayed properly and that they fit in the available space correctly.

Localize web part settings values


SharePoint supports Multilingual User Interface (MUI) where the site administrator can enable multiple languages for the user interface. When the user visits the site, its UI automatically is
displayed using the preferred language based on that user's preferences.
Web parts used on multilingual sites should automatically detect the currently used language and display their contents in that language. The SharePoint Framework simplifies this process
by automatically loading the resource file corresponding to the currently used language. Additionally, when testing SharePoint Framework web parts using the hosted version of the
SharePoint Workbench, the Workbench also automatically uses the language preferred by the user.
Values configured through web part properties are not stored in resource files. By default, the configured value is used as-is, which might lead to inconsistencies, such as greeting the user in
English when the user's preferred language is Dutch.
By using the building blocks provided with the SharePoint Framework, you can extend your web part with support for storing web part configuration values in multiple languages. For each
of the supported languages, the property pane displays a separate text field in which the user can enter the translated value for that property.

NOTE

The SharePoint site used to test the web part shown in this article is a multilingual site with the US English, Dutch, and German languages enabled. For more information about enabling
additional languages on SharePoint sites, see Choose the languages you want to make available for a site’s user interface.

Add list of languages supported by SharePoint Online


The list of languages enabled on a multilingual SharePoint site is returned as an array of locale identifiers (LCID), for example, 1033 for US English.
However, the currently used language is returned as a string, for example, en-US for US English. Because JavaScript doesn't have a native way of converting the LCID number to the locale
name, and vice-versa, you have to do it yourself.
1. In the code editor, open the ./src/webparts/greeting/GreetingWebPart.ts file.
2. Add a new class variable named locales inside of the existing GreetingWebPart with the following code:
export default class GreetingWebPart extends BaseClientSideWebPart<IGreetingWebPartProps> {
private locales = {
1025: 'ar-SA',
1026: 'bg-BG',
1027: 'ca-ES',
1028: 'zh-TW',
1029: 'cs-CZ',
1030: 'da-DK',
1031: 'de-DE',
1032: 'el-GR',
1033: 'en-US',
1035: 'fi-FI',
1036: 'fr-FR',
1037: 'he-IL',
1038: 'hu-HU',
1040: 'it-IT',
1041: 'ja-JP',
1042: 'ko-KR',
1043: 'nl-NL',
1044: 'nb-NO',
1045: 'pl-PL',
1046: 'pt-BR',
1048: 'ro-RO',
1049: 'ru-RU',
1050: 'hr-HR',
1051: 'sk-SK',
1053: 'sv-SE',
1054: 'th-TH',
1055: 'tr-TR',
1057: 'id-ID',
1058: 'uk-UA',
1060: 'sl-SI',
1061: 'et-EE',
1062: 'lv-LV',
1063: 'lt-LT',
1066: 'vi-VN',
1068: 'az-Latn-AZ',
1069: 'eu-ES',
1071: 'mk-MK',
1081: 'hi-IN',
1086: 'ms-MY',
1087: 'kk-KZ',
1106: 'cy-GB',
1110: 'gl-ES',
1164: 'prs-AF',
2052: 'zh-CN',
2070: 'pt-PT',
2074: 'sr-Latn-CS',
2108: 'ga-IE',
3082: 'es-ES',
5146: 'bs-Latn-BA',
9242: 'sr-Latn-RS',
10266: 'sr-Cyrl-RS',
};

// ...
}

The locales variable lists all languages supported by SharePoint Online.


3. Add two class methods that allow you to get the LCID from the locale name, and the locale name from the LCID:

export default class GreetingWebPart extends BaseClientSideWebPart<IGreetingWebPartProps> {


// ...

private getLocaleId(localeName: string): number {


const pos: number = (Object as any).values(this.locales).indexOf(localeName);
if (pos > -1) {
return parseInt(Object.keys(this.locales)[pos]);
}
else {
return 0;
}
}

private getLocaleName(localeId: number): string {


const pos: number = Object.keys(this.locales).indexOf(localeId.toString());
if (pos > -1) {
return (Object as any).values(this.locales)[pos];
}
else {
return '';
}
}
}

Remove the standard greeting web part property


Originally, the Greeting web part had the greeting property defined where the user could specify the greeting to be displayed on the screen. To adapt the web part to support multilingual
SharePoint sites, you need to store multiple values; one for each language. Because you cannot know upfront which languages will be enabled on the site, rather than using one static web
part property, you can dynamically generate web part properties at runtime.
1. In the code editor, open the ./src/webparts/greeting/GreetingWebPart.manifest.json file.
2. Remove the greeting property from the properties property:
{
// ...

"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other", "nl-nl": "Anders" },
"title": { "default": "Greeting", "nl-nl": "Begroeting" },
"description": { "default": "Greets the user", "nl-nl": "Begroet de gebruiker" },
"officeFabricIconFontName": "Page",
"properties": {
}
}]
}

3. Open the ./src/webparts/greeting/GreetingWebPart.ts file.


4. Remove the greeting property from the IGreetingWebPartProps interface definition:

export interface IGreetingWebPartProps {


}

5. Because the main React component should display a greeting, open the ./src/webparts/greeting/components/IGreetingProps.ts file, and change the IGreetingProps interface
to:

export interface IGreetingProps {


greeting: string;
}

With this modification, you can pass the greeting to be displayed from the web part to the React component.

Display property pane text fields for all enabled languages


Initially, by using the web part configuration, the user could configure a welcome message. The web part allowed the user to configure a single value that was displayed to all users no matter
what their language preference was. By retrieving the list of languages enabled on the current site, you can dynamically display text fields to allow the user to provide translations for all the
languages enabled on the site.
Load information about languages enabled on the current site
The first step is to load the information about all languages enabled on the current site.
1. In the code editor, open the ./src/webparts/greeting/GreetingWebPart.ts file.
2. Add a new class variable named supportedLanguageIds:

export default class GreetingWebPart extends BaseClientSideWebPart<IGreetingWebPartProps> {


// ...
private supportedLanguageIds: number[];
// ...
}

Because we will be querying data in SharePoint, we use SharePoint Http Client for the operations.
3. Add the following imports just above the GreetingWebPart.

import {
SPHttpClient,
SPHttpClientResponse
} from '@microsoft/sp-http';

4. In the GreetingWebPart class, add a new method named getSupportedLanguageIds:

export default class GreetingWebPart extends BaseClientSideWebPart<IGreetingWebPartProps> {


// ...

private getSupportedLanguageIds(): Promise<number[]> {


return new Promise<number[]>((resolve: (supportedLanguageIds: number[]) => void, reject: (error: any) => void): void => {
if (this.supportedLanguageIds) {
resolve(this.supportedLanguageIds);
return;
}

this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + '/_api/web?$select=SupportedUILanguageIds', SPHttpClient.configurations.v1)


.then((response: SPHttpClientResponse): Promise<{ SupportedUILanguageIds: number[] }> => {
return response.json();
}).then((siteInfo: { SupportedUILanguageIds: number[] }): void => {
this.supportedLanguageIds = siteInfo.SupportedUILanguageIds;
resolve(siteInfo.SupportedUILanguageIds);
}, (error: any): void => {
reject(error);
});
});
}
}

The list of languages enabled on the current site should be loaded only once. If the information about the languages hasn't been loaded yet, the method uses the standard SharePoint
Framework HTTP Client to call the SharePoint REST API and retrieve the information about languages enabled on the current site.
Dynamically render text fields for all languages
Now that you can retrieve the information about the languages enabled on the current site, you will display text fields for each of these languages so that the user can specify translated
values for the greeting message.
1. In the code editor, open the ./src/webparts/greeting/GreetingWebPart.ts file.
2. Add a new class variable named greetingFields to the GreetingWebPart class:

export default class GreetingWebPart extends BaseClientSideWebPart<IGreetingWebPartProps> {


// ...
private greetingFields: IPropertyPaneField<any>[] = [];
// ...
}

3. Change the import statement for the @microsoft/sp-webpart-base package to:

import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
IPropertyPaneField
} from '@microsoft/sp-webpart-base';

4. Change the propertyPaneSettings getter to get the list of text fields from the newly added greetingFields class variable:

export default class GreetingWebPart extends BaseClientSideWebPart<IGreetingWebPartProps> {


// ...

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.GreetingGroupName,
groupFields: this.greetingFields
}
]
}
]
};
}

// ...
}

If the site has multiple languages enabled, the web part renders multiple fields for the user to enter the greeting message. To make it clear that these fields belong together, put them in
a separate group.
5. In the code editor, open the ./src/webparts/greeting/loc/mystrings.d.ts file, and change its code to:

declare interface IGreetingWebPartStrings {


PropertyPaneDescription: string;
GreetingGroupName: string;
LearnMoreButtonLabel: string;
}

declare module 'GreetingWebPartStrings' {


const strings: IGreetingWebPartStrings;
export = strings;
}

6. Update the resource files accordingly to provide values for the GreetingGroupName string.
./src/webparts/greeting/loc/en-us.js

define([], function() {
return {
"PropertyPaneDescription": "Greeting web part configuration",
"GreetingGroupName": "Greeting to show in the web part",
"LearnMoreButtonLabel": "Learn more"
}
});

./src/webparts/greeting/loc/nl-nl.js

define([], function() {
return {
"PropertyPaneDescription": "Instellingen van het begroeting webonderdeel",
"GreetingGroupName": "Begroeting die in het webonderdeel getoond wordt",
"LearnMoreButtonLabel": "Meer informatie"
}
});

./src/webparts/greeting/loc/qps-ploc.js

define([], function() {
return {
"PropertyPaneDescription": "[!!! Gřèèƭïñϱ ωèβ ƥářƭ çôñƒïϱúřáƭïôñ ℓôřè₥ ïƥƨú !!!]",
"GreetingGroupName": "[!!! Gřèèƭïñϱ ƭô ƨλôω ïñ ƭλè ωèβ ƥářƭ ℓôřè₥ ïƥƨú !!!]",
"LearnMoreButtonLabel": "[!!! £èářñ ₥ôřè ℓôř !!!]"
}
});

7. In the ./src/webparts/greeting/GreetingWebPart.ts file, override the onPropertyPaneConfigurationStart method by using the following code:
export default class GreetingWebPart extends BaseClientSideWebPart<IGreetingWebPartProps> {
// ...
protected onPropertyPaneConfigurationStart(): void {
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'languages');

this.getSupportedLanguageIds()
.then((supportedLanguageIds: number[]): void => {
this.greetingFields = [];
supportedLanguageIds.forEach(localeId => {
this.greetingFields.push(PropertyPaneTextField(`greeting_${localeId}`, {
label: this.getLocaleName(localeId)
}));
});

this.context.propertyPane.refresh();
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
this.render();
});
}
}

When the user opens the web part property pane, the method loads the information about the languages enabled on the current site. Because loading this information might take a
moment, the method displays a loading indicator communicating its status to the user.
After the information about the enabled languages is loaded, the method creates a new property pane text field linked to a dynamic web part property named greeting__lcid_, for
example, greeting_1033 for US English.
After the text fields for all enabled languages are constructed, the method refreshes the property pane by calling the IPropertyPaneAccessor.refresh method.
Finally, the method clears the web part loading indicator and re-renders the web part body.

Show the greeting for the preferred user language


Originally, the web part showed the same greeting for all users no matter what their preferred language was. Now that the web part has different translations of the welcome message
stored, it should display the greeting that uses the language preferred by the current user.
1. In the ./src/webparts/greeting/GreetingWebPart.ts file, change the web part's render method to:

export default class GreetingWebPart extends BaseClientSideWebPart<IGreetingWebPartProps> {


// ...

public render(): void {


const element: React.ReactElement<IGreetingProps> = React.createElement(Greeting, {
greeting: this.getGreeting()
});

ReactDom.render(element, this.domElement);
}
}

2. In the GreetingWebPart, add a new method named getGreeting:


export default class GreetingWebPart extends BaseClientSideWebPart<IGreetingWebPartProps> {
// ...

private getGreeting(): string {


let localeId: number = this.getLocaleId(this.context.pageContext.cultureInfo.currentUICultureName);
if (localeId === 0) {
localeId = 1033;
}

return this.properties[`greeting_${localeId}`];
}

// ...
}

This method gets the currently used language and converts it to a locale ID. It then returns the value of the greeting property translated to that language.

Localization in different build types


Depending on the selected build mode, the SharePoint Framework handles localization files differently. Following are some of the differences between the files generated in a debug build
and a release build.

Localization files in the debug build


When building SharePoint Framework projects in debug mode, only the information about the default locale is included in the generated web part manifest. In debug mode, SharePoint
Framework uses either the default en-US locale, or the locale that has been specified in the project configuration or by using the locale argument in the command line.
Resource files with translated strings are not included in the output dist folder. Instead, they are loaded at runtime from the intermediate lib folder by using the path in the generated web
part manifest.
Looking at the information about the GreetingWebPartStrings module in the web part manifest generated during a debug build, you can see that despite the different locales supported by
the web part (en-US, nl-NL, and qps-ploc), the path to the en-US resource file stored in the intermediate location has been assigned as the default path of the localization module.

{
"id": "edbc4e31-6085-4ffa-85f4-eeffcb0ea2d4",
"alias": "GreetingWebPart",
"componentType": "WebPart",
"version": "0.0.1",
"manifestVersion": 2,
// ...
"loaderConfig": {
"entryModuleId": "greeting-web-part",
"internalModuleBaseUrls": [
"https://localhost:4321/"
],
"scriptResources": {
"greeting-web-part": {
"type": "path",
"path": "dist/greeting-web-part.js"
},
"GreetingWebPartStrings": {
"defaultPath": "lib/webparts/greeting/loc/en-us.js",
"type": "localizedPath",
"paths": {
"en-US": "lib/webparts/greeting/loc/en-us.js",
"nl-NL": "lib/webparts/greeting/loc/nl-nl.js",
"qps-ploc": "lib/webparts/greeting/loc/qps-ploc.js"
}
},
// ...
}
}
}

Localization files in the release build


When building SharePoint Framework projects in release mode, the information about all available locales is included in the generated web part manifest. Additionally, resources for each
locale are stored in a separate file. These resource files are copied, along with the web part manifest and the web part bundle, to the ./temp/deploy folder.
IM P O R T A N T

In release builds, resource files are copied only to the ./temp/deploy folder and not to the ./dist folder. When deploying your web part to production, you should always use files from the
./temp/deploy folder to ensure that you are deploying all files required by your web part.
Examining the latest web part manifest generated in a release build, you can see that now the GreetingWebPartStrings module contains references to all supported locales.
{
"id": "edbc4e31-6085-4ffa-85f4-eeffcb0ea2d4",
"alias": "GreetingWebPart",
"componentType": "WebPart",
"version": "0.0.1",
"manifestVersion": 2,
// ...
"loaderConfig": {
"entryModuleId": "greeting-web-part",
"internalModuleBaseUrls": [
"https://cdn.contoso.com/"
],
"scriptResources": {
"greeting-web-part": {
"type": "path",
"path": "greeting-web-part_159d9eb591c6716cae6d0ff15b78a19a.js"
},
"GreetingWebPartStrings": {
"defaultPath": "react-localization-greetingwebpartstrings_en-us_b5e89eba6e8d819bf1647b3ab505dae5.js",
"type": "localizedPath",
"paths": {
"en-US": "react-localization-greetingwebpartstrings_en-us_b5e89eba6e8d819bf1647b3ab505dae5.js",
"nl-NL": "react-localization-greetingwebpartstrings_nl-nl_d6e80ff75385975e7737774e0802641e.js",
"qps-ploc": "react-localization-greetingwebpartstrings_qps-ploc_effe5ee4af9cadee91bbf84327eb7308.js"
}
},
// ...
}
}
}

When loading the web part on the page, the SharePoint Framework automatically loads the resource file for the corresponding locale by using the information from the context site. If no
matching resource file is found, the SharePoint Framework loads the file specified in the defaultPath property.
By keeping the resource files separate, the SharePoint Framework minimizes the amount of data loaded on the page to the locale that matches the one used on the site.

See also
SharePoint Framework Overview
SharePoint Framework development with SharePoint 2016 Feature Pack 2
3/26/2018 • 3 minutes to read Edit Online

SharePoint 2016 Feature Pack 2 supports SharePoint Framework client-side web parts hosted in classic SharePoint pages.
An introduction to SharePoint Framework development in SharePoint 2016 using Feature Pack 2 is also covered in the following video on the SharePoint PnP YouTube Channel.

https://www.youtube-nocookie.com/embed/LGLMxnmHk6U?list=PLR9nK3mnD-OXZbEvTEPxzIOMGXj_aZKJG

Which version of the SharePoint Framework to use


Because SharePoint Online and SharePoint 2016 have different release cycles for new capabilities, they also have different capabilities when it comes to the SharePoint Framework.
SharePoint Online always uses the latest version of the SharePoint Framework, but SharePoint 2016 only supports the version that matches the server-side dependencies of the deployed
packages.
SharePoint 2016 Feature Pack 2 supports SharePoint Framework client-side web parts hosted on classic SharePoint pages built by using the SharePoint Framework v1.1.0. This means that
when you are targeting the SharePoint 2016 platform, you need to use the SharePoint Framework v1.1.0 due to the server-side version dependencies.
If you are planning to use the same client-side web parts in both SharePoint 2016 and in SharePoint Online, you need to use the SharePoint Framework v1.1.0 as your baseline version to
ensure that the web part works in both environments.
Starting from version 1.3, the SharePoint Framework Yeoman generator supports scaffolding solutions that use both the latest version of the SharePoint Framework meant for use with
SharePoint Online, and solutions that can be used with SharePoint on-premises based on the v1.1.0 of the SharePoint Framework. You don't need to install a separate version of the
SharePoint Framework Yeoman generator to scaffold solutions meant for use with SharePoint on-premises.
IM P O R T A N T

Starting from version 1.4, the SharePoint Framework Yeoman generator supports a new attribute of includeClientSideAssets , which can be used to indicate that assets should be included in
the sppkg package. This capability is, however, only currently supported in SharePoint Online. When a solution is targeted to on-premises, this attribute in package-solution.json should be
updated as false .

Hosting your solution for on-premises deployment


Getting SharePoint Framework client-side web parts deployed to on-premises requires two distinct actions:
Deployment of the solution package to the SharePoint app catalog
Hosting the JavaScript files in a centralized location
You can host the JavaScript files in the location that best fits your environment. For example, these files can be hosted in any of the following locations:
Azure CDN. Similar setup as with SharePoint Online. Requires en-users to have Internet connectivity.
Local server in your network. A server hosting the JavaScript files for your corporate network. This can be using whatever technology is desired as long as the files are accessible
through HTTP requests.
SharePoint 2016. You can also host your files in the local SharePoint farm itself. You can, for example, define a standardized site in your farm where all the SharePoint Framework assets
are being hosted. Take note, however, that by default, .json files are not allowed to be uploaded to SharePoint 2016 libraries, so farm level settings must be adjusted for this option.
For more information about blocked file types in SharePoint 2016, see the following support article: Types of files that cannot be added to a list or library.

Development environment considerations


When you are developing SharePoint Framework client-side web parts, you need Internet connectivity to access npm packages. This is required when solutions are being scaffolded by using
the SharePoint Framework Yeoman templates.
If Internet access is not available for the development machines, you can set up a local on-premises registry for the required npm packages. However, this requires additional software and a
significant amount of work to set up and maintain local package versions with packages in the actual npm gallery.
The Team-based development on the SharePoint Framework guidance document includes different options for development environment setup including when you might need to support
multiple SharePoint Framework versions.

Determine which version was used for a solution


If you have existing SharePoint Framework solutions and you'd like to confirm which version of the SharePoint Framework was used for them, you'll need to check the following locations:
.yo-rc.json. File in the solution's root folder that stores the SharePoint Framework Yeoman template version used when the solution was created.
package.json. File in the solution's root folder that contains references to package versions used in the solution.
npm-shrinkwrap.json. File in the solution's root folder that contains information about the exact versions used (if you used the npm shrinkwrap command to lock down the exact
versions of the solution).
package.json. File in the node_modules/@microsoft/sp-webpart-base folder that contains a version attribute matching the used SharePoint Framework version, if you have installed
packages to your solution.

See also
SharePoint Framework Overview
Try SharePoint Framework preview capabilities
6/5/2018 • 2 minutes to read Edit Online

Starting from version 1.5.0, you can try preview capabilities in the SharePoint Framework. This article outlines how to create SharePoint Framework projects using preview capabilities and
the considerations that you should take into account when working with the preview capabilities.
IM P O R T A N T

Creating SharePoint Framework projects using preview capabilities is meant for evaluation purposes only. Deploying projects using preview capabilities to production environments is not
supported. Microsoft doesn't guarantee that any of the preview capabilities will be released to production tenants. Microsoft can change or remove preview capabilities without any prior
notice.

What are SharePoint Framework preview features?


As the SharePoint Framework evolves, Microsoft would like to get feedback on the different capabilities considered for adding to the SharePoint Framework. At the same time, organizations
have been asking for preview of future capabilities both to provide feedback and take them into account for their future projects.
Starting from version 1.5.0, Microsoft offers the ability for organizations to evaluate preview capabilities in SharePoint Framework. These capabilities are available through a separate set of
npm packages tagged with the plusbeta label and range from additional API options to complete features. Even though commonly labels in SemVer are used to denote a pre-release, in this
case, the plusbeta label indicates that the npm package contains additional preview functionality. For example, the 1.5.0-plusbeta version of the SharePoint Framework includes all the
functionality released in the 1.5.0 version plus some extra experimental features.
When scaffolding SharePoint Framework projects using the regular SharePoint Framework Yeoman generator (@microsoft/generator-sharepoint), you can choose if you want to use the
preview capabilities or not. Based on your choice, the generator will create a project which you can run in a production environment or a project that you can use to evaluate the experimental
features. You should keep in mind, that there is no guarantee that the capabilities from a plusbeta version will be released in a future version of the SharePoint Framework and using
solutions built using the plusbeta version in production is not supported.
NOTE

Feedback on provided preview capabilities is welcome using the issue list at sp-dev-docs GitHub repository.

Create SharePoint Framework projects using preview features


Starting from version 1.5.0, you can use the SharePoint Framework Yeoman generator to create projects that use preview features of the SharePoint Framework. To include preview
capabilities, add the plusbeta switch to the yo command, for example:

yo @microsoft/sharepoint --plusbeta

After executing this command, the SharePoint Framework Yeoman generator, will scaffold a new SharePoint Project using whatever preview capabilities are available at that moment. For
additional information about the available preview capabilities, refer to the release notes of the SharePoint Framework Yeoman generator.
If plusbeta switch was used, package.json will reference different packages for the scaffolded project with the @plusbeta tag.
Designing great SharePoint experiences
3/26/2018 • 2 minutes to read Edit Online

SharePoint is a platform that delivers content to more than 200,000 organizations and 190 million people worldwide. This SharePoint design guidance helps you create compelling
SharePoint experiences and effectively communicate your brand and message to your audience. In addition, this guidance helps you better take advantage of the powerful tools in
SharePoint while creating your own customized and optimized experiences. We welcome your feedback and input so that we can keep making improvements to this guidance.

SharePoint design principles


SharePoint builds on the design principles that shape the Office and Microsoft product families. These principles help the design stay true to our product goals and user needs.

Optimistic and fast


SharePoint is encouraging, knowing people can achieve whatever they set their minds to when given the platform and the support they need. We're fast and agile, and we adjust our product
experience based on feedback and input.

Dynamic and alive


We thrive on the dynamism in the world and love the way that change can open new possibilities for people. We’re fearless about reinventing ourselves, continually changing for the better
to meet the needs of the people and companies changing the world around us.

Authentic and useful


Our passion is to help people achieve, and it has been for more than 30 years. We care about it in a way that no one else does. We understand the importance of our customers and make
sure that SharePoint stays relevant and useful by staying authentic and true.

Forward-thinking
We search for what’s possible beyond today’s way of getting things done. We’re energized by all that people are capable of achieving and seek to support and amplify it through our
platform. We care about the needs of people not only today, but tomorrow—anticipating what and how they’ll want to achieve. So we build our technology around who they can be and what
they can become.

Accessible and optimized


Accessibility is developing an equal experience for all users that enables individuals to adjust their user experience to meet their unique visual, hearing, dexterity, cognitive, and speech needs.
SharePoint believes strongly in providing accessible experiences for everyone, everywhere, and in optimizing our experiences to reflect the needs of all of our customers.

See also
Overview of SharePoint Framework
Designing a SharePoint web part
3/26/2018 • 2 minutes to read Edit Online

Before you design a SharePoint web part, you should understand how to author pages in a SharePoint site. If you haven't already, take some time to create a page and add multiple types of
web parts. It is important to know how to leverage Office Fabric components and styles to make it easier and quicker to get your new web part up and running.
When you design web parts, it's important to be familiar with the following concepts:
Property pane types and when to use each type
Reactive and nonreactive web parts
Titles and descriptions
Placeholders and fallbacks

Property pane types


You can use three types of property panes to design and develop web parts that fit your business or customer needs.
To open a pane to configure settings for a web part, select Edit. Use the pane to enable and disable features, select a source, choose a layout, and set options. Edit web part content within the
web part rather than in the property pane.
The property pane is 320 px and when opened, the page responsively reflows.

Single pane
Use a single pane for simple web parts that have only a small number of properties to configure.

Accordion pane
Use an accordion pane to contain a group or groups of properties with many options, and where the groups result in a long scrolling list of options. For example, you might have three
groups named Properties, Appearance, and Layout, each with ten components.
Use accordion panes when you need to apply categorization for a complex web part.
Accordian groups example with last pane open

Accordion groups example with two groups open


Steps pane
Use a steps pane to group properties in multiple steps or pages when you need the web part to be configured in a linear order, or when choices in the first step affect the options that display
in the second or third step.
Step 1 of the steps pane
In step 1, the back button is disabled and the next button is enabled.
Step 2 of the steps pane
In step 2, the back and next buttons are enabled.

Step 3 of the steps pane


In step 3, the next button is disabled and the back button is enabled.

See also
Designing great SharePoint experiences
Reactive and nonreactive SharePoint web parts
3/26/2018 • 2 minutes to read Edit Online

Reactive web parts are client-side only; nonreactive web parts have elements that require a server to operate. We recommend that you build your SharePoint web parts to be reactive,
because that best fits the UX model and WYSIWYG principles for authoring. However, it might not be possible or cost-effective in all cases to build reactive web parts.

Reactive web parts


Reactive web parts are fully client-side web parts. This means that each component configured in the property pane reflects the change made within the web part on the page. For example,
for the To-Do List web part, unchecking “Completed Tasks” hides this view in the web part.

Nonreactive web parts


Nonreactive web parts are not fully client-side; generally, one or more properties need to make a call to set/pull or store data on a server. For nonreactive web parts, you should enable the
Apply button at the bottom of the property pane.
You can also customize the Apply button to be a more specific action.

The following examples show nonreactive web parts in the context of the three property pane structures.
Single pane example
Accordion groups example

Steps pane example

See also
Designing great SharePoint experiences
SharePoint grid and responsive design
3/26/2018 • 3 minutes to read Edit Online

Responsive experiences seamlessly scale across devices to better display your content on a range of different screen sizes. Responsive design also eliminates the need to build multiple
versions of your site pages to support different devices.
The design guidance for responsive pages in the SharePoint authoring environment incorporates a responsive grid system that is based on Office UI Fabric. This article describes the
underlying page grid system and the breakpoints, or key screen sizes where the layout of the pages will change.

Page type grids


Each page type in the SharePoint authoring experience can have its own rules for how it applies the Fabric responsive grid. This is to ensure that each page looks great, regardless of what
device it's designed for, and that the experience is optimized for that environment. The basic grid in the SharePoint desktop experiences is a 12-column structure. The number of columns and
gutter width adjust based on the screen width.
The following sections show the basic grid structure applied across different types of SharePoint pages, to help you better understand how the grid adjusts to support the experience and
device needs.
Team sites
The content area for a team site is locked to the left. Team sites have a left navigation; therefore, the space that web parts occupy on the grid and the reflow behavior respects the space given
to the navigation. The max width of the content area of a Team site is 1204 px and the minimum size is 320 px for mobile support.

The following examples show how the grid adjusts between key breakpoints on a team site.
Small 320 x 568
The small size has a single centered column area, with 20 px margins left and right.

Medium 480 x 854


The medium size has 12 columns, with 16 px gutters.
Large 640 x 1024
The large size has 12 columns, with 24 px gutters.
XL 1024 x 768
The XL size has 12 columns, with 24 px gutters.

XXL 1366 x 768


The XXL size has 12 columns, with 32 px gutters.

XXXL 1920 x 1080


The XXXL size has 12 columns, with 32 px gutters.

Team site multicolumn pages and web parts


Web parts scale horizontally depending on the page layout. The following example shows how the size of a web part adjusts to accommodate the left navigation.
Communication sites
Communication sites have a top navigation and a centered content area. The maximum width of the content area of a communication site is 1204 px, and the minimum size is 320 px for
mobile support.

The following examples show how the grid adjusts between key breakpoints on a communication site.
Small 320 x 568
The small size has a single centered column area, with 20 px margins left and right.
Medium 480 x 854
The medium size has 12 columns, with 16 px gutters.

Large 640 x 1024


The large size has 12 columns, with 24 px gutters.
XL 1024 x 768
The XL size has 12 columns, with 24 px gutters.

XXL 1366 x 768


The XXL size has 12 columns, with 32 px gutters.

XXXL 1920 x 1080


The XXXL size has 12 columns, with 32 px gutters.

Communication site multicolumn pages and web parts


Web parts scale horizontally depending on the page layout. This example shows a communcation site and web parts for single to three column layouts.
Breakpoints
To create a smooth flowing experience between screen sizes, the SharePoint UI should adapt layouts for the following breakpoint widths:
320 px
1024 px
1366 px
1920 px
Within these breakpoints, you should take into consideration how your content shifts when the viewport size becomes optimized for the nearest breakpoint. Note that this diagram is for
illustration only and is not pixel accurate.

The responsive grid for both team sites and communication sites adjusts when going from large breakpoints to mobile breakpoints. This optimizes the site for the device and screen size. The
following table describes the grid sizes at various breakpoints based on popular device sizes.

W IND O W W ID TH D EV ICE B R E AK PO INT CO LU MNS G U T TER MAX CO LU MNS PER S ECTIO N

320 iPhone 5/SE,320x568 Small 1 N/A 1

480 6" device Medium 1 N/A 1

640 8" device Large 12 16 2


W IND O W W ID TH D EV ICE B R E AK PO INT CO LU MNS G U T TER MAX CO LU MNS PER S ECTIO N

768 iPad portrait 768x1024 Large 12 24 2

1024 iPad landscape 1024x768 X-Large 12 24 3

1368 Surface Pro 3 1368x912 XX-Large 12 32 3

1440 Surface Pro 4 1440x960 XX-Large 12 32 3

1600 Web 1600x900 XX-Large 12 32 3

1920 Web 1920x1080 XXX-Large 12 32 3

See also
Design toolkit and assets
Designing great SharePoint experiences
Titles and descriptions for SharePoint web parts
3/26/2018 • 2 minutes to read Edit Online

You can add titles and descriptions to web parts to help users understand their purpose. This is helpful when a page contains a range of web parts. Some web parts (such as image web
parts) might not need a title, but might need a description before or after the content area. Don't assume that users understand the context of the web part without either a title or a
description, and don't assume that users will include titles or descriptions themselves.
One option is to connect the title and description to the configuration properties of your web part. This ensures that your web parts are prepopulated with content that makes the most sense
based on the configuration.
For example, if you have a web part that queries a document library based on recently added items, you might want to use "Recent documents" for the default title.

For both the title and description, the author of the page can override the default placeholder text and customize them based on what makes the most sense for the page they're creating.

See also
Designing great SharePoint experiences
Commanding within a web part
5/25/2018 • 2 minutes to read Edit Online

Commanding within a web part consists of a single line of commands that sits under the web part title. These commands contain an icon and text, for example the + (plus) icon and the text
Add. The command bar can be extended to support multiple commands. However, be aware of overloading the web part with too many commands. Also, note how the commands reflow
when the web part is placed in different columns, or when the page reflows to smaller screen sizes.

See all
Many web parts may need to support the overflow of content to a secondary page (for example, in News and Events web parts). In addition, only specific layouts within the web part may
need to support the overflow. The recommended pattern is to place a See all command in the far-right corner. To support keyboard navigation, this command should be last in the tab order
of the web part.
Command bar states
A common command is Add for many web parts that require content to be created. In the case of News and Events, the Add command is only enabled in read mode because it takes the
user to a new page or form to create content. The desired web part user experience should determine if commands are active in both read and edit modes, only edit, or only read. Most likely
this is driven by whether the web part is designed to be configured by the author of the page and static to the viewer, or if the viewer/reader can interact with the web part.

Placement and accessibility of commands


Core commands, even when the web part has only one command such as Add, should sit under the title to create consistency and discoverability, and to support easy reflow across all
column sizes. Long web part titles should wrap to two lines, but not interfere with the placement of the commands.
Following is an example of a web part with a simple set of commands that follow the placement guidance. Follow this guide when deciding how to make your web part accessible to support
keyboard navigation and screen reader labels. To learn more about accessibility, see Accessibility in SharePoint web part design.
UI text guidelines for SharePoint web parts
3/26/2018 • 5 minutes to read Edit Online

One aspect of creating effective web parts in SharePoint is to use simple, understandable, and concise UI text. By keeping your message clear and easy to understand, you ensure that
customers move through your experiences quickly and can identify the content they are looking for. This article provides guidance for writing UI text for key areas within SharePoint web
parts.

Capitalization
Use sentence casing (first letter of first word is capitalized, the rest all lowercase) for all UI elements, including buttons, page titles, and control labels.
Always capitalize:
The first word of a new sentence.
The word following a colon in a title or heading. For example, "Step 1: Begin by entering your account information."
Proper nouns, such as the names of people, cities, and so on.

Punctuation
Follow the basic rules of punctuation to avoid grammatical errors in your experience. The following table provides guidance and reminders about what punctuation to use when, and why.

PU NCTU ATIO N G U ID ANCE E X AMPLE

Colons (:) Use colons if you are introducing a list in the web part description. Choose one of the following: Cats, Dogs, Quokkas
Don't use colons in UI labels.

Commas (,) Use serial commas (including before the word "and"). I like cats, birds, and dogs.

Ellipses (…) Use ellipses to show truncation and for progress indicator strings. Truncation: Last modified by John Armstr…
Don't use ellipses to indicate that the user must make further Progress indicator: Uploading…
choices.

Periods (.) Use periods as you normally would for descriptions. Select the content that you want to highlight and how you want it
Don't use periods in titles, headings, or labels. Don't use periods for displayed. Use a filter to narrow your selection.
radio button options or check boxes.

Voice and tone


Crafting the right tone in your product communication is essential to building a strong, lasting relationship with your audience. Try to keep your words crisp and clear, warm and relaxed, and
approachable. How you talk to your audience influences how they engage with your site and content, and how much value they derive from it.
Do:
Use a casual, conversational tone in the UI.
Use contractions. For example, use "can't" instead of "cannot".
Read your UI text out loud to test the tone. Does it sound like everyday language?
Use simple words.
Remove technical details if they're not relevant to the user experience.
Use "Please" only if you are inconveniencing the user. Avoid overuse.
Use "Sorry" only in error messages in SharePoint that result in serious problems for the customer.
Don't:
Clutter the UI text with unnecessary repetition. Make every word meaningful.

Pronouns
Avoid pronouns in UI elements if possible. If you can say something equally well without using a pronoun, don't use it.
If your design does warrant using pronouns, apply the following guidelines to make sure that you're using them correctly.
Do:
Use second person ("you" or "your") when you're presenting something that belongs to the user. For example, "Your drafts" or "Your images".
Use first person ("me" or "my") for UI in which the user instructs the service to do something. For example, "Alert me when someone responds to my post."
Use "they" or "their" as a singular possessive modifier to avoid awkward "he/she" or "his/her" constructs. Ideally, rewrite the sentence as plural if possible.
Avoid using "them"; instead, use words like "someone" or "people". For example, "Enter a user name and domain to give someone permission to use this PC."

Don't:
Use third person references, as they sound impersonal and can create a disconnected customer experience. Instead of saying "Users can change the layout", use a phrase like "You can
change the layout".

Error messages
Error conditions are inherent in any software or service. Your error messages can affect the overall user satisfaction with the product. A good error message should do the following:
Clearly identify what happened and why.
Provide a workaround or resolution suggestions.
Show empathy.
The following is an example of an error message that occurs when a user tries to edit a page that's checked out by another user.
YO U CAN' T ED IT R IG HT NO W

Another user is currently editing this page. Please try again in a few minutes.

Links to help articles


Make an effort to link strategically to help articles. Try to anticipate where the user might need help, and then include a link to the help article close to that UI element. The following are
some key things to remember when you place help article links in your UI.
Do:
Keep the in-product help links specific. Ensure that the target article is appropriate. When the user opens the article, they should be able to locate the information they need.
Use natural language for your hyperlinks.
Don’t:
Put a help article link next to every UI element. This results in visual noise.
Include multiple links that go to the same target in the same UI.
Use "click here" for the text for your hyperlink.

Hint text
Hint text, or ghost text, is the text element you display in a UI element, typically a text box, to help the user interact with the UI. The hint text gives information about what the user should
enter. For example, it might mention field restrictions or show an example.
Do:
Use hint text sparingly, and only if it helps the user. Not all UI elements require hint text. For some complex fields, hint text can help provide more context and clarity. For example, if you
have a field that requires the user to enter a secured URL, the hint text https://www.example.com might be more helpful than the text Enter secure URL here.
Don't
Repeat the label. For example, if you have a text box with the label Name, the hint text Enter name is redundant and potentially confusing.
The following hint text is for the embed web part. The text field can accept a secure website address or an iframe embed code. The text shows an example of both.

See also
Designing great SharePoint experiences
Placeholders and fallbacks in SharePoint web parts
3/26/2018 • 2 minutes to read Edit Online

You can add placeholders to SharePoint web parts that can also be used as a fallback if an issue occurs loading content or data for a web part. The web part name and description are
automatically added from the metadata submitted with the web part.
You can add a button that users can select to return to a state where they can configure the web part.

See also
Designing great SharePoint experiences
Empty state of a web part
5/25/2018 • 2 minutes to read Edit Online

The empty state is a visual representation of a web part, pre-configured to a content source like a list or with placeholder content, such as images and text.
The following web parts have a content source set by default but no content to show for a newly created Communication site (that is, they feature an empty state):
Highlighted content
News
Site activity
Events
Hero
Image gallery
Empty states are designed to convey the purpose, stucture, and layout options of web parts before the web part is configured or content is added. The empty state is also a perfect way to
illustrate the vertical rhythm and layout of a page that starts from a template. Empty states behave similarly to fully configured web parts, and reflow to accommodate available space. They
should support author-configured web part layouts.

Empty states are different from placeholders in that the latter are meant to be displayed as a fallback when no content is added, or to help the author configure the web part. To learn more
about placeholders, see Placeholders and fallbacks in SharePoint web parts.

Empty state and editing rights


Web parts with empty states can change interaction options and display text depending on the permission level and mode of the page.
In the following example (left to right), a person with editing rights sees an empty state of the Events web part in Edit and Read modes. The last image shows a simplified empty state view
for page readers that have no editing rights, with a message appropriate to their permission level.
The following are layout options for the Events web part in an empty state.

Interactions with an empty state


Empty states are designed primarily for people with editing rights and change interaction options based on the current page mode. Authors can manually add content to web parts in the
Read mode, such as adding a new event or new news post.
The following example shows an empty state with multiple items stacked vertically, where the first item acts as a call to action (CTA) to learn more or create an event.
Empty state with pre-provisioned content
The Hero web part is an example of an empty state with pre-provisioned content and text. The empty state is designed to help authors understand the options and the layout capabilities of
the web part. The empty state in this case is a visual template for the web part. When pre-provisioning content for an empty state make sure end users have rights to publish the content
(images, illustrations, etc.) in their pages.
Accessibility in SharePoint web part design
3/26/2018 • 4 minutes to read Edit Online

Developing an experience that meets all users' unique visual, hearing, dexterity, cognitive, and speech needs is an important component of SharePoint web part design. Accessible design
applies not only to people with disabilities, but also to potential situational impairments. Accessible design is good design.

Accessibility guidelines
All Microsoft products must meet the requirements listed in the Microsoft Accessibility Standards.

Making web parts accessible


The SharePoint Framework provides a structure to help make all web parts accessible. The web part container provides keyboard navigation defaults for the web part toolbar to edit, move,
and delete the web part, a method to select the web part, and a keyboard short cut (Ctrl+P) to open the property pane. However, you still need to specify additional keyboard and screen
reader navigation for the other aspects of the UI in the web part and in the property pane.
In addition, many Office UI Fabric components have built-in support for accessibility options, to make it quick to configure keyboard and screen reader navigation when you use the
components in a web part.
The following image shows keyboard navigation on a web part.

Accessibility testing
Test your web part first with Narrator and Microsoft Edge, and then verify the accessibility experience with JAWS.
Narrator and Microsoft Edge are standards compliant. When you test with that combination, you are more likely to find issues, and you can validate that your site meets accessibility
standards.
JAWS is the market leader in screen readers. JAWS includes features that can improve the accessibility of some websites that aren't as accessible in other screen readers. Therefore, testing in
JAWS might not ensure that your site meets all accessibility requirements.
You might also want to test for whatever combination of browser and screen reader has the greatest market share for your website.

Keyboard navigation
For some users, navigating a site via keyboard is more accessible. Power users also often rely on keyboard navigation. Make sure to design keyboard shortcuts such as tabs to go to controls
on the page, and use arrow keys to navigate inside controls.

Navigation between controls


Each control is a tab stop. Within a control, the following rules apply:
In general, the first tab stop is the top left area of the control. The last tab stop is the bottom right control.
For modal surfaces, the last tab stop should be the commit actions.
For lists, the first tab stop should be the first item in the list, the next should be the commands, and then the navigation, settings, and so on.
Navigation within a control
You can use arrow keys to move to items in a control, such as choices in a menu, commands in a command bar, or items in a list.

Selecting the current item


Use the space bar to select or deselect the item currently in focus in a control.
Run a control
Press Enter or the return key to run a control.

Leave a control
Press Escape to exit a control and return to the container.
Go to the first or last item
Press Home or End to go directly to the first or last item in a list, menu, and so on.

Screen reader navigation


Users who have vision impairments rely on screen readers to navigate the site UI. When designing a web part, follow this example when thinking about keyboard navigation and how the
screen reader conveys important actions or information to the user.

Alt text and transcripts


Use alt text to provide descriptions of images that can be consumed by screen readers. This is useful for vision-impaired users who cannot consume information visually. Make sure that your
alt text is descriptive, keeping in mind that some readers are relying on a screen reader to access the information conveyed in the image.
Don't rely only on color to convey meaning; rely on both color and shape.
To be fully compliant with accessibility standards, include alt text and a complete transcript of audio and video content on your site.

Minimum readable contrast


A minimum level of contrast is essential to help users with vision impairments consume the content on the page. It is also important to aid readability in low light and glare situations.
The following image shows theme colors on the left and neutral colors on the right.

THEME CO LO R S NEU TR AL CO LO R S

themeDarker: #004578 black: #000000


themeDark: #005a9e neutralDark: #212121

themeDarkAlt: #106ebe neutralPrimary: #333

neutralPrimaryAlt: #3c3c3c

themePrimary: #0078d7 neutralSecondary: #666666

neutralTertiary: #a6a6a6

themeSecondary: #2b88d8 neutralTertiaryAlt: #c8c8c8

themeTertiary: #71afe5 neutralLight: #eaeaea

themeLight: #c7e0f4 neutralLighter: #f4f4f4

themeLighter: #deecf9 neutralLighterAlt: #f8f8f8

themeLighterAlt: #eff6fc white: #fff

High contrast
Use high contrast colors as a guide for color choices for components and states on the web. Windows computers only have the ability to detect whether a PC is running high contrast or high
contrast white. For this reason, use the default high contrast black setting for any high contrast, non-white theme.

See also
SharePoint themes and colors
Design a web part
Designing great SharePoint experiences
Key web part examples
5/25/2018 • 2 minutes to read Edit Online

Web parts are the building blocks of your page.


This is a visual overview of Communication site and Team site templates, highlighting how web parts work together to create a coherent overall design. Use these pages as reference when
designing a SharePoint web part.
It is important to consider how the web part will look and function when sitting next to other web parts on a page. Follow the patterns in this documentation and on the Office UI Fabric site
to ensure consistency in layout and grid alignment, font size and hierarchy, commanding, empty states, and more.

Communication sites
Topic design
The Topic design is used when you have a lot of information to share, such as news, events, reports, and other content. It is built from the Hero, News, Events, Highlighted content, Quick
links, and People web parts.
Showcase design
The Showcase design is used to feature a product, team, or event. It leverages the Hero and Image gallery web parts to show rich visual content.
Team sites
The Team site design is the default layout for any new team. It features the News, Quick links, Highlighted content, and Document library web parts.
These example site and web part designs have been added to the SharePoint toolkit and can be used as reference when designing web parts. For more information, see the SharePoint
toolkit.
SharePoint web part design showcase: Create a To-Do list property pane
3/26/2018 • 2 minutes to read Edit Online

This article describes how to create a To-Do list web part. This example uses the single pane property pane type and is reactive and based on the Office UI Fabric responsive grid.

Create a To-Do list web part


1. Add a description to help users understand more about the web part and its properties.
In this example, the description is "Select a source for your to-dos and customize the display for the list of tasks."

2. Add a Fabric drop-down component connected to a list.


3. Add a Fabric checkbox component to display completed tasks.

4. Add two more check boxes to control display options.


5. Add a Fabric slider for the maximum number of items to display.

6. Next, the author of the page selects a list or manually adds tasks to prepopulate the To-Do list web part.
7. The web part shows an indicator of items loading onto the page.

8. Items from the list load.


When the new tasks are loaded, they fade into view by using animation components from Office UI Fabric.

9. The property pane controls the UI. Tasks with pivots enabled are displayed via the Display check boxes in the property pane.
Responsive views
The following example shows the 2/3 column view of the web part.

The following example shows the 1/3 column view of the web part.
The following example shows the mobile (read-only) view of the web part.

See also
Designing great SharePoint experiences
Authoring pages in a SharePoint site
3/26/2018 • 2 minutes to read Edit Online

Authoring pages in SharePoint is a simple process, but it does require some familiarity with the SharePoint environment, as well as an understanding of what and who you are designing the
page for. A few basic principles, such as remembering to "Start simple" and "Build on what's working," are valuable things to consider as you start authoring. It's also a good idea to
consistently remind yourself of your audience and the goals that you are trying to help them achieve.
The SharePoint page authoring experience has two modes:
Edit. Allows page authors to add and configure web parts to add content to a page.
Published. Allows your team or audience to view content and interact with web parts.

Edit mode
When creating a new page, users have access to the authoring UI to add content to and customize the page content.

Add hint and Toolbox


The add hint is a horizontal line with a plus icon that is visible when a web part is selected and on hover to indicate where page authors can add new web parts to their page. The Toolbox
opens when a user selects the plus icon. The Toolbox contains all the web parts that can be added to a page.
Toolbar
A vertical toolbar and bounding box is part of the framework for every web part and is provided by the page. Each web part has an edit and delete action in the toolbar.

Active and hover states


On hover/active, the hint bars are primary blue or the primary theme color for the site.

The bounding box for a web part is gray by default, but picks up the primary blue or primary theme color for the site on hover or when the web part is selected.
Contextual edits
Design a WYSIWYG experience for web parts so that users can fill in information or add content that is displayed when published. This content should be entered on the page so that the
user understands how it renders in the viewer. For example, titles and descriptions should be filled out where the text displays; new tasks should be added and modified in the context of the
page.

Item-level edits
UI can change within the web part; for example, text can become a text field, or you can display UI to reorder items or to check off tasks in a web part. You can enable interactive functionality
for web parts in edit mode, in read mode, or in both, depending on your design intent.
Property panes
Property panes are invoked via the Edit icon on the toolbar. Property panes should primarily contain configuration settings that enable or disable features that either show on the page, or
make a call to a service to display content.

Published mode
After the page is published, all editing UI is disabled for the viewer or reader of the page. To continue editing the page, the user selects the Edit button on the top right corner of the
command bar.
Mobile view
All SharePoint pages are responsive to allow the content of the page to be viewed on mobile devices. While designing a web part, it is important to understand how the new SharePoint site
pages render across different devices.

See also
Designing great SharePoint experiences
Design considerations for SharePoint client-side web parts
3/26/2018 • 4 minutes to read Edit Online

To get started designing web parts, you need to be familiar with Office UI Fabric. All of the styles from Fabric Core, including icons, typography, color usage, animation, and the responsive
grid, are loaded by default and available to your web part.
Do not import a copy of Fabric for your web part because this may conflict with the global copy. These classes provide a foundation to your web part's styling, which you can always depart
from if you require different visuals to match your company's brand.

Office UI Fabric React components


Along with Office UI Fabric, you can use Office UI Fabric React components to build your web parts. Fabric React is a responsive, mobile-first collection of components designed to make it
quick and simple for you to create web experiences by using the Office Design Language.
The following To Do list example uses Fabric components in the property pane that lets the page author configure a web part.

You can find a complete list of the Office UI Fabric styles, typography, color, icons, and animations at Office UI Fabric styles.

Responsive behavior
Pages in the new SharePoint authoring experience use the Office UI Fabric responsive grid to help ensure that each page looks great.

Maximum width
We recommend that all web parts use a 100% maximum width to ensure that they re-flow and function properly on any page. The page and column widths are defined by the page template
but can be modified by the author. If a maximum pixel value is set in the web part, there could be unexpected results in both functionality and layout when the page is seen at different widths.
Minimum width
All web parts should be designed to reflow as the page/column width gets smaller down to a minimum width of 320 px.

Web part Edit mode


The new SharePoint page authoring experience has two modes:
Published mode, which allows your team or audience to view content and interact with web parts.
Edit mode, which allows page authors to add and configure web parts to add content to a page.
The following sections describe Edit mode.

Add hint and Toolbox


The add hint is a horizontal line with a plus icon that is visible when a web part is selected and on hover to indicate where page authors can add new web parts to their page. The toolbox
opens when a user selects the plus icon. The toolbox contains all the web parts that can be added to a page.
Toolbar
A vertical toolbar and bounding box is part of the framework for every web part and provided by the page. Each web part has an edit and delete action in the toolbar.

Contextual edits
A WYSIWYG experience should be designed for web parts to fill in information or add content that is displayed to the user when published. Entering this content should be done on the page
so that the user understands how the viewer sees the content. For example, titles and descriptions should be filled out where the text displays, or new tasks should be added and modified in
context of the page.

Item-level edits
UI can change within the web part; for example, turning text into a text field to fill out links or when displaying UI to reorder items or to check tasks in a web part.

Property panes
Property panes are invoked via the edit action icon on the toolbar. Panes should primarily contain configuration settings that enable/disable features that either show on the page or that
make a call to a service to display content.
There are three types of property panes to enable you to design and develop web parts that fit your business or customer needs.

Single pane
A single pane is used for simple web parts that only have a small number of properties to configure.

Accordion pane
An accordion pane is used for containing a group or groups of properties with many options and where the groups would result in a long scrolling list of options. For example, you might
have three groups named Properties, Appearance, and Layout, each with ten components.
Accordion - One group open
Accordion - Two groups open and scrolled

Property pane steps/pages


A steps pane is used for grouping properties in multiple steps or pages when you need the web part to be configured in a linear order, or when choices made on the first step affect options
that display on the second step.
Step 1 of 3
Step 2 of 3

Step 3 of 3
Reactive vs non-reactive web parts
Reactive web parts are designed to be full client-side web parts, which means that each component that is configured in the properties pane reflects the change made within the web part
on the page. For the To-Do List web part, unchecking “Completed Tasks” hides this view in the web part.

Non-reactive web parts are not fully client-side, and generally one or more properties need to make a call to set/pull or store data on a server. In this case, you should enable the Apply and
Cancel buttons at the bottom of the properties pane.
Constructing the To-Do List property pane
The To-Do List example uses the single pane and is a reactive web part. The following diagrams show each Fabric React component and the resulting design.
Adding a description for To-Do List

Dropdown – to select tasks from an existing list


Check box – to allow authors to show or hide different views

Slider – to set the number of tasks visible


After selecting a list from the dropdown, the web part shows an indicator of items loading onto the page

When the new tasks are loaded, they fade into view by using animation styles from Office UI Fabric
See also
Designing a SharePoint web part
Designing great SharePoint experiences
Use custom dialog boxes with SharePoint Framework Extensions
3/26/2018 • 6 minutes to read Edit Online

You can use custom dialog boxes, available from the @microsoft/sp-dialog package, within the context of SharePoint Framework Extensions or client-side web parts.
This article describes how to create a custom dialog box and use it within the context of a ListView Command Set extension.
You can access the sample code that this article is based on in the sp-dev-fx-extensions repo.

Set up your development environment


To create a custom dialog box, you need to follow the steps in Set up your development environment. Make sure that you're using the latest SharePoint Framework Yeoman templates.

Create a new project


1. Create a new folder for the project by using your console of choice:

md dialog-cmd

2. Enter that folder:

cd dialog-cmd

3. Run the Yeoman generator for the SharePoint Framework:

yo @microsoft/sharepoint

4. When prompted:
Accept the default value of dialog-cmd as your solution name, and then select Enter.
Select SharePoint Online only (latest), and then select Enter.
Select Use the current folder, and then select Enter.
Select N to require the extension to be installed on each site explicitly when it's being used.
Select Extension as the client-side component type to be created.
Select ListView Command Set as the extension type to be created.
5. The next set of prompts asks for specific information about your extension:
Use the value of DialogDemo as your extension name, and then select Enter.
Accept the default value of DialogDemo description as your extension description, and then select Enter.

At this point, Yeoman installs the required dependencies and scaffolds the solution files along with the DialogDemo extension. This might take a few minutes.
When the scaffold is complete, you should see the following message indicating a successful scaffold:
6. After the scaffolding completes, lock down the version of the project dependencies by running the following command:

npm shrinkwrap

7. Open your project folder in your code editor. This article uses Visual Studio Code in the steps and screenshots, but you can use any editor that you prefer. To open the folder in Visual
Studio Code, use the following command in the console:

code .

Modify the extension manifest


In the extension manifest, configure the extension to have only one button. In the code editor, open the ./src/extensions/dialogDemo/DialogDemoCommandSet.manifest.json file.
Replace the commands section with the following JSON:

{
//...
"items": {
"COMMAND_1": {
"title": { "default": "Open Custom Dialog" },
"iconImageUrl": "icons/request.png",
"type": "command"
}
}
}
Create a custom dialog box
1. Create a new file called ColorPickerDialog.tsx in the ./src/extensions/dialogDemo/ folder.
2. Add the following import statements at the top of the newly created file. You're creating your custom dialog box by using the Office UI Fabric React components, so the
implementation is in React.

import * as React from 'react';


import * as ReactDOM from 'react-dom';
import { BaseDialog, IDialogConfiguration } from '@microsoft/sp-dialog';
import {
autobind,
ColorPicker,
PrimaryButton,
Button,
DialogFooter,
DialogContent
} from 'office-ui-fabric-react';

3. Add the following interface definition just under the import statements. This is used to pass information and functions between your ListView Command Set extension and your
custom dialog box.

interface IColorPickerDialogContentProps {
message: string;
close: () => void;
submit: (color: string) => void;
defaultColor?: string;
}

4. Add the following class just under the interface definition. This React class is responsible for rendering the UI experiences inside the custom dialog box. Notice that you use the Office
UI Fabric React components for actual rendering and just pass the needed properties.

class ColorPickerDialogContent extends React.Component<IColorPickerDialogContentProps, {}> {


private _pickedColor: string;

constructor(props) {
super(props);
// Default Color
this._pickedColor = props.defaultColor || '#FFFFFF';
}

public render(): JSX.Element {


return <DialogContent
title='Color Picker'
subText={this.props.message}
onDismiss={this.props.close}
showCloseButton={true}
>
<ColorPicker color={this._pickedColor} onColorChanged={this._onColorChange} />
<DialogFooter>
<Button text='Cancel' title='Cancel' onClick={this.props.close} />
<PrimaryButton text='OK' title='OK' onClick={() => { this.props.submit(this._pickedColor); }} />
</DialogFooter>
</DialogContent>;
}

@autobind
private _onColorChange(color: string): void {
this._pickedColor = color;
}
}

5. Add the following class definition for your custom dialog box under the ColorPickerDialogContent class that you just added. This is the actual custom dialog box that is called from the
ListView Command Set button click and is inherited from the BaseDialog .

export default class ColorPickerDialog extends BaseDialog {


public message: string;
public colorCode: string;

public render(): void {


ReactDOM.render(<ColorPickerDialogContent
close={ this.close }
message={ this.message }
defaultColor={ this.colorCode }
submit={ this._submit }
/>, this.domElement);
}

public getConfig(): IDialogConfiguration {


return {
isBlocking: false
};
}

@autobind
private _submit(color: string): void {
this.colorCode = color;
this.close();
}
}

Associate the dialog box with the ListView Command Set button click
To associate the custom dialog box with your custom ListView Command Set, add the code to initiate the dialog box within the button click operation.
1. In the code editor, open the DialogDemoCommandSet.ts file from the ./src/extensions/dialogDemo/ folder.
2. Add the following import statements under the existing strings import. These are for using the custom dialog box in the context of your ListView Command Set.

import ColorPickerDialog from './ColorPickerDialog';

3. Add the following _colorCode variable definition above the onInit function in the DialogDemoCommandSet class. This is used to store the color picker dialog box result.

private _colorCode: string;

4. Update the onExecute function as follows. This code does the following:
Initiates the custom dialog box.
Passes a message for the dialog box, which is used for the title.
Passes a color code for the dialog box with a default value, if not yet set.
Shows the custom dialog box.
Receives and stores the return value from the dialog box.
Shows the received value in a default dialog box by using the Dialog.alert() function.

@override
public onExecute(event: IListViewCommandSetExecuteEventParameters): void {
switch (event.itemId) {
case 'COMMAND_1':
const dialog: ColorPickerDialog = new ColorPickerDialog();
dialog.message = 'Pick a color:';
// Use 'EEEEEE' as the default color for first usage
dialog.colorCode = this._colorCode || '#EEEEEE';
dialog.show().then(() => {
this._colorCode = dialog.colorCode;
Dialog.alert(`Picked color: ${dialog.colorCode}`);
});
break;
default:
throw new Error('Unknown command');
}
}

Test the dialog box in your tenant


1. Open the serve.json file in the ./config/ folder and update the current settings in the file. This file is used to make debugging on SharePoint Framework Extensions easier. You can
update the file content to match your own tenant and site details where you want to test your extension. The key value to update is the pageUrl property in the json definition to
match your own tenant.
2. Update pageUrl to point to a list URL where you want to test the dialog functionality.

"serveConfigurations": {
"default": {
"pageUrl": "https://sppnp.sharepoint.com/sites/team/Shared%20Documents/Forms/AllItems.aspx",
"customActions": {
"9b98b919-fe5e-4758-ac91-6d62e582c4fe": {
"location": "ClientSideExtension.ListViewCommandSet.CommandBar",
"properties": {
"sampleTextOne": "One item is selected in the list",
"sampleTextTwo": "This command is always visible."
}
}
}
},

NOTE

The unique identifier of your extension is automatically updated to this file during initial scaffolding. If you update the properties that your extension uses, you should update
serve.json before you start debugging.
3. Return to the console and run the following command:

gulp serve

This starts the bundling of your solution and serves the resulting manifest from the localhost address. Due to the configuration in the serve.json file, it also opens up a browser in
the specific URL and automatically sets the query parameters based on the solution configuration.
4. Accept the loading of debug manifests by selecting Load debug scripts when prompted.

Notice that the new button is not visible in the toolbar by default because the default solution requires that you select one item from the list. If you do not have any items in the list or
library, create an item or upload a document.
5. Select an item from the list or library, and notice how the Open Custom Dialog button is visible in the toolbar.
6. Click the Open Custom Dialog button to see your custom dialog box rendered within the list view.

7. Select a color in the Color Picker, and then select OK to test how the code is returning the selected value back to the caller. The selection is then shown by using the default alert
dialog box.

NOTE

If you find an issue in the documentation or in SharePoint Framework, report that to SharePoint engineering by using the issue list at the sp-dev-docs repository. Thanks for your input in
advance.

See also
Overview of SharePoint Framework Extensions
Recommendations for working with CSS in SharePoint Framework solutions
3/26/2018 • 8 minutes to read Edit Online

When building SharePoint Framework solutions, you can use CSS to define how your customization should look and behave. This article describes how you can make the best use of the
capabilities provided with the SharePoint Framework and build your CSS styles in a robust way.

SharePoint Framework customizations are part of the page


When building SharePoint customizations using the add-in model, the solution is isolated from other elements on the page. Your code can be executed in an iframe as an add-in part, or as
an immersive application that takes control of the whole page. In both cases, your code is not affected by other elements and styles defined on the page.
SharePoint Framework solutions are a part of the page and integrate fully with the page's DOM. While this removes a number of restrictions that come with the add-in model, it exposes
your solution to risk. Because it's a part of the page, unless explicitly isolated, all CSS styles present on the page apply to it, potentially resulting in an experience different from what you
intended. To avoid such risks, you should define your CSS styles in such a way so that they won't affect anything else on the page other than your customization.

Organize CSS files in your solution


The UI of your solutions often consists of multiple building blocks. In many JavaScript libraries, these building blocks are called components. A component can be simple and define only the
presentation, or it can be more complex and include state and other components. Splitting your solution into multiple components allows you to simplify the development process and
makes it easier to test and reuse the components in your solution.
Because components have presentation, they often require CSS styles. Ideally, components should be isolated and be able to be used on their own. With that in mind, it makes perfect sense
for you to store CSS styles for the particular component along with all other asset files next to the component. Following is a sample structure of a React application with a number of
components, each with its own CSS file.

todoWebPart\components
\todoList
\todoList.tsx
\todoList.module.scss
\todoItem
\todoItem.tsx
\todoItem.module.scss

Use Sass
In SharePoint Framework, you can use both CSS and Sass. Sass is a superset of CSS and offers you a number of features such as variables, nesting selectors, or mixins, all of which simplify
working with and managing CSS styles over the long term.
For a complete set of features, see the Sass website. All valid CSS is also valid Sass, which is very helpful if you haven't worked with Sass before and want to gradually learn its capabilities.

Avoid using IDs in markup


Using SharePoint Framework, you build customizations that end-users add to SharePoint. It's impossible to tell upfront if the particular customization is used only once on a page or if there
are multiple instances of it.
To avoid issues, you should always assume that there are multiple instances of your customization on the same page. With that in mind, you should avoid using any IDs in your markup. IDs
are meant to be unique on a page, and if a user adds your web part to the page twice, it violates this premise, possibly leading to errors.
Bad practice
// ...

export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {

public render(): void {


this.domElement.innerHTML = `
<div id="helloWorld">
Hello world
</div>`;
}

// ...
}

Good practice
// ...

export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {

public render(): void {


this.domElement.innerHTML = `
<div class="${styles.helloWorld}">
Hello world
</div>`;
}

// ...
}

Use CSS modules to avoid styling conflicts


SharePoint Framework solutions are a part of the page. To ensure that CSS styles for one component don't affect other elements on the page, you should define your CSS selectors in such a
way that they apply only to the DOM of your solution. It's tedious and error-prone to do this manually, but SharePoint Framework can do this automatically for you.
To help you avoid styling conflicts, SharePoint Framework uses CSS modules. When building the project, the SharePoint Framework toolchain processes all files with the .module.scss
extension. For each file, it reads all class selectors and appends a unique hash value to them. After it's finished, it writes the updated selectors to intermediate CSS files that are included in the
generated web part bundle.
Following the previous example, assume that you had the following two Sass files:
todoList.module.scss
.todoList {
margin: 1em 0;

.text {
font-weight: bold;
font-size: 1.5em;
}
}

todoItem.module.scss
.todoItem {
padding: 0.5em 1em;

.text {
font-size: 0.9em;
}
}

After building the project, in the lib folder you would see the following two CSS files generated (line breaks and indenting added for readability):
todoList.module.css
.todoList_3e9d35f0 {
margin:1em 0
}

.todoList_3e9d35f0 .text_3e9d35f0 {
font-weight:700;
font-size:1.5em
}

todoItem.module.css
.todoItem_f7081cc4 {
padding:.5em 1em
}

.todoItem_f7081cc4 .text_f7081cc4 {
font-size:.9em
}

Even though there was a .text class defined in both Sass files, notice how in the generated CSS files it has two different hashes appended to it, becoming a unique class name specific to each
component.
The CSS class names in CSS modules are generated dynamically, which makes it impossible for you to refer to them in your code directly. Instead, when processing CSS modules, the
SharePoint Framework toolchain generates a JavaScript file with references to the generated class names.
todoList.module.scss.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* tslint:disable */
require('./todoList.module.css');
var styles = {
todoList: 'todoList_3e9d35f0',
text: 'text_3e9d35f0',
};
exports.default = styles;
/* tslint:enable */

//# sourceMappingURL=todoList.module.scss.js.map

To use the generated class names in your code, you first import the styles of your component, and then use the property pointing to the particular class:

import styles from './todoList.module.scss';


// ...

export default class TodoList extends React.Component<ITodoListProps, void> {


public render(): React.ReactElement<ITodoListProps> {
return (
<div className={styles.todoList}>
<div className={styles.text}>Hello world</div>
</div>
);
}
}
For the CSS modules to work correctly, you have to meet the following conditions:
Your Sass files must have the .module.scss extension. If you use the .scss extension without .module, you see a warning in the build process. The Sass file is transpiled to an
intermediate CSS file, but the class names will not be made unique. In cases when you need to override third-party CSS styles, this might be intended.
Your CSS class names must be valid JavaScript variable names. For example, they cannot contain hyphens: todoList is correct, but todo-list isn't.
We recommend using camelCase naming for classes, but it's not enforced.

Wrap your CSS styles in a class named after the component


By combining CSS modules with Sass support for nesting rule sets, you can simplify your CSS styles and ensure that they don't affect other elements on the page.
When building CSS styles for a component, wrap them in a class named after the component. In the component, assign that class to the component's root element.
todoList.module.scss
.todoList {
a {
display: block;
}
}

TodoList.tsx
// ...

export default class TodoList extends React.Component<ITodoListProps, void> {


public render(): React.ReactElement<ITodoListProps> {
return (
<div className={styles.todoList}>
...
</div>
);
}
}

After transpilation, the generated CSS file looks similar to:

.todoList_3e9d35f0 a {
display: block;
}

Because the selector begins with the unique class name specific to your component, the alternative presentation applies only to hyperlinks inside your component.

Handling of CSS vendor prefix


In SharePoint Framework, no vendor prefixed style properties are required in the Sass or CSS files of a project. If some of the SharePoint Framework-supported browsers require prefixes,
they were added after the Sass to CSS compilation automatically. This method is also known as auto-prefixing, and is a fundamental part of the CSS build chain in SharePoint Framework.
In case a web part should use the new flex box model defined by the display: flex declaration, some older WebKit-based and Internet Explorer versions require a particular vendor prefix
defined in the CSS.

.container{
display: flex;
}

The Sass code of the SharePoint Framework artefact does not need to have vendor prefixes included. After the Sass-to-CSS compilation, those were added automatically, resulting in the
following CSS declaration.

.container_7e976ae1 {
display: -webkit-box; // older Safari on MacOS and iOS
display: -ms-flexbox; // IE 10 - 11
display: flex;
}

Removing already applied prefixes does not only make the code of the artefact cleaner, it also makes it easier to read and future-ready. This process is also configured to support only
SharePoint Framework-supported browsers and makes it more error-safe.
In case a web part already has vendor prefixes included in the Sass files that are not needed anymore, the same process removes those declarations automatically.
The following example makes use of the border-radius property, which does not require vendor prefixes on the supported systems.

.container {
/* Safari 3-4, iOS 1-3.2, Android 1.6- */
-webkit-border-radius: 7px;
/* Firefox 1-3.6 */
-moz-border-radius: 7px;
/* Opera 10.5, IE 9, Safari 5, Chrome, Firefox 4, iOS 4, Android 2.1+ */
border-radius: 7px;
}
The resulting CSS in the package is converted to the following code.

.container_9e54c0b0 {
border-radius: 7px
}

For more information about auto-prefixing, see the autoprefixer GitHub repository. The database for this process is available on Can I use__?.

Integrate Office UI Fabric


By making your customizations look and behave like the standard functionality of SharePoint and Office 365, you make it easier for end-users to work with them. Office UI Fabric offers you
a set of controls and styles to use in your customizations to seamlessly integrate with the existing user experience.
For more information about using Office UI Fabric in SharePoint Framework, see Using Office UI Fabric Core and Fabric React in SharePoint Framework.

Use theme colors


SharePoint allows users to choose the theme color for their sites. In your SharePoint Framework customizations, you should follow the theme selected by the users to make your
customization look like an integral part of the site rather than unnecessarily stand out.
Because the theme is set by users on their site, you cannot tell upfront which colors your customization should use, but SharePoint Framework can dynamically load the currently active color
scheme automatically for you.
For more information about this capability, see Use theme colors in your SharePoint Framework customizations.
SharePoint themes and colors
5/25/2018 • 2 minutes to read Edit Online

Like the Microsoft brand palette, the SharePoint themes are designed to build on the Microsoft brand, while at the same time allow for flexibility to enliven our partnerships without
dominating them. They reveal our shared goals and personality, and they reflect our diversity and ability to optimize the SharePoint experience.

Main colors
The SharePoint color palette is now optimized for screens and devices. In addition, it is optimized to provide enough flexibility to ensure continuity with your brand. The SharePoint-provided
colors also guarantee accessible and legible experiences.

Neutral palette
Neutral colors recede into the background to let our products shine. They allow brand colors to pop when we need to draw attention to content. When coupling neutrals with brand colors,
make sure there is suitable contrast between them.
black: #000000

neutralDark: #212121

neutralPrimary: #333333

neutralPrimaryAlt: #3c3c3c

neutralSecondary: #666666

neutralTertiary: #a6a6a6

neutralTertiaryAlt: #c8c8c8

neutralQuaternary: #d0d0d0

neutralQuaternaryAlt: #dadada

neutralLight: #eaeaea

neutralLighter: #f4f4f4

neutralLighterAlt: #f8f8f8

white: #ffffff

Shades and tints


After you select a color, light and dark shades of the accent color are created based on HSB values of color luminosity. Web parts and apps can use shade variations to create visual hierarchy
and provide an indication of interaction.

themeDarker: #004578

themeDark: #005a9e

themeDarkAlt: #106ebe

themePrimary: #0078d4

themeSecondary: #2b88d8

themeTertiary: #71afe5

themeLight: #c7e0f4

themeLighter: #deecf9

themeLighterAlt: #eff6fc

Dark themes
SharePoint includes a palette that supports dark themes. The SharePoint-provided colors guarantee accessible and legible experiences.
Principles
The following design principles helped form the current SharePoint themes and color palette.

Guided
Our theming system works at a global level so that updates can be made consistently across each site, allowing users to optimize their websites effortlessly. Our theming system operates in
a controlled environment so that successful outcomes can be optimized quickly.

Smart and efficient


Our theming system expedites the site creation process by using smart algorithms to generate options that maximize aesthetic choices.

Professional
Our themes embody a professional look and feel that ensures coherency and conveys the brand of our enterprise audiences.

Accessible
Our built-in accessibility checker ensures universal design at all levels of default themes. For users who decide to customize, we provide helpful guidelines to design for accessibility.

See also
Accessibility
Designing great SharePoint experiences
Use theme colors in your SharePoint Framework customizations
5/3/2018 • 3 minutes to read Edit Online

When building SharePoint Framework customizations, you should use theme colors so that your customizations look like a part of the site. This article explains how can you refer to the
theme colors of the context site in your SharePoint Framework solution.
NOTE

Although this article uses a SharePoint Framework client-side web part as an example, the described techniques apply to all types of SharePoint Framework customizations.

Fixed colors vs. theme colors


When you scaffold a new SharePoint Framework client-side web part, it uses a fixed blue palette. When you add such a web part on a modern site by using a different color scheme, it stands
out and doesn't look like a part of the site.

When using fixed colors, you decide upfront which colors you want to use for which elements. This can lead to a situation like the one just illustrated, where a blue web part is displayed on a
red team site, standing out unnecessarily. In most cases, you should strive to leverage the theme colors of the context site so that your solution doesn't stand out but looks like a part of the
site.
Instead of using fixed colors, SharePoint Framework allows you to refer to the theme colors of the context site. As a result, if your web part is placed on a site that uses a red theme, it uses
the red palette as well, and if it's placed on a site that uses the blue theme, it automatically adjusts itself to use the blue palette. All of this is done automatically without any changes to the
web part code in between.

Use theme colors in the SharePoint Framework


When working with fixed colors, you specify them in CSS properties, for example:

.button {
background-color: #0078d7;
}

To use a theme color instead, replace the fixed color with a theme token:

.button {
background-color: "[theme: themePrimary, default: #0078d7]";
}

When your SharePoint Framework customization is loading on the page, the @microsoft/load-themed-styles package, which is a part of the SharePoint Framework, looks for theme
tokens in CSS files and tries to replace them with the corresponding color from the current theme. If the value for the specified token is not available, SharePoint Framework uses the value
specified by using the default parameter instead, which is why it's important that you always include it.
The following theme tokens are available for you to use:

D EFAU LT V ALU E O N A MO D ER N TE AM S ITE U S ING THE R ED


TO K EN PALE T TE R EMAR K S

backgroundImageUri none
D EFAU LT V ALU E O N A MO D ER N TE AM S ITE U S ING THE R ED
TO K EN PALE T TE R EMAR K S

accent #ee0410

themeDark #b3030c Used for action icons in the command bar and as a hover color.

themeDarkAlt #b3030c

themeDarker #770208

themeLight #fd969b

themeLightAlt #fd969b

themeLighter #fecacd

themeLighterAlt #fecacd

themePrimary #ee0410 st Primary theme color. Used for icons and default buttons.

themeSecondary #fc6169

themeTertiary #fd969b

NOTE

There are more tokens registered with the SharePoint Framework. While all of them have values specified on classic sites, only the subset mentioned earlier has values on modern
SharePoint sites. For the complete list of available tokens, see the value of the window.__themeState__.theme property by using the console in your web browser's developer tools.

Use theme colors in your customizations


When you scaffold a new SharePoint Framework client-side web part, by default, it uses the fixed blue palette. The following steps describe the necessary adjustments to have the web part
use theme colors instead.
NOTE

The following steps apply to a SharePoint Framework client-side web part named HelloWorld built by using React. For web parts built using different libraries and other types of
customizations, you might need to adjust the modifications accordingly.

To use theme colors


1. In the code editor, open the ./src/webparts/helloWorld/components/HelloWorld.tsx file, and from the div with class ms-Grid-row, remove the ms-bgColor-themeDark class.

2. In the same folder, open the HelloWorld.module.scss file. Change the .row selector to:

.row {
padding: 20px;
background-color: "[theme: themeDark, default: #005a9e]";
}
3. In the .button selector, change the background-color and border-color properties to:

.button {
/* ... */
background-color: "[theme: themePrimary, default: #0078d7]";
border-color: "[theme: themePrimary, default: #0078d7]";
/* ... */
}

4. When you add the web part to a site, the colors used by the web part automatically adapt to the theme colors used by the current site.
See also
SharePoint themes and colors
How to use Theme Colors in SPFX web parts by Stefan Bauer (Office Development MVP)
Using Office UI Fabric Core and Fabric React in SharePoint Framework
7/9/2018 • 9 minutes to read Edit Online

The Office UI Fabric is the official front-end framework for building experiences in Office 365 and SharePoint. SharePoint provides seamless integration with Fabric that enables Microsoft to
deliver a robust and consistent design language across various SharePoint experiences such as modern team sites, modern pages, and modern lists. Additionally, the Office UI Fabric is
available for developers in the SharePoint Framework when building custom SharePoint solutions.
Microsoft uses Fabric Core and Fabric React in SharePoint. Microsoft regularly pushes updates to SharePoint Online that could also update the Fabric Core and Fabric React versions as well.
These updates could potentially conflict with third-party customer solutions built with previous versions of Fabric Core and Fabric React, which could cause exceptions in those
customizations. The primary reason for these types of breaks is the use of Global CSS styles in both Fabric libraries. Such conflicts need to be avoided at all costs.
The challenge with Global CSS styles is explained in the following presentation within the context of React and JavaScript: React CSS in JS.
To achieve reliability, one of the main problems we need to solve is that of Global CSS styles. This accounts to not using global class names in the HTML markup and instead using Fabric
Core mixins and variables in the Sass declaration file. This involves importing the Fabric Core's Sass declarations in your Sass file and then consuming the variables and mixins appropriately.

Goals
The goal of the SharePoint Framework is to allow both Microsoft and customers to build rich, beautiful, and consistent user experiences on top of SharePoint.
In accordance with these goals, following are the key design principles:
Customers should be able to smoothly and reliably consume Fabric Core and Fabric React in their solutions.
Microsoft will roll out updated experiences that consume updated versions of Fabric Core and Fabric React in SharePoint without conflicting with customer's solutions.
Customers can customize and override the default styles, designs, and components to tailor the solution's needs.
There are two parts of the Office UI Fabric that are available for use by developers:
Office UI Fabric Core. A set of core styles, typography, a responsive grid, animations, icons, and other fundamental building blocks of the overall design language.
Office UI Fabric React. A set of React components built on top of the Fabric design language for use in React-based projects.

Office UI Fabric Core package


The SharePoint Framework Fabric Core npm package (@microsoft/sp-office-ui-fabric-core) contains a subset of supported Fabric Core styles that can be safely consumed within a
SharePoint Framework component.
The following core styles are supported in the package:
Typography
Layouts
Colors
Themes
Localization
The following are not yet supported in the package:
Animations
Icons
Starting with the SharePoint Framework Yeoman generator version 1.3.4, the default project (web parts and extensions) templates come setup with the new @microsoft/sp-office-ui-
fabric-core package and consume core styles from the package instead of using global CSS styles.

Update existing projects


To use the Fabric Core package in your existing project, install the package as a dependency:

npm install @microsoft/sp-office-ui-fabric-core --save

After it's installed, you can then import the Fabric Core Sass declarations in your Sass definition file and use the mixins and variables as described in the following section.

Use Fabric Core styles


To use the Fabric Core styles, you need to import the SPFabricCore declarations into your Sass file.
NOTE

Make sure you have the @microsoft/sp-office-ui-fabric-core npm package installed.

@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';

Now you can use the core styles as mixins and variables.

.row {
@include ms-Grid-row;
@include ms-fontColor-white;
background-color: $ms-color-themeDark;
padding: 20px;
}

Office UI Fabric React


We recommend that you install the latest Office UI Fabric React package and place an explicit dependency on that specific version of the package. This includes the components used in your
SharePoint Framework solution in your component bundle, either the web part or extension depending on where you use the Fabric React components.
NOTE
Fabric React versions 2.x or older are not supported in SharePoint Framework.
After the Fabric React package is installed, you can import the required components from the Fabric React bundle.

//import Button component from Fabric React Button bundle


import { Button } from 'office-ui-fabric-react/lib/Button';

//use it in your component


render() {
...
<div>
<Button>click me</Button>
</div>
...
}

The Fabric React package includes the supported Fabric Core styles used in the Fabric React components. We recommend that you import the Fabric Core styles from the Fabric React
package instead of from the @microsoft/sp-office-ui-fabric-core package to ensure that the right styles are used in your component.
Because the @microsoft/sp-office-ui-fabric-core package is already installed in your solution by the Yeoman generator, we recommend that you uninstall that package if you decide to use
Fabric components and reduce your component bundle size.

npm uninstall @microsoft/sp-office-ui-fabric-core --save

You can then import the core styles from the Sass declarations available in the Fabric React package.

@import '~office-ui-fabric-react/dist/sass/_References.scss';

Understanding this approach and its shortcomings


Fabric components in your solution are locked to the specific version of Fabric React that you installed. You need to update the Fabric React package to get any new components if they are
available in a newer package version. Because the Fabric components are included in the component bundle, it may increase the size of your component bundle. However, this approach is
the only approach that is officially supported when Office UI Fabric React is being used in SharePoint Framework solutions.

The CSS challenge with Office UI Fabric


The following concepts and references provide insights on the challenge with using Office UI Fabric in the context of client-side web parts.

Global CSS styles


How to avoid Global CSS styles at all costs is a big problem. Today, both Fabric Core and Fabric React have global styles. A lack of any native solutions from the browser to manage the style
scoping makes this a very difficult problem.
Scope CSS is in early stages of discussion.
iframes are not a good option to isolate styles.
Web Components is another standard that talks about scoped styles but is still in the discussion stage.
The React: CSS in JS discussion explains the problem well.
There is plenty of other documentation on the web about the solutions to the global namespace menace.

CSS specificity
How CSS specificity applies to web UI. Higher specificity styles override lower specificity styles, but the key thing to understand is how the specificity rules apply. In general, the precedence
order from highest to lowest is as follows:
The style attribute (for example, style="background:red;" )
ID selectors ( #myDiv { } )
Class selectors ( .myCssClass{} ), attribute selectors ( [type="radio"] ), and pseudo-classes ( :hover )
Type selectors ( h1 )

Loading order. If two classes are applied on an element and have the same specificity, the class that is loaded later takes precedence. As shown in the following code, the button appears red.
If the order of the style tags is changed, the button appears green. This is an important concept, and if not used correctly, the user experience can become load order-dependent (that is,
inconsistent).

<style>
.greenButton { color: green; }
</style>
<style>
.redButton { color: red; }
</style>
<body>
<button class="greenButton redButton"></button>
</body>

Other approaches considered and discarded


Following are some additional insights on the other approaches that were considered but discarded because they did not achieve the key objectives to enable third-party developers to safely
use the Office UI Fabric styles.

Office UI Fabric Core


The web part developer would not be required to do anything explicitly to get the scoping to work. We planned to solve this problem through CSS specificity and descendant selectors. The
Fabric Core team would ship multiple copies of Fabric Core css (for example, fabric-6.css , fabric-6-scoped.css , fabric-6.0.0.css , fabric-6.0.0-scoped.css ).
All the styles in the scoped CSS files would be inside a descendant selector, for example .ms-Fabric--v6-0-0 .ms-Icon--List . At compile time, the tooling would collect the version of the
Office UI Fabric Core that the web part was built with. This version could be the one that comes with SharePoint Framework. Alternatively, web part developers could specify an explicit
dependency on a specific version of Office UI Fabric Core in their package.json file.
The web part div would be assigned this scope, that is <div data-sp-webpart class="ms-Fabric--v6-0-0"> . The Framework would load the specific major version of the Fabric Core-scoped
CSS file. If the web part was built with version 6.0.0 of the Fabric Core CSS, the Framework would download fabric-6-scoped.css when the web part was loaded.
The rest of the page would contain unscoped Office UI Fabric Core styles. This way, as per CSS specificity rules, the scoped CSS would take precedence within the web part div. The web part
and its contents would align to the specific version of the Office UI Fabric Core that the developer had chosen.
Overriding Fabric Core styles would not be supported.

// Sample of how the scoping would work.


import { SPComponentLoader } from '@microsoft/sp-loader';

export default class MyWebPart {


constructor() {
super();

SPComponentLoader.loadCss('https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/6.0.0/css/fabric-6.0.0.scoped.css');
}
}

protected render(): void {


<div className="ms-Fabric--v6-0-0">
{ // Rest of the web part UI }
</div>
}

Shortcomings of this strategy


After analyzing this strategy for a while, it was decided that the descendant selector approach has two serious shortcomings that would make it impossible to build a web part that would
never break.
Lack of reliable nesting support
This approach only works if the Microsoft user experience (that is, page and first-party web parts) use an unscoped version of the Office UI Fabric Core such as ms-Icon--List , while the
third-party web parts only use scoped Office UI Fabric Core CSS as explained earlier.
The reason being that the specificity of the scoped CSS applied on the web part overrides the unscoped CSS on the page. Keep in mind, as explained earlier, that if CSS specificity of the two
classes is the same, their loading order plays a role in how the CSS classes are applied. The class that loads later takes precedence. Hence, the higher specificity of the scoped CSS is
important in getting a consistent experience.
Furthermore, multiple extensions, one contained in the other, cannot use different Fabric Core versions. In the following example, only ms-Fabric--v6-0-0 would get applied:

<div className="ms-Fabric--v6-0-0">
{ // Rest of the web part UI }
{ // inside of this SPExtension trying to use different Fabric core version does not work }
<div className="ms-Fabric--v8-0-0">
</div>
</div>

Here's a more simplistic sample demonstrating the challenge:


<html>
<head>
<title>CSS specifity test</title>
<style>
.myButton {
background-color: brown;
color: brown;
height: 20px;
width: 40px;
}
</style>
<style>
.scope2 .myButton {
background-color: green;
color: green;
}
</style>
<style>
.scope3 .myButton {
background-color: yellow;
color: yellow;
}
</style>
<style>
.scope1 .myButton {
background-color: red;
color: red;
}
</style>
</head>
<body>
<div>
<span>These tests demonstrate descendant selectors, nesting and load order problems.</span>

<div>
<br/>
<span>This test depicts that a descendant selector with the same specificity does not allow nesting.
All buttons below do not take the innermost scope (i.e. they should be different colors), but they are all red.
Further, if you change the ordering of the style tags, the colors will change. (i.e. the UI is load order dependant.)</span>
<div class='scope1'>
<button class='myButton'</button>
<div class='scope2'>
<button class='myButton'></button>
<div class='scope3'>
<button class='myButton'></button>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

Leakage from unscoped classes


There is another problem with descendant selectors. Note in the previous example that the height and the width styles from the unscoped myButton class are applied to all the buttons. This
implies that a change in that style could inadvertently break HTML by using scoped markup.
Say for example, for some reason at the app level we decide to make height 0 px on the myButton class. That results in all third-party web parts that use the myButton class to have a height
of 0 px (that is, a serious regression in the user experience).

See also
Overview of the SharePoint Framework
SharePoint Framework development tools and libraries
7/6/2018 • 3 minutes to read Edit Online

The SharePoint Framework includes several client-side JavaScript libraries that you can use to build your solutions. This article provides an overview of the tools and libraries that you can
use to develop client-side web parts.

TypeScript
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. SharePoint client-side development tools are built using TypeScript classes, modules, and interfaces. You can
use these to build robust client-side web parts.
To get started with TypeScript, see the following resources:
TypeScript Quick Start
TypeScript Playground
TypeScript Handbook
TypeScript community on Stack Overflow

JavaScript frameworks
You can choose any one of a number of JavaScript frameworks to develop client-side web parts. The following are some of the most popular:
React
AngularJS 1.x
Angular 2 for TypeScript 2.x
Vue.js
Handlebars
Because client-side web parts are components that are dropped into a SharePoint page, we recommend that you choose a JavaScript framework that supports a similar component model.
Lightweight frameworks such as React, Handlebars, and Angular 2 all support a component model and are well suited to building client-side web parts.
We also recommend that you look at the SharePoint PnP JavaScript Core library, which is a community driven effort targeted for providing easy access on SharePoint REST APIs.

Node Package Manager (npm)


SharePoint client-side development tools use the npm package manager, which is similar to NuGet, to manage dependencies and other required JavaScript helpers. npm is typically included
as part of Node.js setup.
For more information about npm, see the npm documentation.

Node.js
Node.js is an open source, cross-platform runtime environment for hosting and serving JavaScript code. You can use Node.js to develop server-side web applications written in JavaScript.
The Node.js ecosystem is tightly coupled with npm and task runners such as gulp to provide an efficient environment for building JavaScript-based applications. Node.js is similar to IIS
Express or IIS, but includes tools to simplify client-side development.
For more information about Node.js, see the following:
About Node.js
Node.js API reference documentation
Node.js Usage and Example

Gulp task runner


SharePoint client-side development tools use gulp as the build process task runner to:
Bundle and minify JavaScript and CSS files.
Run tools to call the bundling and minification tasks before each build.
Compile LESS or Sass files to CSS.
Compile TypeScript files to JavaScript.
For more information about gulp, see the following:
Getting started with Gulp
TypeScript and Gulp
Articles about Gulp

Webpack
Webpack is a module bundler that takes your web part files and dependencies and generates one or more JavaScript bundles so that you can load different bundles for different scenarios.
The development tool chain uses CommonJS for bundling. This enables you to define modules and where you want to use them. The tool chain also uses SystemJS, a universal module
loader, to load your modules. This helps you to scope your web parts by making sure that each web part is executed in its own namespace.
For more information about webpack, see the following:
Webpack documentation
TypeScript, React, and Webpack

Yeoman generators
Yeoman helps you to kickstart new projects, prescribing best practices and tools to help you stay productive. The Yeoman SharePoint generator is available as part of the framework to
kickstart new client-side web part projects.
For more information about Yeoman, see the following:
Scaffold a web app with Yeoman
List of available Yeoman generators
Scaffold projects by using Yeoman SharePoint generator
The following are some common Yeoman generators that you can try, depending on your choice of framework:
generator-react-webpack
generator-angular

Source code editors


SharePoint Framework is client-side driven and thus you can use your choice of HTML/JavaScript code editors, such as:
Visual Studio Code
Atom
Webstorm
SharePoint Framework documentation uses Visual Studio Code in the docs and examples. Visual Studio Code is a lightweight but powerful source code editor from Microsoft that runs on
your desktop and is available for Windows, Mac, and Linux. It comes with built-in support for JavaScript, TypeScript, and Node.js, and has a rich ecosystem of extensions for other languages
(such as C++, C#, Python, PHP) and runtimes.

SharePoint REST APIs


The SharePoint Framework provides key integrations with SharePoint experiences and targets web development. The SharePoint REST APIs enable you to interact with SharePoint and
other workloads that shape your web part functionality.
We recommend that you become familiar with the following set of REST APIs:
SharePoint List REST APIs

Patterns and Practices


The Office Dev Patterns and Practices / SharePoint Pattern and Practices (PnP) initiative provides code samples, patterns, and other resources to help you transform your existing solution to
the SharePoint Framework. Be sure to become familiar with the code samples and guidance that is available through the PnP effort.

See also
SharePoint Framework toolchain
Build a Hello World client-side web part
SharePoint Framework Overview
SharePoint Framework toolchain
3/26/2018 • 8 minutes to read Edit Online

The SharePoint Framework toolchain is the set of build tools, framework packages, and other items that manage building and deploying your client-side projects.
The toolchain:
Helps you build client-side components such as web parts.
Helps you test client-side components in your local development environment by using tools such as the SharePoint Workbench.
Enables you to package and deploy to SharePoint.
Provides you with a set of build commands that help you complete key build tasks such as code compilation, packaging the client-side project into a SharePoint app package, and more.

Use npm packages


Before diving into the various toolchain components, it’s important to understand how the SharePoint Framework uses npm to manage different modules in the project. npm is one of the
preferred open source package managers for JavaScript client-side development.
A typical npm package consists of one or more reusable JavaScript code files, called modules, along with a list of dependency packages. When you install the package, npm also installs those
dependencies.
The official npm registry consists of hundreds of packages that you can download to build your application. You can also publish your own packages to npm and share them with other
developers. The SharePoint Framework uses some of the npm packages in the toolchain and also publishes its own packages to the npm registry.

SharePoint Framework packages


The SharePoint Framework consists of several npm packages that work together to help you build client-side experiences in SharePoint.
The following npm packages are in the SharePoint Framework:
@microsoft/generator-sharepoint. A Yeoman plug-in for use with the SharePoint Framework. Using this generator, developers can quickly set up a new client-side web part project
with sensible defaults and best practices.
@microsoft/sp-client-base. Defines the core libraries for client-side applications built using the SharePoint Framework.
@microsoft/sp-webpart-workbench. The SharePoint Workbench is a standalone environment for testing and debugging client-side web parts.
@microsoft/sp-module-loader. A module loader that manages versioning and loading of client-side components, web parts, and other assets. It also provides basic diagnostic services.
It is built on familiar standards such as SystemJS and webpack, and is the first part of the SharePoint Framework to load on a page.
@microsoft/sp-module-interfaces. Defines several module interfaces that are shared by the SharePoint Framework module loader and also the build system.
@microsoft/sp-lodash-subset. Provides a custom bundle of lodash for use with the SharePoint Framework's module loader. To improve runtime performance, it only includes a subset
of the most essential lodash functions.
@microsoft/sp-tslint-rules. Defines custom tslint rules for usage with SharePoint client-side projects.
@microsoft/office-ui-fabric-react-bundle. Provides a custom bundle of office-ui-fabric-react that is optimized for use with the SharePoint Framework's module loader.

Common build tool packages


Along with the SharePoint Framework packages, a common set of build tools are also used to perform build tasks such as compiling TypeScript code to JavaScript and converting SCSS to
CSS.
The following common npm build tools packages are in the SharePoint Framework:
@microsoft/sp-build-core-tasks. A collection of tasks for the SharePoint Framework build system, which is based on gulp. The sp-build-core-tasks package implements operations
specific to SharePoint, such as packaging solutions and writing manifests.
@microsoft/sp-build-web. Imports and configures a set of build tasks that are appropriate for a build target that runs in a web browser (as opposed to a Node.js environment). This
package is intended to be imported directly by a gulp file that uses the SharePoint Framework build system.
@microsoft/gulp-core-build. The core gulp build tasks for building TypeScript, HTML, less, and other build formats. This package depends on several other npm packages that contain
the following tasks:
@microsoft/gulp-core-build-typescript
@microsoft/gulp-core-build-sass
@microsoft/gulp-core-build-webpack
@microsoft/gulp-core-build-serve
@microsoft/gulp-core-build-karma
@microsoft/gulp-core-build-mocha
@microsoft/loader-cased-file. A wrapper for webpack's file-loader that can be used to modify the casing of the resulting file name. This is useful in some scenarios, such as when using
a content delivery network (CDN) that only allows lowercase file names.
@microsoft/loader-load-themed-styles. A loader that wraps the loading of CSS in script equivalent to require('load-themed-styles').loadStyles( /* css text */ ) . It is designed to be
a replacement for style-loader.
@microsoft/loader-raw-script. A loader that loads a script file's contents directly in a webpack bundle by using an eval(…) .
@microsoft/loader-set-webpack-public-path. A loader that sets the webpack_public_path variable to a value specified in the arguments, optionally appended to the SystemJS
baseURL property.

Scaffold a new client-side project


The SharePoint generator scaffolds a client-side project with a web part. The generator also downloads and configures the required toolchain components for the specified client-side project.

Install npm packages


The generator installs required npm packages locally in the project folder. npm allows you to install a package either locally to your project or globally. There are benefits to both, but the
general guidance is to install the npm packages locally if your code depends on those package modules. In the case of a web part project, your web part code depends on the various
SharePoint and common build packages, and thus requires those packages to be installed locally.
As the packages are installed locally, npm also installs the dependencies associated with each package. You can find the packages installed under the node_modules folder in your project
folder. This folder contains the packages along with all their dependencies. It is ideal that this folder contains dozens to hundreds of folders, because npm packages are always broken down
to smaller modules, which results in dozens to hundreds of packages being installed. The key SharePoint Framework packages are located under the node_modules\@microsoft folder. The
@microsoft is an npm scope that collectively represents packages published by Microsoft.

Every time you create a new project using the generator, the generator installs the SharePoint Framework packages along with its dependencies for that specific project locally. In this way,
npm makes it easier to manage your web part projects without affecting other projects in the local dev environment.

Specify dependencies with package.json


The package.json file in the client-side project specifies the list of dependencies the project depends on. The list defines what dependencies to install. As described earlier, each dependency
could contain several more. npm allows you to define both runtime and build dependencies for your package by using the dependencies and devDependencies properties. The
devDependencies property is used when you want to use that module in your code as in the case of building web parts.

The following is the package.json of the helloworld-webpart.

{
"name": "helloword-webpart",
"version": "0.0.1",
"private": true,
"engines": {
"node": ">=0.10.0"
},
"dependencies": {
"@microsoft/sp-client-base": "~1.0.0",
"@microsoft/sp-core-library": "~1.0.0",
"@microsoft/sp-webpart-base": "~1.0.0",
"@types/webpack-env": ">=1.12.1 <1.14.0"
},
"devDependencies": {
"@microsoft/sp-build-web": "~1.0.0",
"@microsoft/sp-module-interfaces": "~1.0.0",
"@microsoft/sp-webpart-workbench": "~1.0.0",
"gulp": "~3.9.1",
"@types/chai": ">=3.4.34 <3.6.0",
"@types/mocha": ">=2.2.33 <2.6.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
}
}

While there are lot of packages installed for the project, they are required only for building the web part in the dev environment. With the help of these packages, you can depend on the
modules, and you can build, compile, bundle, and package your web part for deployment. The final minified bundled version of the web part that you deploy to a CDN server or SharePoint
does not include any of these packages. That said, you can also configure to include certain modules depending on your requirements. For more information, see Add an external library to a
web part.

Work with source control systems


As project dependencies increase, the number of packages to install also increases. You don’t want to check in the node_modules folder, which contains all the dependencies, to your source
control system. You should exclude the node_modules from the list of files to ignore during check-ins.
If you are using git as your source control system, the Yeoman scaffolded web part project includes a .gitignore file that excludes the node_modules folder, among other things.
When you check out, or clone, the web part project from your source control system the first time, run the command to initialize and install all the project dependencies locally:

npm i

After you run the command, npm scans the package.json file and installs the required dependencies.

Build tasks
The SharePoint Framework uses gulp as its task runner to handle processes like the following:
Bundle and minify JavaScript and CSS files.
Run tools to call the bundling and minification tasks before each build.
Compile LESS or Sass files to CSS.
Compile TypeScript files to JavaScript.
The toolchain consists of the following gulp tasks defined in the @microsoft/sp-build-core-tasks package:
build - Builds the client-side solution project.
bundle - Bundles the client-side solution project entry point and all its dependencies into a single JavaScript file.
serve - Serves the client-side solution project and assets from the local machine.
clean - Cleans the client-side solution project's build artifacts from the previous build and from the build target directories (lib and dist).
test - Runs unit tests, if available, for the client-side solution project.
package-solution - Packages the client-side solution into a SharePoint package.
deploy-azure-storage - Deploys client-side solution project assets to Azure Storage.
To initiate different tasks, append the task name with the gulp command. For example, to compile and then preview your web part in the SharePoint Workbench, run the following command:

gulp serve

NOTE

You cannot execute multiple tasks at the same time.


The serve task runs the different tasks and finally launches SharePoint Workbench.

Build targets
In the previous screenshot, you can see that the task indicates your build target as follows:

Build target: DEBUG

If no parameter is specified, the commands target the BUILD mode. If the ship parameter is specified, the commands target the SHIP mode.
Usually, when your web part project is ready to ship or deploy in a production server, you target SHIP. For other scenarios, such as testing and debugging, you would target BUILD. The SHIP
target also ensures that the minified version of the web part bundle is built.
To target SHIP mode, append the task with --ship :

gulp --ship

In DEBUG mode, the build tasks copy all of the web part assets, including the web part bundle, into the dist folder.
In SHIP mode, the build tasks copy all of the web part assets, including the web part bundle, into the temp\deploy folder.

See also
SharePoint Framework development tools and libraries
Scaffold projects by using Yeoman SharePoint generator
SharePoint Framework Overview
Scaffold projects by using Yeoman SharePoint generator
7/6/2018 • 3 minutes to read Edit Online

Yeoman helps you to kickstart new projects, prescribing best practices and tools to help you stay productive. Using the Yeoman SharePoint generator, developers are able to scaffold new
client-side solution projects to build, package, and deploy SharePoint solutions. The generator provides common build tools, boilerplate code, and a common playground website to host web
parts for testing.

Install the Yeoman SharePoint generator


Yeoman SharePoint generator is available as part of the framework as an npm package. You can install the generator by executing the following command in a console:

npm install @microsoft/generator-sharepoint -g

NOTE

The Yeoman SharePoint generator is targeted to get deployed globally with the initial General Availability (GA) version. There are some known issues if it's installed locally to the project,
which are planned to be addressed post-GA.
We recommend that you follow the set up your development environment instructions to configure your machine with the complete set of developer tools, including Yeoman SharePoint
generator.

Use the Yeoman SharePoint generator


After the generator is installed, you can invoke the generator by just typing the following command in a console:

yo

The command lists all the generators available on your machine. Select @microsoft/sharepoint to invoke the SharePoint generator and continue with the prompts to successfully create your
client-side solution:

Use available command-line options for the generator


You can use the command-line options available with the Yeoman SharePoint generator to scaffold projects in one command instead of going through the prompts. Execute the following
command to see the list of command-line options available for the SharePoint generator:

yo @microsoft/sharepoint --help

Command-line options

O PTIO N D ES CR IPTIO N

--help Print the generator's options and usage.

--skip-cache Do not remember prompt answers. Default: false.

--skip-install Do not automatically install dependencies. Default: false.

--component-type The type of component. Currently "webpart" or "extension" is supported.

--component-description Description of the component.

--component-name Name of the component.

--framework Framework to use for the solution. Choose one from "none", "react", "knockout".
O PTIO N D ES CR IPTIO N

--plusbeta Use the beta packages. Scaffolding should be done with @plusbeta

--extension-type The type of extension: Currently ApplicationCustomizer, FieldCustomizer, ListViewCommandSet.

--solution-name Client-side solution name, as well as folder name.

--environment The target environment for the solution. Either "onprem" or "spo".

--package-manager The package manager for the solution. Options are: "npm", "pnpm", or "yarn". Default: npm

--skip-feature-deployment If specified, allow the tenant admin the choice of being able to deploy the components to all sites
immediately without running any feature deployment or adding apps in sites. Default: false.

W A R N IN G

skip-feature-deployment command line support was introduced with the SharePoint Framework v1.5. This option was previously a command line argument called skipFeatureDeployment.
Also solution-name, extension-type, component-type, component-description and component-name have been renamed.
Following is an example of a command that creates a solution called "hello-world" with:
A web part "HelloWorld"
The "react" framework targeted only to SharePoint Online
Tenant-scoped deployment optional enabled
Notice that some of the options have dependencies between each other. You cannot, for example, create an extension with an on-premises option.

yo @microsoft/sharepoint
--solution-name "hello-world"
--framework "react"
--component-type "webpart"
--component-name "HelloWorld"
--component-description "HelloWorld web part"
--skip-install
--environment "spo"
--skip-feature-deployment true

NOTE

Using the --skip-install command scaffolds the project and skips installing dependencies. This means that to successfully build the project, you need to install the dependencies later after
the project is scaffolded.
If you try to build your project without installing the dependencies, you get the following error. This indicates that you need to install the dependencies before building the project:

Local gulp not found in ~/<project-name>


Try running: npm install gulp

You can execute the following command to install the dependencies:

npm install

See also
SharePoint Framework toolchain
SharePoint Framework development tools and libraries
Set up your SharePoint Framework development environment
SharePoint Framework Overview
Debug SharePoint Framework solutions in Visual Studio Code
7/9/2018 • 8 minutes to read Edit Online

Visual Studio Code is a popular code editor frequently used for building SharePoint Framework solutions. By setting up debugging of your SharePoint Framework solution in Visual Studio
Code, you can more efficiently step through your code and fix errors.
You can also see the required steps to enable debugging in Visual Studio Code in this video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/watch?v=oNChcluMrm8?list=PLR9nK3mnD-OXZbEvTEPxzIOMGXj_aZKJG

Prerequisites
The easiest way to configure Visual Studio Code to debug SharePoint Framework solutions is by using the Debugger for Chrome or Debugger for Edge Visual Studio Code extensions.
Starting with the SharePoint Framework Yeoman generator version 1.3.4, the default project (web parts and extensions) templates come set up with the prerequisites and prompt for the
required Visual Studio Code extensions to install. In this case, it prompts to install Debugger for Chrome Visual Studio Code extension.
You also need the Google Chrome browser. Download and install the latest version of Google Chrome.
If you are using a version of SharePoint Framework Yeoman generator that is older than version 1.3.4, you can install the Chrome debugger extension for Visual Studio Code from the Visual
Studio Marketplace.
In case you want to debug your projects with Microsoft Edge, you need to install the Debugger for Edge extension for Visual Studio Code from the Visual Studio Marketplace and follow the
steps in Debugging with Microsoft Edge or older projects.

Debug configurations
You can locate the debug configurations in the launch.json file under the Visual Studio Code workspace folder:

project-name\.vscode

The launch.json contains two debug configurations:


Local workbench configuration
Hosted workbench configuration

Debug solution using local workbench


When building SharePoint Framework solutions, you can use the local workbench to verify that your web part is working correctly. Using the local workbench is convenient for testing all
scenarios that do not require communicating with SharePoint as well as for offline development.
With Visual Studio Code configured for debugging SharePoint Framework solutions by using Google Chrome and the local workbench, you can verify that everything is working as
expected.

Configure a breakpoint
1. In Visual Studio Code, open the main web part source file, and add a breakpoint in the first line of the render method by either selecting the margin that is left to the line number or
by highlighting the code line in the editor and selecting the F9 key.
2. In Visual Studio Code, on the View menu, select the Integrated Terminal option or select Ctrl+` on the keyboard.
3. In the terminal run the following command:

gulp serve --nobrowser

Running this command builds your SharePoint Framework solution and starts the local webserver to serve the output files. Because the debugger starts its own instance of the
browser, you use the --nobrowser argument to prevent the serve task from opening a browser window.

Start debugging in Visual Studio Code


After the gulp task is finished, move the focus to the code area of Visual Studio Code and select F5 (or on the Debug menu, select the Start Debugging option).
The debug mode in Visual Studio Code starts, changing the color of the status bar to orange and opening a new window of Google Chrome showing the local version of the SharePoint
Workbench.
NOTE

At this point the breakpoint is disabled because the web part's code hasn't been loaded yet. SharePoint Framework loads web parts on demand only after they have been added to the page.
Add a web part to the canvas
To verify that debugging is working, in the workbench, add your web part to the canvas.

Notice that with the code loaded on the page, the breakpoint indicator changed to active.

If you now reload the page, your breakpoint in Visual Studio Code is hit, and you are able to inspect all the properties and step through the code.
Debug solution using hosted workbench
When building SharePoint Framework solutions that communicate with SharePoint, you might want to verify the interaction between your solution in SharePoint. To do this easily, you can
use the hosted version of the SharePoint Workbench, which is available on every Office 365 tenant at https://yourtenant.sharepoint.com/_layouts/workbench.aspx .
When building SharePoint Framework solutions, you will be doing such tests regularly, and it is a good idea to create a separate debug configuration for the hosted version of the SharePoint
Workbench.

Debug Web Part solution using hosted workbench


1. Open launch.json, and update the url property under the Hosted workbench configuration to your SharePoint site URL.

"url": "https://enter-your-SharePoint-site/_layouts/workbench.aspx",

2. In Visual Studio Code, activate the Debug pane, and in the Configurations list, select the newly added Hosted workbench configuration.

3. Start debugging either by selecting F5 or by selecting the Start Debugging option on the Debug menu. Visual Studio Code switches into debug mode, indicated by the orange
status bar, and the Debugger for Chrome extension opens a new instance of Google Chrome with the Office 365 sign-in page.
4. After you sign in, add the web part to the canvas and refresh the workbench, just like you did with the local workbench. You will see the breakpoint in Visual Studio Code be hit, and
you are able to inspect variables and step through the code.

Debug Extension solution using hosted workbench


Debuging an Extension in a hosted workbench is very similar to the steps for a Web Part with a few key differences.
1. Open launch.json, and update the url property under the Hosted workbench configuration to your SharePoint site URL.

"url": "https://enter-your-SharePoint-site/_layouts/workbench.aspx",

2. In Visual Studio Code, activate the Debug pane, and in the Configurations list, select the newly added Hosted workbench configuration.

3. After initiating the gulp serve in the Terminal start debugging either by selecting F5 or by selecting the Start Debugging option on the Debug menu. Visual Studio Code switches
into debug mode, indicated by the orange status bar, and the Debugger for Chrome extension opens a new instance of Google Chrome with the Office 365 sign-in page.
4. In the workbench tab that was opened in your browser navigate to a SharePoint Online page that you wish to test your extension.
5. Append the following query string parameters to the URL. Notice that you need to update the ID to match your own extension identifier. This is available in the
HelloWorldApplicationCustomizer.manifest.json file.

?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":"ClientSideExtension.ApplicationCustomizer","p

More detail about the URL query parameters:


loadSPFX=true. Ensures that the SharePoint Framework is loaded on the page. For performance reasons, the framework does not load unless at least one extension is
registered. Because no components are registered, you must explicitly load the framework.
debugManifestsFile. Specifies that you want to load SPFx components that are locally served. The loader only looks for components in the app catalog (for your deployed
solution) and the SharePoint manifest server (for the system libraries).
customActions. Simulates a custom action. When you deploy and register this component in a site, you'll create this CustomAction object and describe all the different
properties you can set on it.
Key. Use the GUID of the extension as the key to associate with the custom action. This has to match the ID value of your extension, which is available in the extension
manifest.json file.
Location. The type of custom action. Use ClientSideExtension.ApplicationCustomizer for the Application Customizer extension.
Properties. An optional JSON object that contains properties that are available via the this.properties member. In this HelloWorld example, it defined a testMessage
property.
The full URL should look similar to the following:

contoso.sharepoint.com/Lists/Contoso/AllItems.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":

6. Select Load debug scripts to continue loading scripts from your local host.

When the page loads you should now be able to see the Extension on your page(in this case a list view command extension):
In addition you can now toggle Breakpoints and step through the code:

Debugging with Microsoft Edge or older projects


If you are using an older version of SharePoint Framework Yeoman generator or want to debug with Microsoft Edge, follow these steps to create the launch.json file manually.
NOTE

In order for you to debug with Microsoft Edge, you will have to install the Windows 10 April 2018 Update which includes the Microsoft Edge DevTools Protocol.

Create debug configuration for local workbench


1. In Visual Studio Code, activate the Debug pane.
2. In the top section of the pane, open the Configurations list, and select the Add Configuration option.

3. In the list of debug environments, select Edge or Chrome.

4. For Edge, replace the contents of the generated launch.json file with:
{
"version": "0.2.0",
"configurations": [
{
"name": "Local workbench",
"type": "edge",
"request": "launch",
"url": "https://localhost:4321/temp/workbench.html",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
}
}
]
}

This configuration uses the Edge debugger provided with the Debugger for Edge extension. It points to the URL of the local workbench as the starting point. What is essential in
debugging TypeScript code is the configuration of source maps that the debugger uses to map the JavaScript running in the browser to the original TypeScript code.
5. For Chrome, replace the contents of the generated launch.json file with:

{
"version": "0.2.0",
"configurations": [
{
"name": "Local workbench",
"type": "chrome",
"request": "launch",
"url": "https://localhost:4321/temp/workbench.html",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
},
"runtimeArgs": [
"--remote-debugging-port=9222"
]
}
]
}

This configuration uses the Chrome debugger provided with the Debugger for Chrome extension. It points to the URL of the local workbench as the starting point. What is essential
in debugging TypeScript code is the configuration of source maps that the debugger uses to map the JavaScript running in the browser to the original TypeScript code.

Create debug configuration for hosted workbench


1. In Visual Studio Code, open the ./.vscode/launch.json file.
2. For Edge, copy the existing debug configuration and use the URL of the hosted workbench:

{
"version": "0.2.0",
"configurations": [
{
"name": "Local workbench",
"type": "edge",
"request": "launch",
"url": "https://localhost:4321/temp/workbench.html",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
}
},
{
"name": "Hosted workbench",
"type": "edge",
"request": "launch",
"url": "https://contoso.sharepoint.com/_layouts/workbench.aspx",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
}
}
]
}

3. For Chrome, copy the existing debug configuration and use the URL of the hosted workbench:
{
"version": "0.2.0",
"configurations": [
{
"name": "Local workbench",
"type": "chrome",
"request": "launch",
"url": "https://localhost:4321/temp/workbench.html",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
},
"runtimeArgs": [
"--remote-debugging-port=9222"
]
},
{
"name": "Hosted workbench",
"type": "chrome",
"request": "launch",
"url": "https://contoso.sharepoint.com/_layouts/workbench.aspx",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
},
"runtimeArgs": [
"--remote-debugging-port=9222"
]
}
]
}

See also
How to debug your SharePoint Framework web part (Elio Struyf)
Debug SPFx React webpart with Visual Studio Code (Velin Georgiev)
Scaffold projects by using Yeoman SharePoint generator
SharePoint Framework Overview
Debug SharePoint Framework solutions in Visual Studio Code
7/9/2018 • 8 minutes to read Edit Online

Visual Studio Code is a popular code editor frequently used for building SharePoint Framework solutions. By setting up debugging of your SharePoint Framework solution in Visual Studio
Code, you can more efficiently step through your code and fix errors.
You can also see the required steps to enable debugging in Visual Studio Code in this video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/watch?v=oNChcluMrm8?list=PLR9nK3mnD-OXZbEvTEPxzIOMGXj_aZKJG

Prerequisites
The easiest way to configure Visual Studio Code to debug SharePoint Framework solutions is by using the Debugger for Chrome or Debugger for Edge Visual Studio Code extensions.
Starting with the SharePoint Framework Yeoman generator version 1.3.4, the default project (web parts and extensions) templates come set up with the prerequisites and prompt for the
required Visual Studio Code extensions to install. In this case, it prompts to install Debugger for Chrome Visual Studio Code extension.
You also need the Google Chrome browser. Download and install the latest version of Google Chrome.
If you are using a version of SharePoint Framework Yeoman generator that is older than version 1.3.4, you can install the Chrome debugger extension for Visual Studio Code from the Visual
Studio Marketplace.
In case you want to debug your projects with Microsoft Edge, you need to install the Debugger for Edge extension for Visual Studio Code from the Visual Studio Marketplace and follow the
steps in Debugging with Microsoft Edge or older projects.

Debug configurations
You can locate the debug configurations in the launch.json file under the Visual Studio Code workspace folder:

project-name\.vscode

The launch.json contains two debug configurations:


Local workbench configuration
Hosted workbench configuration

Debug solution using local workbench


When building SharePoint Framework solutions, you can use the local workbench to verify that your web part is working correctly. Using the local workbench is convenient for testing all
scenarios that do not require communicating with SharePoint as well as for offline development.
With Visual Studio Code configured for debugging SharePoint Framework solutions by using Google Chrome and the local workbench, you can verify that everything is working as
expected.

Configure a breakpoint
1. In Visual Studio Code, open the main web part source file, and add a breakpoint in the first line of the render method by either selecting the margin that is left to the line number or
by highlighting the code line in the editor and selecting the F9 key.
2. In Visual Studio Code, on the View menu, select the Integrated Terminal option or select Ctrl+` on the keyboard.
3. In the terminal run the following command:

gulp serve --nobrowser

Running this command builds your SharePoint Framework solution and starts the local webserver to serve the output files. Because the debugger starts its own instance of the
browser, you use the --nobrowser argument to prevent the serve task from opening a browser window.

Start debugging in Visual Studio Code


After the gulp task is finished, move the focus to the code area of Visual Studio Code and select F5 (or on the Debug menu, select the Start Debugging option).
The debug mode in Visual Studio Code starts, changing the color of the status bar to orange and opening a new window of Google Chrome showing the local version of the SharePoint
Workbench.
NOTE

At this point the breakpoint is disabled because the web part's code hasn't been loaded yet. SharePoint Framework loads web parts on demand only after they have been added to the page.
Add a web part to the canvas
To verify that debugging is working, in the workbench, add your web part to the canvas.

Notice that with the code loaded on the page, the breakpoint indicator changed to active.

If you now reload the page, your breakpoint in Visual Studio Code is hit, and you are able to inspect all the properties and step through the code.
Debug solution using hosted workbench
When building SharePoint Framework solutions that communicate with SharePoint, you might want to verify the interaction between your solution in SharePoint. To do this easily, you can
use the hosted version of the SharePoint Workbench, which is available on every Office 365 tenant at https://yourtenant.sharepoint.com/_layouts/workbench.aspx .
When building SharePoint Framework solutions, you will be doing such tests regularly, and it is a good idea to create a separate debug configuration for the hosted version of the SharePoint
Workbench.

Debug Web Part solution using hosted workbench


1. Open launch.json, and update the url property under the Hosted workbench configuration to your SharePoint site URL.

"url": "https://enter-your-SharePoint-site/_layouts/workbench.aspx",

2. In Visual Studio Code, activate the Debug pane, and in the Configurations list, select the newly added Hosted workbench configuration.

3. Start debugging either by selecting F5 or by selecting the Start Debugging option on the Debug menu. Visual Studio Code switches into debug mode, indicated by the orange
status bar, and the Debugger for Chrome extension opens a new instance of Google Chrome with the Office 365 sign-in page.
4. After you sign in, add the web part to the canvas and refresh the workbench, just like you did with the local workbench. You will see the breakpoint in Visual Studio Code be hit, and
you are able to inspect variables and step through the code.

Debug Extension solution using hosted workbench


Debuging an Extension in a hosted workbench is very similar to the steps for a Web Part with a few key differences.
1. Open launch.json, and update the url property under the Hosted workbench configuration to your SharePoint site URL.

"url": "https://enter-your-SharePoint-site/_layouts/workbench.aspx",

2. In Visual Studio Code, activate the Debug pane, and in the Configurations list, select the newly added Hosted workbench configuration.

3. After initiating the gulp serve in the Terminal start debugging either by selecting F5 or by selecting the Start Debugging option on the Debug menu. Visual Studio Code switches
into debug mode, indicated by the orange status bar, and the Debugger for Chrome extension opens a new instance of Google Chrome with the Office 365 sign-in page.
4. In the workbench tab that was opened in your browser navigate to a SharePoint Online page that you wish to test your extension.
5. Append the following query string parameters to the URL. Notice that you need to update the ID to match your own extension identifier. This is available in the
HelloWorldApplicationCustomizer.manifest.json file.

?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":"ClientSideExtension.ApplicationCustomizer","p

More detail about the URL query parameters:


loadSPFX=true. Ensures that the SharePoint Framework is loaded on the page. For performance reasons, the framework does not load unless at least one extension is
registered. Because no components are registered, you must explicitly load the framework.
debugManifestsFile. Specifies that you want to load SPFx components that are locally served. The loader only looks for components in the app catalog (for your deployed
solution) and the SharePoint manifest server (for the system libraries).
customActions. Simulates a custom action. When you deploy and register this component in a site, you'll create this CustomAction object and describe all the different
properties you can set on it.
Key. Use the GUID of the extension as the key to associate with the custom action. This has to match the ID value of your extension, which is available in the extension
manifest.json file.
Location. The type of custom action. Use ClientSideExtension.ApplicationCustomizer for the Application Customizer extension.
Properties. An optional JSON object that contains properties that are available via the this.properties member. In this HelloWorld example, it defined a testMessage
property.
The full URL should look similar to the following:

contoso.sharepoint.com/Lists/Contoso/AllItems.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-e6c2c3afa485":{"location":

6. Select Load debug scripts to continue loading scripts from your local host.

When the page loads you should now be able to see the Extension on your page(in this case a list view command extension):
In addition you can now toggle Breakpoints and step through the code:

Debugging with Microsoft Edge or older projects


If you are using an older version of SharePoint Framework Yeoman generator or want to debug with Microsoft Edge, follow these steps to create the launch.json file manually.
NOTE

In order for you to debug with Microsoft Edge, you will have to install the Windows 10 April 2018 Update which includes the Microsoft Edge DevTools Protocol.

Create debug configuration for local workbench


1. In Visual Studio Code, activate the Debug pane.
2. In the top section of the pane, open the Configurations list, and select the Add Configuration option.

3. In the list of debug environments, select Edge or Chrome.

4. For Edge, replace the contents of the generated launch.json file with:
{
"version": "0.2.0",
"configurations": [
{
"name": "Local workbench",
"type": "edge",
"request": "launch",
"url": "https://localhost:4321/temp/workbench.html",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
}
}
]
}

This configuration uses the Edge debugger provided with the Debugger for Edge extension. It points to the URL of the local workbench as the starting point. What is essential in
debugging TypeScript code is the configuration of source maps that the debugger uses to map the JavaScript running in the browser to the original TypeScript code.
5. For Chrome, replace the contents of the generated launch.json file with:

{
"version": "0.2.0",
"configurations": [
{
"name": "Local workbench",
"type": "chrome",
"request": "launch",
"url": "https://localhost:4321/temp/workbench.html",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
},
"runtimeArgs": [
"--remote-debugging-port=9222"
]
}
]
}

This configuration uses the Chrome debugger provided with the Debugger for Chrome extension. It points to the URL of the local workbench as the starting point. What is essential
in debugging TypeScript code is the configuration of source maps that the debugger uses to map the JavaScript running in the browser to the original TypeScript code.

Create debug configuration for hosted workbench


1. In Visual Studio Code, open the ./.vscode/launch.json file.
2. For Edge, copy the existing debug configuration and use the URL of the hosted workbench:

{
"version": "0.2.0",
"configurations": [
{
"name": "Local workbench",
"type": "edge",
"request": "launch",
"url": "https://localhost:4321/temp/workbench.html",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
}
},
{
"name": "Hosted workbench",
"type": "edge",
"request": "launch",
"url": "https://contoso.sharepoint.com/_layouts/workbench.aspx",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
}
}
]
}

3. For Chrome, copy the existing debug configuration and use the URL of the hosted workbench:
{
"version": "0.2.0",
"configurations": [
{
"name": "Local workbench",
"type": "chrome",
"request": "launch",
"url": "https://localhost:4321/temp/workbench.html",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
},
"runtimeArgs": [
"--remote-debugging-port=9222"
]
},
{
"name": "Hosted workbench",
"type": "chrome",
"request": "launch",
"url": "https://contoso.sharepoint.com/_layouts/workbench.aspx",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
},
"runtimeArgs": [
"--remote-debugging-port=9222"
]
}
]
}

See also
How to debug your SharePoint Framework web part (Elio Struyf)
Debug SPFx React webpart with Visual Studio Code (Velin Georgiev)
Scaffold projects by using Yeoman SharePoint generator
SharePoint Framework Overview
Debug SharePoint Framework solutions on modern SharePoint pages
4/20/2018 • 8 minutes to read Edit Online

When building SharePoint Framework solutions, you can test them on modern SharePoint pages. For building SharePoint Framework extensions, testing on modern pages is the only
option, since at this moment the SharePoint Workbench doesn't support loading extensions. Testing on modern pages can however be also used for debugging web parts where it offers
developers additional value.
IM P O R T A N T

While there are no technical restrictions for debugging local SharePoint Framework solutions on modern SharePoint pages, you should be careful when using it in your production tenant.
This capability allows you to execute code that hasn't been tested and verified against your organization's policies and could be harmful to your production data.

Debug SharePoint Framework extensions on modern SharePoint pages


At this moment, SharePoint Framework extension can be debugged only on modern SharePoint pages. SharePoint Workbench doesn't support testing extensions. Depending on the version
of the SharePoint Framework that you use, there are different ways to debug extensions on modern pages.

Debug extensions using serve configuration


Starting from version 1.3.0, when you add a SharePoint Framework extension to your project, the SharePoint Framework Yeoman generator will extend your project's configuration. Using
this configuration, you can automatically start a modern SharePoint page in your web browser with all parameters required to debug the extension on that page already present.
How it works
When you add a new SharePoint Framework extension to your project, the SharePoint Framework Yeoman generator will add a new entry to the config/serve.json file in your project. A
sample entry looks as follows:

{
"$schema": "https://dev.office.com/json-schemas/core-build/serve.schema.json",
"port": 4321,
"https": true,
"serveConfigurations": {
"default": {
"pageUrl": "https://contoso.sharepoint.com/sites/mySite/SitePages/myPage.aspx",
"customActions": {
"d7678bd7-b58a-44fc-b9fa-a621a89edcad": {
"location": "ClientSideExtension.ApplicationCustomizer",
"properties": {
"testMessage": "Test message"
}
}
}
},
"helloWorld": {
"pageUrl": "https://contoso.sharepoint.com/sites/mySite/SitePages/myPage.aspx",
"customActions": {
"d7678bd7-b58a-44fc-b9fa-a621a89edcad": {
"location": "ClientSideExtension.ApplicationCustomizer",
"properties": {
"testMessage": "Test message"
}
}
}
}
}
}

Next to the default configuration, the SharePoint Framework Yeoman generator will create an entry for each extension that you add to your project. Each entry contains a URL of the modern
page that should be used to test the particular extension, the list of extensions that should be loaded and for each extension, the list of properties that should be set on them. To use the
particular serve configuration, execute in the command line:

gulp serve --config=<name>

for example:

gulp serve --config=helloWorld

After running this command, gulp will start your web browser with the modern page specified in your configuration. The page will show a popup asking you to confirm that you now will be
loading debug scripts.

Once you confirm, the page will load with the extensions you specified in your serve configuration.

Debug extensions by manually building the debug URL


If you're working with a version of the SharePoint Framework older than 1.3.0, and you want to debug an extension on a modern page, you have to manually construct the URL with the
required parameters. First, start the local gulp server, by in the command line changing the working directory to your project folder and then executing:

gulp serve --nobrowser


Next, in the web browser, navigate to the modern page, on which you want to test the extension. After the page loaded, copy its URL. Depending on the type of extension you want to test,
there are different parameters that you need to add to the URL.
Debug Application Customizer
To debug an Application Customizer, to the URL of your modern page, add
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"<extensionId>":{"location":"<extensionType>","properties":<propertiesJSON>}} , for example:
https://contoso.sharepoint.com/sites/team-a/sitepages/news.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"e5625e23-5c5a-4007-a335-
e6c2c3afa485":{"location":"ClientSideExtension.ApplicationCustomizer","properties":{"testMessage":"Hello as property!"}}}
.
Following are the query string parameters that you need to add:

PAR AME TER D ES CR IPTIO N

loadSPFX=true Ensures that the SharePoint Framework is loaded on the page. For performance reasons, the framework
does not load unless at least one extension is registered. Because no components are registered, you
must explicitly load the framework.

debugManifestsFile Specifies that you want to load SPFx components that are locally served. The loader only looks for
components in the app catalog (for your deployed solution) and the SharePoint manifest server (for the
system libraries).

customActions Simulates a custom action. When you deploy and register this component in a site, you'll create this
CustomAction object and describe all the different properties you can set on it.

key Use the GUID of the extension as the key to associate with the custom action. This has to match the ID
value of your extension, which is available in the extension manifest.json file.

location The type of custom action. Use ClientSideExtension.ApplicationCustomizer for the Application
Customizer extension.

properties An optional JSON object that contains properties that are available via the this.properties member

With the parameters added to the URL, reload the page in the web browser. The page will show a popup asking you to confirm that you now will be loading debug scripts.

Once you confirm, the page will load with the extensions you specified in your serve configuration.
Debug field customizer
To debug a field customizer, to the URL of your list view page, add
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&fieldCustomizers={"<fieldName>":{"id":"<fieldCustomizerId>","properties":<properties>}} , for example:
https://contoso.sharepoint.com/sites/team-a/Lists/Orders/AllItems.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&fieldCustomizers={"Percent":
{"id":"45a1d299-990d-4917-ba62-7cb67158be16","properties":{"sampleText":"Hello!"}}}
.
Following are the query string parameters that you need to add:

PAR AME TER D ES CR IPTIO N

loadSPFX=true Ensures that the SharePoint Framework is loaded on the page. For performance reasons, the framework
does not load unless at least one extension is registered. Because no components are registered, you
must explicitly load the framework.

debugManifestsFile Specifies that you want to load SPFx components that are locally served. The loader only looks for
components in the app catalog (for your deployed solution) and the SharePoint manifest server (for the
system libraries).

fieldCustomizers indicates which fields in your list should have their rendering controlled by the Field Customizer. The ID
parameter specifies the GUID of the extension that should be used to control the rendering of the field.
The properties parameter is an optional text string containing a JSON object that is deserialized into
this.properties for your extension.

key Use the internal name of the field as the key.

id The GUID of the Field Customizer extension associated with this field.

properties The property values defined in the extension. In this example, sampleText is a property defined by the
extension.

With the parameters added to the URL, reload the page in the web browser. The page will show a popup asking you to confirm that you now will be loading debug scripts.
Once you confirm, the page will load with the extensions you specified in your serve configuration.
Debug list view command set
To debug a list view command set, to the URL of your list view page, add
?loadSpfx=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"<extensionId>":{"location":"ClientSideExtension.ListViewCommandSet.CommandBar","properties":
<properties>}}
, for example:
https://contoso.sharepoint.com/sites/team-a/Lists/Orders/AllItems.aspx?loadSpfx=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"a8047e2f-30d5-40fc-b880-
b2890c7c16d6":{"location":"ClientSideExtension.ListViewCommandSet.CommandBar","properties":{"sampleTextOne":"One item is selected in the list.","sampleTextTwo":"This command is always
visible."}}}
.
Following are the query string parameters that you need to add:

PAR AME TER D ES CR IPTIO N

loadSPFX=true Ensures that the SharePoint Framework is loaded on the page. For performance reasons, the framework
does not load unless at least one extension is registered. Because no components are registered, you
must explicitly load the framework.

debugManifestsFile Specifies that you want to load SPFx components that are locally served. The loader only looks for
components in the app catalog (for your deployed solution) and the SharePoint manifest server (for the
system libraries).

customActions simulates a custom action. You can set many properties on this CustomAction object that affect the
look, feel, and location of your button; we’ll cover them all later.

key GUID of the extension.

Location Where the commands are displayed. The possible values are:
ClientSideExtension.ListViewCommandSet.ContextMenu : The context menu of the item(s),
ClientSideExtension.ListViewCommandSet.CommandBar : The top command set menu in a list or
library. ClientSideExtension.ListViewCommandSet : Both the context menu and the command bar
(corresponds to SPUserCustomAction.Location="CommandUI.Ribbon" ).

properties An optional JSON object containing properties that are available via the this.properties member.

With the parameters added to the URL, reload the page in the web browser. The page will show a popup asking you to confirm that you now will be loading debug scripts.

Once you confirm, the page will load with the extensions you specified in your serve configuration.

Debug SharePoint Framework web parts on modern SharePoint pages


To test the local versions of your SharePoint Framework client-side web parts on modern SharePoint pages in your tenant, first, start the local gulp server, by changing the working directory
to your project folder and executing in the command line:

gulp serve --nobrowser

Next, in the web browser, navigate to the modern page, on which you want to test the web parts. After the page loaded, add to its URL
?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js , for example:
https://contoso.sharepoint.com/sites/team-a/sitepages/news.aspx?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js . The page will reload and show a popup asking
you to confirm that you now will be loading debug scripts.
Once you confirm, that you want to load the web parts that you are developing, you can edit the page, and in the toolbox, select any of your local web parts.

Added value of testing SharePoint Framework web parts on modern pages


When building SharePoint Framework web parts, you can test them using the local workbench. This is not only convenient but also efficient: each time you change something in your code,
the local workbench will automatically reload and show your latest changes.
In some cases, like when building web parts that communicate with SharePoint, you cannot use the local SharePoint workbench, because you need access to the SharePoint APIs that can be
called only in the context of a SharePoint site. In such cases, rather than using the local workbench, you can use the hosted SharePoint workbench which you can access by adding
/_layouts/15/workbench.aspx to the URL of your site, for example https://contoso.sharepoint.com/sites/team-a/_layouts/15/workbench.aspx .

UI constraints
SharePoint Framework workbench conveniently mimics the canvas of modern SharePoint pages. But it doesn't mimic all their aspects. The width of the canvas is different, not all theme
colors are reflected, and the workbench doesn't allow you to test the full-bleed experience where a web part spans the full width of the web browser without any horizontal margin or
padding.
Does it work with other web parts and extensions
Using the SharePoint workbench, you can only test web parts from your solution. But what if you wanted to see how your web part works with other web parts on the page? Testing your
local solution on modern pages using the approach outlined in this article, is way more efficient than packaging your project, deploying it to the app catalog and adding the web part to the
page.

See also
Debug SharePoint Framework solutions in Visual Studio Code
Easily test SharePoint Framework web parts on modern pages (Waldek Mastykarz, Rencore)
Testing and debugging your SPFx solutions in production without causing any impact (Elio Struyf)
Scaffold projects by using Yeoman SharePoint generator
SharePoint Framework Overview
SharePoint Framework roadmap
6/25/2018 • 3 minutes to read Edit Online

The first release of the SharePoint Framework contained only support for client-side web parts. This was, however, just a start on the journey for providing additional modern customization
capabilities to SharePoint. Following is a list of key capabilities released after General Availability:
Tenant-scoped deployment support
On-premises support for SharePoint 2016 (Feature Pack 2)
SharePoint Framework Extensions
Tenant properties
Application Lifecycle Management (ALM) APIs for SPFx solutions and add-ins
Office UI Fabric Core support
Asset packaging and site collection app catalog
Improved MS Graph integration with additional scopes
Call securely Azure AD secured applications from SharePoint Framework
Connect SharePoint Framework components using dynamic data
Support for Yarn and PNPM package managers
Relocating preview code to isolated packages
SPFx Yeoman package extensibility
NOTE

This is a list of areas that SharePoint engineering has in the backlog and is looking into. This does NOT mean that all of them will be delivered, but we are looking into getting items and
topics from this list gradually released with the future releases of SharePoint Framework.

General improvements
Updated 'store' story with SharePoint Framework support
'Store' story for SharePoint Framework solutions with easy distribution channel for ISVs
React 16 support
Modern experiences in SharePoint 2019 - End-to-end SharePoint Framework support for modern sites with web parts and extensions
Content Security Policy (CSP) support
Additional placeholder, like content header, content footer, navigation extensions, search extensions
"App pages" - developer defined pages which end users cannot edit

Client-side web parts++ and add-ins


Support more complex scenarios and interactions with web parts
JavaScript Framework isolation
"Citizen developer" model for lightweight development
Bring add-ins to the modern world: let’s make them play nicer with the new UX
Azure AD registration
Native responsive support
Build add-ins with SharePoint Framework
Host SharePoint Framework web parts as Microsoft Teams tabs
Host Microsoft Team ISV solutions in SharePoint as "web parts"

Application Lifecycle Management


Streamlined approval experience: no need to know who your tenant admin is anymore
Owner initiates the approval process.
Tenant admin gets automatically notified.
Settings to control the default experience around approval process.
Tenant wide deployment of extensions

Developer experience
SharePoint Framework Workbench 2.0: Development story for SharePoint Framework Extensions
Toolchain components
Additional Yeoman templates for different JavaScript frameworks

Already shipped capabilities


The following sections list older items that have already shipped.

Improved Microsoft Graph and Azure AD secured API access


Use any tenant administrator approved Microsoft Graph scope in your SharePoint Framework solutions
Call securely APIs secured with Azure Active Directory - Like custom WebAPIs or Azure Functions

Asset packaging
Automatic CDN hosting for code. Package JavaScript bundle into app package, which is automatically deployed to a library that gets hosted on your tenant Office 365 CDN.

ALM REST APIs


ALM REST APIs. Deploy, activate, delete, and upgrade apps and add-ins.
ALM REST APIs targeted to support everything in the app catalog, including add-ins.
CSOM and PowerShell cmdlets released as an open source community initiative.

JavaScript embedding support (JSLink, User Custom Actions)


The same toolchain and deployment model as client-side web parts.
Derive from a strongly typed base class wherever possible, rather than manipulating the page DOM directly.
Enable modern extension usage with modern experiences similar to Custom Actions and JSLink in classic experience.
Work with NoScript via tenant app catalog.

On-premises support - Sharepoint 2016 Feature Pack 2


Shipping as part of Feature Pack 2 for SharePoint 2016.
Similar feature capabilities as in SharePoint Online.
Target is to provide common development platform across on-premises and the cloud.
Leveraging modern toolchain and open source in on-premises environments.
Targeting SharePoint 2016 version during calendar year 2017.

See also
dev.office.com blog
OfficeDev Twitter account
SharePoint Framework Overview
SharePoint Framework known issues and frequently asked questions
3/26/2018 • 2 minutes to read Edit Online

This page is for listing any known issues or to answer any frequently asked questions about SharePoint Framework.

Known issues
Dev certificate issue with Chrome (v58-)
Date - April 28, 2017
Updated - May 2, 2017
If you are using Chrome as your development browser, you might have challenges with the developer certificate regardless of executing the gulp trust-dev-cert command. Chrome has
changed its model for certificate validation starting from version 58, and you might see a "Your connection is not private" warning when you are accessing the local workbench.
You should update your Yeoman template packages. We have updated certification creation logic in the @microsoft/gulp-core-build-serve package.
In existing solutions, you can simply delete this folder and run npm install to get the updated package. You also need to execute untrust-dev-cert and trust-dev-cert commands on your
machine to address the certification creation logic issue.

Frequently asked questions


When will custom actions and JSLink be available in the SharePoint Framework?
Date - June 6, 2017
SharePoint Framework Extensions with additional customization capabilities is now available in SharePoint Online. You can find more information about SharePoint Framework Extensions
from our documentation:
SharePoint Framework Extensions Overview
SharePoint Framework Extensions Tutorials

Will SharePoint Framework be available in on-premises?


Date - June 6, 2017
SharePoint Framework client-side web parts on classic pages were released to SharePoint 2016 as part of the Feature Pack 2 (FP2). There are no plans currently to provide SharePoint
Framework capabilities to SharePoint 2013. There's no specific list of SharePoint Framework capabilities that will be included in the SharePoint 2019 release.

See also
Please use following resources to provide feedback, comments, and questions to SharePoint engineering.
GitHub sp-dev-docs issues
SharePoint Developer Microsoft Tech Community space
Overview of the "Connect to new Office 365 group" feature
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The option to connect an Office 365 group to an existing site is not yet available and will be released during Q2 of calendar year 2018.
With the Connect to new Office 365 group feature, you can augment your team site collaboration capabilities with the benefits of other group services such as Outlook, Planner, and
Microsoft Teams. This keeps your site, its content, permissions, and customizations intact and eliminates the need to migrate content to a new group-backed site.

What happens when you connect your site to an Office 365 group?
When you connect your site to a new Office 365 group, a number of things happen:
A new Office 365 group is created, and that group is connected to your site collection
A new modern home page is created on your site and set as the site's home page
The group's Owners are now the site collection administrators
The group's Owners are added to your site's Owners group
The group's Members are added to your site's Members group
After your site is connected to an Office 365 group, it behaves like a modern group-connected team site, so members added to the Office 365 group have access to the site and other group
resources (such as Outlook mailbox, Planner, and optional Microsoft Teams).

Additional details
An admin setting exists that specifies whether this feature is available to site administrators in the classic team site UI. Tenant admins will always be able to connect team sites to new
Office 365 groups by using PowerShell cmdlets or API.
Group-connection can be performed for top-level site collections only. You cannot connect subsites to Office 365 groups.
If executed via the UI, group-connection is only available for the Team site template (STS#0).
Because this process results in the creation of a new Office 365 group, membership must be managed independently of the site’s membership.

See also
Connect a classic SharePoint team site to a new Office 365 group
SharePoint Modernization scanner tool
PowerShell cmdlet to connect a SharePoint team site to a new Office 365 group
Modernize your classic SharePoint sites
Connect to new Office 365 group: CSOM development
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The option to connect an Office 365 group to an existing site is not yet available and will be released during Q2 of calendar year 2018.
The SharePoint client-side object model (CSOM) provides access to the SharePoint object model from code that is running locally or on a different server than SharePoint.

Prerequisites
Before you get started, make sure that you're familiar with the following:
Using the Client Object Model
Common Programming Tasks in the Managed Client Object Model
You also need to reference the Microsoft.SharePointOnline.CSOM NuGet package (version 16.1.6906.1200 or later).

CSOM code example


The following example shows how to create a Microsoft.Online.SharePoint.TenantAdministration.Tenant object and call the GetAllTenantThemes method to return a list of themes.
NOTE

The URL used to create the context object includes the -admin suffix, because TenantAdministration methods work with the admin site.
Create a Tenant instance with the Tenant constructor, and then call the methods on that instance.

using System.Security;
using Microsoft.SharePoint.Client;
using Microsoft.Online.SharePoint.TenantAdministration;
using Microsoft.Online.SharePoint.TenantManagement;

...

ClientContext ctx = new ClientContext("https://contoso-admin.sharepoint.com/");


var pwd = "mypassword";
var passWord = new SecureString();
foreach (char c in pwd.ToCharArray()) passWord.AppendChar(c);
ctx.Credentials = new SharePointOnlineCredentials("admin@mydomain.com", passWord);
Tenant tenant = new Tenant(ctx);
tenant.CreateGroupForSite("https://contoso.sharepoint.com/sites/team-site", "display-name-for-group", "alias-for-group", true);

Methods in Microsoft.Online.SharePoint.TenantAdministration.Tenant class


Use the following methods to customize the set of available themes for a SharePoint tenant administration site. You can add a new custom theme, update an existing theme, or delete a
theme, and you can retrieve a specific theme or all themes. You can also hide or restore the default themes that come with SharePoint.

CreateGroupForSite method
Create a new Office 365 group and attach it to an existing site. After this succeeds for a given site, calling it again with the same site will throw an Exception.
Namespace: Microsoft.Online.SharePoint.TenantAdministration.Tenant
Return type: void

PAR AME TER T YPE D ES CR IPTIO N

siteUrl string URL of the site to connect to a new Office 365 group.

displayName string Display Name group to create.

alias string Alias of the new group to create.

isPublic bool Whether the group is public or private.

optionalParams GroupCreationParams An optional set of creation parameters for the group.

type: Microsoft.Online.SharePoint.TenantAdministration.GroupCreationParams

PR O PER T Y T YPE D ES CR IPTIO N

Description string Gets and sets the group description.

Owners string[] Gets and sets the group owners. These should be the principal
names of the users.

CreationOptions string[] Gets and sets the group's creation options.

Classification string Gets and sets the group's data classification.

See also
Overview of the "Connect to new Office 365 group" feature
Modernize your classic SharePoint sites
SharePoint hub sites overview
6/18/2018 • 2 minutes to read Edit Online

SharePoint hub sites connect and organize sites based on organizational attributes such as project, department, division, or region. You can use PowerShell cmdlets or the SharePoint REST
API to automate tasks such as creating, removing, or controlling permissions for hub sites.
For more information about SharePoint hub sites, see What is a SharePoint hub site.
For more information about creating hub sites, see Create SharePoint hub sites using PowerShell.

Additional details
We recommend that you select a communication site or a team site that uses the modern template. If you use a classic team site, the hub site navigation will only appear on modern
pages, including document libraries, lists, and site contents. Hub site settings will only appear on modern pages.
You can create up to 50 hub sites for an organization.
If you set up SharePoint Multi-Geo for your organization, only sites within the same geographical location can be associated with a hub site.
When users associate their sites with a hub site, it doesn't impact the permissions of either the hub site or the associated sites. It's important to ensure that all users you allow to
associate sites to the hub site have permission to the hub site.
The hub site navigation that is shown on all associated sites is based on the top navigation bar of the hub site. To make programmatic changes to the hub site navigation, you can use
the REST API, CSOM API, or PnP PowerShell.

See also
PowerShell cmdlets for SharePoint hub sites
Get to know the SharePoint REST service
Create SharePoint hub sites using PowerShell
4/23/2018 • 4 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
If you're a global or SharePoint admin in Office 365, you can convert any existing site to a hub site by using Windows PowerShell. In this example, you'll learn how to create a SharePoint hub
site and to associate another site with it. In this scenario, you are setting up sites for the Contoso marketing department:
You will create a hub site that all other marketing sites will be associated with.
You will then specify settings and permissions for the hub site.
Finally, you will create a second site and associate it with the hub site.
NOTE

To work with this example in SharePoint Online, we recommend that you use a developer tenant and not your production tenant. All of the following steps use a fictional tenant named
"Contoso" that you can replace with your tenant name.

Connect to SPO
First, you need to connect to SharePoint Online by using Windows PowerShell. The commands use both the SharePoint Online Management Shell (-SPO) and the SharePoint PnP
PowerShell Online module (-PnP).
1. Start Windows PowerShell.
2. Run the Connect-SPOService cmdlet to connect to SharePoint Online. Sign in with your global or SharePoint admin credentials:

Connect-SPOService -Url "https://<your tenant name>-admin.sharepoint.com"

NOTE

In the remainder of this exercise, contoso will be used as the tenant name. Continue to use your own tenant name in place of contoso.

Create a new hub site


Next, create the marketing site that will serve as a hub site that other sites can associate with. The intent is that any sites that are marketing-oriented will be part of the hub site. This applies
common navigation and branding across the associated sites, enables team members to search across all the sites associated with the single hub site, and takes advantage of other hub site
features.
1. Create the site using the New-PnPSite cmdlet:

Connect-PnPOnline -SPOManagementShell
New-PnPSite -Type TeamSite
-title "Contoso marketing division"
-alias "marketing"
-Description "Main site for collaboration for marketing teams at Contoso"

The -SPOManagementShell parameter allows you to reuse the credentials you signed in with by using the Connect-SPOService cmdlet.
The cmdlet returns the URL of the new site similar to the following:

https://contoso.sharepoint.com/sites/marketing

2. Register the new marketing site as a hub site by using the Register-SPOHubSite cmdlet:

Register-SPOHubSite -Site https://contoso.sharepoint.com/sites/marketing

You will see output similar to the following:

ID : bf0245ee-6bff-48a5-968f-0f155e2b7bbc
Title : Contoso marketing division
SiteId : bf0245ee-6bff-48a5-968f-0f155e2b7bbc
SiteUrl : https://contoso.sharepoint.com/sites/marketing
LogoUrl :
Description :
Permissions :

Set properties and permissions on the hub site


The hub site doesn't have a logo or description yet. We also want to constrain it so that only one person can make changes to the hub site.

Set properties
1. Upload a logo image for the site by going to https://contoso.sharepoint.com/sites/marketing/SiteAssets and uploading any image you like. Make a note of the image file name.
2. Use the Set-SPOHubSite cmdlet to set the logo and description. In place of mylogo.jpg , specify the name of the image that you uploaded:

Set-SPOHubSite
-Identity https://contoso.sharepoint.com/sites/marketing
-LogoUrl https://contoso.sharepoint.com/marketing/SiteAssets/mylogo.jpg
-Description "Main hub site for collaboration on marketing activities across Contoso"

You will see output similar to the following:


ID : bf0245ee-6bff-48a5-968f-0f155e2b7bbc
Title : Contoso marketing division
SiteId : bf0245ee-6bff-48a5-968f-0f155e2b7bbc
SiteUrl : https://contoso.sharepoint.com/sites/marketing
LogoUrl : https://contoso.sharepoint.com/sites/marketing/SiteAssets/mylogo.jpg
Description : Main hub site for collaboration on marketing activities across Contoso
Permissions :

Set permissions
Now we will restrict access so that only the user nestorw@contoso can make changes to the hub site associations.
Run the Grant-SPOHubSiteRights cmdlet to grant a user rights to the marketing hub site. We'll use nestorw@contoso in this example, but you can use any valid user on your tenant
(you can specify multiple users by separating them with a comma):

Grant-SPOHubSiteRights -Identity https://contoso.sharepoint.com/sites/marketing -Principals "nestorw@contoso" -Rights Join

You will see output similar to the following:

ID : bf0245ee-6bff-48a5-968f-0f155e2b7bbc
Title : Contoso marketing division
SiteId : bf0245ee-6bff-48a5-968f-0f155e2b7bbc
SiteUrl : https://contoso.sharepoint.com/sites/marketing
LogoUrl : https://contoso.sharepoint.com/sites/marketing/SiteAssets/mylogo.jpg
Description : Main hub site for collaboration on marketing activities across Contoso
Permissions : {0#.f|membership|nestorw@contoso.onmicrosoft.com}

Create and associate a new site


The final step is to create the site we want to associate with the hub. You can repeat these steps for as many sites as you want to join to the hub.
1. Provision the site by using the New-PnPSite cmdlet:

New-PnPSite -Type TeamSite


-title "Online advertising team"
-alias "online-advertising"
-Description "For collaboration on online advertising resources"

The cmdlet returns the URL of the new site similar to the following:

https://contoso.sharepoint.com/sites/online-advertising

2. Associate this site with the hub site by using the Add-SPOHubSiteAssociation cmdlet:

Add-SPOHubSiteAssociation
-Site https://contoso.sharepoint.com/sites/online-advertising
-HubSite https://contoso.sharepoint.com/sites/marketing

Confirm the hub site is working


To confirm, you can either:
Run the Get-SPOHubSite cmdlet.
Sign in to SharePoint Online and view the hub site directly at https://contoso.sharepoint.com/sites/marketing .
The hub site navigation appears at the top of the site. If you go to the https://contoso.sharepoint.com/sites/online-advertising site, it shows the same hub site navigation at the top.

See also
SharePoint hub sites overview
PowerShell cmdlets for SharePoint hub sites
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
Use PowerShell cmdlets to create and manage SharePoint hub sites.

Get started
To run the PowerShell cmdlets:
1. Download and install the SharePoint Online Management Shell. If you already have a previous version of the shell installed, uninstall it first, and then install the latest version.
2. Follow the instructions at Connect to SharePoint Online PowerShell to connect to your SharePoint tenant.
To verify your setup, try using the Get-SPOHubSite cmdlet to read the current list of hub sites. If the cmdlet runs and returns with no errors, you're ready to proceed.

Hub site cmdlets


The following PowerShell cmdlets are available for managing hub sites:

CMD LE T D ES CR IPTIO N

Add-SPOHubSiteAssociation Adds a new association between a site and a hub site.

Remove-SPOHubSiteAssociation Removes an association between a site and a hub site.

Get-SPOHubSite Lists hub sites or hub site information.

Grant-SPOHubSiteRights Grants rights to users or security groups to access the hub site.

Register-SPOHubSite Enables the hub site feature on a site to make it a hub site.

Revoke-SPOHubSiteRights Revokes rights for specified principals to a hub site.

Set-SPOHubSite Sets the hub site information such as name, logo, and description.

Unregister-SPOHubSite Disables the hub site feature on a site.

See also
SharePoint hub sites overview
Hub site REST API
4/23/2018 • 2 minutes to read Edit Online

You can use the SharePoint REST interface to register sites as hub sites, associate existing sites with hub sites, and obtain or update information about hub sites.
The SharePoint Online (and SharePoint 2016 and later on-premises) REST service supports combining multiple requests into a single call to the service by using the OData $batch query
option.
For details and links to code samples, see Make batch requests with the REST APIs.

Prerequisites
Before you get started, make sure that you're familiar with the following:
Get to know the SharePoint REST service
Complete basic operations using SharePoint REST endpoints

REST commands
The following REST commands are available for working with site designs and site scripts:
SP.HubSites.CanCreate – Returns whether the current user can create a hub site. Only tenant admins can create hub sites.
GetById – Gets or updates information about a hub site.
HubSiteData – Gets hub site data for the current web.
HubSites – Gets information about all hub sites that the current user can access.
JoinHubSite – Associates a site with an existing hub site.
RegisterHubSite – Registers an existing site as a hub site.
SyncHubSiteTheme – Applies any theme updates from the parent hub site.
UnRegisterHubSite – Unregisters a hub site so that it is no longer a hub site.
SPHubSite object type – Contains data describing a SharePoint hub site.
SPHubSiteData object type – Contains data describing a SharePoint hub site.

Scenarios
Some of the following scenario examples are not intuitive from the method name. See each cmdlet article for more details.

Update a hub site


Call the GetById method to update a hub site.

Disassociate a site from its hub site


To remove, or disassociate a site from a hub site, call JoinHubSite with the value "00000000-0000-0000-0000-000000000000".

See also
SharePoint hub sites overview
SP.HubSites.CanCreate
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
Returns whether the current user can create a hub site. Only tenant admins can create hub sites.

HTTP request
GET /_api/SP.HubSites.CanCreate

URI parameters
None

Request headers
HE AD ER V ALU E

Accept application/json;odata=verbose

Content-Type application/json;odata=verbose;charset=utf-8

x-requestdigest The appropriate digest for current site.

Request body
Do not supply a request body for this method.

Responses
NAME T YPE D ES CR IPTIO N

200 OK SPHubSiteCanCreate Success

Examples
Check if you can create hub sites
Sample request
GET
https://contoso.sharepoint.com/sites/marketing/_api/SP.HubSites.CanCreate

Sample response
Status code: 200

{
"@odata.context": "https://contoso.sharepoint.com/sites/marketing/_api/$metadata#Edm.Boolean",
"value": true
}

Definitions
T YPE D ES CR IPTIO N

SPHubSiteCanCreate Indicates if you have permissions to create a hub site.

SPHubSiteCanCreate
Indicates if you have permissions to create a hub site.

NAME T YPE D ES CR IPTIO N

value Boolean True if you have permissions to create a hub site; otherwise, false

See also
Hub site REST API
GetById
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
Gets or updates information about a hub site.

HTTP request
GET /_api/HubSites/GetById
POST /_api/HubSites/GetById

URI parameters
NAME IN R EQ U IR ED T YPE D ES CR IPTIO N

hubSiteId query True string The ID of the hub site to get


information about.

Request headers
HE AD ER V ALU E

Accept application/json;odata=verbose

Content-Type application/json;odata=verbose;charset=utf-8

x-requestdigest The appropriate digest for current site.

When using POST to update a hub site with new information, use the following additional header values:

HE AD ER V ALU E

X-HTTP-Method MERGE

If-Match *

Request body
For GET, no request body is needed. When using POST to update a hub site with new information, use the following body.

NAME R EQ U IR ED T YPE D ES CR IPTIO N

Title no string The display name of the hub.

LogoUrl no string The URL of a logo to use in the hub site


navigation.

Description no string A description of the hub site.

Responses
NAME T YPE D ES CR IPTIO N

200 OK SPHubSite Hub site information successfully returned.

204 No Content Hub site was updated.

Examples
Get a hub site
Sample request
GET
https://contoso.sharepoint.com/_api/HubSites/GetById?hubSiteId='f93eff08-5806-499c-92db-38800eefbe44'

Sample response
Status code: 200
{
"@odata.context": "https://contoso.sharepoint.com/_api/$metadata#hubsites/$entity",
"@odata.type": "#SP.HubSite",
"@odata.id": "https://contoso.sharepoint.com/_api/HubSites/GetById",
"@odata.etag": "\"3\"",
"@odata.editLink": "HubSites/GetById",
"Description": null,
"ID": "f93eff08-5806-499c-92db-38800eefbe44",
"LogoUrl": "https://contoso.sharepoint.com/sites/marketing/SiteAssets/__hubLogo____hubLogo__.png",
"SiteId": "f93eff08-5806-499c-92db-38800eefbe44",
"SiteUrl": "https://contoso.sharepoint.com/sites/marketing",
"Targets": "<acl><ace identityName=\"c:0t.c|tenant|0d4b97fc-37fb-4db3-84f3-d34243a3afac\" displayName=\"0t.c|tenant|0d4b97fc-37fb-4db3-84f3-d34243a3afac\" sid=\"\" binaryIdType=\"1\" binaryId
"TenantInstanceId": "00000000-0000-0000-0000-000000000000",
"Title": ""
}

Update a hub site


Sample request
POST
https://contoso.sharepoint.com/_api/HubSites/GetById?hubSiteId='f93eff08-5806-499c-92db-38800eefbe44'

Sample response
Status code: 204

{
"Title": "Marketing hub site",
"LogoUrl": "https://contoso.sharepoint.com/sites/marketing/SiteAssets/__hubLogo____hubLogo__.png",
"Description": "Hub site for marketing coordination"
}

See also
Hub site REST API
HubSiteData
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
Gets hub site data for the current web.

HTTP request
GET /_api/web/HubSiteData

URI parameters
NAME IN R EQ U IR ED T YPE D ES CR IPTIO N

forceRefresh query False boolean Default value is false. When false, the
data is returned from the server's
cache. When true, the cache is
refreshed with the latest updates and
then returned. Use this if you just
made changes and need to see those
changes right away.

Request headers
HE AD ER V ALU E

Accept application/json;odata=verbose

Content-Type application/json;odata=verbose;charset=utf-8

x-requestdigest The appropriate digest for current site.

Request body
Do not supply a request body for this method.

Responses
NAME T YPE D ES CR IPTIO N

200 OK SPHubSiteData OK

Examples
Get hub site data for marketing web
Sample request
GET
https://contoso.sharepoint.com/sites/marketing/_api/web/HubSiteData(true)

Sample response
Status code: 200

{
"themeKey": null,
"name": "marketing",
"url": "https://contoso.sharepoint.com/sites/marketing",
"logoUrl": "https://contoso.sharepoint.com/sites/marketing/SiteAssets/__hubLogo.jpg",
"usesMetadataNavigation": false,
"navigation": [
{
"Id": 2006,
"Title": "online team",
"Url": "https://spdfcontosodemo2.sharepoint.com/sites/online-advertising",
"IsDocLib": false,
"IsExternal": false,
"ParentId": 1002,
"ListTemplateType": 0,
"Children": []
}
]
}

See also
Hub site REST API
HubSites
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
Gets information about all hub sites that the current user can access.

HTTP request
GET /_api/HubSites

URI parameters
There are no parameters for this method.

Request headers
HE AD ER V ALU E

Accept application/json;odata=verbose

Content-Type application/json;odata=verbose;charset=utf-8

x-requestdigest The appropriate digest for current site.

Request body
Do not supply a request body for this method.

Responses
NAME T YPE D ES CR IPTIO N

200 OK SPHubSiteCollection OK

Examples
Get list of hub sites
Sample request
GET
https://contoso.sharepoint.com/_api/HubSites

Sample response
Status code: 200

{
"@odata.context": "https://contoso.sharepoint.com/_api/$metadata#hubsites",
"value": [
{
"@odata.type": "#SP.HubSite",
"@odata.id": "https://contoso.sharepoint.com/_api/SP.HubSite9dbd0488-5d8d-4ce6-941e-e5650bc216f4",
"@odata.etag": "\"2\"",
"@odata.editLink": "SP.HubSite9dbd0488-5d8d-4ce6-941e-e5650bc216f4",
"Description": null,
"ID": "82e8cb67-c4f1-4b38-80aa-0342294f5ece",
"LogoUrl": "https://contoso.sharepoint.com/sites/ContosoTravelMarketing/SiteAssets/__hubLogo____hubLogo__.png",
"SiteId": "82e8cb67-c4f1-4b38-80aa-0342294f5ece",
"SiteUrl": "https://contoso.sharepoint.com/sites/ContosoTravelMarketing",
"Targets": null,
"TenantInstanceId": "00000000-0000-0000-0000-000000000000",
"Title": "Contoso Travel Marketing"
},
{
"@odata.type": "#SP.HubSite",
"@odata.id": "https://contoso.sharepoint.com/_api/SP.HubSitee3e23fc3-870c-4de1-89c0-85b378e42b2e",
"@odata.etag": "\"1\"",
"@odata.editLink": "SP.HubSitee3e23fc3-870c-4de1-89c0-85b378e42b2e",
"Description": null,
"ID": "d8ab01e9-1634-44dd-91fe-1e6ff8385c34",
"LogoUrl": "https://contoso.sharepoint.com/sites/ContosoDepartment/SiteAssets/__sitelogo__keep_calm_hit_refresh.png",
"SiteId": "d8ab01e9-1634-44dd-91fe-1e6ff8385c34",
"SiteUrl": "https://contoso.sharepoint.com/sites/ContosoDepartment",
"Targets": null,
"TenantInstanceId": "00000000-0000-0000-0000-000000000000",
"Title": "Contoso Department Hub"
}
]
}

See also
Hub site REST API
JoinHubSite
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
Associates a site with an existing hub site. You can also use this method to disassociate a site from a hub site (see example).

HTTP request
POST /_api/site/JoinHubSite(hubSiteId)

URI parameters
NAME IN R EQ U IR ED T YPE D ES CR IPTIO N

hubSiteId query True GUID ID of the hub site to join.

Request headers
HE AD ER V ALU E

Accept application/json;odata=verbose

Content-Type application/json;odata=verbose;charset=utf-8

x-requestdigest The appropriate digest for current site.

Request body
Do not supply a request body for this method.

Responses
NAME T YPE D ES CR IPTIO N

204 OK Success

Examples
Join the advertising site to the marketing hub site
In this sample, the ID of the marketing hub site is 27c5fcba-abfd-4c34-823d-0b4a48f7ffe6 .
Sample request
POST
https://contoso.sharepoint.com/sites/advertising/_api/site/JoinHubSite('27c5fcba-abfd-4c34-823d-0b4a48f7ffe6')

Sample response
Status code: 204

Remove the advertising site from the marketing hub site


To remove, or disassociate a site from a hub site, call JoinHubSite with the value "00000000-0000-0000-0000-000000000000".
Sample request
POST
https://contoso.sharepoint.com/sites/advertising/_api/site/JoinHubSite('00000000-0000-0000-0000-000000000000')

Sample response
Status code: 204

See also
Hub site REST API
RegisterHubSite
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
Registers an existing site as a hub site.

HTTP request
POST /_api/site/RegisterHubSite

URI parameters
None

Request headers
HE AD ER V ALU E

Accept application/json;odata=verbose

Content-Type application/json;odata=verbose;charset=utf-8

x-requestdigest The appropriate digest for current site.

Request body
Do not supply a request body for this method.

Responses
NAME T YPE D ES CR IPTIO N

200 OK SPHubSite OK

Other Status Codes Error Error response describing why the operation failed.

Examples
Register a marketing site as a hub site
Sample request
POST
https://contoso.sharepoint.com/sites/marketing/_api/site/RegisterHubSite

Sample response
Status code: 200

{
"@odata.context": "https://contoso.sharepoint.com/sites/marketing/_api/$metadata#hubsites/$entity",
"@odata.type": "#SP.HubSite",
"@odata.id": "https://contoso.sharepoint.com/sites/marketing/_api/site/RegisterHubSite",
"@odata.etag": "\"1\"",
"@odata.editLink": "site/RegisterHubSite",
"Description": null,
"ID": "2714709b-b5d0-4001-9d43-6a0e4d6e7a19",
"LogoUrl": null,
"SiteId": "2714709b-b5d0-4001-9d43-6a0e4d6e7a19",
"SiteUrl": "https://contoso.sharepoint.com/sites/marketing",
"Targets": null,
"TenantInstanceId": "4aa2157b-4935-472d-8169-281c2e9d50a1",
"Title": "Marketing site"
}

See also
Hub site REST API
SyncHubSiteTheme
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
Applies any theme updates from the parent hub site.

HTTP request
POST /_api/web/SyncHubSiteTheme

URI parameters
None

Request headers
HE AD ER V ALU E

Accept application/json;odata=verbose

Content-Type application/json;odata=verbose;charset=utf-8

x-requestdigest The appropriate digest for current site.

Request body
Do not supply a request body for this method.

Responses
NAME T YPE D ES CR IPTIO N

204 OK Boolean Success

Examples
Apply themes from parent hub site to the /advertising/collections web
Sample request
POST
https://contoso.sharepoint.com/sites/advertising/collections/_api/web/SyncHubSiteTheme

Sample response
Status code: 204

See also
Hub site REST API
UnRegisterHubSite
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
Unregisters a hub site so that it is no longer a hub site. It will become a regular site. Any sites associated with the hub site will no longer be associated. This can take up to an hour to
propagate. If you want to speed up the process, first remove any associated sites before unregistering the hub site.

HTTP request
POST /_api/site/UnRegisterHubSite

URI parameters
None

Request headers
HE AD ER V ALU E

Accept application/json;odata=verbose

Content-Type application/json;odata=verbose;charset=utf-8

x-requestdigest The appropriate digest for current site.

Request body
Do not supply a request body for this method.

Responses
NAME T YPE D ES CR IPTIO N

204 OK Success

Other Status Codes Error Error response describing why the operation failed.

Examples
UnRegister a marketing site so it is no longer a hub site
Sample request
POST
https://contoso.sharepoint.com/sites/marketing/_api/site/UnRegisterHubSite

Sample response
Status code: 204

See also
Hub site REST API
SPHubSite object type
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
Contains data describing a SharePoint hub site.

NAME T YPE D ES CR IPTIO N

ID GUID Identifies the hub site.

Title string The display name of the hub site.

SiteId GUID ID of the hub parent site.

TenantInstanceId GUID The tenant instance ID in which the hub site is located. Use empty
GUID for the default tenant instance.

SiteUrl string URL of the hub parent site.

logoUrl string The URL of a logo to use in the hub site navigation.

Description string A description of the hub site.

Targets string List of security groups with access to join the hub site. Null if
everyone has permission.

See also
Hub site REST API
SPHubSiteData object type
4/23/2018 • 2 minutes to read Edit Online

IM P O R T A N T

The hub sites feature is currently in preview and is subject to change. It is not currently supported for use in production environments.
Contains data describing a SharePoint hub site.

NAME T YPE D ES CR IPTIO N

themeKey string Identifies the theme currently applied to all associated sites.

name string The name of the hub site.

url string Full URL of the hub site.

LogoUrl string The URL of a logo to use in the hub site navigation.

usesMetadataNavigation Boolean True if publishing features are enabled on the hub parent site;
otherwise, false.

navigation SP.NavigationNode[] navigation is only list if usesMetadataNavigation is false.

Navigation node properties


NAME T YPE D ES CR IPTIO N

Id number ID of the navigation node

Title string Text of the navigation node

Url string URL the navigation node points to

ParentId number ID of the parent navigation node

Children List of navigation nodes List of child navigation nodes

See also
Hub site REST API
SharePoint .NET Server, CSOM, JSOM, and REST API index
5/3/2018 • 2 minutes to read Edit Online

Use the API index to look up many of the most frequently used types and objects that are implemented in the .NET server object model and at least one client programming model: .NET
client-side object model (CSOM), JavaScript object model (JSOM), and/or REST.
This table lists the most frequently used core APIs, which are in most cases based on types from the .NET server implementation. In some cases, types are native to SharePoint client
programming, and there is no equivalent .NET server type. In other cases, some but not all possible client programming model implementations of a specific type exist.
NOTE

Before using a REST endpoint URI shown in the table, replace the … abbreviation with the path to your SharePoint site; for example http://<site collection>/<site>/_api/web/lists .

SharePoint API index


API S P.O B JECT/ENU MER ATIO N (S P.JS ) R ES T END PO INT

AttachmentCollection SPAttachmentCollection SP.AttachmentCollection …/_api/web/lists('<list id>')/items(<item


id>)/attachmentfiles

BasePermissions SPBasePermissions SP.BasePermissions object N/A

CalendarType SPCalendarType SP.CalendarType enumeration N/A

ChangeCollection SPChangeCollection SP.ChangeCollection object …/_api/web/getchanges(changequery)

ChangeSite SPChangeSite SP.ChangeSite enumeration N/A

ClientContext SP.ClientContext object …/_api/contextinfo

ContentType SPContentType SP.ContentType object …/_api/web/contenttypes('<content type id>')

ContentTypeCollection SPContentTypeCollection SP.ContentTypeCollection object …/_api/web/contenttypes

SPContext SP.RequestContext object N/A

EventReceiverDefinition SPEventReceiverDefinition SP.EventReceiverDefinition object …/_api/web/eventreceivers

EventReceiverDefinitionCollection SP.EventReceiverDefinitionCollection object …/_api/web/eventreceivers(eventreceiverid)


SPEventReceiverDefinitionCollection

EventReceiverDefinitionCreationInformation SP.EventReceiverDefinitionCreationInformation object N/A


SPEventReceiverDefinitionCreationInformation

EventReceiverType SPEventReceiverType SP.EventReceiverType enumeration N/A

Feature SPFeature SP.Feature object …/_api/web/features(featureid)

FeatureCollection SPFeatureCollection SP.FeatureCollection object …/_api/web/features

FeatureDefinitionScope SPFeatureDefinitionScope SP.FeatureDefinitionScope enumeration N/A

Field SPField SP.Field object …/_api/web/fields('')

FieldCalculated SPFieldCalculated SP.FieldCalculated object …/_api/web/fields('')

FieldChoice SPFieldChoice SP.FieldChoice object …/_api/web/fields('')

FieldCollection SPFieldCollection SP.FieldCollection object …/_api/web/fields

FieldComputed SPFieldComputed SP.FieldComputed object …/_api/web/fields('')

FieldCurrency SPFieldCurrency SP.FieldCurrency object …/_api/web/fields('')

FieldLink SPFieldLink SP.FieldLink object …/_api/web/contenttypes('<content type


id>')/fieldlinks('<field link id>')

FieldLookupValue SPFieldLookupValue SP.FieldLookup object N/A

FieldMultiChoice SPFieldMultiChoice SP.FieldMultiChoice object …/_api/web/fields('')

FieldMultiLineText SPFieldMultiLineText SP.FieldMultiLineText object …/_api/web/fields('')

FieldNumber SPFieldNumber SP.FieldNumber object …/_api/web/fields('')

FieldText SPFieldText SP.FieldText object …/_api/web/fields('')

FieldUrl SPFieldUrl SP.FieldUrl object …/_api/web/fields('')

FieldUrlValue SPFieldUrlValue SP.FieldUrlValue object N/A


API S P.O B JECT/ENU MER ATIO N (S P.JS ) R ES T END PO INT

FieldUser SPFieldUser SP.FieldUser object …/_api/web/fields('')

File SPFile SP.File object …/_api/web/getfilebyserverrelativeurl('//')

FileCollection SPFileCollection SP.FieldCollection object …/_api/web/getfolderbyserverrelativeurl('/')/files

Folder SPFolder SP.Folder object …/_api/web/getfolderbyserverrelativeurl('/')

Form SPForm SP.Form object …/_api/web/lists(guid'<list id>')/forms('<form id>')

Group SPGroup SP.Group object …/_api/web/sitegroups()

GroupCollection SPGroupCollection SP.GroupCollection object …/_api/web/sitegroups

Language SPLanguage SP.Language object N/A

List SPList SP.List object …/_api/web/lists(guid'')

ListCollection SPListCollection SP.ListCollection object …/_api/web/lists

ListDataSource SPListDataSource SP.ListDataSource object N/A

ListItem SPListItem SP.ListItem object …/_api/web/lists(guid'')/items()

ListItemCollection SPListItemCollection SP.ListItemCollection object …/_api/web/lists(guid'')/items

ListTemplateType SPListTemplateType SP.ListTemplateType enumeration N/A

Navigation SPNavigation SP.Navigation object …/_api/web/navigation

NavigationNode SPNavigationNode SP.NavigationNode object N/A

Principal SPPrincipal SP.Principal object N/A

SPQuery N/A

RecycleBinItem SPRecycleBinItem SP.RecycleBinItem object …/_api/web/RecycleBin(recyclebinitemid)

RecycleBinItemCollection SPRecycleBinItemCollection SP.RecycleBinItemCollection object …/_api/web/RecycleBin

RegionalSettings SPRegionalSettings SP.RegionalSettings object …/_api/web/RegionalSettings

RoleAssignment SPRoleAssignment SP.RoleAssignment object …/_api/web/roleassignments()

RoleAssignmentCollection SPRoleAssignmentCollection SP.RoleAssignmentCollection object …/_api/web/roleassignments

RoleDefinition SPRoleDefinition SP.RoleDefinition object …/_api/web/roledefinitions()

RoleType SPRoleType SP.RoleType enumeration N/A

SecurableObject SPSecurableObject SP.SecurableObject object N/A

Site SPSite SP.Site object …/_api/site

TimeZone SPTimeZone SP.TimeZone object …/_api/web/RegionalSettings/TimeZones(timzoneid)

Taxonomy SPTaxonomySession SP.Taxonomy.TaxonomySession object NA

TimeZoneCollection SPTimeZoneCollection SP.TimeZoneCollection object …/_api/web/RegionalSettings/TimeZones

User SPUser SP.User object …/_api/web/siteusers(@v)?@v=''

UserCollection SPUserCollection SP.UserCollection object …/_api/web/sitegroups()/users

Utility SPUtility SP.Utilities.Utility object (sp.js) N/A

View SPView SP.View object (sp.js) …/_api/web/lists(guid'')/views('')

ViewCollection SPViewCollection SP.ViewCollection object …/_api/web/lists(guid'')/views

ViewFieldCollection SPViewFieldCollection SP.ViewFieldCollection object …/_api/web/lists(guid'')/views('')/fields

Web SPWeb SP.Web object …/_api/web

WebCollection SPWebCollection SP.WebCollection object …/_api/web/webs

WebInformation SPWebInfo SP.WebInformation object …/_api/web/webinfos('<web information id>')


API S P.O B JECT/ENU MER ATIO N (S P.JS ) R ES T END PO INT

WebTemplate SPWebTemplate SP.WebTemplate object …/_api/web/GetAvailableWebTemplates(languageid,includecrosslanguage

WebTemplateCollection SPWebTemplateCollection SP.WebTemplateCollection object …/_api/web/GetAvailableWebTemplates(languageid,includecrosslanguage

See also
Develop SharePoint Add-ins
Complete basic operations using SharePoint client library code
Complete basic operations using JavaScript library code in SharePoint
Complete basic operations using SharePoint client library code
5/3/2018 • 21 minutes to read Edit Online

You can use the SharePoint client object model (CSOM) to retrieve, update, and manage data in SharePoint. SharePoint makes the CSOM available in several forms:
.NET Framework redistributable assemblies
JavaScript library
REST/OData endpoints
Windows Phone assemblies
Silverlight redistributable assemblies
For more information about the sets of APIs available on the SharePoint platform, see Choose the right API set in SharePoint.
This article shows how to perform basic operations by using the .NET Framework object model, which is available as a redistributable package on the Microsoft Download Center (search for
"SharePoint Server 2013 Client Components SDK" or "SharePoint Online Client Components SDK").
For information about how to use the other client APIs, see:
Complete basic operations using JavaScript library code in SharePoint
Complete basic operations using SharePoint REST endpoints
Build Windows Phone apps that access SharePoint
Using the Silverlight Object Model in the SharePoint 2010 SDK

Basic operations with the SharePoint .NET client object model


The following sections describe tasks that you can complete programmatically, and they include C# code examples that demonstrate CSOM operations.
When you create an Add-in for SharePoint project in Visual Studio 2012, references to the .NET Framework assemblies, Microsoft.SharePoint.Client.Runtime.dll and
Microsoft.SharePoint.Client.dll, are automatically added to the project. For other kinds of projects, such as .NET Framework applications or console applications, you should add these
references. The files are located on any SharePoint server at %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\ISAPI.
All of these examples assume that the code is in a code-behind file for a Microsoft ASP.NET webpage. You must add the following using statement to the code file.

using Microsoft.SharePoint.Client;

Except where specified otherwise, you can assume that each of these examples is in a parameterless method that is defined in the page's class. Also, label1 , label2 , and so on, are the
names of Label objects on the page.
NOTE

When you are making a provider-hosted SharePoint Add-in with an ASP.NET web application, and you add a reference to an assembly to the web application project in Visual Studio, set the
Copy Local property of the assembly to True, unless you know that the assembly is already installed on the web server, or you can ensure that it is installed before you deploy your add-in.
The .NET Framework is installed on Microsoft Azure Web Roles and Azure websites. But the SharePoint client assemblies and the various Microsoft managed code extensions and
foundations are not installed. Office Developer Tools for Visual Studio 2012 automatically adds references to some assemblies commonly used in SharePoint Add-ins and sets the Copy
Local property.

SharePoint website tasks


These examples show how to use the .NET Framework CSOM to complete website-related tasks.

Retrieve the properties of a website


Retrieve the title of a SharePoint website.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// The SharePoint web at the URL.


Web web = context.Web;

// We want to retrieve the web's properties.


context.Load(web);

// Execute the query to the server.


context.ExecuteQuery();

// Now, the web's properties are available and we could display


// web properties, such as title.
label1.Text = web.Title;

Retrieve only selected properties of a website


Sometimes, the client is interested only in a few properties of an object. The SharePoint .NET Framework CSOM does not require you to get all properties from the object on a server—you
can use anonymous methods, which can be lambda expressions, to specifically request property names. The client library queries only for those properties on the server, and the server
sends only those properties to the client. This technique reduces unnecessary data transfer between the client and the server. It is also useful when the user does not have permission to one
or more of the other, unused properties on an object.
Note that you need to add a using statement for System.Linq.
// Starting with ClientContext, the constructor requires a URL to the
// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// The SharePoint web at the URL.


Web web = context.Web;

// We want to retrieve the web's title and description.


context.Load(web, w => w.Title, w => w.Description);

// Execute the query to server.


context.ExecuteQuery();

// Now, only the web's title and description are available. If you
// try to print out other properties, the code will throw
// an exception because other properties are not available.
label1.Text = web.Title;
label1.Text = web. Description;

NOTE

If you try to access other properties, the code throws an exception because other properties are not available.

Write to website's properties


This example shows how to write to the website's properties.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// The SharePoint web at the URL.


Web web = context.Web;

web.Title = "New Title";


web.Description = "New Description";

// Note that the web.Update() does not trigger a request to the server
// because the client library until ExecuteQuery() is called.
web.Update();

// Execute the query to server.


context.ExecuteQuery();

Create a new SharePoint website


This example shows how to create a new SharePoint site as a subsite of the current website. Use the WebCreationInformation class to create a new website. You also need to add using
statements for System.Collections.Generic and System.Text.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

WebCreationInformation creation = new WebCreationInformation();


creation.Url = "web1";
creation.Title = "Hello web1";
Web newWeb = context.Web.Webs.Add(creation);

// Retrieve the new web information.


context.Load(newWeb, w => w.Title);
context.ExecuteQuery();

label1.Text = newWeb.Title;

SharePoint list tasks


These examples show how to use the .NET Framework CSOM to complete list-related tasks.

Retrieve all SharePoint lists in a website


This example retrieves all SharePoint lists in a SharePoint website. To compile this code, you need to add a using statement for System.Linq.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// The SharePoint web at the URL.


Web web = context.Web;

// Retrieve all lists from the server.


context.Load(web.Lists,
lists => lists.Include(list => list.Title, // For each list, retrieve Title and Id.
list => list.Id));

// Execute query.
context.ExecuteQuery();

// Enumerate the web.Lists.


foreach (List list in web.Lists)
{
label1.Text = label1.Text + ", " + list.Title;
}
NOTE

Alternatively, you can use the LoadQuery method to store the return value in another collection, rather than use the web.Lists property. You will also need to add using statements for
System.Collections.Generic and System.Linq. Also, add an alias to the using statement for the Microsoft.SharePoint.Client namespace so you can refer to its classes unambiguously. For
example, using SP = Microsoft.SharePoint.Client; .

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// The SharePoint web at the URL.


Web web = context.Web;

// Retrieve all lists from the server, and put the return value in another
// collection instead of the web.Lists.
IEnumerable<SP.List> result = context.LoadQuery(web.Lists.Include( // For each list, retrieve Title and Id.
list => list.Title,
list => list.Id));

// Execute query.
context.ExecuteQuery();

// Enumerate the result.


foreach (List list in web.Lists)
{
label1.Text = label1.Text + ", " + list.Title;
}

Create and update a SharePoint list


This example creates a SharePoint list and updates it by using the ListCreationInformation class.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// The SharePoint web at the URL.


Web web = context.Web;

ListCreationInformation creationInfo = new ListCreationInformation();


creationInfo.Title = "My List";
creationInfo.TemplateType = (int)ListTemplateType.Announcements;
List list = web.Lists.Add(creationInfo);
list.Description = "New Description";

list.Update();
context.ExecuteQuery();

Delete a SharePoint list


This example deletes a SharePoint list.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// The SharePoint web at the URL.


Web web = context.Web;

List list = web.Lists.GetByTitle("My List");


list.DeleteObject();

context.ExecuteQuery();

Add a field to a SharePoint list


This example adds a field to a SharePoint list. Add an alias to the using statement for the Microsoft.SharePoint.Client namespace so you can refer to its classes unambiguously. For
example, using SP = Microsoft.SharePoint.Client; .
NOTE

The example uses context.CastTo to do a cast. Before executing the query, the client library does not know the real type of the returned object "field", and SharePoint.Field is the only
possible type. If you know the real type, you can use the ClientContext.CastTo method to cast the object.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

SP.List list = context.Web.Lists.GetByTitle("Announcements");

SP.Field field = list.Fields.AddFieldAsXml("<Field DisplayName='MyField2' Type='Number' />",


true,
AddFieldOptions.DefaultValue);
SP.FieldNumber fldNumber = context.CastTo<FieldNumber>(field);
fldNumber.MaximumValue = 100;
fldNumber.MinimumValue = 35;
fldNumber.Update();

context.ExecuteQuery();
SharePoint list item tasks
These examples demonstrate how to use the .NET Framework CSOM to complete tasks that are related to list items.

Retrieve items from a SharePoint list


This example retrieves the items in a SharePoint list. You also need to add a using statement for Microsoft.SharePoint.Client.QueryExpression.
NOTE

You can use the FolderServerRelativeUrl property to further restrict the items that are returned to those in a specified folder.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// Assume the web has a list named "Announcements".


List announcementsList = context.Web.Lists.GetByTitle("Announcements");

// This creates a CamlQuery that has a RowLimit of 100, and also specifies Scope="RecursiveAll"
// so that it grabs all list items, regardless of the folder they are in.
CamlQuery query = CamlQuery.CreateAllItemsQuery(100);
ListItemCollection items = announcementsList.GetItems(query);

// Retrieve all items in the ListItemCollection from List.GetItems(Query).


context.Load(items);
context.ExecuteQuery();
foreach (ListItem listItem in items)
{
// We have all the list item data. For example, Title.
label1.Text = label1.Text + ", " + listItem["Title"];
}

Create a new list item


This example creates a new SharePoint list item by using the ListItemCreationInformation class.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// Assume that the web has a list named "Announcements".


List announcementsList = context.Web.Lists.GetByTitle("Announcements");

// We are just creating a regular list item, so we don't need to


// set any properties. If we wanted to create a new folder, for
// example, we would have to set properties such as
// UnderlyingObjectType to FileSystemObjectType.Folder.
ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
ListItem newItem = announcementsList.AddItem(itemCreateInfo);
newItem["Title"] = "My New Item!";
newItem["Body"] = "Hello World!";
newItem.Update();

context.ExecuteQuery();

Update a list item


This example updates a SharePoint list item.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// Assume that the web has a list named "Announcements".


List announcementsList = context.Web.Lists.GetByTitle("Announcements");

// Assume there is a list item with ID=1.


ListItem listItem = announcementsList.GetItemById(1);

// Write a new value to the Body field of the Announcement item.


listItem["Body"] = "This is my new value!!";
listItem.Update();

context.ExecuteQuery();

Delete a list item


This example deletes a SharePoint list item.
// Starting with ClientContext, the constructor requires a URL to the
// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// Assume that the web has a list named "Announcements".


List announcementsList = context.Web.Lists.GetByTitle("Announcements");

// Assume that there is a list item with ID=2.


ListItem listItem = announcementsList.GetItemById(2);
listItem.DeleteObject();

context.ExecuteQuery(); }

SharePoint field tasks


These examples show how to use the SharePoint .NET Framework CSOM to complete field-related tasks.

Retrieve all of the fields in a list


This example retrieves all of the fields in a SharePoint list. You also need to add an alias to the using statement for the Microsoft.SharePoint.Client namespace so you can refer to its
classes unambiguously; for example, using SP = Microsoft.SharePoint.Client; .

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

SP.List list = context.Web.Lists.GetByTitle("Shared Documents");


context.Load(list.Fields);

// We must call ExecuteQuery before enumerate list.Fields.


context.ExecuteQuery();

foreach (SP.Field field in list.Fields)


{
label1.Text = label1.Text + ", " + field.InternalName;
}

Retrieve a specific field from the list


If you want to retrieve information about a specific field, use the Fields.GetByInternalNameOrTitle method. The return type of this method is Field. Before the query is executed, the client
does not know the type of object, and C# syntax is not available for casting it to the derived type. Therefore, use the ClientContext.CastTo method to cast it, which instructs the client library
to recreate an object. You also need to add a using statement for System.Collections.Generic. You also need to add an alias to the using statement for the Microsoft.SharePoint.Client
namespace so you can refer to its classes unambiguously. For example, using SP = Microsoft.SharePoint.Client; .
NOTE

The GetByInternalNameOrTitle method used in this example is a remote method. It does not use the data from the client collection even if the client collection is already populated.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

SP.List list = context.Web.Lists.GetByTitle("Shared Documents");


SP.Field field = list.Fields.GetByInternalNameOrTitle("Title");
FieldText textField = context.CastTo<FieldText>(field);
context.Load(textField);
context.ExecuteQuery();

// Now, we can access the specific text field properties.


label1.Text = textField.MaxLength;

SharePoint user tasks


You can use the SharePoint .NET Framework CSOM to manage SharePoint users, groups, and user security.

Add a user to a SharePoint group


This example adds a user and some user information to a SharePoint group named Members.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

GroupCollection siteGroups = context.Web.SiteGroups;

// Assume that there is a "Members" group, and the ID=5.


Group membersGroup = siteGroups.GetById(5);

// Let's set up the new user info.


UserCreationInformation userCreationInfo = new UserCreationInformation();
userCreationInfo.Email = "user@domain.com";
userCreationInfo.LoginName = "domain\\user";
userCreationInfo.Title = "Mr User";

// Let's add the user to the group.


User newUser = membersGroup.Users.Add(userCreationInfo);

context.ExecuteQuery();
Retrieve all users in a SharePoint group
This example retrieves information about all users from a SharePoint group named Members.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

GroupCollection siteGroups = context.Web.SiteGroups;

// Assume that there is a "Members" group, and the ID=5.


Group membersGroup = siteGroups.GetById(5);
context.Load(membersGroup.Users);
context.ExecuteQuery();

foreach (User member in membersGroup.Users)


{
// We have all the user info. For example, Title.
label1.Text = label1.Text + ", " + member.Title;
}

Create a role
This example creates a role that has create and manage alerts permissions.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

BasePermissions perm = new BasePermissions();


perm.Set(PermissionKind.CreateAlerts);
perm.Set(PermissionKind.ManageAlerts);

RoleDefinitionCreationInformation creationInfo = new RoleDefinitionCreationInformation();


creationInfo.BasePermissions = perm;
creationInfo.Description = "A role with create and manage alerts permission";
creationInfo.Name = "Alert Manager Role";
creationInfo.Order = 0;
RoleDefinition rd = context.Web.RoleDefinitions.Add(creationInfo);

context.ExecuteQuery();

Add a user to a role


This example adds a user to a role.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

// Assume that we have a SiteUser with Login user.


Principal user = context.Web.SiteUsers.GetByLoginName(@"domain\user");

// Assume that we have a RoleDefinition named "Read".


RoleDefinition readDef = context.Web.RoleDefinitions.GetByName("Read");
RoleDefinitionBindingCollection roleDefCollection = new RoleDefinitionBindingCollection(context);
roleDefCollection.Add(readDef);
RoleAssignment newRoleAssignment = context.Web.RoleAssignments.Add(user, roleDefCollection);

context.ExecuteQuery();

Rules and best practices for using the SharePoint .NET client object model
These examples illustrate some important best practices and requirements you should conform to when using the SharePoint .NET Framework CSOM.

Call ClientContext.ExecuteQuery before accessing any value properties


The SharePoint .NET Framework CSOM requires that you use a SQL-like programming pattern: declare what you want and execute the query before you access the data. For example, the
following code, which attempts to display the SharePoint website's title, throws an exception.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

Web web = context.Web;


label1.Text = web.Title;

This code fails because SharePoint .NET Framework CSOM code must:
Build either an ad hoc SQL query or a stored procedure.
Execute the SQL query.
Read results from SQL.
In SharePoint .NET Framework CSOM, when you call a method, you build a query. Queries accumulate and are not sent to the server until ExecuteQuery is called.
The following example shows the code that is required to display the website's title. You also need to add a using statement for System.Linq. Also, add an alias to the using statement for the
Microsoft.SharePoint.Client namespace so you can refer to its classes unambiguously. For example, using SP = Microsoft.SharePoint.Client; .
// Starting with ClientContext, the constructor requires a URL to the
// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

Web web = context.Web;

context.Load(web, w => w.Title);

context.ExecuteQuery();

label1.Text = web.Title;

The differences are the addition of these lines; the first line creates a query for the web's Title property. The second line executes the query.

context.Load(web, w => w.Title);


context.ExecuteQuery();

Do not use value objects returned from methods or properties in the same query
When a value object is returned from a method or property, you cannot use that object until after you have executed the query. For example, the following code tries to create a SharePoint
list that has the same title as the parent website, but it throws an exception.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

Web web = context.Web;


ListCreationInformation creationInfo = new ListCreationInformation();
creationInfo.Description = web.Title;
creationInfo.Title = web.Title;
List newList = web.Lists.Add(creationInfo);

An exception is thrown because the property is not available before you execute the query. In SQL, you would declare a local variable to hold the value for web.Title and use the local
variable for web creation. In the client library, you can't create a local variable. You have to split functionality into two separate queries as is shown in the following example. You also need to
add a using statement for System.Linq. Also, add an alias to the using statement for the Microsoft.SharePoint.Client namespace so you can refer to its classes unambiguously. For
example, using SP = Microsoft.SharePoint.Client; .

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

Web web = context.Web;

context.Load(web, w => w.Title);

context.ExecuteQuery();

ListCreationInformation creationInfo = new ListCreationInformation();


creationInfo.Description = web.Description;
creationInfo.Title = web.Title;
SP.List newList = web.Lists.Add(creationInfo);

context.ExecuteQuery();

The difference is the following three lines:

context.Load(web, w => w.Title);


context.ExecuteQuery();
...
context.ExecuteQuery();

Using methods or properties that return client objects in another method call in the same query
Unlike a value object, a client object can be used in another method call in the same query.
In .NET remoting, the value object is a class or struct that is marshaled by value, while the client object is a class or struct that is marshaled by reference. For example, the ListItem is a client
object, while the UrlFieldValue and other field values are value objects.
In the client library, the corresponding server object has the [ClientCallable(ValueObject = true)] attribute. Those values could have only properties and no methods. Primitive types, such
as strings and ints, are treated as value objects. All the values are marshaled between the client and the server. The default value of the ValueObject is false.
The counterpart to the value object is the client object. If the corresponding server object has the [ClientCallable(ValueObject = false)] attribute, the object is a client object. For client
objects, we keep track of how the object is created; this is called ObjectPath in the client library implementation. For example, if we have code like the following:

ClientContext context = new ClientContext("http://SiteUrl");


Web web = context.Web;
SP.List list = web.Lists.GetByTitle("Announcements");

We know that the list is created by:


Getting the Web property from the context.
Getting the Lists property from the above result.
Invoking the GetByTitle method with the Announcements parameter from the above result.
When the SharePoint .NET Framework CSOM passes this information to the server, you can recreate the object on the server. In the client library, you can keep track of the ObjectPath that
the client object created. Because you know how the object is created, you could use the object as a parameter to invoke other methods within the same query.

Group data retrieval on the same object together to improve performance


When reading multiple pieces of data from the same object, you should try to get all of it in a single query; that is, a single call to the Load(T, []) method. The following code shows two ways
to retrieve a website's title and description and the Announcements list's description. To compile this code, you need to add a using statement for System.Linq. Also, add an alias to the
using statement for the Microsoft.SharePoint.Client namespace so you can refer to its classes unambiguously. For example, using SP = Microsoft.SharePoint.Client; .

static void Method1()


{
ClientContext context = new ClientContext("http://SiteUrl");
Web web = context.Web;
SP.List list = web.Lists.GetByTitle("Announcements");
context.Load(web, w => w.Title, w => w.Description);
context.Load(list, l => l.Description);
context.ExecuteQuery();
}

static void Method2()


{
ClientContext context = new ClientContext("http://SiteUrl");
Web web = context.Web;
SP.List list = web.Lists.GetByTitle("Announcements");
context.Load(web, w => w.Title);
context.Load(list, l => l.Description);
context.Load(web, w => w.Description);
context.ExecuteQuery();
}

These are not equally efficient. In Method1, the code to retrieve the web's title and description is grouped together. In Method2, the code to retrieve the web's title and description is
separated by other actions. This means that Method2 triggers two separated queries on the same web object, and there are two result sets for the same web. Because the client library tries
to return consistent data, the second result set includes both the title and description. You could think of the previous code as the following.

Method1:
SELECT Title, Description FROM Webs WHERE ...
SELECT Description FROM Lists WHERE …

Method2:
SELECT Title FROM Webs WHERE …
SELECT Description FROM Lists WHERE …
SELECT Title, Description FROM Webs WHERE …

Specify which properties of objects you want to return


In the SharePoint server object model, if you get an SPWeb object, you can inspect all of its properties. In SQL, to get all of the columns of a table you can run:

SELECT * FROM Webs

In the client library, neither Load nor any other method returns all properties, so you have to explicitly specify what you want. For example, the following code retrieves the website object
without specifying which properties to return. It then tries to read two properties and one of them is not among the properties that is automatically returned by Load. This code throws an
exception.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

Web web = context.Web;


context.Load(web);
context.ExecuteQuery();

Console.WriteLine(web.Title);
Console.WriteLine(web.HasUniqueRoleAssignments);

To get the code to compile successfully, update it to the following. To compile this code, you need to add a using statement for System.Linq. Also, add an alias to the using statement for the
Microsoft.SharePoint.Client namespace so you can refer to its classes unambiguously. For example, using SP = Microsoft.SharePoint.Client; .

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

Web web = context.Web;


context.Load(web);
context.Load(web, web => web.HasUniqueRoleAssignments);
context.ExecuteQuery();

Console.WriteLine(web.Title);
Console.WriteLine(web.HasUniqueRoleAssignments);

Use conditional scope to test for preconditions before loading data


To conditionally execute code, set a conditional scope by using a ConditionalScope object. For example, retrieve the list property when the list is not null. You also need to add using
statements for System.Collections.Generic and System.Linq. Also, add an alias to the using statement for the Microsoft.SharePoint.Client namespace so you can refer to its classes
unambiguously. For example, using SP = Microsoft.SharePoint.Client; .
NOTE

Calling method and setting properties within a conditional scope are not permitted, because the client library does not track the side effects of method calls and property settings. You should
use only Load inside the conditional scope.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

SP.List list = context.Web.GetCatalog(ListTemplateType.WebPartCatalog);


BasePermissions perm = new BasePermissions();
perm.Set(PermissionKind.ManageLists);

ConditionalScope scope =
new ConditionalScope(context,
() => list.ServerObjectIsNull &amp;&amp; context.Web.DoesUserHavePermissions(perm).Value);
using (scope.StartScope())
{
context.Load(list, l => l.Title);
}
context.ExecuteQuery();

label1.Text = scope.TestResult.Value;

if (scope.TestResult.Value)
{
label1.Text = list.Title;
}

Use an exception handling scope to catch exceptions


This example shows how to create and use an exception handling scope with an ExceptionHandlingScope object. The scenario is to update the description of a list and also enable folder
creation. There is a possibility that the list might not exist.

// Starting with ClientContext, the constructor requires a URL to the


// server running SharePoint.
ClientContext context = new ClientContext("http://SiteUrl");

ExceptionHandlingScope scope = new ExceptionHandlingScope(context);

using (scope.StartScope())
{
using (scope.StartTry())
{
List fooList = context.Web.Lists.GetByTitle("Sample");
fooList.Description = "In Try Block";
fooList.Update();
}
using (scope.StartCatch())
{
// Assume that if there's an exception,
// it can be only because there was no "Sample" list.
ListCreationInformation listCreateInfo = new ListCreationInformation();
listCreateInfo.Title = "Sample";
listCreateInfo.Description = "In Catch Block";
listCreateInfo.TemplateType = (int)ListTemplateType.Announcements;
List fooList = context.Web.Lists.Add(listCreateInfo);
}
using (scope.StartFinally())
{
List fooList = context.Web.Lists.GetByTitle("Sample");
fooList.EnableFolderCreation = true;
fooList.Update();
}
}

context.ExecuteQuery();

See also
Develop SharePoint Add-ins
Build sites for SharePoint
Complete basic operations using JavaScript library code in SharePoint
6/18/2018 • 21 minutes to read Edit Online

You can use the SharePoint client object model to retrieve, update, and manage data in SharePoint. SharePoint makes the object model available in several forms:
.NET Framework redistributable assemblies
JavaScript library
REST/OData endpoints
Windows Phone assemblies
Silverlight redistributable assemblies
For more information about the sets of APIs that are available for SharePoint, see Choose the right API set in SharePoint.
NOTE

For a "Hello World" level sample SharePoint Add-in that uses the JavaScript library, see Use the SharePoint JavaScript APIs to work with SharePoint data.
This article shows how to perform basic operations using the JavaScript object model. You can add a reference to the object model by using HTML <script> tags. For information about how
to use the other client APIs, see the following:
Complete basic operations using SharePoint client library code
Complete basic operations using SharePoint REST endpoints
Build Windows Phone apps that access SharePoint
Using the Silverlight Object Model in the SharePoint 2010 SDK

Perform basic tasks in SharePoint using the JavaScript client object model
The following sections describe tasks that you can complete programmatically, and they include JavaScript code examples that demonstrate the operations.
When you create a cloud-hosted add-in, you can add a reference to the object model by using HTML <script> tags. We recommend that you reference the host web because the add-in web
may not exist in every scenario in cloud-hosted add-ins. You can retrieve the host web URL from the SPHostUrl query string parameter if you are using the {StandardTokens} token. You
can also use your custom defined query string parameter if you are using the {HostUrl} token. After you have the host web URL, you must use JavaScript code to dynamically create the
reference to the object model.
The following code example performs these tasks to add a reference to the JavaScript object model:
References the AJAX library from the Microsoft Content Delivery Network (CDN).
References the jQuery library from the Microsoft CDN.
Extracts the host web URL from the query string.
Loads the SP.Runtime.js and SP.js files by using the getScript function in jQuery. After loading the files, your program has access to the JavaScript object model for SharePoint.
Continues the flow in the execOperation function.
<script
src="//ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"
type="text/javascript">
</script>
<script
type="text/javascript"
src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js">
</script>
<script type="text/javascript">
var hostweburl;

// Load the required SharePoint libraries.


$(document).ready(function () {

// Get the URI decoded URLs.


hostweburl =
decodeURIComponent(
getQueryStringParameter("SPHostUrl")
);

// The js files are in a URL in the form:


// web_url/_layouts/15/resource_file
var scriptbase = hostweburl + "/_layouts/15/";

// Load the js files and continue to


// the execOperation function.
$.getScript(scriptbase + "SP.Runtime.js",
function () {
$.getScript(scriptbase + "SP.js", execOperation);
}
);
});

// Function to execute basic operations.


function execOperation() {

// Continue your program flow here.

// Function to retrieve a query string value.


// For production purposes you may want to use
// a library to handle the query string.
function getQueryStringParameter(paramToRetrieve) {
var params =
document.URL.split("?")[1].split("&amp;");
var strParams = "";
for (var i = 0; i < params.length; i = i + 1) {
var singleParam = params[i].split("=");
if (singleParam[0] == paramToRetrieve)
return singleParam[1];
}
}
</script>

When you create a SharePoint-hosted add-in, you can add a reference to the object model by using HTML <script> tags. The add-in web in a SharePoint-hosted add-in allows you to use
relative paths to reference the required files to use the JavaScript object model.
The following markup performs these tasks to add a reference to the JavaScript object model:
References the AJAX library from the Microsoft CDN.
References the SP.Runtime.js file by using a URL relative to the add-in web.
References the SP.js file by using a URL relative to the add-in web.

<script
src="//ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"
type="text/javascript">
</script>
<script
type="text/javascript"
src="/_layouts/15/sp.runtime.js">
</script>
<script
type="text/javascript"
src="/_layouts/15/sp.js">
</script>
<script type="text/javascript">

// Continue your program flow here.

</script>

SharePoint website tasks


To work with websites using JavaScript, start by using the ClientContext(serverRelativeUrl) constructor and pass a URL or URI to return a specific request context.

Retrieve the properties of a website


Use the web property of the ClientContext class to specify the properties of the website object that is located at the specified context URL. After you load the website object through the
load(clientObject) method and then call executeQueryAsync(succeededCallback, failedCallback), you acquire access to all the properties of that website.
The following example displays the title and description of the specified website, although all other properties that are returned by default become available after you load the website object
and execute the query.
function retrieveWebSite(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
this.oWebsite = clientContext.get_web();

clientContext.load(this.oWebsite);

clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded(sender, args) {


alert('Title: ' + this.oWebsite.get_title() +
' Description: ' + this.oWebsite.get_description());
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Retrieve only selected properties of a website


To reduce unnecessary data transference between client and server, you might want to return only specified properties of the website object, not all of its properties. In this case, use LINQ
query or lambda expression syntax with the load(clientObject) method to specify which properties to return from the server. In the following example, only the title and creation date of the
website object become available after executeQueryAsync(succeededCallback, failedCallback) is called.

function retrieveWebSiteProperties(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
this.oWebsite = clientContext.get_web();

clientContext.load(this.oWebsite, 'Title', 'Created');

clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded(sender, args) {


alert('Title: ' + this.oWebsite.get_title() +
' Created: ' + this.oWebsite.get_created());
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

NOTE

If you try to access other properties, the code throws an exception because other properties are not available.

Write to a website's properties


To modify a website, you set its properties and call the update() method, similarly to how the server object model functions. However, in the client object model, you must call
executeQueryAsync(succeededCallback, failedCallback) to request batch processing of all commands that you specify. The following example changes the title and description of a
specified website.

function updateWebSite(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
this.oWebsite = clientContext.get_web();

this.oWebsite.set_title('Updated Web Site');


this.oWebsite.set_description('This is an updated website.');
this.oWebsite.update();

clientContext.load(this.oWebsite, 'Title', 'Description');

clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded(sender, args) {


alert('Title: ' + this.oWebsite.get_title() +
' Description: ' + this.oWebsite.get_description());
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

SharePoint list tasks


Working with list objects using JavaScript is similar to working with website objects. Start by using the ClientContext(serverRelativeUrl) constructor and passing a URL or URI to return a
specific request context. You can then use the lists property of the Web class to get the collection of lists in the website.
Retrieve all properties of all lists in a website
To return all the lists of a website, load the list collection through the load(clientObject) method, and then call executeQueryAsync(succeededCallback, failedCallback). The following
example displays the URL of the website and the date and time that the list was created.

function retrieveAllListProperties(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
var oWebsite = clientContext.get_web();
this.collList = oWebsite.get_lists();
clientContext.load(collList);

clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded() {
var listInfo = '';
var listEnumerator = collList.getEnumerator();

while (listEnumerator.moveNext()) {
var oList = listEnumerator.get_current();
listInfo += 'Title: ' + oList.get_title() + ' Created: ' +
oList.get_created().toString() + '\n';
}
alert(listInfo);
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Retrieve only specified properties of lists


The previous example returns all properties of the lists in a website. To reduce unnecessary data transference between client and server, you can use LINQ query expressions to specify which
properties to return. In JavaScript, you specify Include as part of the query string that is passed to the load(clientObject) method to specify which properties to return. The following
example uses this approach to return only the title and ID of each list in the collection.

function retrieveSpecificListProperties(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
var oWebsite = clientContext.get_web();
this.collList = oWebsite.get_lists();

clientContext.load(collList, 'Include(Title, Id)');


clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded() {
var listInfo = '';
var listEnumerator = collList.getEnumerator();

while (listEnumerator.moveNext()) {
var oList = listEnumerator.get_current();
listInfo += 'Title: ' + oList.get_title() +
' ID: ' + oList.get_id().toString() + '\n';
}
alert(listInfo);
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Store retrieved lists in a collection


As the following example shows, you can use the loadQuery(clientObjectCollection, exp) method instead of the load(clientObject) method to store the return value in another
collection instead of storing it in the lists property.
function retrieveSpecificListPropertiesToCollection(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
var oWebsite = clientContext.get_web();
var collList = oWebsite.get_lists();

this.listInfoCollection = clientContext.loadQuery(collList, 'Include(Title, Id)');


clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded() {
var listInfo = '';

for (var i = 0; i < this.listInfoCollection.length; i++) {


var oList = this.listInfoCollection[i];
listInfo += 'Title: ' + oList.get_title() +
' ID: ' + oList.get_id().toString();
}
alert(listInfo.toString());
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Apply filters to list retrieval


As the following example shows, you can nest Include statements in a JavaScript query to return metadata for both a list and its fields. The example returns all fields from all lists within a
website and displays the title and internal name of all fields whose internal name contains the string "name".

function retrieveAllListsAllFields(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
var oWebsite = clientContext.get_web();
var collList = oWebsite.get_lists();

this.listInfoArray = clientContext.loadQuery(collList,
'Include(Title,Fields.Include(Title,InternalName))');

clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this._onQueryFailed)
);
}

function onQuerySucceeded() {
var listInfo = '';

for (var i = 0; i < this.listInfoArray.length; i++) {


var oList = this.listInfoArray[i];
var collField = oList.get_fields();
var fieldEnumerator = collField.getEnumerator();

while (fieldEnumerator.moveNext()) {
var oField = fieldEnumerator.get_current();
var regEx = new RegExp('name', 'ig');

if (regEx.test(oField.get_internalName())) {
listInfo += '\nList: ' + oList.get_title() +
'\n\tField Title: ' + oField.get_title() +
'\n\tField Name: ' + oField.get_internalName();
}
}
}
alert(listInfo);
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Create, update, and delete lists


Creating, updating, and deleting lists through the client object model works similarly to how you perform these tasks using the .NET client object model, although client operations do not
complete until you call the executeQueryAsync(succeededCallback, failedCallback) function.

Create and update a list


To create a list object using JavaScript, use the ListCreationInformation object to define its properties, and then pass this object to the add(parameters) function of the ListCollection
object. The following example creates a new announcements list.
function createList(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
var oWebsite = clientContext.get_web();

var listCreationInfo = new SP.ListCreationInformation();


listCreationInfo.set_title('My Announcements List');
listCreationInfo.set_templateType(SP.ListTemplateType.announcements);

this.oList = oWebsite.get_lists().add(listCreationInfo);

clientContext.load(oList);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded() {
var result = oList.get_title() + ' created.';
alert(result);
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

If you need to update the list after it has been created, you can set list properties and call the update() function before calling executeQueryAsync(succeededCallback, failedCallback)
as shown in the following modifications of the previous example.

.
.
.
.
this.oList = oWebsite.get_lists().add(listCreationInfo);

oList.set_description('New Announcements List');


oList.update();

clientContext.load(oList);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);

Add a field to a list


Use the add(field) or addFieldAsXml(schemaXml, addToDefaultView, options) function of the FieldCollection object to add a field to the field collection of a list. The following
example creates a field and then updates it before calling executeQueryAsync(succeededCallback, failedCallback).

function addFieldToList(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);

var oList = clientContext.get_web().get_lists().getByTitle('Announcements');


this.oField = oList.get_fields().addFieldAsXml(
'<Field DisplayName=\'MyField\' Type=\'Number\' />',
true,
SP.AddFieldOptions.defaultValue
);

var fieldNumber = clientContext.castTo(oField,SP.FieldNumber);


fieldNumber.set_maximumValue(100);
fieldNumber.set_minimumValue(35);
fieldNumber.update();

clientContext.load(oField);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded() {
var result = oField.get_title() + ' added.';
alert(result);
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Delete a list
To delete a list, call the deleteObject() function of the list object, as shown in the following example.
function deleteList(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
var oWebsite = clientContext.get_web();
this.listTitle = 'My Announcements List';

this.oList = oWebsite.get_lists().getByTitle(listTitle);
oList.deleteObject();

clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded() {
var result = listTitle + ' deleted.';
alert(result);
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Create, update, and delete folders


You can manipulate folders to organize your content by using the JavaScript object model. The following sections show you how to perform basic operations on folders.

Create a folder in a document library


To create a folder, you use a ListItemCreationInformation object, set the underlying object type to SP.FileSystemObjectType.folder, and pass it as a parameter to the
addItem(parameters) function of the List object. Set properties on the list item object that this method returns, and then call the update() function, as shown in the following example.

function createFolder(resultpanel) {
var clientContext;
var oWebsite;
var oList;
var itemCreateInfo;

clientContext = new SP.ClientContext.get_current();


oWebsite = clientContext.get_web();
oList = oWebsite.get_lists().getByTitle("Shared Documents");

itemCreateInfo = new SP.ListItemCreationInformation();


itemCreateInfo.set_underlyingObjectType(SP.FileSystemObjectType.folder);
itemCreateInfo.set_leafName("My new folder!");
this.oListItem = oList.addItem(itemCreateInfo);
this.oListItem.set_item("Title", "My new folder!");
this.oListItem.update();

clientContext.load(this.oListItem);
clientContext.executeQueryAsync(
Function.createDelegate(this, successHandler),
Function.createDelegate(this, errorHandler)
);

function successHandler() {
resultpanel.innerHTML = "Go to the " +
"<a href='../Lists/Shared Documents'>document library</a> " +
"to see your new folder.";
}

function errorHandler() {
resultpanel.innerHTML =
"Request failed: " + arguments[1].get_message();
}
}

Update a folder in a document library


To update the folder name, you can write to the FileLeafRef property and call the update() function so that changes take effect when you call the executeQueryAsync method.
function updateFolder(resultpanel) {
var clientContext;
var oWebsite;
var oList;

clientContext = new SP.ClientContext.get_current();


oWebsite = clientContext.get_web();
oList = oWebsite.get_lists().getByTitle("Shared Documents");

this.oListItem = oList.getItemById(1);
this.oListItem.set_item("FileLeafRef", "My updated folder");
this.oListItem.update();

clientContext.load(this.oListItem);
clientContext.executeQueryAsync(
Function.createDelegate(this, successHandler),
Function.createDelegate(this, errorHandler)
);

function successHandler() {
resultpanel.innerHTML = "Go to the " +
"<a href='../Lists/Shared Documents'>document library</a> " +
"to see your updated folder.";
}

function errorHandler() {
resultpanel.innerHTML = "Request failed: " + arguments[1].get_message();
}
}

Delete a folder in a document library


To delete a folder, call the deleteObject() function on the object. The following example uses the getFolderByServerRelativeUrl method to retrieve the folder from the document library
and then deletes the item.

function deleteFolder(resultpanel) {
var clientContext;
var oWebsite;
var folderUrl;

clientContext = new SP.ClientContext.get_current();


oWebsite = clientContext.get_web();

clientContext.load(oWebsite);
clientContext.executeQueryAsync(function () {
folderUrl = oWebsite.get_serverRelativeUrl() + "/Lists/Shared Documents/Folder1";
this.folderToDelete = oWebsite.getFolderByServerRelativeUrl(folderUrl);
this.folderToDelete.deleteObject();

clientContext.executeQueryAsync(
Function.createDelegate(this, successHandler),
Function.createDelegate(this, errorHandler)
);
}, errorHandler);

function successHandler() {
resultpanel.innerHTML = "Go to the " +
"<a href='../Lists/Shared Documents'>document library</a> " +
"to make sure the folder is no longer there.";
}

function errorHandler() {
resultpanel.innerHTML = "Request failed: " + arguments[1].get_message();
}
}

Create, read, update, and delete files


You can manipulate files by using the JavaScript object model. The following sections show you how to perform basic operations on files.
NOTE

You can only work with files up to 1.5 MB by using the JavaScript object model. To upload larger files, use REST (Representational State Transfer). For more information, see Complete basic
operations using SharePoint REST endpoints.

Create a file in a document library


To create files, you use a FileCreationInformation object, set the URL attribute, and append content as a base64 encoded array of bytes, as shown in this example.
function createFile(resultpanel) {
var clientContext;
var oWebsite;
var oList;
var fileCreateInfo;
var fileContent;

clientContext = new SP.ClientContext.get_current();


oWebsite = clientContext.get_web();
oList = oWebsite.get_lists().getByTitle("Shared Documents");

fileCreateInfo = new SP.FileCreationInformation();


fileCreateInfo.set_url("my new file.txt");
fileCreateInfo.set_content(new SP.Base64EncodedByteArray());
fileContent = "The content of my new file";

for (var i = 0; i < fileContent.length; i++) {

fileCreateInfo.get_content().append(fileContent.charCodeAt(i));
}

this.newFile = oList.get_rootFolder().get_files().add(fileCreateInfo);

clientContext.load(this.newFile);
clientContext.executeQueryAsync(
Function.createDelegate(this, successHandler),
Function.createDelegate(this, errorHandler)
);

function successHandler() {
resultpanel.innerHTML =
"Go to the " +
"<a href='../Lists/Shared Documents'>document library</a> " +
"to see your new file.";
}

function errorHandler() {
resultpanel.innerHTML = "Request failed: " + arguments[1].get_message();
}
}

Read a file in a document library


To read a file's content, you perform a GET operation on the file's URL, as shown in the following example.

function readFile(resultpanel) {
var clientContext;
var oWebsite;
var fileUrl;

clientContext = new SP.ClientContext.get_current();


oWebsite = clientContext.get_web();

clientContext.load(oWebsite);
clientContext.executeQueryAsync(function () {
fileUrl = oWebsite.get_serverRelativeUrl() +
"/Lists/Shared Documents/TextFile1.txt";
$.ajax({
url: fileUrl,
type: "GET"
})
.done(Function.createDelegate(this, successHandler))
.error(Function.createDelegate(this, errorHandler));
}, errorHandler);

function successHandler(data) {
resultpanel.innerHTML =
"The content of file \"TextFile1.txt\": " + data
}

function errorHandler() {
resultpanel.innerHTML =
"Request failed: " + arguments[2];
}
}

Update a file in a document library


To update the file's content, you can use a FileCreationInformation object, and set the overwrite attribute to true by using the set_overwrite() method, as shown in this example.
function updateFile(resultpanel) {
var clientContext;
var oWebsite;
var oList;
var fileCreateInfo;
var fileContent;

clientContext = new SP.ClientContext.get_current();


oWebsite = clientContext.get_web();
oList = oWebsite.get_lists().getByTitle("Shared Documents");

fileCreateInfo = new SP.FileCreationInformation();


fileCreateInfo.set_url("TextFile1.txt");
fileCreateInfo.set_content(new SP.Base64EncodedByteArray());
fileCreateInfo.set_overwrite(true);
fileContent = "The updated content of my file";

for (var i = 0; i < fileContent.length; i++) {

fileCreateInfo.get_content().append(fileContent.charCodeAt(i));
}

this.existingFile = oList.get_rootFolder().get_files().add(fileCreateInfo);

clientContext.load(this.existingFile);
clientContext.executeQueryAsync(
Function.createDelegate(this, successHandler),
Function.createDelegate(this, errorHandler)
);

function successHandler() {
resultpanel.innerHTML =
"Go to the " +
"<a href='../Lists/Shared Documents'>document library</a> " +
"to see the updated \"TextFile1.txt\" file.";
}

function errorHandler() {
resultpanel.innerHTML =
"Request failed: " + arguments[1].get_message();
}
}

Delete a file in a document library


To delete a file, call the deleteObject() function on the object. The following example uses the getFileByServerRelativeUrl method to retrieve the file from the document library, and then
deletes the item.

function deleteFile(resultpanel) {
var clientContext;
var oWebsite;
var fileUrl;

clientContext = new SP.ClientContext.get_current();


oWebsite = clientContext.get_web();

clientContext.load(oWebsite);
clientContext.executeQueryAsync(function () {
fileUrl = oWebsite.get_serverRelativeUrl() +
"/Lists/Shared Documents/TextFile1.txt";
this.fileToDelete = oWebsite.getFileByServerRelativeUrl(fileUrl);
this.fileToDelete.deleteObject();

clientContext.executeQueryAsync(
Function.createDelegate(this, successHandler),
Function.createDelegate(this, errorHandler)
);
}, errorHandler);

function successHandler() {
resultpanel.innerHTML =
"Go to the " +
"<a href='../Lists/Shared Documents'>document library</a> " +
"to confirm that the \"TextFile1.txt\" file has been deleted.";
}

function errorHandler() {
resultpanel.innerHTML = "Request failed: " + arguments[1].get_message();
}
}

SharePoint list item tasks


To return items from a list by using JavaScript, use the getItemById(id) function to return a single item, or use the getItems(query) function to return multiple items. You then use the
load(clientObject) function to attain list item objects that represent the items.

Retrieve items from a list


The getItems(query) function enables you to define a Collaborative Application Markup Language (CAML) query that specifies which items to return. You can pass an undefined
CamlQuery object to return all items from the list, or use the set_viewXml function to define a CAML query and return items that meet specific criteria. The following example displays the
ID, in addition to the Title and Body column values, of the first 100 items in the Announcements list, starting with list items whose collection ID is greater than 10.
function retrieveListItems(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
var oList = clientContext.get_web().get_lists().getByTitle('Announcements');

var camlQuery = new SP.CamlQuery();


camlQuery.set_viewXml(
'<View><Query><Where><Geq><FieldRef Name=\'ID\'/>' +
'<Value Type=\'Number\'>1</Value></Geq></Where></Query>' +
'<RowLimit>10</RowLimit></View>'
);
this.collListItem = oList.getItems(camlQuery);

clientContext.load(collListItem);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded(sender, args) {


var listItemInfo = '';
var listItemEnumerator = collListItem.getEnumerator();

while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
listItemInfo += '\nID: ' + oListItem.get_id() +
'\nTitle: ' + oListItem.get_item('Title') +
'\nBody: ' + oListItem.get_item('Body');
}

alert(listItemInfo.toString());
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Use the Include method to access properties of ListItem objects


Four properties of ListItem objects are not available by default when you return the list items displayName, effectiveBasePermissions, hasUniqueRoleAssignments, and
roleAssignments. The previous example returns a PropertyOrFieldNotInitializedException if you try to access one of these properties. To access these properties, use the Include
method as part of the query string, as shown in the following example.
NOTE

When you use LINQ to create queries against the client object model, you are using LINQ to Objects, not the LINQ to SharePoint provider, which can only be used when you write code
against the server object model.

function retrieveListItemsInclude(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
var oList = clientContext.get_web().get_lists().getByTitle('Announcements');

var camlQuery = new SP.CamlQuery();


camlQuery.set_viewXml('<View><RowLimit>100</RowLimit></View>');
this.collListItem = oList.getItems(camlQuery);

clientContext.load(
collListItem,
'Include(Id, DisplayName, HasUniqueRoleAssignments)'
);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded(sender, args) {


var listItemInfo = '';
var listItemEnumerator = collListItem.getEnumerator();

while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
listItemInfo += '\nID: ' + oListItem.get_id() +
'\nDisplay name: ' + oListItem.get_displayName() +
'\nUnique role assignments: ' +
oListItem.get_hasUniqueRoleAssignments();
}

alert(listItemInfo.toString());
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Because this example uses an Include, only the specified properties are available after query execution. Therefore, you receive a PropertyOrFieldNotInitializedException if you try to
access other properties beyond those that have been specified. In addition, you receive this error if you try to use functions such as get_contentType or get_parentList to access the
properties of containing objects.

Restrictions on retrieving items


The loadQuery(clientObjectCollection, exp) method of the JavaScript object model in SharePoint Foundation 2010 does not support LINQ methods and operators that are used by the
managed object model.
Create, update, and delete list items
Creating, updating, or deleting list items through the client object model works similarly to performing these tasks through the server object model. You create a list item object, set its
properties, and then update the object. To modify or delete a list item object, use the getById(id) function of the ListItemCollection object to return the object, and then either set
properties and call update on the object that this method returns, or call the object's own method for deletion. Unlike the server object model, each of these operations in the client object
model must conclude with a call to executeQueryAsync(succeededCallback, failedCallback) for changes to take effect on the server.

Create a list item


To create list items, you create a ListItemCreationInformation object, set its properties, and pass it as a parameter to the addItem(parameters) function of the List object. Set properties
on the list item object that this method returns, and then call the update() function, as shown in the following example.

function createListItem(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
var oList = clientContext.get_web().get_lists().getByTitle('Announcements');

var itemCreateInfo = new SP.ListItemCreationInformation();


this.oListItem = oList.addItem(itemCreateInfo);
oListItem.set_item('Title', 'My New Item!');
oListItem.set_item('Body', 'Hello World!');
oListItem.update();

clientContext.load(oListItem);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded() {
alert('Item created: ' + oListItem.get_id());
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Update a list item


To set most list item properties, you can use a column indexer to make an assignment, and call the update() function so that changes take effect when you call
executeQueryAsync(succeededCallback, failedCallback). The following example sets the title of the third item in the Announcements list.

function updateListItem(siteUrl) {
var clientContext = new SP.ClientContext(siteUrl);
var oList = clientContext.get_web().get_lists().getByTitle('Announcements');

this.oListItem = oList.getItemById(3);
oListItem.set_item('Title', 'My Updated Title');
oListItem.update();

clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded() {
alert('Item updated!');
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Delete a list item


To delete a list item, call the deleteObject() function on the object. The following example uses the getItemById(id) function to return the second item from the list, and then deletes the
item. SharePoint maintains the integer IDs of items within collections, even if they have been deleted. So, for example, the second item in a list might not have 2 as its identifier. A
ServerException is returned if the deleteObject() function is called for an item that does not exist.
function deleteListItem(siteUrl) {
this.itemId = 2;
var clientContext = new SP.ClientContext(siteUrl);
var oList = clientContext.get_web().get_lists().getByTitle('Announcements');
this.oListItem = oList.getItemById(itemId);
oListItem.deleteObject();

clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}

function onQuerySucceeded() {
alert('Item deleted: ' + itemId);
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

If you want to retrieve, for example, the new item count that results from a delete operation, include a call to the update() method to refresh the list. In addition, you must load either the list
object itself or the itemCount property on the list object before executing the query. If you want to retrieve both a start and end count of the list items, you must execute two queries and
return the item count twice, as shown in the following modification of the previous example.

function deleteListItemDisplayCount(siteUrl) {
this.clientContext = new SP.ClientContext(siteUrl);
this.oList = clientContext.get_web().get_lists().getByTitle('Announcements');
clientContext.load(oList);

clientContext.executeQueryAsync(
Function.createDelegate(this, this.deleteItem),
Function.createDelegate(this, this.onQueryFailed)
);
}

function deleteItem() {
this.itemId = 58;
this.startCount = oList.get_itemCount();
this.oListItem = oList.getItemById(itemId);
oListItem.deleteObject();

oList.update();
clientContext.load(oList);

clientContext.executeQueryAsync(
Function.createDelegate(this, this.displayCount),
Function.createDelegate(this, this.onQueryFailed)
);
}

function displayCount() {
var endCount = oList.get_itemCount();
var listItemInfo = 'Item deleted: ' + itemId +
'\nStart Count: ' + startCount +
' End Count: ' + endCount;

alert(listItemInfo)
}

function onQueryFailed(sender, args) {


alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}

Access objects in the host web


While developing your add-in, you might need to access the host web to interact with items in it. Use the AppContextSite object to reference the host web or other SharePoint sites, as
shown in the following example. For a full code sample, see Get the host web title using the cross-domain library (JSOM).
function execCrossDomainRequest(appweburl, hostweburl) {
// context: The ClientContext object provides access to
// the web and lists objects.
// factory: Initialize the factory object with the
// add-in web URL.
var context;
var factory;
var appContextSite;

context = new SP.ClientContext(appweburl);


factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
context.set_webRequestExecutorFactory(factory);
appContextSite = new SP.AppContextSite(context, hostweburl);

this.web = appContextSite.get_web();
context.load(this.web);

// Execute the query with all the previous


// options and parameters.
context.executeQueryAsync(
Function.createDelegate(this, successHandler),
Function.createDelegate(this, errorHandler)
);

// Function to handle the success event.


// Prints the host web's title to the page.
function successHandler() {
alert(this.web.get_title());
}

// Function to handle the error event.


// Prints the error message to the page.
function errorHandler(data, errorCode, errorMessage) {
alert("Could not complete cross-domain call: " + errorMessage);
}
}

The previous example uses the cross-domain library in SharePoint to access the host web. For more information, see Access SharePoint data from add-ins using the cross-domain library.

See also
Develop SharePoint Add-ins
Secure data access and client object models for SharePoint Add-ins
Work with external data in SharePoint
Get to know the SharePoint REST service
4/20/2018 • 7 minutes to read Edit Online

SharePoint introduces a Representational State Transfer (REST) service that is comparable to the existing SharePoint client object models. Now, developers can interact remotely with
SharePoint data by using any technology that supports REST web requests. This means that developers can perform Create, Read, Update, and Delete (CRUD) operations from their
SharePoint Add-ins, solutions, and client applications, using REST web technologies and standard Open Data Protocol (OData) syntax.

Prerequisites
This topic assumes you have a basic familiarity with REST and how to construct REST requests.

How the SharePoint REST service works


SharePoint adds the ability for you to remotely interact with SharePoint sites by using REST. Now you can interact directly with SharePoint objects by using any technology that supports
standard REST capabilities.
To access SharePoint resources using REST, construct a RESTful HTTP request by using the OData standard, which corresponds to the desired client object model API. For example:
Client object model method:
List.GetByTitle(listname)

REST endpoint:
http://server/site/_api/lists/getbytitle('listname')

The client.svc web service in SharePoint handles the HTTP request, and serves the appropriate response in either Atom or JavaScript Object Notation (JSON) format. Your client application
must then parse that response. The following figure shows a high-level view of the SharePoint REST architecture.
SharePoint REST service architecture

Because of the functionality and ease of use that client object models provide, they remain the primary development option for communicating with SharePoint sites by using .NET
Framework managed code, Silverlight, or JavaScript.

Use HTTP commands with the SharePoint REST service


To use the REST capabilities that are built into SharePoint, you construct a RESTful HTTP request by using the OData standard, which corresponds to the client object model API you want to
use. The client.svc web service handles the HTTP request and serves the appropriate response in either Atom or JSON format. The client application must then parse that response.
The endpoints in the SharePoint REST service correspond to the types and members in the SharePoint client object models. By using HTTP requests, you can use these REST endpoints to
perform typical CRUD operations against SharePoint entities, such as lists and sites.

IF YO U W ANT TO D O THIS TO AN END PO INT U S E THIS HT TP R EQ U ES T K EEP IN MIND

Read a resource GET

Create or update a resource POST - Use POST to create entities such as lists and sites.
- The SharePoint REST service supports sending POST commands
that include object definitions to endpoints that represent
collections.
- For POST operations, any properties that are not required are set
to their default values.
- If you attempt to set a read-only property as part of a POST
operation, the service returns an exception.

Update or insert a resource PUT - Use PUT and MERGE operations to update existing SharePoint
objects.
- Any service endpoint that represents an object property set
operation supports both PUT requests and MERGE requests.
- For MERGE requests, setting properties is optional; any properties
that you do not explicitly set retain their current property.
- For PUT requests, if you do not specify all required properties in
object updates, the REST service returns an exception.
- In addition, any optional properties you do not explicitly set are
set to their default properties.

Delete a resource DELETE - Use the HTTP DELETE command against the specific endpoint URL
to delete the SharePoint object represented by that endpoint.
- In the case of recyclable objects, such as lists, files, and list items,
this results in a Recycle operation.

Construct REST URLs to access SharePoint resources


Whenever possible, the URI for these REST endpoints closely mimics the API signature of the resource in the SharePoint client object model. The main entry points for the REST service
represent the site collection and site of the specified context.
To access a specific site collection, use the following construction:
http://server/site/_api/site

To access a specific site, use the following construction:


http://server/site/_api/web

In each case, server represents the name of the server, and site represents the name of, or path to, the specific site.
From this starting point, you can then construct more specific REST URIs by "walking" the object model, using the names of the APIs from the client object model separated by a forward
slash (/).
This syntax doesn't apply to the SocialFeedManager or SocialFollowingManager REST APIs. For more information, see:
Social feed REST API reference for SharePoint
Following people and content REST API reference for SharePoint
For more guidelines for determining SharePoint REST endpoint URIs from the signature of the corresponding client object model APIs, see Determine SharePoint REST service endpoint
URIs.

SharePoint REST endpoint examples


The following table contains typical REST endpoint URL examples to get you started working with SharePoint data. Prepend http://server/site/_api/ to the URL fragments shown in the
table to construct a fully qualified REST URL. Where necessary for POST commands, the table contains sample data you must pass in the HTTP request body to create the specified
SharePoint item. Items in quotes represent variables that you must replace with your values.

D ES CR IPTIO N U R L END PO INT HT TP ME THO D B O D Y CO NTENT

Retrieves the title of a list web/title GET Not applicable

Retrieves all lists on a site lists GET Not applicable

Retrieves a single list's metadata lists/getbytitle('listname') GET Not applicable

Retrieves items within a list lists/getbytitle('listname')/items GET Not applicable

Retrieves a specific property of a document lists/getbytitle('listname')?select=Title GET Not applicable


(in this case, the document title)

Creates a list lists POST See sample

Adds an item to a list lists/getbytitle('listname')/items POST See sample

Creates a list sample data

{
'__metadata':{'type':SP.List},
'AllowContentTypes': true,
'BaseTemplate': 104 ,
'ContentTypesEnabled': true,
'Description': 'My list description ',
'Title': 'RestTest '
}

Adds an item to a list sample data

{
'__metadata':{'type': SP.Data.'listname'.ListItem},
'Title': 'MyItem'
}

Batch job support


The SharePoint Online (and on-premises SharePoint 2016 or later) REST service supports combining multiple requests into a single call to the service by using the OData $batch query
option. For details and links to code samples, see Make batch requests with the REST APIs.

OData resources
Developing Service-Oriented Applications with WCF
Open Data Protocol
OData Protocol URI Conventions
Addressing Service Operations
OData Protocol Operations
Error Conditions

SharePoint REST service topics


To learn more about using the SharePoint REST service, use the following resources.

TITLE D ES CR IPTIO N

Complete basic operations using SharePoint REST endpoints Perform basic create, read, update, and delete (CRUD) operations with the SharePoint REST interface.
TITLE D ES CR IPTIO N

Working with lists and list items with REST Perform basic CRUD operations on lists and list items with the SharePoint REST interface.

Working with folders and files with REST Perform basic CRUD operations on folders and files with the SharePoint REST interface.

Navigate the SharePoint data structure represented in the REST service Start from a REST endpoint for a given SharePoint item, and navigate to and access related items, such
as parent sites or the library structure where that item resides.

Determine SharePoint REST service endpoint URIs General guidelines for determining SharePoint REST endpoint URIs from the signature of the
corresponding client object model APIs.

Use OData query operations in SharePoint REST requests Use a wide range of OData query string operators to select, filter, and order the data you request from
the SharePoint REST service.

Make batch requests with the REST APIs Combine multiple requests into a single call to the REST service.

Synchronize SharePoint items using the REST service Synchronize items between SharePoint and your add-ins or services by using the
GetListItemChangesSinceToken resource, part of the SharePoint REST service.

Upload a file by using the REST API and jQuery The code examples in this article use the REST interface and jQuery AJAX requests to add a local file to
the Documents library, and then change properties of the list item that represents the uploaded file.

Set custom permissions on a list by using the REST interface SharePoint sites, lists, and list items are types of SecurableObject, which inherits the permissions of its
parent. To set custom permissions for an object, you need to break its inheritance so that it stops
inheriting permissions from its parent, and then define new permissions by adding or removing role
assignments.

SharePoint workflow fundamentals Add search functionality to client and mobile applications using the Search REST service in SharePoint
Server 2013 and any technology that supports REST web requests.

Social feed REST API reference for SharePoint SharePoint REST endpoints for feed-related tasks.

Following people and content REST API reference for SharePoint SharePoint REST endpoints for following people and content.

Develop SharePoint Add-ins Find in-depth articles and resources to help you build advanced capabilities into your SharePoint Add-
ins.

REST API reference and samples Comprehensive API reference for working with Microsoft tools, services, and technologies. Whether
you're building apps, developing websites, or working with the cloud, you'll find detailed syntax, code
snippets, and best practices.
Complete basic operations using SharePoint REST endpoints
5/3/2018 • 15 minutes to read Edit Online

You can perform basic create, read, update, and delete (CRUD) operations by using the Representational State Transfer (REST) interface provided by SharePoint. The REST interface exposes
all the SharePoint entities and operations that are available in the other SharePoint client APIs. One advantage of using REST is that you don't have to add references to any SharePoint
libraries or client assemblies. Instead, you make HTTP requests to the appropriate endpoints to retrieve or update SharePoint entities, such as webs, lists, and list items.
For an introduction to the SharePoint REST interface and its architecture, see Get to know the SharePoint REST service.
For information about how to work with core SharePoint entities, see Working with lists and list items with REST and Working with folders and files with REST.
For a sample that shows you how to do many of these operations in the context of an ASP.NET web application written in C#, see SharePoint-Add-in-REST-OData-BasicDataOperations.
For information about the sets of APIs available on the SharePoint platform, see Choose the right API set in SharePoint.
For information about how to use the other client APIs, see:
Complete basic operations using JavaScript library code in SharePoint- Complete basic operations using SharePoint client library code
Build Windows Phone apps that access SharePoint

HTTP operations in SharePoint REST services


The endpoints in the SharePoint REST service correspond to the types and members in the SharePoint client object models. By using HTTP requests, you can use these REST endpoints to
perform typical CRUD (Create, Read, Update, and Delete) operations against SharePoint entities, such as lists and sites.
Typically, endpoints that represent Read operations map to HTTP GET commands, endpoints that represent update operations map to HTTP POST commands, and endpoints that represent
update or insert operations map to HTTP PUT commands.
In SharePoint, use POST to create entities such as lists and sites. The SharePoint REST service supports sending POST commands that include object definitions to endpoints that represent
collections. For example, you could send a POST command that included a new list object definition in ATOM to the following URL, to create a SharePoint list:
http://<site url>/_api/web/lists

For POST operations, any properties that are not required are set to their default values. If you attempt to set a read-only property as part of a POST operation, the service returns an
exception.
Use PUT and MERGE operations to update existing SharePoint objects. Any service endpoint that represents an object property set operation supports both PUT requests and MERGE
requests. For MERGE requests, setting properties is optional; any properties that you do not explicitly set retain their current property. For PUT commands, however, any properties you do
not explicitly set are set to their default properties. In addition, if you do not specify all required properties in object updates when using HTTP PUT commands, the REST service returns an
exception.
Use the HTTP DELETE command against the specific endpoint URL to delete the SharePoint object represented by that endpoint. In the case of recyclable objects, such as lists, files, and list
items, this results in a Recycle operation.

Reading data with the SharePoint REST interface


To use the REST capabilities that are built into SharePoint, you construct a RESTful HTTP request, using the OData standard, which corresponds to the client object model API you want to
use. Each SharePoint entity is exposed at an endpoint on the SharePoint site that you are targeting, and its metadata is represented in either XML or JSON format. You can make the HTTP
requests in any language, including but not limited to JavaScript and C#.
To read information from a REST endpoint, you must know both the URL of the endpoint and the OData representation of the SharePoint entity that is exposed at that endpoint. For
example, to retrieve all the lists in a specific SharePoint site, you would make a GET request to http://<site url>/_api/web/lists . You can navigate to this URL in your browser and see the
XML that gets returned. When you make the request in code, you can specify whether to receive the OData representation of the lists in XML or JSON.
The following C# code demonstrates how to make this GET request that returns a JSON representation of all of a site's lists by using JQuery. It also assumes that you have a valid OAuth
access token that is stored in the accessToken variable. You do not need the access token if you make this call from inside an add-in web, as you would in a SharePoint-hosted add-in. Note
that you cannot obtain an access token from code that is running on a browser client. You must obtain the access token from code that is running on a server.
For more information about how you can obtain an access token, see Context Token OAuth flow for SharePoint Add-ins and Authorization Code OAuth flow for SharePoint Add-ins.

HttpWebRequest endpointRequest =
(HttpWebRequest)HttpWebRequest.Create(
"http://<site url>/_api/web/lists");
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";
endpointRequest.Headers.Add("Authorization",
"Bearer " + accessToken);
HttpWebResponse endpointResponse =
(HttpWebResponse)endpointRequest.GetResponse();

This request would look a little different if you are writing your add-in in JavaScript while using the SharePoint cross-domain library. In this case, you don't need to provide an access token.
The following code demonstrates how this request would look if you are using the cross-domain library and want to receive the OData representation of the lists as XML instead of JSON.
(Because Atom is the default response format, you don't have to include an Accept header.) For more information about using the cross-domain library, see Access SharePoint data from
add-ins using the cross-domain library.
var executor = new SP.RequestExecutor(appweburl);
executor.executeAsync(
{
url:
appweburl +
"/_api/SP.AppContextSite(@target)/web/lists?@target='" +
hostweburl + "'",
method: "GET",
success: successHandler,
error: errorHandler
}
);

The code in the following example shows you how to request a JSON representation of all of the lists in a site by using C#. It assumes that you have an OAuth access token that you are
storing in the accessToken variable.

HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(sharepointUrl.ToString() + "/_api/web/lists");


endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";
endpointRequest.Headers.Add("Authorization", "Bearer " + accessToken);
HttpWebResponse endpointResponse = (HttpWebResponse)endpointRequest.GetResponse();

Getting properties that aren't returned with the resource


Many property values are returned when you retrieve a resource, but for some properties, you have to send a GET request directly to the property endpoint. This is typical of properties that
represent SharePoint entities.
The following example shows how to get a property by appending the property name to the resource endpoint. The example gets the value of the Author property from a File resource.
http://<site url>/_api/web/getfilebyserverrelativeurl('/<folder name>/<file name>')/author

To get the results in JSON format, include an Accept header set to "application/json;odata=verbose" .

Writing data by using the REST interface


You can create and update SharePoint entities by constructing RESTful HTTP requests to the appropriate endpoints, just as you do when you're reading data. One key difference, however, is
that you use a POST request. When you're updating entities, you also pass a PUT or MERGE HTTP request method by adding one of those terms to the headers of your request as the value
of the X-HTTP-Method key. The MERGE method updates only the properties of the entity that you specify, while the PUT method replaces the existing entity with a new one that you
supply in the body of the POST. Use the DELETE method to delete the entity. When you create or update an entity, you must provide an OData representation of the entity that you want to
create or change in the body of your HTTP request.
Another important consideration when creating, updating, and deleting SharePoint entities is that if you aren't using OAuth to authorize your requests, these operations require the server's
request form digest value as the value of the X-RequestDigest header. You can retrieve this value by making a POST request with an empty body to http://<site url>/_api/contextinfo
and extracting the value of the d:FormDigestValue node in the XML that the contextinfo endpoint returns. The following example shows an HTTP request to the contextinfo endpoint in
C#.

HttpWebRequest endpointRequest =
(HttpWebRequest)HttpWebRequest.Create(
"http://<site url>/_api/contextinfo");
endpointRequest.Method = "POST";
endpointRequest.Accept = "application/json;odata=verbose";
HttpWebResponse endpointResponse =
(HttpWebResponse)endpointRequest.GetResponse();

If you're using the authentication and authorization flow described in Authorization and authentication of SharePoint Add-ins, you don't need to include the request digest in your requests.
If you're using the JavaScript cross-domain library, SP.RequestExecutor handles getting and sending the form digest value for you.
If you're creating a SharePoint-hosted SharePoint Add-in, you don't have to make a separate HTTP request to retrieve the form digest value. Instead, you can retrieve the value in JavaScript
code from the SharePoint page (if the page uses the default master page), as shown in the following example, which uses JQuery and creates a list.

jQuery.ajax({
url: "http://<site url>/_api/web/lists",
type: "POST",
data: JSON.stringify({ '__metadata': { 'type': 'SP.List' }, 'AllowContentTypes': true,
'BaseTemplate': 100, 'ContentTypesEnabled': true, 'Description': 'My list description', 'Title': 'Test' }
),
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
"content-length": <length of post body>,
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: doSuccess,
error: doError
});

The following example shows how to update the list that is created in the previous example. The example changes the title of the list, uses JQuery, and assumes that you are doing this
operation in a SharePoint-hosted add-in.
jQuery.ajax({
url: "http://<site url>/_api/web/lists/GetByTitle('Test')",
type: "POST",
data: JSON.stringify({ '__metadata': { 'type': 'SP.List' }, 'Title': 'New title' }),
headers: {
"X-HTTP-Method":"MERGE",
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
"content-length": <length of post body>,
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"IF-MATCH": "*"
},
success: doSuccess,
error: doError
});

The value of the IF-MATCH key in the request headers is where you specify the etag value of a list or list item. This particular value applies only to lists and list items, and is intended to help
you avoid concurrency problems when you update those entities. The previous example uses an asterisk () for this value, and you can use that value whenever you don't have any reason to
worry about concurrency issues. Otherwise, you should obtain the **etag* value or a list or list item by performing a GET request that retrieves the entity. The response headers of the
resulting HTTP response pass the etag as the value of the ETag key. This value is also included in the entity metadata.
The following example shows the opening <entry> tag for the XML node that contains the list information. The m:etag property contains the etag value.

<entry xml:base="http://site url/_api/" xmlns=http://www.w3.org/2005/Atom


xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:etag=""1"">

Creating a site with REST


The following example shows how to create a site in JavaScript.

jQuery.ajax({
url: "http://<site url>/_api/web/webinfos/add",
type: "POST",
data: JSON.stringify(
{'parameters': {
'__metadata': {'type': 'SP.WebInfoCreationInformation' },
'Url': 'RestSubWeb',
'Title': 'RestSubWeb',
'Description': 'REST created web',
'Language':1033,
'WebTemplate':'sts',
'UseUniquePermissions':false}
}
),
headers: {
"accept": "application/json; odata=verbose",
"content-type":"application/json;odata=verbose",
"content-length": <length of post body>,
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: doSuccess,
error: doError
});

NOTE

Setting WebTemplate to 'sts' will create a modern homepage. To create a classic homepage, set WebTemplate to 'sts#0'.

How REST requests differ by environment


Building and sending an HTTP request may vary according to language, library, and add-in type, so you often need to change one or more request components when you're translating a
request from one environment to another. For example, jQuery AJAX requests use data and type parameters to specify the request body and type, but cross-domain library requests use
body and method parameters to specify those values.
The following sections describe other common differences across environments.

The way you get and send the form digest value depends on the add-in
When you send a POST request, the request must include the form digest value in the X-RequestDigest header. However, the way you get and send the value differs by add-in:
In SharePoint-hosted add-ins, you can just pass the following header:
"X-RequestDigest": $("#__REQUESTDIGEST").val()

In cloud-hosted add-ins that use OAuth, first retrieve the form digest value by sending a request to the contextinfo endpoint, and then add it to requests, as shown in Writing data by
using the REST interface.
In cloud-hosted add-ins that use the JavaScript cross-domain library, you don't need to specify the form digest value. By default, SP.RequestExecutor automatically handles this for
you. (It also handles the content-length value.)

Add-ins that use OAuth must pass access tokens in requests


Cloud-hosted add-ins use either OAuth or the cross-domain library to authorize access to SharePoint data. Add-in components with code that runs on a remote web server must use OAuth
to authorize access to SharePoint data. In this case, you need to include an Authorization header to send the access token. For an example that adds an authorization header to an
HTTPWebRequest object, see Reading data with the SharePoint REST interface.
NOTE

Cloud-hosted add-in components that are written in JavaScript must use the SP.RequestExecutor object in the cross-domain library to access to SharePoint data. Cross-domain library
requests don't need to include an access token.
To learn more about OAuth access tokens and how to get them, see Context Token OAuth flow for SharePoint Add-ins and Authorization Code OAuth flow for SharePoint Add-ins.

Endpoint URIs in cross-domain requests use SP.AppContextSite to change the context


Requests are sent to the resource endpoint that's specified in the url property of the request. Endpoint URIs use the following format:
<site url>/_api/<context>/<resource> (example, https://contoso.com/_api/web/lists)
Cross-domain library requests use this format when they access data on the add-in web, which is the default context for cross-domain library requests. But to access data on the host web or
on another site collection, the requests need to initialize the host web or other site collection as the context. To do this, they use the SP.AppContextSite endpoint in the URI, as shown in
Table 1. The example URIs in Table 1 use the @target alias to send the target URL in the query string because the URL contains a special character (':').
NOTE

An add-in web instance is required for a cloud-hosted add-in to access SharePoint data when using the cross-domain library.
Table 1. Using the SP.AppContextSite endpoint to change the context of the request

AD D - IN T YPE CR O S S - D O MAIN D ATA ACCES S S CENAR IO E X AMPLE END PO INT U R I

Cloud-hosted JavaScript add-in component accessing host web data by using the <app web url>/_api/SP.AppContextSite(@target)/web/lists?
cross-domain library @target='<host web url>'

Cloud-hosted JavaScript add-in component accessing data in a site collection <app web url>/_api/SP.AppContextSite(@target)/web/title?
other than the host web by using the cross-domain library (tenant- @target='<target site url>'
scoped add-ins only)

SharePoint-hosted Add-in web component accessing data in another site collection <app web url>/_api/SP.AppContextSite(@target)/web/title?
(tenant-scoped add-ins only) @target='<target site url>'

NOTE

Cross-domain data access scenarios also require appropriate add-in permissions. For more information, see Access data from the host web and Access data across site collections.
SharePoint Add-ins can get the add-in web URL and host web URL from the query string of the add-in page, as shown in the following code example. The example also shows how to
reference the cross-domain library, which is defined in the SP.RequestExecutor.js file on the host web. The example assumes that your add-in launches from SharePoint. For guidance about
setting your SharePoint context correctly when your add-in does not launch from SharePoint, see Authorization Code OAuth flow for SharePoint Add-ins.

var hostweburl;
var appweburl;

// Get the URLs for the add-in web the host web URL from the query string.
$(document).ready(function () {
//Get the URI decoded URLs.
hostweburl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
appweburl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));

// Load the SP.RequestExecutor.js file.


$.getScript(hostweburl + "/_layouts/15/SP.RequestExecutor.js", runCrossDomainRequest);
});

// Build and send the HTTP request.


function runCrossDomainRequest() {
var executor = new SP.RequestExecutor(appweburl);
executor.executeAsync({
url: appweburl + "/_api/SP.AppContextSite(@target)/web/lists?@target='" + hostweburl + "'",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: successHandler,
error: errorHandler
});
}

// Get a query string value.


// For production add-ins, you may want to use a library to handle the query string.
function getQueryStringParameter(paramToRetrieve) {
var params = document.URL.split("?")[1].split("&amp;");
var strParams = "";
for (var i = 0; i < params.length; i = i + 1) {
var singleParam = params[i].split("=");
if (singleParam[0] == paramToRetrieve) return singleParam[1];
}
}
??? // success and error callback functions

Properties used in REST requests


Table 2 shows properties that are commonly used in HTTP requests for the SharePoint REST service.
Table 2. When to use REST request properties in HTTP requests

PR O PER TIES W HEN R EQ U IR ED D ES CR IPTIO N

url All requests The URL of the REST resource endpoint. Example:
http://<site url>/_api/web/lists

method (or type) All requests The HTTP request method: GET for read operations and POST for
write operations. POST requests can perform update or delete
operations by specifying a DELETE, MERGE, or PUT verb in the X-
HTTP-Method header.

body (or data) POST requests that send data in the request body The body of the POST request. Sends data (such as complex types)
that can't be sent in the endpoint URI. Used with the content-
length header.
PR O PER TIES W HEN R EQ U IR ED D ES CR IPTIO N

Authentication header Remote add-ins that are using OAuth to authenticate users; does Sends the OAuth access token (obtained from a Microsoft Access
not apply when using JavaScript or the cross domain library Control Service (ACS) secure token server) that's used to
authenticate the user for the request. Example:
"Authorization": "Bearer " + accessToken , where
accessToken represents the variable that stores the token. Tokens
must be retrieved by using server-side code.

X-RequestDigest header POST requests (except SP.RequestExecutor requests) Remote add-ins that use OAuth can get the form digest value from
the http://<site url>/_api/contextinfo endpoint. SharePoint-
hosted add-ins can get the value from the #__REQUESTDIGEST
page control if it's available on the SharePoint page. See Writing
data by using the REST interface.

accept header Requests that return SharePoint metadata Specifies the format for response data from the server. The default
format is application/atom+xml . Example:
"accept":"application/json;odata=verbose"

content-type header POST requests that send data in the request body Specifies the format of the data that the client is sending to the
server. The default format is application/atom+xml . Example:
"content-type":"application/json;odata=verbose"

content-length header POST requests that send data in the request body (except Specifies the length of the content. Example:
SP.RequestExecutor requests) "content-length":requestBody.length

IF-MATCH header POST requests for DELETE, MERGE, or PUT operations, primarily Provides a way to verify that the object being changed has not been
for changing lists and libraries changed since it was last retrieved. Or, lets you specify to overwrite
any changes, as shown in the following example: "IF-MATCH":"*"

X-HTTP-Method header POST requests for DELETE, MERGE, or PUT operations Used to specify that the request performs an update or delete
operation. Example: "X-HTTP-Method":"PUT"

binaryStringRequestBody SP.RequestExecutor POST requests that send binary data in the Specifies whether the request body is a binary string. Boolean.
body

binaryStringResponseBody SP.RequestExecutor requests that return binary data Specifies whether the response is a binary string. Boolean.

Batch job support


The SharePoint Online (and on-premises SharePoint 2016 and later) REST service supports combining multiple requests into a single call to the service by using the OData $batch query
option. For details and links to code samples, see Make batch requests with the REST APIs.

See also
Get to know the SharePoint REST service
SharePoint: Perform basic data access operations on files and folders by using REST
Secure data access and client object models for SharePoint Add-ins
Work with external data in SharePoint
OData resources
Set custom permissions on a list by using the REST interface
Develop SharePoint Add-ins
Working with lists and list items with REST
4/20/2018 • 18 minutes to read Edit Online

 T IP

The SharePoint Online (and on-premises SharePoint 2016 and later) REST service supports combining multiple requests into a single call to the service by using the OData $batch query
option. For details and links to code samples, see Make batch requests with the REST APIs.

Prerequisites
This topic assumes that you are already familiar with the topics Get to know the SharePoint REST service and Complete basic operations using SharePoint REST endpoints. It does not
provide code snippets.

Retrieving lists and list properties with REST


The following example shows how to retrieve a specific list if you know its GUID.

url: http://site url/_api/web/lists(guid'list GUID'),


method: GET
Headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"

NOTE

If you want the response in JSON, use application/json;odata=verbose in the accept header .
If you want the response in Atom format, use application/atom+xml in the accept header.

The following example shows how to retrieve a specific list if you know its title.

url: http://site url/_api/web/lists/GetByTitle('Test')


method: GET
Headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"

The following XML shows an example of the list properties that are returned when you request the XML content type.

<content type="application/xml">
<m:properties>
<d:AllowContentTypes m:type="Edm.Boolean">true</d:AllowContentTypes>
<d:BaseTemplate m:type="Edm.Int32">100</d:BaseTemplate>
<d:BaseType m:type="Edm.Int32">0</d:BaseType>
<d:ContentTypesEnabled m:type="Edm.Boolean">false</d:ContentTypesEnabled>
<d:Created m:type="Edm.DateTime">2012-06-26T23:15:58Z</d:Created>
<d:DefaultContentApprovalWorkflowId m:type="Edm.Guid">00000000-0000-0000-0000-000000000000</d:DefaultContentApprovalWorkflowId>
<d:Description>A list created by Project Based Retention used to store Project Policy Items.</d:Description>
<d:Direction>none</d:Direction>
<d:DocumentTemplateUrl m:null="true" />
<d:DraftVersionVisibility m:type="Edm.Int32">0</d:DraftVersionVisibility>
<d:EnableAttachments m:type="Edm.Boolean">true</d:EnableAttachments>
<d:EnableFolderCreation m:type="Edm.Boolean">false</d:EnableFolderCreation>
<d:EnableMinorVersions m:type="Edm.Boolean">false</d:EnableMinorVersions>
<d:EnableModeration m:type="Edm.Boolean">false</d:EnableModeration>
<d:EnableVersioning m:type="Edm.Boolean">false</d:EnableVersioning>
<d:EntityTypeName>ProjectPolicyItemList</d:EntityTypeName>
<d:ForceCheckout m:type="Edm.Boolean">false</d:ForceCheckout>
<d:HasExternalDataSource m:type="Edm.Boolean">false</d:HasExternalDataSource>
<d:Hidden m:type="Edm.Boolean">true</d:Hidden>
<d:Id m:type="Edm.Guid">74de3ff3-029c-42f9-bd2a-1e9463def69d</d:Id>
<d:ImageUrl>/_layouts/15/images/itgen.gif</d:ImageUrl>
<d:IrmEnabled m:type="Edm.Boolean">false</d:IrmEnabled>
<d:IrmExpire m:type="Edm.Boolean">false</d:IrmExpire>
<d:IrmReject m:type="Edm.Boolean">false</d:IrmReject>
<d:IsApplicationList m:type="Edm.Boolean">false</d:IsApplicationList>
<d:IsCatalog m:type="Edm.Boolean">false</d:IsCatalog>
<d:IsPrivate m:type="Edm.Boolean">false</d:IsPrivate>
<d:ItemCount m:type="Edm.Int32">0</d:ItemCount>
<d:LastItemDeletedDate m:type="Edm.DateTime">2012-06-26T23:15:58Z</d:LastItemDeletedDate>
<d:LastItemModifiedDate m:type="Edm.DateTime">2012-06-26T23:15:59Z</d:LastItemModifiedDate>
<d:ListItemEntityTypeFullName>SP.Data.ProjectPolicyItemListItem</d:ListItemEntityTypeFullName>
<d:MultipleDataList m:type="Edm.Boolean">false</d:MultipleDataList>
<d:NoCrawl m:type="Edm.Boolean">true</d:NoCrawl>
<d:ParentWebUrl>/</d:ParentWebUrl>
<d:ServerTemplateCanCreateFolders m:type="Edm.Boolean">true</d:ServerTemplateCanCreateFolders>
<d:TemplateFeatureId m:type="Edm.Guid">00bfea71-de22-43b2-a848-c05709900100</d:TemplateFeatureId>
<d:Title>Project Policy Item List</d:Title>
</m:properties>
</content>

NOTE

The ListItemEntityTypeFullName property (SP.Data.ProjectPolicyItemListItem in the previous example) is especially important if you want to create and update list items. This value
must be passed as the type property in the metadata that you pass in the body of the HTTP request whenever you create and update list items.

Working with lists by using REST


The following example shows how to create a list.

url: http://site url/_api/web/lists


method: POST
body: { '__metadata': { 'type': 'SP.List' }, 'AllowContentTypes': true, 'BaseTemplate': 100,
'ContentTypesEnabled': true, 'Description': 'My list description', 'Title': 'Test' }
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
content-length:length of post body

The following example shows how to update a list by using the MERGE method.

url: http://site url/_api/web/lists(guid'list GUID')


method: POST
body: { '__metadata': { 'type': 'SP.List' }, 'Title': 'New title' }
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
IF-MATCH": etag or "*"
X-HTTP-Method: MERGE,
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
content-length:length of post body

The following example shows how to create a custom field for a list.

Url: url: http://site url/_api/web/lists(guid'list GUID')/Fields


Method:POST
Body: { '__metadata': { 'type': 'SP.Field' }, 'Title': 'field title', 'FieldTypeKind': FieldType value,'Required': 'true/false', 'EnforceUniqueValues': 'true/false','StaticName': 'field name'}
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
content-type: "application/json;odata=verbose"
content-length:length of post body

The following example shows how to delete a list.

url: http://site url/_api/web/lists(guid'list GUID')


method: POST
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
IF-MATCH: etag or "*"
X-HTTP-Method: DELETE

Working with list items by using REST


Retrieve all list items
The following example shows how to retrieve all of a list's items.
NOTE

The OData $skip query option does not work when querying list items. In may situations, you can use the $skiptoken option instead.

url: http://site url/_api/web/lists/GetByTitle('Test')/items


method: GET
headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"

Retrieve specific list item


The following example shows how to retrieve a specific list item.

url: http://site url/_api/web/lists/GetByTitle('Test')/items(item id)


method: GET
headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"

The following XML shows an example of the list item properties that are returned when you request the XML content type.
<content type="application/xml">
<m:properties>
<d:FileSystemObjectType m:type="Edm.Int32">0</d:FileSystemObjectType>
<d:Id m:type="Edm.Int32">1</d:Id>
<d:ID m:type="Edm.Int32">1</d:ID>
<d:ContentTypeId>0x010049564F321A0F0543BA8C6303316C8C0F</d:ContentTypeId>
<d:Title>an item</d:Title>
<d:Modified m:type="Edm.DateTime">2012-07-24T22:47:26Z</d:Modified>
<d:Created m:type="Edm.DateTime">2012-07-24T22:47:26Z</d:Created>
<d:AuthorId m:type="Edm.Int32">11</d:AuthorId>
<d:EditorId m:type="Edm.Int32">11</d:EditorId>
<d:OData__UIVersionString>1.0</d:OData__UIVersionString>
<d:Attachments m:type="Edm.Boolean">false</d:Attachments>
<d:GUID m:type="Edm.Guid">eb6850c5-9a30-4636-b282-234eda8b1057</d:GUID>
</m:properties>
</content>

Retrieve items as a stream


Retrieves information about the list and its data. Using this API you can retrieve list items in case they use complex fields such as lookups or managed metadata.

POST /_api/web/GetList(@listUrl)/RenderListDataAsStream?@listUrl=%27%2Fsites%2Fteam-a%2Flists%2FList%27

URI Parameters
Following properties can be added as query string parameters to manipulate the returned data.

PR O PER T Y D ES CR IPTIO N T YPE E X AMPLE

CascDelWarnMessage Specifies if a message should be displayed if there number 1


is a cascade deletion warning

DrillDown Specifies that some groups in a grouped view is string


expanded. Used with GroupString .

GroupString Group identifier used for drill down feature. string

HasOverrideSelectCommand Used to ensure that certain fields are present for string
proper functioning of the SharePoint ListView
control.

Field Specifies a special field that should be included. string

FieldInternalName Used to identify a field when a list has an external string


data source. Also used when filtering on a custom
field.

Filter Specifies whether the requested view should have string


a filter applied.

FilterData Data specified by a particular filter. string

FilterData1 Data specified by a particular filter. string

FilterData2 Data specified by a particular filter. string

FilterData3 Data specified by a particular filter. string

FilterData4 Data specified by a particular filter. string

FilterData5 Data specified by a particular filter. string

FilterData6 Data specified by a particular filter. string

FilterData7 Data specified by a particular filter. string

FilterData8 Data specified by a particular filter. string

FilterData9 Data specified by a particular filter. string

FilterData10 Data specified by a particular filter. string

FilterField A filter field name for a specific filter that is string


applied to the view.

FilterField1 A filter field name for a specific filter that is string ID


applied to the view.

FilterField2 A filter field name for a specific filter that is string ID


applied to the view.

FilterField3 A filter field name for a specific filter that is string ID


applied to the view.

FilterField4 A filter field name for a specific filter that is string ID


applied to the view.
PR O PER T Y D ES CR IPTIO N T YPE E X AMPLE

FilterField5 A filter field name for a specific filter that is string ID


applied to the view.

FilterField6 A filter field name for a specific filter that is string ID


applied to the view.

FilterField7 A filter field name for a specific filter that is string ID


applied to the view.

FilterField8 A filter field name for a specific filter that is string ID


applied to the view.

FilterField9 A filter field name for a specific filter that is string ID


applied to the view.

FilterField10 A filter field name for a specific filter that is string ID


applied to the view.

FilterFields Specifies multiple fields that are being filtered on string


for a multiplier filter.

FilterFields1 Specifies multiple fields that are being filtered on string


for a multiplier filter.

FilterFields2 Specifies multiple fields that are being filtered on string


for a multiplier filter.

FilterFields3 Specifies multiple fields that are being filtered on string


for a multiplier filter.

FilterFields4 Specifies multiple fields that are being filtered on string


for a multiplier filter.

FilterFields5 Specifies multiple fields that are being filtered on string


for a multiplier filter.

FilterFields6 Specifies multiple fields that are being filtered on string


for a multiplier filter.

FilterFields7 Specifies multiple fields that are being filtered on string


for a multiplier filter.

FilterFields8 Specifies multiple fields that are being filtered on string


for a multiplier filter.

FilterFields9 Specifies multiple fields that are being filtered on string


for a multiplier filter.

FilterFields10 Specifies multiple fields that are being filtered on string


for a multiplier filter.

FilterValue The filter value associated with a particular filter. string


For example, FilterField3 goes with FilterValue3
and so forth.

FilterValue1 The filter value associated with a particular filter. string 1


For example, FilterField3 goes with FilterValue3
and so forth.

FilterValue2 The filter value associated with a particular filter. string 1


For example, FilterField3 goes with FilterValue3
and so forth.

FilterValue3 The filter value associated with a particular filter. string 1


For example, FilterField3 goes with FilterValue3
and so forth.

FilterValue4 The filter value associated with a particular filter. string 1


For example, FilterField3 goes with FilterValue3
and so forth.

FilterValue5 The filter value associated with a particular filter. string 1


For example, FilterField3 goes with FilterValue3
and so forth.

FilterValue6 The filter value associated with a particular filter. string 1


For example, FilterField3 goes with FilterValue3
and so forth.

FilterValue7 The filter value associated with a particular filter. string 1


For example, FilterField3 goes with FilterValue3
and so forth.
PR O PER T Y D ES CR IPTIO N T YPE E X AMPLE

FilterValue8 The filter value associated with a particular filter. string 1


For example, FilterField3 goes with FilterValue3
and so forth.

FilterValue9 The filter value associated with a particular filter. string 1


For example, FilterField3 goes with FilterValue3
and so forth.

FilterValue10 The filter value associated with a particular filter. string 1


For example, FilterField3 goes with FilterValue3
and so forth.

FilterValues Used with FilterFields for multiplier filter. For string


example, FilterFields3 would go with FilterValues3
and so forth.

FilterValues1 Used with FilterFields for multiplier filter. For string


example, FilterFields3 would go with FilterValues3
and so forth.

FilterValues2 Used with FilterFields for multiplier filter. For string


example, FilterFields3 would go with FilterValues3
and so forth.

FilterValues3 Used with FilterFields for multiplier filter. For string


example, FilterFields3 would go with FilterValues3
and so forth.

FilterValues4 Used with FilterFields for multiplier filter. For string


example, FilterFields3 would go with FilterValues3
and so forth.

FilterValues5 Used with FilterFields for multiplier filter. For string


example, FilterFields3 would go with FilterValues3
and so forth.

FilterValues6 Used with FilterFields for multiplier filter. For string


example, FilterFields3 would go with FilterValues3
and so forth.

FilterValues7 Used with FilterFields for multiplier filter. For string


example, FilterFields3 would go with FilterValues3
and so forth.

FilterValues8 Used with FilterFields for multiplier filter. For string


example, FilterFields3 would go with FilterValues3
and so forth.

FilterValues9 Used with FilterFields for multiplier filter. For string


example, FilterFields3 would go with FilterValues3
and so forth.

FilterValues10 Used with FilterFields for multiplier filter. For string


example, FilterFields3 would go with FilterValues3
and so forth.

FilterLookupId Used when filtering on a lookup field. This is the string


item id in the foreign list that has a value that is
being filtered on.

FilterLookupId1 Used when filtering on a lookup field. This is the string


item id in the foreign list that has a value that is
being filtered on.

FilterLookupId2 Used when filtering on a lookup field. This is the string


item id in the foreign list that has a value that is
being filtered on.

FilterLookupId3 Used when filtering on a lookup field. This is the string


item id in the foreign list that has a value that is
being filtered on.

FilterLookupId4 Used when filtering on a lookup field. This is the string


item id in the foreign list that has a value that is
being filtered on.

FilterLookupId5 Used when filtering on a lookup field. This is the string


item id in the foreign list that has a value that is
being filtered on.

FilterLookupId6 Used when filtering on a lookup field. This is the string


item id in the foreign list that has a value that is
being filtered on.
PR O PER T Y D ES CR IPTIO N T YPE E X AMPLE

FilterLookupId7 Used when filtering on a lookup field. This is the string


item id in the foreign list that has a value that is
being filtered on.

FilterLookupId8 Used when filtering on a lookup field. This is the string


item id in the foreign list that has a value that is
being filtered on.

FilterLookupId9 Used when filtering on a lookup field. This is the string


item id in the foreign list that has a value that is
being filtered on.

FilterLookupId10 Used when filtering on a lookup field. This is the string


item id in the foreign list that has a value that is
being filtered on.

FilterOnly string

FilterOp Filter operator. Used when filtering with other string Geq
operators than Eq (Geq, Leq etc.)

FilterOp1 Filter operator. Used when filtering with other string Geq
operators than Eq (Geq, Leq etc.)

FilterOp2 Filter operator. Used when filtering with other string Geq
operators than Eq (Geq, Leq etc.)

FilterOp3 Filter operator. Used when filtering with other string Geq
operators than Eq (Geq, Leq etc.)

FilterOp4 Filter operator. Used when filtering with other string Geq
operators than Eq (Geq, Leq etc.)

FilterOp5 Filter operator. Used when filtering with other string Geq
operators than Eq (Geq, Leq etc.)

FilterOp6 Filter operator. Used when filtering with other string Geq
operators than Eq (Geq, Leq etc.)

FilterOp7 Filter operator. Used when filtering with other string Geq
operators than Eq (Geq, Leq etc.)

FilterOp8 Filter operator. Used when filtering with other string Geq
operators than Eq (Geq, Leq etc.)

FilterOp9 Filter operator. Used when filtering with other string Geq
operators than Eq (Geq, Leq etc.)

FilterOp10 Filter operator. Used when filtering with other string Geq
operators than Eq (Geq, Leq etc.)

ID The item id of the item whose information is number


being sought.

InplaceSearchQuery Search term for a full list search. string

InplaceFullListSearch A boolean that specifies whether there is a full list string


search.

IsCSR Whether this view is a client side rendered view. string

CustomAction string

IsGroupRender Used to set the IsGroupRender property of the string


SPView.

IsRibbon string

IsXslView Whether this view is an xslt list view. string

List string

ListId string

ListViewPageUrl string

OverrideScope Used to override a scope on the rendered view: string


SPView.Scope

OverrideSelectCommand Used to make sure that certain fields are present string
in the query regardless of whether they are
explicitly included in the view.
PR O PER T Y D ES CR IPTIO N T YPE E X AMPLE

PageFirstRow Paging information about the first row that is string


requested. Used for paging list views.

PageLastRow Paging information about the last row that is string


requested. Used for paging list views.

RootFolder The folder that the view is displaying. string

SortField A field that the view should be sorted on. string ID

SortField1 A field that the view should be sorted on. string ID

SortField2 A field that the view should be sorted on. string ID

SortField3 A field that the view should be sorted on. string ID

SortField4 A field that the view should be sorted on. string ID

SortField5 A field that the view should be sorted on. string ID

SortField6 A field that the view should be sorted on. string ID

SortField7 A field that the view should be sorted on. string ID

SortField8 A field that the view should be sorted on. string ID

SortField9 A field that the view should be sorted on. string ID

SortField10 A field that the view should be sorted on. string ID

SortFields Specifies the name of the first field to sort by string

SortFieldValues Specifies the name of the first field to sort by string

SortDir The sort direction of an ad hoc sort that is being string Desc
applied to the view.

SortDir1 The sort direction of an ad hoc sort that is being string Desc
applied to the view.

SortDir2 The sort direction of an ad hoc sort that is being string Desc
applied to the view.

SortDir3 The sort direction of an ad hoc sort that is being string Desc
applied to the view.

SortDir4 The sort direction of an ad hoc sort that is being string Desc
applied to the view.

SortDir5 The sort direction of an ad hoc sort that is being string Desc
applied to the view.

SortDir6 The sort direction of an ad hoc sort that is being string Desc
applied to the view.

SortDir7 The sort direction of an ad hoc sort that is being string Desc
applied to the view.

SortDir8 The sort direction of an ad hoc sort that is being string Desc
applied to the view.

SortDir9 The sort direction of an ad hoc sort that is being string Desc
applied to the view.

SortDir10 The sort direction of an ad hoc sort that is being string Desc
applied to the view.

View Specifies the base view that will be used to render GUID 3d13559e-3071-5000-76b8-8f1ca6b835f0
the list.

ViewPath Specifies the path of the view that will be used to string
render the list. If ViewId is given then the
ViewId will be used and this parameters will be
ignored.

ViewCount When multiple list views are on a page, this string


identifies one of them.
PR O PER T Y D ES CR IPTIO N T YPE E X AMPLE

ViewId Specifies the base view that will be used to render string
the list. ad-hoc parameters will be applied on top
of this view. If both ViewXml and BaseViewId
are given then the ViewXml will be used and the
ad-hoc parameters will be ignored.

WebPartId The id of the list view web part that is showing string
this view.

Request headers
HE AD ER V ALU E

Accept application/json;odata=nometadata

Content-Type application/json;odata=nometadata

Request body
{
"parameters": {
"AddRequiredFields": "true",
"DatesInUtc": "true",
"RenderOptions": 17
}
}

PR O PER T Y D ES CR IPTIO N T YPE E X AMPLE

AddRequiredFields Specifies if required fields should be returned or bool true


not

AllowMultipleValueFilterForTaxonomyFields Specifies if multi value filtering is allowed for bool true


taxonomy fields or not

DatesInUtc Specifies if we return DateTime field in UTC or bool true


local time.

ExpandGroups Specifies if the grouping should be expanded or bool true


not.

FirstGroupOnly Specifies if only the first group should be returned bool true
or not (regardless of view schema).

FolderServerRelativeUrl Specifies the url to the folder from which to return string /sites/team-a/lists/Orders/Europe
items.

ImageFieldsToTryRewriteToCdnUrls Comma-separated list of field names whose string ArticleImage,SecondaryImage


values should be rewritten to CDN URLs

OverrideViewXml Specifies the override XML to be combined with string <Query><Where><Gt><FieldRef


the View CAML. Applies only to the Name=\"OrderCount\" /><Value
Type=\"Number\">3</Value></Gt></Where>
Query/Where part of the View CAML. </Query>

Paging Specifies the paging information. string

RenderOptions Specifies the type of output to return. SPRenderListDataOptions See the next section for possible values. You can
specify multiple values by adding their values
together

ReplaceGroup Specifies if the grouping should be replaced or bool true


not to deal with GroupBy throttling.

ViewXml Specifies the CAML view XML. string

S P R E N D E R LIS T D A T A O P T IO N S

L AB EL D ES CR IPTIO N V ALU E

None Return default output 0

ContextInfo Return list context information 1

ListData Return list data (same as None ) 2

ListSchema Return list schema 4

MenuView Return HTML for the list menu 8

ListContentType Returns information about list content types. Must be combined 16


with the ContextInfo flag

FileSystemItemId The returned list will have a FileSystemItemId field on each item if 32
possible. Must be combined with the ListData flag
L AB EL D ES CR IPTIO N V ALU E

ClientFormSchema Returns the client form schema to add and edit items. 64

QuickLaunch Returns QuickLaunch navigation nodes. 128

Spotlight Returns Spotlight rendering information. 256

Visualization Returns Visualization rendering information. 512

ViewMetadata Returns view XML and other information about the current view. 1024

DisableAutoHyperlink Prevents AutoHyperlink from being run on text fields in this query. 2048

EnableMediaTAUrls Enables URLs pointing to Media TA service, such as .thumbnailUrl, 4096


.videoManifestUrl, .pdfConversionUrls.

ParentInfo Returns parent folder information. 8192

PageContextInfo Returns page context info for the current list being rendered. 16384

ClientSideComponentManifest Return client-side component manifest information associated with 32768


the list. Reserved for future use

Examples
Retrieve item with specific ID

POST https://contoso.sharepoint.com/sites/team-a/_api/web/GetList(@listUrl)/RenderListDataAsStream?@listUrl=%27%2Fsites%2Fteam-a%2Flists%2FList%27&FilterField1=ID&FilterValue1=1
accept: application/json;odata=nometadata

Sort items descending by ID

POST https://contoso.sharepoint.com/sites/team-a/_api/web/GetList(@listUrl)/RenderListDataAsStream?@listUrl=%27%2Fsites%2Fteam-a%2Flists%2FList%27&SortField=ID&SortDir=Desc
accept: application/json;odata=nometadata

Retrieve items from the specified folder

POST https://contoso.sharepoint.com/sites/team-a/_api/web/GetList(@listUrl)/RenderListDataAsStream?@listUrl=%27%2Fsites%2Fteam-a%2Flists%2FOrders%27
accept: application/json;odata=nometadata
content-type: application/json;odata=nometadata

{
"parameters": {
"FolderServerRelativeUrl": "/sites/team-a/lists/Orders/Europe"
}
}

Retrieve list schema

POST https://contoso.sharepoint.com/sites/team-a/_api/web/GetList(@listUrl)/RenderListDataAsStream?@listUrl=%27%2Fsites%2Fteam-a%2Flists%2FList%27
accept: application/json;odata=nometadata
content-type: application/json;odata=nometadata

{
"parameters": {
"RenderOptions": 4
}
}

Retrieve information about list content types

POST https://contoso.sharepoint.com/sites/team-a/_api/web/GetList(@listUrl)/RenderListDataAsStream?@listUrl=%27%2Fsites%2Fteam-a%2Flists%2FList%27
accept: application/json;odata=nometadata
content-type: application/json;odata=nometadata

{
"parameters": {
"RenderOptions": 17
}
}

Create list item


The following example shows how to create a list item.
NOTE

To do this operation, you must know the ListItemEntityTypeFullName property of the list and pass that as the value of type in the HTTP request body.
url: http://site url/_api/web/lists/GetByTitle('Test')/items
method: POST
body: { '__metadata': { 'type': 'SP.Data.TestListItem' }, 'Title': 'Test'}
headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
content-length:length of post body

Create list item in a folder


The following example shows how to create a list item in a folder.

POST /_api/web/lists/GetByTitle('Test')/AddValidateUpdateItemUsingPath

URI Parameters
None
Request headers
HE AD ER V ALU E

Accept application/json;odata=nometadata

Content-Type application/json;odata=nometadata

x-requestdigest The appropriate digest for current site

Request body
{
"listItemCreateInfo": {
"FolderPath": { "DecodedUrl": "https://contoso.sharepoint.com/lists/Test/Folder/SubFolder" },
"UnderlyingObjectType": 0
},
"formValues": [
{
"FieldName": "Title",
"FieldValue": "Item"
}
],
"bNewDocumentUpdate": false
}

PR O PER T Y D ES CR IPTIO N

listItemCreateInfo Information about the list and folder where the item should be created

listItemCreateInfo.FolderPath.DecodedUrl Absolute URL of the folder where the item should be created

listItemCreateInfo.UnderlyingObjectType Type of item to create. For more information see https://msdn.microsoft.com/en-


us/library/microsoft.sharepoint.client.filesystemobjecttype(v=office.14).aspx

formValues Array of field names and values to set on the newly created item

bNewDocumentUpdate Set to false to create a list item

Responses
NAME T YPE D ES CR IPTIO N

200 OK Boolean Success

{
"value": [
{
"ErrorMessage": null,
"FieldName": "Title",
"FieldValue": "Item",
"HasException": false,
"ItemId": 0
},
{
"ErrorMessage": null,
"FieldName": "Id",
"FieldValue": "1",
"HasException": false,
"ItemId": 0
}
]
}

The value property contains the list of properties that have been set when creating the list item.

Update list item


The following example shows how to update a list item.
NOTE

To do this operation, you must know the ListItemEntityTypeFullName property of the list and pass that as the value of type in the HTTP request body.
url: http://site url/_api/web/lists/GetByTitle('Test')/items(item id)
method: POST
body: { '__metadata': { 'type': 'SP.Data.TestListItem' }, 'Title': 'TestUpdated'}
headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
"IF-MATCH": etag or "*"
"X-HTTP-Method":"MERGE",
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
content-length:length of post body

Delete list item


The following example shows how to delete a list item.

url: http://site url/_api/web/lists/GetByTitle('Test')/items(item id)


method: POST
headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
"IF-MATCH": etag or "*"
"X-HTTP-Method":"DELETE"

Using ETag values to determine document and list item versioning


The SharePoint REST service, which follows the OData standard, uses HTML ETags for concurrency control of SharePoint lists and list items. To check on an item's version when you perform
a PUT, MERGE, or DELETE request, specify an ETag in the If-Match HTTP request header.
If the ETag you specify in your request does not match the ETag of the document or list item on the server, the REST service returns a 412 exception, per the OData specification.
To force an overwrite of the item regardless of version, set the ETag value to "*".
If you do not specify an ETag, SharePoint overwrites the item regardless of version.
Within SharePoint, ETags apply only to SharePoint lists and list items.

See also
Get to know the SharePoint REST service
SharePoint-Add-in-REST-OData-BasicDataOperations
SharePoint: Perform basic data access operations on files and folders by using REST
Secure data access and client object models for SharePoint Add-ins
Work with external data in SharePoint
REST API reference and samples
OData resources
Develop SharePoint Add-ins
Working with folders and files with REST
4/20/2018 • 5 minutes to read Edit Online

 T IP

The SharePoint Online (and on-premises SharePoint 2016 and later) REST service supports combining multiple requests into a single call to the service by using the OData $batch query
option. For details and links to code samples, see Make batch requests with the REST APIs.

Working with folders by using REST


You can retrieve a folder inside a document library when you know its URL. For example, you can retrieve the root folder of your Shared Documents library by using the endpoint in
the following example.

url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Shared Documents')


method: GET
headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"

The following XML shows an example of folder properties that are returned when you request the XML content type.

<content type="application/xml">
<m:properties>
<d:ItemCount m:type="Edm.Int32">0</d:ItemCount>
<d:Name>Shared Documents</d:Name>
<d:ServerRelativeUrl>/Shared Documents</d:ServerRelativeUrl>
<d:WelcomePage/>
</m:properties>
</content>

The following example shows how to create a folder.

url: http://site url/_api/web/folders


method: POST
body: { '__metadata': { 'type': 'SP.Folder' }, 'ServerRelativeUrl': '/document library relative url/folder name'}
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
content-length:length of post body

The following example shows how to update a folder by using the MERGE method.

url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Folder Name')


method: POST
body: { '__metadata': { 'type': 'SP.Folder' }, 'Name': 'New name' }
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
"IF-MATCH": etag or "*"
"X-HTTP-Method":"MERGE",
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
content-length:length of post body

The following example shows how to delete a folder.

url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Folder Name')


method: POST
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
"IF-MATCH": etag or "*"
"X-HTTP-Method":"DELETE"

Working with files by using REST


The following example shows how to retrieve all of the files in a folder.

url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Folder Name')/Files


method: GET
headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"

The following example shows how to retrieve a specific file.


url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Folder Name')/Files('file name')/$value
method: GET
headers:
Authorization: "Bearer " + accessToken

You can also retrieve a file when you know its URL, as in the following example.

url: http://site url/_api/web/GetFileByServerRelativeUrl('/Folder Name/file name')/$value


method: GET
headers:
Authorization: "Bearer " + accessToken

The following example shows how to create a file and add it to a folder.

url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Folder Name')/Files/add(url='a.txt',overwrite=true)


method: POST
body: "Contents of file"
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
content-length:length of post body

The following example shows how to update a file by using the PUT method.
NOTE

PUT is the only method that you can use to update a file. The MERGE method is not allowed.

url: http://site url/_api/web/GetFileByServerRelativeUrl('/Folder Name/file name')/$value


method: POST
body: "Contents of file."
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
X-HTTP-Method:"PUT"
content-length:length of post body

If you want to update a file's metadata, you have to construct an endpoint that reaches the file as a list item. You can do this because each folder is also a list, and each file is also a list item.
Construct an endpoint that looks like this: https://<site url>/_api/web/lists/getbytitle('Documents')/items(<item id>) . For information about how to update a list item's metadata, see
Working with lists and list items with REST.
You may want to check out a file to make sure that no one changes it before you update it. After your update, you should check the file back in so that others can work with it.
The following example shows how to check out a file.

url: http://site url/_api/web/GetFileByServerRelativeUrl('/Folder Name/file name')/CheckOut(),


method: POST
headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value

The following example shows how to check in a file.

url: http://site url/_api/web/GetFileByServerRelativeUrl('/Folder Name/file name')/CheckIn(comment='Comment',checkintype=0)


method: POST
headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value

The following example shows how to delete a file.

url: http://site url/_api/web/GetFileByServerRelativeUrl('/Folder Name/file name')


method: POST
headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
IF-MATCH: etag or "*"
X-HTTP-Method:"DELETE"

Working with large files by using REST


When you need to upload a binary file that is larger than 1.5 megabytes (MB), the REST interface is your only option. For a code example that shows you how to upload a binary file that is
smaller than 1.5 MB by using the SharePoint JavaScript object model, see Complete basic operations using JavaScript library code in SharePoint. The maximum size of a binary file that you
can create with REST is 2 gigabytes (GB).
The following example shows how to create a large binary file.
W A R N IN G
This approach works only with Internet Explorer 10 and the latest versions of other browsers.

url: http://site url/_api/web/GetFolderByServerRelativeUrl('/Folder Name')/Files/Add(url='file name', overwrite=true)


method: POST
body: contents of binary file
headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
content-type: "application/json;odata=verbose"
content-length:length of post body

The following code sample shows how to create a file by using this REST endpoint and the cross-domain library.

function uploadFileBinary() {
XDomainTestHelper.clearLog();
var ro;
if (document.getElementById("TxtViaUrl").value.length > 0) {
ro = new SP.RequestExecutor(document.getElementById("TxtWebUrl").value, document.getElementById("TxtViaUrl").value);
}
else {
ro = new SP.RequestExecutor(document.getElementById("TxtWebUrl").value);
}
var body = "";
for (var i = 0; i < 1000; i++) {
var ch = i % 256;
body = body + String.fromCharCode(ch);
}
var info = {
url: "_api/web/lists/getByTitle('Shared Documents')/RootFolder/Files/Add(url='a.dat', overwrite=true)",
method: "POST",
binaryStringRequestBody: true,
body: body,
success: success,
error: fail,
state: "Update"
};
ro.executeAsync(info);
}

Working with files attached to list items by using REST


The following example shows how to retrieve all of the files that are attached to a list item.

url: http://site url/_api/web/lists/getbytitle('list title')/items(item id)/AttachmentFiles/


method: GET
headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"

The following example shows how to retrieve a file that is attached to a list item.

url: http://site url/_api/web/lists/getbytitle('list title')/items(item id)/AttachmentFiles('file name')/$value


method: GET
headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"

The following example shows how to create a file attachment to a list item.

url: http://site url/_api/web/lists/getbytitle('list title')/items(item id)/AttachmentFiles/ add(FileName='file name')


method: POST
headers:
Authorization: "Bearer " + accessToken
body: "Contents of file."
X-RequestDigest: form digest value
content-length:length of post body

The following example shows how to update a file attachment to a list item by using the PUT method.
NOTE

PUT is the only method that you can use to update a file. The MERGE method is not allowed.

url: http://site url/_api/web/lists/getbytitle('list title')/items(item id)/AttachmentFiles('file name')/$value


method: POST
body: "Contents of file."
headers:
Authorization: "Bearer " + accessToken
"X-HTTP-Method":"PUT"
X-RequestDigest: form digest value
content-length:length of post body
See also
Get to know the SharePoint REST service
Complete basic operations using SharePoint client library code
REST API reference and samples
Upload a file by using the REST API and jQuery
SharePoint-Add-in-REST-OData-BasicDataOperations
SharePoint: Perform basic data access operations on files and folders by using REST
Secure data access and client object models for SharePoint Add-ins
Work with external data in SharePoint
OData resources
Develop SharePoint Add-ins
Determine SharePoint REST service endpoint URIs
3/26/2018 • 6 minutes to read Edit Online

Before you start


Get to know the SharePoint REST service
Navigate the SharePoint data structure represented in the REST service
Next steps
Use OData query operations in SharePoint REST requests

SharePoint REST endpoint URI structure


Before you can access a SharePoint resource using the REST service, you first have to figure out the URI endpoint that points to that resource. Whenever possible, the URI for these REST
endpoints closely mimics the API signature of the resource in the SharePoint client object model. For example:
Client object model method:
List.GetByTitle(listname).GetItems()

REST endpoint:
http://server/site/_api/lists/getbytitle('listname')/items

In some cases, however, the endpoint URI differs from the corresponding client object model signature, in order to comply with REST or OData conventions.
The following figure shows the general syntax structure of SharePoint REST URIs.
SharePoint REST URI syntax structure

Some endpoints for SharePoint resources deviate from this syntax structure:
Methods that require complex types as parameters. If the corresponding client object model method requires that complex types are passed as parameters, the REST endpoint
may deviate from this syntax construction to account for REST limitations.
Static methods and properties. REST endpoints deviate from this syntax structure for URIs that represent static methods and properties.

Determine SharePoint REST service endpoints


To construct a REST endpoint for a SharePoint resource, follow these steps:
1. Start with the REST service reference:
http://server/site/_api

2. Specify the appropriate entry point. For example:


http://server/site/_api/web

3. Navigate from the entry point to the specific resources you want to access. This includes specifying parameters for endpoints that correspond to methods in the client object model.
For example:
http://server/site/_api/web/lists/getbytitle('listname')

Reference the SharePoint REST service in your endpoint URI


Use _api to denote the SharePoint REST service in your endpoint URIs. The REST service is part of the client.svc web service. However, to make REST URI construction easier and to
shorten the base REST URI path, the REST service uses _api to abstract away the need to explicitly reference the client.svc web service.
The REST service still recognizes and accepts URIs that reference the client.svc web service. For example, you can use http://server/site/_vti_bin/client.svc/web/lists instead of
http://server/site/_api/web/lists . However, using _api is the preferred convention. URLs have a 256 character limit, so using _api shortens the base URI, leaving more characters for
use in constructing the rest of the URL.

Specify entry points for the SharePoint REST service


The main entry points for the REST service represent the site collection and site of the specified context. In this way, these entry points correspond to the ClientContext.Site property and
ClientContext.Web property in the client object models.
To access a specific site collection, use the following construction, where server represents the name of the server, and site represents the name of, or path to, the specific site:
http://server/site/_api/site

To access a specific site, use the following construction:


http://server/site/_api/web

In addition to /site and /web , the REST service includes several other access points that enable developers to navigate to specific functionality. The following table lists some of these
access points.

FE ATU R E AR E A ACCES S PO INT

Site http://server/site/_api/site

Web http://server/site/_api/web

User Profile http://server/site/_api/SP.UserProfiles.PeopleManager

Search http://server/site/_api/search

Navigate to the specific resources you want to access


From here, construct more specific REST endpoints by "walking" the object model, using the names of the APIs from the client object model separated by a forward slash (/). The following
table shows examples of client object model calls and the equivalent REST endpoint.

CLIENT O B JECT MO D EL API R ES T END PO INT

ClientContext.Web.Lists http://server/site/_api/web/lists

ClientContext.Web.Lists[guid] http://server/site/_api/web/lists('<guid>')

ClientContext.Web.Lists.GetByTitle("Title") http://server/site/_api/web/lists/getbytitle('<Title>')

Endpoint URIs are case-insensitive. In the previous table, for example, use /getbytitle to specify the REST equivalent of the GetByTitle() method.

Specify parameters in REST endpoint URIs


SharePoint extends the OData specification to enable you to use parentheses to specify method parameters and index values. This prevents potential disambiguation issues in URIs that
contain multiple parameters with the same name. For example, the following two URIs contain parameters that have the same name:
http://server/site/_api/web/lists/getByTitle('Announcements')/fields/getByTitle('Description')

http://server/site/_api/web/lists('<guid>')/fields/getById('<guid>')

To specify multiple parameters, include the parameter as a name-value pair, and separate the parameters with commas. For example:
http://server/site/_api/web/getAvailableWebTemplates(lcid=1033, includeCrossLanguage=true)

The following figure shows the SharePoint REST parameter syntax.


SharePoint REST parameter syntax

Complex types as parameters for the REST service


Some methods in the client object model require a large payload as a parameter. For REST endpoints to maintain functionality parity with their corresponding client object model APIs, the
endpoints must accept a complex type as a parameter. In these cases, the REST service extends the existing OData protocol to enable these REST endpoints to accept a single complex type
as a parameter. This applies to POST operations only, and you have to pass the complex type in Atom format or JSON format, according to OData standards.
For example, the ListCollection.Add method takes a Microsoft.SharePoint.Client.ListCreationInformation object as a parameter. To add a list to a specified site, construct the
appropriate REST endpoint as follows:
http://server/site/_api/web/lists/add

Next, pass the complex type in the request body, formatted here using JSON.

{ "d" : {
"results": {
"__metadata": {
"type": "SP.ListCreationInformation"
},
"CustomSchemaXml": "…large payload…/",
"Description": "desc",
"DocumentTemplateType": "1",
"TemplateType": "101",
"Title": "Announcements"
}
}
}

Using parameter aliases in REST service calls


You can use the "parameter aliasing" semantic in OData to pass parameters to a SharePoint REST endpoint. In parameter aliasing, the parameter value is identified with an alias in the
parameter call, and the actual value is specified in the query string of the URI. This enables you to support more types of characters and consistent formatting by using the query string.
For example, the following two REST URIs are equivalent:
Specify the parameter value directly:
http://server/site/_api/web/applyWebTemplate("STS#0")

Use a parameter alias, and specify the actual parameter value in the query string of the URI:
http://server/site/_api/web/applyWebTemplate(title=@template)?@template="STS#0"

However, the SharePoint REST service does not support passing complex types via parameter aliasing. For example, the following URI, which contains a complex type in the parameter alias,
is not supported:
http://server/site/_api/userProfiles/People(7)/GetWorkplace(@address)?@address={"__metadata":{"type: "ODataDemo.Address"},"Street":"NE 228th",
"City":"Sammamish","State":"WA","ZipCode":"98074","Country": "USA"}

SharePoint REST service parameter aliasing syntax

Specifying dictionaries as parameter values


For REST endpoints that correspond to methods that take Dictionary<String, String> dictionaries as parameters, pass the dictionary as a series of comma delimited name-value pairs in the
query string.
REST service syntax for Dictionary parameters

A Dictionary<String, object> is represented as a multi-value object, named KeyedPropertyValue, with the following string properties:
Key The key of the multi-value object.
Value The value of the object.
ValueType The value type of the object. For simple value types that map to existing Entity Data Model (EDM) types, the REST service returns the appropriate EDM type string; for
example, "Edm.String." If not, the REST service returns the value type returned by the Type.ToString function.

Specifying parameter values in the query string


If your REST URI terminates in a method call, you can use query string syntax to specify the parameter values of the method. For example:
http://server/site/_api/web/applyWebTemplate?template="STS#0"

The following figure shows the REST service syntax for parameters in the query string.
REST service syntax for parameters in query string

Specify static methods and properties as REST service URIs


To construct URIs that correspond to static methods or properties, use the corresponding API name from the ECMAScript object model, starting with the namespace declaration and using
dot notation. For example, SP.Utilities.Utility.getImageUrl(imageName) in the ECMAScript client object model would have the following REST equivalent:
http://server/site/_api/SP.Utilities.Utility.getImageUrl('imageName')

However, static properties can be accessed only directly, and are not allowed as part of a larger URI composition. For example, directly accessing the SP.Utility.AssetsLibrary method in
REST is allowable, as follows:
http://server/site/_api/SP.Utility.assetsLibrary/id

However, using that resource location as a parameter for a more complex URI, as shown in the following example, is not allowed:
http://server/site/_api/getList(~SP.Utility/assetsLibrary/id)

The following figure shows the SharePoint REST service static member syntax.
SharePoint REST service static member syntax

If you want to select, filter, or order the data you requested from an endpoint, the SharePoint REST service supports a wide range of OData query string operators. For more information, see
Use OData query operations in SharePoint REST requests.

See also
Get to know the SharePoint REST service
REST API reference and samples
Use ETag values through the REST service to get document list item versioning
OData resources
Develop SharePoint Add-ins
Use OData query operations in SharePoint REST requests
5/3/2018 • 4 minutes to read Edit Online

Before you start


Get to know the SharePoint REST service
Navigate the SharePoint data structure represented in the REST service
Determine SharePoint REST service endpoint URIs
The SharePoint REST service supports a wide range of OData query string operators that enable you to select, filter, and order the data you request.
 T IP

The SharePoint Online (and on-premises SharePoint 2016 and later) REST service supports combining multiple requests into a single call to the service by using the OData $batch query
option. For details and links to code samples, see Make batch requests with the REST APIs.

Select fields to return


Use the $select query option to specify which fields to return for a given list, list item, or other SharePoint object represented by an entity set. You can use $select=* to return all available
fields.
NOTE

In general, if you do not specify the $select query option, the REST service returns all available fields by default. However, in a few cases, some SharePoint objects include properties that
are very resource intensive to retrieve; to optimize REST service performance, these properties are not included in the default query, and must be explicitly requested.For example, the
SPWeb.EffectiveBasePermissions property is not returned by default, and must be explicitly requested by using the $select query option.
In addition, you can specify that the request returns projected fields from other lists and the values of lookups. To do this, specify the field name in both the $select and $expand query
options. For example:
http://server/site/_api/web/lists('guid')/items?$select=Title,Products/Name&$expand=Products/Name

Bulk expansion and selection of related items is not supported.

Select items to return


Use the $filter query option to select which items to return. OData query operators supported in the SharePoint REST service lists the filter query comparison options and functions you can
use with the SharePoint REST service.

Query for single value lookup fields


Single value lookup fields are represented by two separate fields in the SharePoint REST service: one field representing the actual field value, and another representing the field name. You
can perform queries against the lookup field value as you would any other field of that data type. For example, if the lookup field value is a string, you can use string comparison options in
your query.

Query for users


In the SharePoint REST service, users are represented by the user's friendly (display) name, and not their alias or domain\alias combination. Therefore, you must construct user queries
against users' friendly names.
NOTE

Membership-based user queries are not supported. Usage of the Current operator to do queries using the ID of the current user is not supported.

Query for multi-value lookup fields and users


Because multi-value lookup fields are returned as a string of multiple values, there is no way to query for them (for example, the equivalent of an Includes element or NotIncludes element
is not supported).

Sort returned items


Use the $orderby query option to specify how to sort the items in your query return set. To sort by multiple fields, specify a comma-separated list of fields. You can also specify whether to
sort the items in ascending or descending order by appending the asc or desc keyword to your query.

Page through returned items


Use the $top and $skiptoken query options to select a subset of the items that would otherwise be returned by your query.
NOTE

The $skip query option does not work with queries for SharePoint list items.
The $top option enables you to select the first n items of the return set for return. For example, the following URI requests that only the first ten items in the prospective return set actually
be returned:
http://server/site/_api/web/lists('<guid>')/items$top=10

The $skiptoken option enables you to skip over items until the specified item is reached and return the rest.
$skiptoken=Paged=TRUE%26p_ID=5

NOTE

When using these query options, take into account that paging in OData is ordinal. For example, suppose you are implementing a next page button to display SharePoint list items. You use
the REST service to enable the button to return items 1 through 20 when clicked, and then items 21 through 40, and so on. However, suppose another user deletes items 4 and 18 between
clicks of the next button. In such a case, the ordinal positioning of the remaining items is reset, and displaying items 21 through 40 actually skips over two items.

OData query operators supported in the SharePoint REST service


S U PPO R TED NO T S U PPO R TED

Numeric comparisons Lt Le Gt Ge Eq Ne Arithmetic operators (Add, Sub, Mul, Div, Mod)


Basic math functions (round, floor, ceiling)

String comparisons startsWith substringof Eq Ne endsWith replace substring tolower toupper trim concat

Date and time functions day() month() year() hour() minute() second() DateTimeRangesOverlap operator
Querying as to whether a date time falls inside a recurrent date time pattern

The following figure shows the supported OData query options.


Supported OData query options

See also
Get to know the SharePoint REST service
OData resources
REST API reference and samples
Develop SharePoint Add-ins
Navigate the SharePoint data structure represented in the REST service
3/26/2018 • 3 minutes to read Edit Online

When you're working with the SharePoint REST service, you'll often start out knowing the URL of a specific SharePoint item, but want to access related items, such as the folder or library
structure where that item resides. For example, suppose you create an add-in where your user enters the URL of a document in a SharePoint library. Your add-in must then break down that
URL to figure out the actual SharePoint site URL. After it's done that, the add-in can then make more requests from the site on the user's behalf, such as to create, update, or delete related
items or resources.
To do this, your add-in needs to query SharePoint for the following information:
The server relative URLs of the site and site collection containing the resource.
A form digest to enable you to perform requests that change the state of the resource, such as POST, PUT, MERGE, and DELETE.

The basic process


1. Use the /contextinfo operator with the given URL to access the site and site collection addresses, and the form digest. Use the /contextinfo operator in the following format:
http://server/web/doclib/forms/_api/contextinfo

To increase security against cross-site scripting attempts, the /contextinfo operator accepts only POST requests.
2. Use the SPContextWebInformation object properties that the /contextinfo operator returns to access additional resources as desired.

Try it
1. Start with a URL to a given SharePoint item. For example:
http://site/web/doclib/myDocument.docx

2. Remove the name of the specific resource from the end of the URL, so that the URL points to a document library, folder, or list. In this case:
http://site/web/doclib/

3. Append the REST service pointer and the /contextinfo operator to the URL:
http://site/web/doclib/_api/contextinfo

4. Read the form digest and webFullUrl properties from the response.
5. Append the REST service pointer _api to the web URL.
6. Use the resulting URL and the form digest to make requests for other resources you need.
You don't have to pass the form digest if you're making GET requests, or making requests using a validated OAuth token.

Navigate parent and child sites


When you navigate your site structure using the SharePoint server object model, you use the SPWeb.ParentWeb and SPWeb.Webs properties to access objects that represent parent and
child sites.
The corresponding REST resources— web/parentweb and web/webs —don't return objects that represent sites. This is because the REST service conforms to OData standards, and returning
complete site representations would make such requests inefficient. Instead, they return a WebInfo object that contains the site's scalar properties, but without related entity sets such as like
collections or field collections.
To navigate to a specific parent or child site, construct the appropriate REST URL to that site by using the Id or Title property. From there, you can access that site's related entity sets.

Navigate folder structure


The SharePoint REST service does not support traversing the folder hierarchy of a site through the URL construction. Instead, use the REST equivalent of the
Web.GetFolderByServerRelativeUrl method. For example:
Navigation not supported through the REST service:
/_vti_bin/client.svc/web/lists/SharedDocuments/folder1/stuff/things/Recycle

Navigation that is supported by the REST service:


/_vti_bin/client.svc/web/GetFolderByServerRelativeUrl('SharedDocuments/folder1/stuff/things')/Recycle

SPContextWebInformation object properties


S PCO NTE X T W EB INFO R MATIO N PR O PER T Y D ES CR IPTIO N

webFullUrl Gets the server-relative URL of the nearest site.

siteFullUrl Gets the server-relative URL of the root of the site collection that the site is contained within.
If the nearest web is the root of a site collection, the value of the webFullUrl property is equal to the
siteFullUrl property.

formDigestValue Gets the server's request form digest.

LibraryVersion Gets the current version of the REST library.

SupportedSchemaVersions Gets the versions of the schema of the REST/CSOM library that are supported.

WebInfo object
W EB INFO PR O PER T Y D ES CR IPTIO N

Created Gets a value that specifies when the site was created.

Description Gets or sets the description for the site.

Id Gets a value that specifies the site identifier.

Language Gets a value that specifies the locale ID (LCID) for the language that is used on the site.

LastItemModifiedDate Gets a value that specifies when an item was last modified on the site.

Title Gets or sets the title for the site.

WebTemplateId Gets the identifier of the site template.

See also
Get to know the SharePoint REST service
REST API reference and samples
Use ETag values through the REST service to get document list item versioning
OData resources
Develop SharePoint Add-ins
Synchronize SharePoint items using the REST service
3/26/2018 • 2 minutes to read Edit Online

If you want to synchronize items between SharePoint and your add-ins or services, you can use the GetListItemChangesSinceToken resource to do so. The
GetListItemChangesSinceToken, part of the SharePoint REST service, corresponds to the Lists.GetListItemChangesSinceToken web service call.
Perform a POST request that includes an SP.ChangeLogItemQuery object properties object in the request body.
The request returns ADO rowset XML, which includes rows corresponding to any list item change matching the specified query. For more information about these properties, including
property data structures, CAML element descriptions, and return values, see Lists.GetListItemChangesSinceToken.

Example
Example request
POST http://server/site/_api/web/Lists/GetByTitle('Announcements')/GetListItemChangesSinceToken

Example POST body

{ 'd' : {
'query': {
'__metadata': { 'type': 'SP.ChangeLogItemQuery'},
'ViewName': '',
'Query': '
<Query>
<Where>
<Contains>
<FieldRef Name="Title" />
<Value Type='Text'>Te</Value>
</Contains></Where>'</Query>,
'QueryOptions': '<QueryOptions>
<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>
<DateInUtc>False</DateInUtc>
<IncludePermissions>TRUE</IncludePermissions>
<IncludeAttachmentUrls>FALSE</IncludeAttachmentUrls>
<Folder>Shared Documents/Test1</Folder></QueryOptions>',
'ChangeToken':'1;3;eee4c6d5-f88a-42c4-8ce1-685122984870;634397182229400000;3710',
'Contains':'<Contains>
<FieldRef Name="Title"/>
<Value Type="Text">Testing</Value></Contains>' }
}
}

SP.ChangeLogItemQuery object properties


PR O PER T Y D ES CR IPTIO N

ListName A string that contains either the title or the GUID for the list. When querying the UserInfo table, the
string contains UserInfo. Using the GUID results in better performance.

ViewName A string that contains the GUID for the view, which determines the view to use for the default view
attributes represented by the query, viewFields, and rowLimit parameters. If this argument is not
supplied, the default view is assumed.

If it is supplied, the value of the query, viewFields, or rowLimit parameter overrides the equivalent
setting within the view.

For example, if the view specified by the viewFields parameter has a row limit of 100 rows, but the
rowLimit parameter contains a value of 1000, then 1,000 rows are returned in the response.

Query A Query element containing the query that determines which records are returned and in what order.

QueryOptions An XML fragment in the following form that contains separate nodes for the various properties of the
SPQuery object.

ChangeToken A string that contains the change token for the request.

For a description of the format that is used in this string, see Overview of the Change Log. If null is
passed, all items in the list are returned.

Contains A Contains element that defines custom filtering for the query.

See also
Get to know the SharePoint REST service
Use ETag values through the REST service to get document list item versioning
REST API reference and samples
OData resources
Develop SharePoint Add-ins
Upload a file by using the REST API and jQuery
4/20/2018 • 8 minutes to read Edit Online

The code examples in this article use the REST interface and jQuery AJAX requests to add a local file to the Documents library, and then change properties of the list item that represents
the uploaded file.
This process uses the following high-level steps:
1. Convert the local file to an array buffer by using the FileReader API, which requires HTML5 support. The jQuery(document).ready function checks for FileReader API support in
the browser.
2. Add the file to the Shared Documents folder by using the Add method on the folder's file collection. The array buffer is passed in the body of the POST request.
These examples use the getfolderbyserverrelativeurl endpoint to reach the file collection, but you can also use a list endpoint (example:
…/_api/web/lists/getbytitle('<list title>')/rootfolder/files/add ).

3. Get the list item that corresponds to the uploaded file by using the ListItemAllFields property of the uploaded file.
4. Change the display name and title of the list item by using a MERGE request.

Running the code examples


Both code examples in this article use the REST API and jQuery AJAX requests to upload a file to the Shared Documents folder and then change list item properties.
The first example uses SP.AppContextSite to make calls across SharePoint domains, like a SharePoint-hosted add-in would do when uploading files to the host web.
The second example makes same-domain calls, like a SharePoint-hosted add-in would do when uploading files to the add-in web, or a solution that's running on the server would do when
uploading files.
NOTE

Provider-hosted add-ins written in JavaScript must use the SP.RequestExecutor cross-domain library to send requests to a SharePoint domain. For an example, see upload a file by using the
cross-domain library.
To use the examples in this article, you'll need the following:
SharePoint Server or SharePoint Online.
Write permissions to the Documents library for the user running the code. If you're developing a SharePoint Add-in, you can specify Write add-in permissions at the List scope.
Browser support for the FileReader API (HTML5).
A reference to the jQuery library in your page markup. For example:

<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js" type="text/javascript"></script>

The following controls in your page markup.

<input id="getFile" type="file"/><br />


<input id="displayName" type="text" value="Enter a unique name" /><br />
<input id="addFileButton" type="button" value="Upload" onclick="uploadFile()"/>

Code example 1: Upload a file across SharePoint domains by using the REST API and jQuery
The following code example uses the SharePoint REST API and jQuery AJAX requests to upload a file to the Documents library and to change properties of the list item that represents the
file. The context for this example is a SharePoint-hosted add-in that uploads a file to a folder on the host web.
You need to meet these requirements to use this example.

'use strict';

var appWebUrl, hostWebUrl;

jQuery(document).ready(function () {

// Check for FileReader API (HTML5) support.


if (!window.FileReader) {
alert('This browser does not support the FileReader API.');
}

// Get the add-in web and host web URLs.


appWebUrl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));
hostWebUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
});

// Upload the file.


// You can upload files up to 2 GB with the REST API.
function uploadFile() {

// Define the folder path for this example.


var serverRelativeUrlToFolder = '/shared documents';

// Get test values from the file input and text input page controls.
// The display name must be unique every time you run the example.
var fileInput = jQuery('#getFile');
var newName = jQuery('#displayName').val();

// Initiate method calls using jQuery promises.


// Get the local file as an array buffer.
var getFile = getFileBuffer();
getFile.done(function (arrayBuffer) {

// Add the file to the SharePoint folder.


var addFile = addFileToFolder(arrayBuffer);
addFile.done(function (file, status, xhr) {
addFile.done(function (file, status, xhr) {

// Get the list item that corresponds to the uploaded file.


var getItem = getListItem(file.d.ListItemAllFields.__deferred.uri);
getItem.done(function (listItem, status, xhr) {

// Change the display name and title of the list item.


var changeItem = updateListItem(listItem.d.__metadata);
changeItem.done(function (data, status, xhr) {
alert('file uploaded and updated');
});
changeItem.fail(onError);
});
getItem.fail(onError);
});
addFile.fail(onError);
});
getFile.fail(onError);

// Get the local file as an array buffer.


function getFileBuffer() {
var deferred = jQuery.Deferred();
var reader = new FileReader();
reader.onloadend = function (e) {
deferred.resolve(e.target.result);
}
reader.onerror = function (e) {
deferred.reject(e.target.error);
}
reader.readAsArrayBuffer(fileInput[0].files[0]);
return deferred.promise();
}

// Add the file to the file collection in the Shared Documents folder.
function addFileToFolder(arrayBuffer) {

// Get the file name from the file input control on the page.
var parts = fileInput[0].value.split('\\');
var fileName = parts[parts.length - 1];

// Construct the endpoint.


var fileCollectionEndpoint = String.format(
"{0}/_api/sp.appcontextsite(@target)/web/getfolderbyserverrelativeurl('{1}')/files" +
"/add(overwrite=true, url='{2}')?@target='{3}'",
appWebUrl, serverRelativeUrlToFolder, fileName, hostWebUrl);

// Send the request and return the response.


// This call returns the SharePoint file.
return jQuery.ajax({
url: fileCollectionEndpoint,
type: "POST",
data: arrayBuffer,
processData: false,
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
"content-length": arrayBuffer.byteLength
}
});
}

// Get the list item that corresponds to the file by calling the file's ListItemAllFields property.
function getListItem(fileListItemUri) {

// Construct the endpoint.


// The list item URI uses the host web, but the cross-domain call is sent to the
// add-in web and specifies the host web as the context site.
fileListItemUri = fileListItemUri.replace(hostWebUrl, '{0}');
fileListItemUri = fileListItemUri.replace('_api/Web', '_api/sp.appcontextsite(@target)/web');

var listItemAllFieldsEndpoint = String.format(fileListItemUri + "?@target='{1}'",


appWebUrl, hostWebUrl);

// Send the request and return the response.


return jQuery.ajax({
url: listItemAllFieldsEndpoint,
type: "GET",
headers: { "accept": "application/json;odata=verbose" }
});
}

// Change the display name and title of the list item.


function updateListItem(itemMetadata) {

// Construct the endpoint.


// Specify the host web as the context site.
var listItemUri = itemMetadata.uri.replace('_api/Web', '_api/sp.appcontextsite(@target)/web');
var listItemEndpoint = String.format(listItemUri + "?@target='{0}'", hostWebUrl);

// Define the list item changes. Use the FileLeafRef property to change the display name.
// For simplicity, also use the name as the title.
// The example gets the list item type from the item's metadata, but you can also get it from the
// ListItemEntityTypeFullName property of the list.
var body = String.format("{{'__metadata':{{'type':'{0}'}},'FileLeafRef':'{1}','Title':'{2}'}}",
itemMetadata.type, newName, newName);

// Send the request and return the promise.


// This call does not return response content from the server.
return jQuery.ajax({
url: listItemEndpoint,
type: "POST",
data: body,
headers: {
"X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
"content-type": "application/json;odata=verbose",
"content-length": body.length,
"content-length": body.length,
"IF-MATCH": itemMetadata.etag,
"X-HTTP-Method": "MERGE"
}
});
}
}

// Display error messages.


function onError(error) {
alert(error.responseText);
}

// Get parameters from the query string.


// For production purposes you may want to use a library to handle the query string.
function getQueryStringParameter(paramToRetrieve) {
var params = document.URL.split("?")[1].split("&amp;");
for (var i = 0; i < params.length; i = i + 1) {
var singleParam = params[i].split("=");
if (singleParam[0] == paramToRetrieve) return singleParam[1];
}
}

Code example 2: Upload a file in the same domain by using the REST API and jQuery
The following code example uses the SharePoint REST API and jQuery AJAX requests to upload a file to the Documents library and to change properties of the list item that represents the
file. The context for this example is a solution that's running on the server. The code would be similar in a SharePoint-hosted add-in that uploads files to the add-in web.
You need to meet these requirements before you can run this example.

'use strict';

jQuery(document).ready(function () {

// Check for FileReader API (HTML5) support.


if (!window.FileReader) {
alert('This browser does not support the FileReader API.');
}
});

// Upload the file.


// You can upload files up to 2 GB with the REST API.
function uploadFile() {

// Define the folder path for this example.


var serverRelativeUrlToFolder = '/shared documents';

// Get test values from the file input and text input page controls.
var fileInput = jQuery('#getFile');
var newName = jQuery('#displayName').val();

// Get the server URL.


var serverUrl = _spPageContextInfo.webAbsoluteUrl;

// Initiate method calls using jQuery promises.


// Get the local file as an array buffer.
var getFile = getFileBuffer();
getFile.done(function (arrayBuffer) {

// Add the file to the SharePoint folder.


var addFile = addFileToFolder(arrayBuffer);
addFile.done(function (file, status, xhr) {

// Get the list item that corresponds to the uploaded file.


var getItem = getListItem(file.d.ListItemAllFields.__deferred.uri);
getItem.done(function (listItem, status, xhr) {

// Change the display name and title of the list item.


var changeItem = updateListItem(listItem.d.__metadata);
changeItem.done(function (data, status, xhr) {
alert('file uploaded and updated');
});
changeItem.fail(onError);
});
getItem.fail(onError);
});
addFile.fail(onError);
});
getFile.fail(onError);

// Get the local file as an array buffer.


function getFileBuffer() {
var deferred = jQuery.Deferred();
var reader = new FileReader();
reader.onloadend = function (e) {
deferred.resolve(e.target.result);
}
reader.onerror = function (e) {
deferred.reject(e.target.error);
}
reader.readAsArrayBuffer(fileInput[0].files[0]);
return deferred.promise();
}

// Add the file to the file collection in the Shared Documents folder.
function addFileToFolder(arrayBuffer) {

// Get the file name from the file input control on the page.
var parts = fileInput[0].value.split('\\');
var fileName = parts[parts.length - 1];
// Construct the endpoint.
var fileCollectionEndpoint = String.format(
"{0}/_api/web/getfolderbyserverrelativeurl('{1}')/files" +
"/add(overwrite=true, url='{2}')",
serverUrl, serverRelativeUrlToFolder, fileName);

// Send the request and return the response.


// This call returns the SharePoint file.
return jQuery.ajax({
url: fileCollectionEndpoint,
type: "POST",
data: arrayBuffer,
processData: false,
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
"content-length": arrayBuffer.byteLength
}
});
}

// Get the list item that corresponds to the file by calling the file's ListItemAllFields property.
function getListItem(fileListItemUri) {

// Send the request and return the response.


return jQuery.ajax({
url: fileListItemUri,
type: "GET",
headers: { "accept": "application/json;odata=verbose" }
});
}

// Change the display name and title of the list item.


function updateListItem(itemMetadata) {

// Define the list item changes. Use the FileLeafRef property to change the display name.
// For simplicity, also use the name as the title.
// The example gets the list item type from the item's metadata, but you can also get it from the
// ListItemEntityTypeFullName property of the list.
var body = String.format("{{'__metadata':{{'type':'{0}'}},'FileLeafRef':'{1}','Title':'{2}'}}",
itemMetadata.type, newName, newName);

// Send the request and return the promise.


// This call does not return response content from the server.
return jQuery.ajax({
url: itemMetadata.uri,
type: "POST",
data: body,
headers: {
"X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
"content-type": "application/json;odata=verbose",
"content-length": body.length,
"IF-MATCH": itemMetadata.etag,
"X-HTTP-Method": "MERGE"
}
});
}
}

// Display error messages.


function onError(error) {
alert(error.responseText);
}

See also
Get to know the SharePoint REST service
Access SharePoint data from add-ins using the cross-domain library
REST API reference and samples
OData resources
Develop SharePoint Add-ins
Set custom permissions on a list by using the REST interface
4/20/2018 • 5 minutes to read Edit Online

SharePoint sites, lists, and list items are types of SecurableObject. By default, a securable object inherits the permissions of its parent. To set custom permissions for an object, you need to
break its inheritance so that it stops inheriting permissions from its parent, and then define new permissions by adding or removing role assignments.
NOTE

See the See also section for links to articles about setting fine-grained permissions.
The code example in this article sets custom permissions on a list, and then changes a group's permissions to it. The example uses the REST interface to:
Get the ID of the target group. The example uses the group ID to get the current role bindings for the group on the list and to add the new role to the list.
Get the ID of the role definition that defines the new permissions for the group. The ID is used to add the new role to the list. This example uses an existing role definition for the new
role, but you can optionally create a new role definition.
Break role inheritance on the list by using the BreakRoleInheritance method. The example breaks role inheritance but keeps the current set of roles. (Alternatively, you can choose not
to copy any role assignments and to add the current user to the Manage permission level.)
Remove the group's current role assignment on the list by sending a DELETE request to the role assignment endpoint. (If you choose not to copy any role assignments, you would skip
this step.)
Add a role assignment for the group to the list by using the AddRoleAssignment method, which binds the group to the role definition and adds the role to the list.

Prerequisites for using the example in this article


To use the example in this article, you'll need:
A SharePoint development environment (app isolation required for on-premises scenarios)
Visual Studio 2012 or Visual Studio 2013 with Office Developer Tools for Visual Studio 2012, or later
You'll also need to set Full Control add-in permissions at the Web scope. Only users who have sufficient permissions to change list permissions (such as site owners) can run this add-in.

Examples: Set custom permissions on a list by using the REST interface


The following examples represent the contents of the App.js file in a SharePoint-hosted add-in. The first example uses the JavaScript cross-domain library to build and send HTTP requests.
The second example uses jQuery AJAX requests.
Before you run the code, replace the placeholder values with actual values. If you're using a different language or environment, you need to add or change some request components. For
more information, see How REST requests differ by environment.

Example 1: Cross-domain library requests


'use strict';

// Change placeholder values before you run this code.


var listTitle = 'List 1';
var groupName = 'Group A';
var targetRoleDefinitionName = 'Contribute';
var appweburl;
var hostweburl;
var executor;
var groupId;
var targetRoleDefinitionId;

$(document).ready( function() {

//Get the URI decoded URLs.


hostweburl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
appweburl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));

// Load the cross-domain library file and continue to the custom code.
var scriptbase = hostweburl + "/_layouts/15/";
$.getScript(scriptbase + "SP.RequestExecutor.js", getTargetGroupId);
});

// Get the ID of the target group.


function getTargetGroupId() {
executor = new SP.RequestExecutor(appweburl);
var endpointUri = appweburl + "/_api/SP.AppContextSite(@target)/web/sitegroups/getbyname('";
endpointUri += groupName + "')/id" + "?@target='" + hostweburl + "'";

executor.executeAsync({
url: endpointUri,
method: 'GET',
headers: { 'accept':'application/json;odata=verbose' },
success: function(responseData) {
var jsonObject = JSON.parse(responseData.body);
groupId = jsonObject.d.Id;
getTargetRoleDefinitionId();
},
error: errorHandler
});
}

// Get the ID of the role definition that defines the permissions


// you want to assign to the group.
function getTargetRoleDefinitionId() {
var endpointUri = appweburl + "/_api/SP.AppContextSite(@target)/web/roledefinitions/getbyname('";
endpointUri += targetRoleDefinitionName + "')/id" + "?@target='" + hostweburl + "'";

executor.executeAsync({
url: endpointUri,
method: 'GET',
headers: { 'accept':'application/json;odata=verbose' },
success: function(responseData) {
var jsonObject = JSON.parse(responseData.body)
targetRoleDefinitionId = jsonObject.d.Id;
breakRoleInheritanceOfList();
},
error: errorHandler
});
}

// Break role inheritance on the list.


function breakRoleInheritanceOfList() {
var endpointUri = appweburl + "/_api/SP.AppContextSite(@target)/web/lists/getbytitle('";
endpointUri += listTitle + "')/breakroleinheritance(true)?@target='" + hostweburl + "'";

executor.executeAsync({
url: endpointUri,
method: 'POST',
headers: { 'X-RequestDigest':$('#__REQUESTDIGEST').val() },
success: deleteCurrentRoleForGroup,
error: errorHandler
});
}

// Remove the current role assignment for the group on the list.
function deleteCurrentRoleForGroup() {
var endpointUri = appweburl + "/_api/SP.AppContextSite(@target)/web/lists/getbytitle('";
endpointUri += listTitle + "')/roleassignments/getbyprincipalid('" + groupId + "')?@target='" + hostweburl + "'";

executor.executeAsync({
url: endpointUri,
method: 'POST',
headers: {
'X-RequestDigest':$('#__REQUESTDIGEST').val(),
'X-HTTP-Method':'DELETE'
},
success: setNewPermissionsForGroup,
error: errorHandler
});
}

// Add the new role assignment for the group on the list.
function setNewPermissionsForGroup() {
var endpointUri = appweburl + "/_api/SP.AppContextSite(@target)/web/lists/getbytitle('";
endpointUri += listTitle + "')/roleassignments/addroleassignment(principalid=" + groupId;
endpointUri += ",roledefid=" + targetRoleDefinitionId + ")?@target='" + hostweburl + "'";

executor.executeAsync({
url: endpointUri,
method: 'POST',
headers: { 'X-RequestDigest':$('#__REQUESTDIGEST').val() },
success: successHandler,
error: errorHandler
});
}

// Get parameters from the query string.


// For production purposes you may want to use a library to handle the query string.
function getQueryStringParameter(paramToRetrieve) {
var params = document.URL.split("?")[1].split("&amp;");
for (var i = 0; i < params.length; i = i + 1) {
var singleParam = params[i].split("=");
if (singleParam[0] == paramToRetrieve) return singleParam[1];
}
}

function successHandler() {
alert('Request succeeded.');
}

function errorHandler(xhr, ajaxOptions, thrownError) {


alert('Request failed: ' + xhr.status + '\n' + thrownError + '\n' + xhr.responseText);
}

Example 2: jQuery AJAX requests


// Change placeholder values before you run this code.
var siteUrl = 'http://server/site';
var listTitle = 'List 1';
var groupName = 'Group A';
var targetRoleDefinitionName = 'Contribute';
var groupId;
var targetRoleDefinitionId;

$(document).ready( function() {
getTargetGroupId();
});

// Get the ID of the target group.


function getTargetGroupId() {
$.ajax({
url: siteUrl + '/_api/web/sitegroups/getbyname(\'' + groupName + '\')/id',
type: 'GET',
headers: { 'accept':'application/json;odata=verbose' },
success: function(responseData) {
groupId = responseData.d.Id;
getTargetRoleDefinitionId();
},
error: errorHandler
});
}

// Get the ID of the role definition that defines the permissions


// you want to assign to the group.
function getTargetRoleDefinitionId() {
$.ajax({
url: siteUrl + '/_api/web/roledefinitions/getbyname(\''
+ targetRoleDefinitionName + '\')/id',
type: 'GET',
headers: { 'accept':'application/json;odata=verbose' },
success: function(responseData) {
targetRoleDefinitionId = responseData.d.Id;
breakRoleInheritanceOfList();
},
error: errorHandler
});
}

// Break role inheritance on the list.


function breakRoleInheritanceOfList() {
$.ajax({
url: siteUrl + '/_api/web/lists/getbytitle(\'' + listTitle
+ '\')/breakroleinheritance(true)',
type: 'POST',
headers: { 'X-RequestDigest':$('#__REQUESTDIGEST').val() },
success: deleteCurrentRoleForGroup,
error: errorHandler
});
}

// Remove the current role assignment for the group on the list.
function deleteCurrentRoleForGroup() {
$.ajax({
url: siteUrl + '/_api/web/lists/getbytitle(\'' + listTitle
+ '\')/roleassignments/getbyprincipalid(' + groupId + ')',
type: 'POST',
headers: {
'X-RequestDigest':$('#__REQUESTDIGEST').val(),
'X-HTTP-Method':'DELETE'
},
success: setNewPermissionsForGroup,
error: errorHandler
});
}

// Add the new role assignment for the group on the list.
function setNewPermissionsForGroup() {
$.ajax({
url: siteUrl + '/_api/web/lists/getbytitle(\'' + listTitle
+ '\')/roleassignments/addroleassignment(principalid='
+ groupId + ',roledefid=' + targetRoleDefinitionId + ')',
type: 'POST',
headers: { 'X-RequestDigest':$('#__REQUESTDIGEST').val() },
success: successHandler,
error: errorHandler
});
}

function successHandler() {
alert('Request succeeded.');
}

function errorHandler(xhr, ajaxOptions, thrownError) {


alert('Request failed: ' + xhr.status + '\n' + thrownError + '\n' + xhr.responseText);
}

See also
Get to know the SharePoint REST service
OData resources
Fine-grained permission reference for SharePoint Server 2013
Best practices for using fine-grained permissions in SharePoint Server 2013
User permissions and permission levels in SharePoint
Develop SharePoint Add-ins
Make batch requests with the REST APIs
3/26/2018 • 2 minutes to read Edit Online

This article describes how you can batch queries and operations against the REST/OData API of Microsoft SharePoint Online (and on-premises SharePoint 2016 and later) and the Files and
folders subset of the Office 365 REST APIs. With this technique you can improve the performance of your add-in by combining many operations into a single request to the server and a
single response back.

Executive summary of the $batch option


SharePoint Online (and on-premises SharePoint 2016 and later) and the Office 365 APIs implement the OData $batch query option, so you can rely on the official documentation for
details about how to use it. (Another option is to see Andrew Connell's blog posts on the subject beginning at Part 1 - SharePoint REST API Batching.)
The following is a reminder of the major points:
The request URL consists of the root service URL and the $batch option; for example, https://fabrikam.sharepoint.com/_api/$batch or
https://fabrikam.office365.com/api/v1.0/me/$batch .

The HTTP request body is MIME type multipart/mixed.


The body of the request is divided into parts that are separated from each other by a boundary string that is specified in the header of the request.
Each part of the body has its own HTTP verb and REST URL, and its own internal body when applicable.
A part can be a read operation (or function invocation), or a ChangeSet of one or more write operations (or function invocations). A ChangeSet is itself a MIME type multipart/mixed
with subparts that contain insert, update, or delete operations.
IM P O R T A N T

At this time, SharePoint and Office 365 APIs do not support "all or nothing" functionality for ChangeSets that have more than one operation within them. If any of the child operations fails,
the others still complete and are not rolled back.

Code samples
Samples of code that uses the $batch query option against the SharePoint REST/OData APIs:
C#: OfficeDev/Core.ODataBatch
JavaScript: andrewconnell/sp-o365-rest

Example requests and responses


The following is an example of a raw HTTP request that batches two GET operations that retrieve the titles of all the items in two different lists.

POST https://fabrikam.sharepoint.com/_api/$batch HTTP/1.1


Authorization: Bearer <access token omitted>
Content-Type: multipart/mixed; boundary=batch_e3b6819b-13c3-43bb-85b2-24b14122fed1
Host: fabrikam.sharepoint.com
Content-Length: 527
Expect: 100-continue

--batch_e3b6819b-13c3-43bb-85b2-24b14122fed1
Content-Type: application/http
Content-Transfer-Encoding: binary

GET https://fabrikam.sharepoint.com/_api/Web/lists/getbytitle('Composed%20Looks')/items?$select=Title HTTP/1.1

--batch_e3b6819b-13c3-43bb-85b2-24b14122fed1
Content-Type: application/http
Content-Transfer-Encoding: binary

GET https://fabrikam.sharepoint.com/_api/Web/lists/getbytitle('User%20Information%20List')/items?$select=Title HTTP/1.1

--batch_e3b6819b-13c3-43bb-85b2-24b14122fed1--

The following is an example of the body of a raw HTTP request that batches a DELETE of a list and a GET of the SharePoint list-of-lists.

POST https://fabrikam.sharepoint.com/_api/$batch HTTP/1.1


Authorization: Bearer <access token omitted>
Content-Type: multipart/mixed; boundary=batch_7ba8d60b-efce-4a2f-b719-60c27cc0e70e
Host: fabrikam.sharepoint.com
Content-Length: 647
Expect: 100-continue

--batch_7ba8d60b-efce-4a2f-b719-60c27cc0e70e
Content-Type: multipart/mixed; boundary=changeset_efb6b37c-a5cd-45cb-8f5f-4d648006e65d

--changeset_efb6b37c-a5cd-45cb-8f5f-4d648006e65d
Content-Type: application/http
Content-Transfer-Encoding: binary

DELETE https://fabrikam.sharepoint.com/_api/Web/lists/getbytitle('OldList') HTTP/1.1


If-Match: "1"

--changeset_efb6b37c-a5cd-45cb-8f5f-4d648006e65d--
--batch_7ba8d60b-efce-4a2f-b719-60c27cc0e70e
Content-Type: application/http
Content-Transfer-Encoding: binary

GET https://fabrikam.sharepoint.com/_api/Web/lists HTTP/1.1

--batch_7ba8d60b-efce-4a2f-b719-60c27cc0e70e--
OData libraries
OData libraries support OData batching for many languages. Following are two examples. For a more complete list, see OData Libraries.
.NET OData library. See especially the ODataBatch* classes.
Datajs library. See especially Batch operations.

See also
Get to know the SharePoint REST service
Develop SharePoint Add-ins
SharePoint Online Migration API
7/6/2018 • 37 minutes to read Edit Online

API Documention
The following API description is based upon use of the SharePoint Client Side Object Model (CSOM). We do recommend using NuGet packages when you reference CSOM in your
solution. You can find latest version of the SharePoint Online CSOM package from the NuGet library using id of Microsoft.SharePointOnline.CSOM .
NOTE

You can find latest version of the SharePoint Online Client Side Object Model from NuGet gallery.

Methods
CreateMigrationJob
This method creates a new migration import job and queues it up for later processing by a separate timer job. The job will consume a well formed (pre-defined format) import package that
is located in the Azure Blob Storage Containers specified in this method. The SL A for migration job processing is be controlled through pre-configured queue and work load throttling
settings, and there is no guaranteed SL A or return time for a submitted job.
Syntax
public Guid CreateMigrationJob(
Guid gWebId,
string azureContainerSourceUri,
string azureContainerManifestUri,
string azureQueueReportUri)

Parameters
G W E B ID

The unique identifier of the destination web targeted for the package import. Addition information and identifiers for the import are specified within the import package itself. This identifier
can be found programmatically by querying the target web using CSOM calls.
A Z U R E C O N T A IN E R S O U R C E U R I

The valid URL including SAS token for accessing the Azure Blob Storage Container which contains the binary files of type block. The SAS token must have been created with only Read and
List permissions or the migration job will fail. The SAS token should at least have a lifetime that starts at from no later than when the job was submitted, until a reasonable time for
successful import to have concluded.
The required permissions are as follows in the Azure Storage API:

(SharedAccessBlobPermissions.Read |
SharedAccessBlobPermissions.List)

Note: The change to enforce Read and List permissions on the SAS token is coming in a future build. Until then it will not be enforced. However, it is a best practice to use these values.
All files in the container must have at least a single snapshot applied to them to ensure that no file modification can occur from the customer during import. Any file that does not have a
snapshot will be skipped during import and an error thrown, although the job will attempt to continue to import. The import pipeline will use the latest snapshot of the file available at the
time of import. The following is an example of code that might be used to create a snapshot on a file after it is uploaded to Azure Blob Storage:

CloudBlockBlob blob = blobContainerObj.GetBlockBlobReference(file);


blob.UploadFromStream(stm);
blob.CreateSnapshot();

NOTE

The change to require and use the latest SnapShots on all files is coming in a future build, and until then will be ignored.
A Z U R E C O N T A IN E R M A N IF E S T U R I

The valid URL including SAS token for accessing the Azure Blob Storage Container which contains the block blobs for the manifest and other package describing XML files. This location will
also be used for the log output. This container cannot be the same as the one used for the azureContainerSourceUri. The SAS token must have been created with only Read, List and Write
permissions or the migration job will fail. The SAS token should at least have a lifetime that starts at from no later than when the job was submitted, until a reasonable time for successful
import to have concluded.
NOTE

The change to enforce Read, List and Write permissions on the SAS token is coming in a future build, and until then will be not be enforced, however it is best practice to use these values. If
an issue arises using a current build, try removing the List permission as a temporary workaround, noting that it will become required soon.
All files in the container must have at least a single snapshot applied to them to ensure that no file modification can occur from the customer during import. Any file that does not have a
snapshot will cause failures during import and errors thrown, potentially failing the entire migration job.
NOTE

The change to require and use the latest SnapShots on all files is coming in a future build. Until then they will be ignored.
A ZU R E QU E U E R E POR TU R I

The valid URL including SAS token for accessing the user provided Azure Queue used for returning notifications of migration job progress. This value can be null if no notification queue will
be used during import. If this value is not null and proper access is granted in the SAS token in this URI, it will be used for real time status update. The SAS token must have been created
with only Add, Read and Update permissions or the migration job will be unable to add events to the queue. The required permissions are as follows in the Azure Storage API:

(SharedAccessQueuePermissions.Add | SharedAccessQueuePermissions.Read | SharedAccessQueuePermissions.Update)

Once accepted, the job ID will be written to the notification queue if it was provided and access is valid. The notification queue can be used for multiple migration jobs at the same time, as
each job will identify itself in values sent back to the notification queue.
Return values
The unique identifier for the migration job is returned if the job is successfully queued, or if unsuccessful, a null value will be returned. The migration job unique identifier can be used to
query the migration job status while it is in the queue or being processed by using the GetMigrationJobStatus method.
Example:
Guid MigrationJobId = TargetSite.CreateMigrationJob(
TargetWebId,
azureContainerSourceUri,
azureContainerManifestUri,
azureQueueReportUri);

GetMigrationJobStatus
This method queries the queue status for the specified migration job. It is an optional check after calling the CreateMigrationJob method. Once the migration job has completed, it will no
longer show up in the queue and the notification queue and/or log output should be checked for detailed status.
Syntax
[ClientNS.ClientCallableMethod]
public SPMigrationJobState GetMigrationJobStatus(Guid MigrationJobId)

Parameters
ID

The unique identifier of the migration job returned from CreateMigrationJob method.
Return values
The migration job status is returned using a SPMigrationJobState object if the job is found in the queue, or if unsuccessful, a value of none (0) will be returned.
Example

SPMigrationJobState CurrentJobState = TargetSite.GetMigrationJobStatus(MigrationJobId);

Enumerations
SPMigrationJobState
SPMigrationJobState is an enumeration that tracks possible major states in the import queue.
Members
MEMB ER NAME D ES CR IPTIO N

None Migration job is currently unknown to the queue, either through completion and removal, or invalid job
identifier. Value=0.

Queued Migration job is currently known by the queue and not being processed. Value=2.

Processing Migration job is currently known by the queue and is being actively processed. Value=4.

Import Package Structure


Package structure is based on a constrained version of the Content Deployment package schema. Documentation for the original full schema can be found at docs.microsoft.com. Until
published on docs.microsoft.com, the constrained structure can be found in this document in the appendix.

X ML FILE S CHEMA FILE D ES CR IPTIO N

ExportSettings.XML DeploymentExportSettings Schema Provides validation for the ExportSettings.XML file exported into the
content migration package. ExportSettings.XML does the following:
- Contains the export settings specified by using the
SPExportSettings class and other classes that are part of the content
migration object model.
- Ensures that the subsequent import process (at the migration
target site) enforces the directives specified in the export settings.
- Maintains a catalog of all objects exported to the migration
package.

LookupListMap.XML DeploymentLookupListMap Schema Provides validation for the LookupListMap.XML file exported into
the content migration package. LookupListMap.XML maintains a
simple lookup list that records SharePoint list item (list item to list
item) references.

Manifest.XML DeploymentManifest Schema Provides validation for the Manifest.xml file that is exported into the
content migration package.Provides a comprehensive manifest
containing listings of both the contents and the structure of the
source site. The migration operation uses the manifest file to
reconstitute the source site and its components when it is imported
to the destination site.

Requirements.XML DeploymentRequirements Schema Provides validation for the Requirements.xml file exported into the
content migration package. Requirements.xml maintains list of
deployment requirements in the form of installation requirements
on the migration target, such as feature definitions, template
versions, Web Part assemblies, language packs, and so forth.

RootObjectMap.XML DeploymentRootObjectMap Schema Provides validation for the RootObjectMap.xml file exported into the
content migration package.RootObjectMap.xml maintains a list of
mappings of secondary (dependent) objects, which allows the
import phase of the migration operation to correctly place the
dependent objects relative to the locations of the root object
mappings.
X ML FILE S CHEMA FILE D ES CR IPTIO N

SystemData.XML DeploymentSystemData Schema Provides validation for the SystemData.xml file exported into the
content migration package.SystemData.xml does the following:
Collects a variety of low-level system data. Records the number and
names of Manifest.xml files (in cases where the migration uses
multiple manifests).

UserGroupMap.XML DeploymentUserGroupMap Schema Provides validation for the UserGroup.xml file exported into the
content migration package. UserGroup.xml maintains a list of users
and user security groups with respect to access security and
permissions.

ViewFormsList.XML DeploymentViewFormsList Schema Provides validation for the ViewFormsList.xml file exported into the
content migration package.ViewFormsList.xml maintains a list of
Web Parts and tracks whether each is a view or form.

Content structure
File content that is referenced within the manifest of the package structure must be stored in either a flat or hierarchical structure within the Azure Blob Store Container defined by the
CreateMigrationJob’s azureContainerSourceUri parameter. For example, import packages generated form a legacy version export will not be hierarchical, and will instead have all files stored
at the root level with a pattern like ########.dat where the # symbols are hexadecimal characters starting at 0 and no file names are repeated within a package. Alternately, a package
generated from a file share can have the source folder hierarchy and file names preserved in the same hierarchy.
The main requirement for the structure is that the FileValue references in the Manifest.XML file must refer to the exact name and physical hierarchy that the content is stored in within the
Azure Blob Store location for import. The destination file names and folder hierarchy from the import operation are not directly related to the physical naming and hierarchy and are instead
defined through the Manifest.XML file.

ExportSettings.XML
The ExportSettings.XML file is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s azureContainerManifestUri parameter. This required file is
validated using the constrained DeploymentExportSettings.XSD, which has some limited changes from current published full 2013 package schema.
The main requirement is that the ExportSettings SiteUrl value must be populated with a URL consistent with the source URL used for the rest of the import package. In the case of file
shares as a source, the URL would be pre-specified to be the source URL in the rest of the package, whereas a package generated through an export operation at a source site would be its
original source site collection URL.

LookupListMap.XML
The LookupListMap.XML file, if included, is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s azureContainerManifestUri parameter. This
optional file is validated using the constrained DeploymentLookupListMap.XSD, which has no change from current published full 2013 package schema.
Since an import package for the pipeline does not include defining fields or views on a list or document library, the LookupListMap.XML file will normally include no child nodes under the
root and as such can also be excluded from the package if not required, although a warning may be logged in this case.

Manifest.XML
All instances of the Manifest.XML file for a package are expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s azureContainerManifestUri
parameter. This required file is validated using the constrained DeploymentManifest.XSD, which has multiple major changes and significant reduction in types from current published full
2013 package schema.
The Manifest.XML is the primary descriptor for metadata within the package, and provides the list/folder/item hierarchy, along with metadata for the items including references back to
users and groups defined in the UserGroupMap.XML file. There may be more than one Manifest.XML file (which can be identified using different file names to uniquely identify them),
and all are found by the import pipeline through references within the SystemData.XML file’s ManifestFile entries.
The main requirements for Manifest.XML to be possible to successfully import through the pipeline is that the Web Id and Document Library ID/List ID be consistent with the target
location. If a Web ID is used which doesn’t match the target location, errors will occur because the parent web for the import operation cannot be found.
Likewise, an incorrect Document Library ID/List ID will prevent the importation into the target Document Library or List. IDs should never be reused within the same site collection, so same
packages should not be imported to the same target site collection regardless of the destination web.
For individual files and folders within the document library or list, their identifiers should be consistent between import events to the same location. Specifically, performing an import of a
package generated form a file share would initially require generating new GUIDs for each file and folder, along with matching GUIDs for the list items that represent them. Therefore,
performing a second import against the same target using the same package would keep the same IDs, but performing a second import against the same target using a new package for the
same content would result in ID conflicts and import errors for all items in conflict.
The initial generated package from a file share is effectively a form of record for the original generated IDs and can potentially be used as a reference for follow up package generation to
prevent ID collisions when unintended, and to allow like IDs to ensure correct overwrite, deletion or move activities.

Requirements.XML
The Requirements.XML file is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s azureContainerManifestUri parameter. This optional file is
validated using the constrained DeploymentRequirements.XSD, which has no change from current published full 2013 package schema.
For file shares this is expected to normally include no child nodes under the root and as such can also be excluded from the package if not required, although a warning will be logged in this
case.

RootObjectMap.XML
The RootObjectMap.XML file is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s azureContainerManifestUri parameter. This required file
is validated using the constrained DeploymentRootObjectMap.XSD, which has some limited changes from current published full 2013 package schema. The most common RootObject
that will be included will be a single object of type List. The Id for this item should be the List Id for the target list, and the ParentWebID should match the Id of the parent target web
containing this list in order for migration to be successful. The Id, WebUrl and Url values of this object must also match the related structure laid out in the Manifest.XML file.

SystemData.XML
The SystemData.XML file is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s azureContainerManifestUri parameter. This required file is
validated using the constrained DeploymentSystemData.XSD, which has no change from current published full 2013 package schema.
The SchemaVersion information is expected to reference the current Build and DatabaseVersion of the target farm, a Version of “15.0.0.0”, and the SiteVersion value is expected to always
match the target site collection UIVersion (i.e. most commonly this will be “15”). Each Manifest.XML file for the package is expected to be listed in this file within the ManifestFile entries.
The SystemObjects that define dependent objects that should remain immutable by the migration code should also be listed here to ensure correct behavior of the import operation. The
following is an example of the common objects in the SystemObjects.XML file from a file share based import, noting that the IDs are expected to be different for each package, and the
URLs may be different.
Table 1: Example SystemData.XML file
<?xml version="1.0" encoding="utf-8"?>
<SystemData xmlns="urn:deployment-systemdata-schema">
<SchemaVersion Version="15.0.0.0" Build="16.0.3111.1200" DatabaseVersion="11552"
SiteVersion="15" />
<ManifestFiles>
<ManifestFile Name="Manifest.xml" />
</ManifestFiles>
<SystemObjects>
<SystemObject Id="34321c39-3254-4bd1-b749-c99e16d1f4ab" Type="Folder"
Url="/personal/username" />
<SystemObject Id="9efb9686-baab-432d-a192-858ac34c073f" Type="Web"
Url="/personal/username" />
<SystemObject Id="e8ec714f-91a0-4c6f-9926-08328c8b3e05" Type="List"
Url="/personal/username/Documents/deleteme2" />
<SystemObject Id="a05e1f95-5712-4cc2-958c-31cf0a2cfb62" Type="List"
Url="/personal/username/_catalog/users" />
</SystemObjects>
<RootWebOnlyLists />
</SystemData>

UserGroupMap.XML
The UserGroupMap.XML file is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s azureContainerManifestUri parameter. This required file is
validated using the constrained DeploymentUserGroupMap.XSD, which has no change from current published full 2013 package schema.
The UserGroupMap.XML file may not contain any User or Group entries but doing so will prevent author or security information from being populated during import and warnings will be
logged in this case. Login and SID values for users must be either adjusted to match the values in SharePoint Online, or if the account no longer should exist can be listed as
IsDeleted = “true” to prevent lookup failures and additional slowdown during the import operation.

ViewFormsList.XML
The ViewForms.XML file, if included, is expected to be at the root of the Azure Blob Store Container defined by the CreateMigrationJob’s azureContainerManifestUri parameter. This
optional file is validated using the constrained DeploymentViewFormsList.XSD, which has no change from current published full 2013 package schema.
Since an import package for the pipeline does not include defining fields or views on a list or document library, the ViewFormsList.XML file will normally include no child nodes under the
root and as such can also be excluded from the package if not required, although a warning may be logged in this case.

Logging
The logs that the import pipeline creates must be easily parsed by machine with a goal of being able to pinpoint when and where failures occur, including errors and warnings, and will tell
the consumer or the ISV where and why the failure occurred. As the import is processed by the import pipeline, the job results are placed into log files at the server side file system.
Upon completion, these logs will be copied to the azureContainerManifestUri location as the SAS token specified in the URI allows write access. The same output logs are also placed at the
“_catalogs/Maintenance Logs” location of the target site collection as a text file. The logs will only be copied to the destination locations once the job has finished and removed from the
queue.
Several log types can be included such as the full import log, along with warning and error files that contain only the subset of import warnings or errors respectively. Log files have unique
datetime and job id stamps to allow each attempted import event to have a unique log for better debugging purposes.  

Changes for those using the "Ship Disk" option


To use the Migration API, you must have a temporary storage container in Azure. When uploading files into the temporary storage, an MD5 is required as a property on every file. However,
when shipping the data on hard drives this MD5 property doesn’t get assigned automatically. As a work around, we have adapted the Migration API to allow the MD5 to be passed for every
file as part of the manifest. This also applies for IV values when encrypting the data.
Since the MD5 is generated at the source instead of at the upload time in Azure, Microsoft can confirm the integrity of the file directly against the source MD5.

What is stored in those Azure Blob Containers?


The Migration API requires the Azure Container for content passing and also for log and queue reporting. It can be split down as a summary as follows:

CO NTENT MANIFES T

Files and folders XML files

There are two new optional parameters in manifest.xml:


MD5Hash
InitializationVector
Preparing the package
The method for calling the migration job doesn’t change; only the package generation needs to be changed.
In the Manifest container one file is named Manifest.xml. There are 2 optional attributes added to the file node: MD5Hash and InitializationVector.
Example:

<File … MD5Hash="CXPP/MWYxY87NjjnLZrFg==" InitializationVector="4WlC5zQK0r9s39LoB2w==" />

Best Practices and Special Mentions


Package size
Even if the API support 15GB files, we recommend package sizes of up to 250 MB OR 250 items (depending which one comes first). If you have one large files larger than that
recommended size limit you should send it in its own package. The same applies to versions; each version counts against the size limit and item count. Additionally all the versions of a file
should be in the same package.
File size
Currently the import pipeline supports individual files of 15 GB maximum size.

Only un-compressed packages are supported


The import pipeline does not support compressed packages. The file content must be stored in a different Azure Storage container from the manifest and related descriptive XML files. This
decision was made to prevent the overhead of processing time on both ends of the migration (to compress and decompress), and also to ease package creation and modification.
Compression of individual files such as into zip archives is supported as long as they are referenced in the import package as the archive itself, not the contents.

API supports import of multiple file versions


Import packages can have references to multiple versions of a file, major and minor, up to regular limits imposed within SharePoint. It is important that each version of that file be included in
the package even if some of the versions already exist in SPO.

API supports preservation of identifiers


The identifiers used within the import package explicitly are used during import to identify content. This allows preservation of existing identifiers for document library contents from a
source environment. However, it also imposes a complexity during import package creation or transformation that mandates that the package explicitly reference the target web and list
identifiers. Content type identifiers, file/folder item GUIDs, and list item integer identifiers are all preserved during import. If incorrect identifiers are specified in the package, import will fail.
Additionally, due to identifier preservation, import events can potentially be done in successive iterations using different packages, allowing items to potentially move in location if their
identifiers have not changed.

This is an overwrite API


The import pipeline does support import of versioning data on files and list item metadata, but as of now if you submit a file and then resubmit the same file with changes the import
process will delete and replace the original and all versions with the ones included in the ones in the current package being imported.

We do not support Active-Active scenario


This means we expect that the target site will remain non-active for users until the migration is over. The source may be kept in a read write state until the final migration event, as a method
of reducing downtime for end users, but once the migration is complete there should be a switch for the users to start using their new SPO destinations and stop using the previous
repository.

Permissions in Azure
To ensure immutability of source blobs, the import pipeline will accept a SAS key with only the Read and List access flags set for the File container. Likewise, the import pipeline requires a
SAS key with Read, List and Write access for the Manifest container so that we can write back log files at the end of the import operation. If these criteria are not met, the pipeline will reject it
during job creation.

All files in Azure must have snapshot created to import successfully


To prevent unintended file modification of the source blobs, the import pipeline will only import files if they have a snapshot created for them within Azure. If they do not, then the import
pipeline will skip the files in this state and throw errors. The import pipeline will use the latest snapshot of the file available at the time of import.

Security and encryption


The import pipeline is using Azure Blob Storage security model as is. This means we will not do any special treatment for those azure containers that would differentiate from any other
azure containers. Additionally, the import pipeline currently does not accept encryption keys for content from the customer. Any encrypted content will be treated as opaque files that
SharePoint may list, but be unable to index, the same as if encrypted files were uploaded through the UI to the environment.

Events and event handlers


The import pipeline allows event handlers to be referenced on list items but doesn’t allow defining event handlers at the list level at this time. The import pipeline does not fire events as
items are imported, so existing event handlers will not fire due to the import event. 

Appendices
Acronyms Defined
ACR O NYM D EFINITIO N

BOT SharePoint server running timer jobs

CDB Content database, containing site collections and content

CFE Content farm front end server

SPO SharePoint Online

ABS Azure Blob Storage

Helpful Resources
SharePoint Online Client Components SDK
Azure Windows Azure SDK for .NET - 2.4
Bulk Creation of OneDrive for Business sites
So you want to programmatically provision personal sites in OneDrive for Business in Office 365
Restrictions and limitations when you sync SharePoint libraries to your computer through OneDrive for Business
Types of files that cannot be added to a list or library

Working with import package security structures


This section covers a brief overview of what is contained within an export package that includes security with regard to permissions. This can allow the system to determine user and group
membership along with roles, and specific assignments (unique permissions set at the object level and its children unless overridden at a deeper child object).

How to interpret the security identifiers in the package files


UserGroup.xml file defines all users and groups within the exported web(s). The items within this file do the following:
User objects include the information about specific users, including identification of a specific security principle as a domain group or not, login, and the base 64 encoded SystemId (SID)
of the security principle.
Group objects include the information about specific groups and the direct membership list of that group.
Owner values on group objects and UserId values on member objects within group objects map to other Id values of other user or group objects respectively.
Table 2: Users and Groups annotated in UserGroupMap
<UserGroupMap xmlns="urn:deployment-usergroupmap-schema">
<Users>
<User Id="1" Name="John Doe" Login="DOMAIN\JDoe" Email="DJoe@contoso.com"
IsDomainGroup="false" IsSiteAdmin="true" SystemId="AQUAAAAAAAUVAAAAXSj1f9U62DVDVOAqToYSAA==" IsDeleted="false" Flags="0" />
<User Id="2" Name="Jane Smith" Login="DOMAIN\JSmith" Email="jsmith@contoso.com"
IsDomainGroup="false" IsSiteAdmin="true" SystemId="AQUAAAAAAAUVAAAAXSj1f9U62DVDVOAqdUwNAA==" IsDeleted="false" Flags="0" />

</Users>
<Groups>
<Group Id="3" Name="Temp Group" Description="A Temp Group" Owner="2"
OwnerIsUser="true"
OnlyAllowMembersViewMembership="true">
<Member UserId="2" />
</Group>
<Group Id="4" Name="Temp Group 2" Description="Another Temp Group" Owner="2"
OwnerIsUser="false" RequestToJoinLeaveEmailSetting="JSmith@contoso.com" OnlyAllowMembersViewMembership="true">
<Member UserId="1" />
<Member UserId="2" />
</Group>

</Groups>
</UserGroupMap>

Manifest.xml contains the metadata about all the content within the exported web(s). The items within this file do the following:
Roles objects include the list of defined roles on the web.
Role objects define the individual role, including ID, internal permissions rights mask flags and display information.
RoleId values define the identifiers of the Role objects.
PermMask values contain the rights mask flags.
RoleAssignments objects include the list of unique permissions (RoleAssignment objects).
RoleAssignment objects include the list of distinct Assignment objects (if any).
Individual RoleAssignment objects contain the actual membership of one distinct user or group and their actual Role.
RoleId values map to the RoleId values of the Role objects.
PrincipalId values map to Id values of user or group objects respectively in UserGroups.xml.
Table 3: Roles and RoleAssignments annotated in manifest
<SPObjects xmlns="urn:deployment-manifest-schema">

<SPObject Id="0b3c1b13-b260-453c-ac8d-8053a537d610" ObjectType="DeploymentRoles"
ParentId="203e30e2-1139-4adf-b545-e74235f105c2" ParentWebId="203e30a2-1139-4acf-b535-e74235f105c2" ParentWebUrl="/teams/temp">
<Roles>
<Role RoleId="1073751825" Title="Test Role" Description="This is a test role"
PermMask="206292717568" Hidden="true" RoleOrder="160" Type="1" />
<Role RoleId="1073751826" Title="Test Role 2" Description="This is another test
role" PermMask="756052856929" Hidden="false" RoleOrder="128" Type="2" />

</Roles>
</SPObject>
<SPObject Id="373ea0ba-107a-4a78-9563-bc642f9ab14d"
ObjectType="DeploymentRoleAssignments" ParentId="203e30e2-1139-4adf-b545-e74235f105c2" ParentWebId="203e30a2-1139-4acf-b535-e74235f105c2" ParentWebUrl="/teams/temp">
<RoleAssignments>
<RoleAssignment ScopeId="ffcab9b9-94ef-4701-e6d9-19a370760e1e"
RoleDefWebId="203e11c2-1139-4abe-b534-e74235f106c2" RoleDefWebUrl="teams/temp" ObjectId="9f743aaf-65f9-473e-0c37-37f147960560" ObjectType="1" ObjectUrl="teams/temp/IWConvertedForms" AnonymousPerm
<RoleAssignment ScopeId="c3f564f3-62cd-4b25-8da4-2da7722402ab"
RoleDefWebId="203e30a2-1139-4acf-b535-e74255e105c2" RoleDefWebUrl="teams/temp" ObjectId="2b9b0a32-51fb-4af8-a218-c90f63fd1de4" ObjectType="1" ObjectUrl="teams/temp/Relationships List" AnonymousPe
<Assignment RoleId="1073751825" PrincipalId="5" />
<Assignment RoleId="1073751825" PrincipalId="6" />
<Assignment RoleId="1073751826" PrincipalId="4" />
<Assignment RoleId="1073751828" PrincipalId="1" />
</RoleAssignment>

</RoleAssignments >
</SPObject>

</SPObjects>

Constrained XSD structures


Included below are the XSD files used for package validation in the import pipeline, when different than the original 2013 full schema which can be found at official SharePoint
documentation.

DeploymentExportSettings.XSD
Table 4: Constrained DeploymentExportSettings.XSD
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema
targetNamespace="urn:deployment-exportsettings-schema"
elementFormDefault="qualified"
xmlns="urn:deployment-exportsettings-schema"
xmlns:mstns="urn:deployment-exportsettings-schema"
xmlns:mstns="urn:deployment-exportsettings-schema"
xmlns:xs="http://www.w3.org/2001/XMLSchema">

<!-- Guid SimpleType definition -->


<xs:simpleType name="Guid">
<xs:restriction base="xs:string"></xs:restriction>
</xs:simpleType>

<!-- Used for SPExportObjects -->


<xs:simpleType name="SPDeploymentObjectType">
<xs:restriction base="xs:string">
<xs:enumeration value="Folder" />
<xs:enumeration value="List" />
<xs:enumeration value="ListItem" />
<xs:enumeration value="File" />
</xs:restriction>
</xs:simpleType>

<!-- Used for SPExportObjects -->


<xs:simpleType name="SPIncludeDescendants">
<xs:restriction base="xs:string">
<xs:enumeration value="None" />
<xs:enumeration value="Content" />
<xs:enumeration value="All" />
</xs:restriction>
</xs:simpleType>

<!-- From SPDeploymentSettings -->


<xs:simpleType name="SPIncludeSecurity">
<xs:restriction base="xs:string">
<xs:enumeration value="None" />
<xs:enumeration value="WssOnly" />
<xs:enumeration value="All" />
</xs:restriction>
</xs:simpleType>

<!-- From SPExportSettings -->


<xs:simpleType name="SPIncludeVersions">
<xs:restriction base="xs:string">
<xs:enumeration value="LastMajor" />
<xs:enumeration value="CurrentVersion" />
<xs:enumeration value="LastMajorAndMinor" />
<xs:enumeration value="All" />
</xs:restriction>
</xs:simpleType>

<!-- From SPExportSettings -->


<xs:simpleType name="SPExportMethodType">
<xs:restriction base="xs:string">
<xs:enumeration value="ExportAll" />
<xs:enumeration value="ExportChanges" />
</xs:restriction>
</xs:simpleType>

<!-- This defines that the XML can contain 0-N instances of the -->
<!-- SPExportObjects element -->
<xs:complexType name="SPExportSettings">
<xs:sequence>
<xs:element
name="ExportObjects" type="SPExportObjectCollection"
minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>

<!-- SPDeploymentSettings -->


<xs:attribute name="SiteUrl" type="xs:string" use="required" />
<xs:attribute name="FileLocation" type="xs:string" />
<xs:attribute name="BaseFileName" type="xs:string" />
<xs:attribute name="IncludeSecurity" type="SPIncludeSecurity" />

<!-- SPExportSettings -->


<xs:attribute name="IncludeVersions" type="SPIncludeVersions" />
<xs:attribute name="ExportMethod" type="SPExportMethodType" />
<xs:attribute name="ExportChangeToken" type="xs:string" />
<xs:attribute name="ExportPublicSchema" type="xs:boolean" default="true" />
<xs:attribute name="ExportFrontEndFileStreams" type="xs:boolean" default="true" />
<xs:attribute name="ExcludeDependencies" type="xs:boolean" />

<xs:anyAttribute namespace="##any" processContents="skip" />


</xs:complexType>

<xs:complexType name="SPExportObjectCollection">
<xs:sequence>
<xs:element
name="DeploymentObject" type="SPExportObject"
minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<xs:complexType name="SPExportObject">
<!-- SPDeploymentObject -->
<xs:attribute name="Id" type="Guid" />
<xs:attribute name="Type" type="SPDeploymentObjectType" />
<xs:attribute name="ParentId" type="Guid" />

<!-- SPExportObject -->


<xs:attribute name="Url" type="xs:string" />
<xs:attribute name="ExcludeChildren" type="xs:boolean" />
<xs:attribute name="IncludeDescendants" type="SPIncludeDescendants" />
<xs:attribute name="ExportChangeToken" type="xs:string" />
</xs:complexType>

<!--This defines that the XML can contain 0-N instances of the ExportSettings element-->
<xs:element name="ExportSettings" type="SPExportSettings" />
</xs:schema>
DeploymentLookupListMap.XSD
There is no change from current published full 2013 package schema.

DeploymentManifest.XSD
T A B LE 5 : C O N S T R A IN E D D E P LO Y M E N T M A N IF E S T. X S D

<?xml version="1.0" encoding="utf-8" ?>


<xs:schema
targetNamespace="urn:deployment-manifest-schema"
elementFormDefault="qualified"
xmlns="urn:deployment-manifest-schema"
xmlns:mstns="urn:deployment-manifest-schema"
xmlns:xs="http://www.w3.org/2001/XMLSchema">

<!-- From CoreDefinitions.xsd -->


<xs:simpleType name="TRUEFALSE">
<xs:restriction base="xs:string">
<xs:enumeration value="TRUE" />
<xs:enumeration value="FALSE" />
<xs:enumeration value="true" />
<xs:enumeration value="false" />
</xs:restriction>
</xs:simpleType>

<!-- Guid SimpleType definition -->


<xs:simpleType name="Guid">
<xs:restriction base="xs:string"></xs:restriction>
</xs:simpleType>

<!-- SPGenericObjectCollection definition -->


<xs:complexType name="SPGenericObjectCollection">
<xs:sequence>
<xs:element name="SPObject" type="SPGenericObject" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<!-- Generic complex Type definition that wraps a Sharepoint top-level element -->
<xs:complexType name="SPGenericObject">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="1">
<xs:element name="List" type="SPList" />
<xs:element name="DocumentLibrary" type="SPDocumentLibrary" />
<xs:element name="ListItem" type="SPListItem" />
<xs:element name="Folder" type="SPFolder" />
<xs:element name="File" type="SPFile" />
<xs:element name="ContentType" type="SPContentType" />
<xs:element name="UserX" type="DeploymentUserX" />
<xs:element name="GroupX" type="DeploymentGroupX" />
<xs:element name="Roles" type="DeploymentRoles" />
<xs:element name="RoleX" type="DeploymentRoleX" />
<xs:element name="RoleAssignments" type="DeploymentRoleAssignments" />
<xs:element name="RoleAssignmentX" type="DeploymentRoleAssignmentX" />
</xs:choice>
</xs:sequence>

<xs:attribute name="ObjectType" type="SPObjectType" />


<xs:attribute name="Id" type="Guid" />
<xs:attribute name="ParentId" type="Guid" />
<xs:attribute name="Name" type="xs:string" />
<xs:attribute name="IsDeleted" type="xs:boolean" />
<xs:attribute name="IsSiteRename" type="xs:boolean" />
<xs:attribute name="ParentWebId" type="Guid" />
<xs:attribute name="ParentWebUrl" type="xs:string" use="optional" />
<xs:attribute name="ContentTypeId" type="xs:string" use ="optional" />
<xs:attribute name="Url" type="xs:string" />
</xs:complexType>

<xs:simpleType name="SPDictionaryEntryValueType">
<xs:restriction base="xs:string">
<xs:enumeration value="String" />
<xs:enumeration value="Integer" />
<xs:enumeration value="Time" />
<xs:enumeration value="StringVector" />
<xs:enumeration value="Boolean" />
<xs:enumeration value="FileSystemTime" />
<xs:enumeration value="IntVector" />
<xs:enumeration value="Double" />
<xs:enumeration value="LongText" />
<xs:enumeration value="Empty" />
</xs:restriction>
</xs:simpleType>

<xs:simpleType name="SPDictionaryEntryAccess">
<xs:restriction base="xs:string">
<xs:enumeration value="ReadOnly" />
<xs:enumeration value="ReadWrite" />
</xs:restriction>
</xs:simpleType>

<!-- Enumeration of all the top-level serialized Sharepoint Types -->


<xs:simpleType name="SPObjectType">
<xs:restriction base="xs:string">
<xs:enumeration value="SPList" />
<xs:enumeration value="SPDocumentLibrary" />
<xs:enumeration value="SPListItem" />
<xs:enumeration value="SPFolder" />
<xs:enumeration value="SPFile" />
<xs:enumeration value="SPContentType" />
<xs:enumeration value="SPDocumentTemplate" />
<xs:enumeration value="DeploymentUserX" />
<xs:enumeration value="DeploymentGroupX" />
<xs:enumeration value="DeploymentRoles" />
<xs:enumeration value="DeploymentRoleX" />
<xs:enumeration value="DeploymentRoleX" />
<xs:enumeration value="DeploymentRoleAssignments" />
<xs:enumeration value="DeploymentRoleAssignmentX" />
</xs:restriction>
</xs:simpleType>

<!-- Enumeration of all the non-top level serialized Sharepoint Types -->
<xs:simpleType name="OtherObjectType">
<xs:restriction base="xs:string">
<xs:enumeration value="SPFileVersion" />
<xs:enumeration value="SPListEvent" />
<xs:enumeration value="SPListItemVersion" />
<xs:enumeration value="SPModerationInfo" />
</xs:restriction>
</xs:simpleType>

<!-- DeploymentRole definition -->


<xs:complexType name="DeploymentRole">
<xs:attribute name="RoleId" type="xs:string" use="required" />
<xs:attribute name="Title" type="xs:string" use="required" />
<xs:attribute name="Description" type="xs:string" use="optional" />
<xs:attribute name="PermMask" type="xs:string" use="required" />
<xs:attribute name="Hidden" type="xs:boolean" use="required" />
<xs:attribute name="RoleOrder" type="xs:string" use="optional" />
<xs:attribute name="Type" type="xs:string" use="optional" />
</xs:complexType>

<!-- DeploymentRoles definition -->


<xs:complexType name="DeploymentRoles">
<xs:sequence>
<xs:element name="Role" type="DeploymentRole" minOccurs="0" maxOccurs="unbounded"
/>
</xs:sequence>
</xs:complexType>

<!-- DeploymentAssignment definition -->


<xs:complexType name="DeploymentAssignment">
<xs:attribute name="RoleId" type="xs:string" use="required" />
<xs:attribute name="PrincipalId" type="xs:string" use="required" />
</xs:complexType>

<!-- DeploymentRoleAssignment Definition -->


<xs:complexType name="DeploymentRoleAssignment">
<xs:sequence>
<xs:element name="Assignment" type="DeploymentAssignment" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>

<xs:attribute name="ScopeId" type="xs:string" use="required" />


<xs:attribute name="RoleDefWebId" type="xs:string" use="required" />
<xs:attribute name="RoleDefWebUrl" type="xs:string" use="required" />
<xs:attribute name="ObjectId" type="xs:string" use="required" />
<xs:attribute name="ObjectType" type="xs:string" use="required" />
<xs:attribute name="ObjectUrl" type="xs:string" use="required" />
<xs:attribute name="AnonymousPermMask" type="xs:string" />
</xs:complexType>

<xs:complexType name="DeploymentRoleAssignments">
<xs:sequence>
<xs:element name="RoleAssignment" type="DeploymentRoleAssignment" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<!-- SPProperty definition -->


<xs:complexType name="DictionaryEntry">
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="Value" type="xs:string" use="optional" />
<xs:attribute name="Value2" type="xs:string" use="optional" />
<xs:attribute name="Id" type="Guid" use="optional" />
<xs:attribute name="Type" type="SPDictionaryEntryValueType" default="String"
use="optional" />
<xs:attribute name="Access" type="SPDictionaryEntryAccess" default="ReadWrite"
use="optional" />
</xs:complexType>

<!-- Dictionary definition -->


<xs:complexType name="Dictionary">
<xs:sequence>
<xs:element name="Property" type="DictionaryEntry" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<!-- SPAttachment definition -->


<xs:complexType name="SPAttachment">
<xs:sequence>
<xs:element name="Properties" type="Dictionary" minOccurs="0" />
</xs:sequence>

<xs:attribute name="Name" type="xs:string" />


<xs:attribute name="DirName" type="xs:string" />
<xs:attribute name="Url" type="xs:string" />
<xs:attribute name="Id" type="Guid" />
<xs:attribute name="ParentWebId" type="Guid" />

<!-- Map to file on disk -->


<xs:attribute name="FileValue" type="xs:string" />

<xs:attribute name="MetaInfo" type="xs:string" use="optional" />

<xs:attribute name="Author" type="xs:string" use="optional" />


<xs:attribute name="ModifiedBy" type="xs:string" use="optional" />
<xs:attribute name="TimeCreated" type="xs:dateTime" use="optional" />
<xs:attribute name="TimeLastModified" type="xs:dateTime" use="optional" />
<!-- Case where it fails at export time but too late to ignore -->
<xs:attribute name="FailureMessage" type="xs:string" use="optional" />
</xs:complexType>

<!-- SPAttachmentCollection definition -->


<xs:complexType name="SPAttachmentCollection">
<xs:sequence>
<xs:element name="Attachment" type="SPAttachment" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<!-- SPLink definition -->


<xs:complexType name="SPLink">
<xs:sequence></xs:sequence>
<xs:attribute name="TargetId" type="Guid" use="required" />
<xs:attribute name="TargetUrl" type="xs:string" use="required" />
<xs:attribute name="IsDirty" type="xs:boolean" use="required" />
<xs:attribute name="WebPartId" type="Guid" use="optional" />
<xs:attribute name="LinkNumber" type="xs:int" use="optional" />
<xs:attribute name="Type" type="xs:unsignedByte" use="optional" />
<xs:attribute name="Security" type="xs:unsignedByte" use="optional" />
<xs:attribute name="Dynamic" type="xs:unsignedByte" use="optional" />
<xs:attribute name="ServerRel" type="xs:boolean" use="optional" />
<xs:attribute name="Level" type="xs:unsignedByte" use="optional" />
<xs:attribute name="Search" type="xs:string" use="optional" />
</xs:complexType>

<!-- SPLinkCollection definition -->


<xs:complexType name="SPLinkCollection">
<xs:sequence>
<xs:element name="Link" type="SPLink" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<!-- AnonymousState definition -->


<xs:simpleType name="AnonymousState">
<xs:restriction base="xs:string">
<xs:enumeration value="Disabled" />
<xs:enumeration value="Enabled" />
<xs:enumeration value="On" />
</xs:restriction>
</xs:simpleType>

<!-- SPModerationStatusType definition -->


<xs:simpleType name="SPModerationStatusType">
<xs:restriction base="xs:string">
<xs:enumeration value="Approved" />
<xs:enumeration value="Denied" />
<xs:enumeration value="Pending" />
<xs:enumeration value="Draft" />
<xs:enumeration value="Scheduled" />
</xs:restriction>
</xs:simpleType>

<!-- SPModerationInformation definition -->


<xs:complexType name="SPModerationInformation">
<xs:attribute name="Comment" type="xs:string" />
<xs:attribute name="ModerationStatus" type="SPModerationStatusType" />
</xs:complexType>

<!-- SPBaseType definition -->


<xs:simpleType name="SPBaseType">
<xs:restriction base="xs:string">
<xs:enumeration value="UnspecifiedBaseType" />
<xs:enumeration value="GenericList" />
<xs:enumeration value="DocumentLibrary" />
<xs:enumeration value="Unused" />
<xs:enumeration value="DiscussionBoard" />
<xs:enumeration value="Survey" />
<xs:enumeration value="Issue" />
</xs:restriction>
</xs:simpleType>

<!-- SPListTemplateType definition -->


<xs:simpleType name="SPListTemplateType">
<xs:restriction base="xs:string"></xs:restriction>
</xs:simpleType>

<!-- DraftVisibilityType definition -->


<xs:simpleType name="DraftVisibilityType">
<xs:restriction base="xs:string">
<xs:enumeration value="Reader" />
<xs:enumeration value="Author" />
<xs:enumeration value="Approver" />
</xs:restriction>
</xs:simpleType>

<!-- SPEventHostType definition -->


<xs:simpleType name="SPEventHostType">
<xs:restriction base="xs:string">
<xs:enumeration value="Site" />
<xs:enumeration value="Web" />
<xs:enumeration value="List" />
<xs:enumeration value="ListItem" />
<xs:enumeration value="ContentType" />
<xs:enumeration value="Feature" />
</xs:restriction>
</xs:simpleType>

<!-- SPEventReceiverSynchronization definition -->


<xs:simpleType name="SPEventReceiverSynchronization">
<xs:restriction base="xs:string">
<xs:enumeration value="Default" />
<xs:enumeration value="Synchronous" />
<xs:enumeration value="Asynchronous" />
</xs:restriction>
</xs:simpleType>

<!-- SPEventReceiverType definition -->


<xs:simpleType name="SPEventReceiverType">
<xs:restriction base="xs:string">
<xs:enumeration value="ItemAdding" />
<xs:enumeration value="ItemUpdating" />
<xs:enumeration value="ItemDeleting" />
<xs:enumeration value="ItemCheckingIn" />
<xs:enumeration value="ItemCheckingOut" />
<xs:enumeration value="ItemUncheckingOut" />
<xs:enumeration value="ItemAttachmentAdding" />
<xs:enumeration value="ItemAttachmentDeleting" />
<xs:enumeration value="ItemFileMoving" />
<xs:enumeration value="ItemVersionDeleting" />
<xs:enumeration value="FieldAdding" />
<xs:enumeration value="FieldUpdating" />
<xs:enumeration value="FieldDeleting" />
<xs:enumeration value="ListAdding" />
<xs:enumeration value="ListDeleting" />
<xs:enumeration value="SiteDeleting" />
<xs:enumeration value="WebDeleting" />
<xs:enumeration value="WebMoving" />
<xs:enumeration value="WebAdding" />
<xs:enumeration value="GroupAdding" />
<xs:enumeration value="GroupUpdating" />
<xs:enumeration value="GroupDeleting" />
<xs:enumeration value="GroupUserAdding" />
<xs:enumeration value="GroupUserDeleting" />
<xs:enumeration value="RoleDefinitionAdding" />
<xs:enumeration value="RoleDefinitionUpdating" />
<xs:enumeration value="RoleDefinitionDeleting" />
<xs:enumeration value="RoleAssignmentAdding" />
<xs:enumeration value="RoleAssignmentDeleting" />
<xs:enumeration value="InheritanceBreaking" />
<xs:enumeration value="InheritanceResetting" />
<xs:enumeration value="ItemAdded" />
<xs:enumeration value="ItemUpdated" />
<xs:enumeration value="ItemDeleted" />
<xs:enumeration value="ItemCheckedIn" />
<xs:enumeration value="ItemCheckedOut" />
<xs:enumeration value="ItemUncheckedOut" />
<xs:enumeration value="ItemAttachmentAdded" />
<xs:enumeration value="ItemAttachmentDeleted" />
<xs:enumeration value="ItemFileMoved" />
<xs:enumeration value="ItemFileConverted" />
<xs:enumeration value="ItemFileTransformed" />
<xs:enumeration value="ItemVersionDeleted" />
<xs:enumeration value="FieldAdded" />
<xs:enumeration value="FieldUpdated" />
<xs:enumeration value="FieldDeleted" />
<xs:enumeration value="ListAdded" />
<xs:enumeration value="ListDeleted" />
<xs:enumeration value="SiteDeleted" />
<xs:enumeration value="WebDeleted" />
<xs:enumeration value="WebMoved" />
<xs:enumeration value="WebProvisioned" />
<xs:enumeration value="WebRestored" />
<xs:enumeration value="GroupAdded" />
<xs:enumeration value="GroupUpdated" />
<xs:enumeration value="GroupDeleted" />
<xs:enumeration value="GroupUserAdded" />
<xs:enumeration value="GroupUserDeleted" />
<xs:enumeration value="RoleDefinitionAdded" />
<xs:enumeration value="RoleDefinitionUpdated" />
<xs:enumeration value="RoleDefinitionDeleted" />
<xs:enumeration value="RoleAssignmentAdded" />
<xs:enumeration value="RoleAssignmentDeleted" />
<xs:enumeration value="InheritanceBroken" />
<xs:enumeration value="InheritanceReset" />
<xs:enumeration value="EmailReceived" />
<xs:enumeration value="ContextEvent" />
<xs:enumeration value="InvalidReceiver" />
<xs:enumeration value="WorkflowCompleted" />
</xs:restriction>
</xs:simpleType>

<xs:simpleType name="DefaultItemOpen">
<xs:restriction base="xs:string">
<xs:enumeration value="Browser" />
<xs:enumeration value="PreferClient" />
</xs:restriction>
</xs:simpleType>

<!-- SPList definition -->


<xs:complexType name="SPList">
<xs:sequence >
<xs:choice minOccurs="0" maxOccurs="11">
<xs:element name="ContentTypes" type="SPContentTypeCollection" minOccurs="0"
maxOccurs="1" />
<xs:element name="DeletedContentTypes" type="ListDeletedContentTypes"
minOccurs="0" maxOccurs="1" />
</xs:choice>
</xs:sequence>

<xs:attribute name="Id" type="Guid" use="required" />


<xs:attribute name="Title" type="xs:string" use="required" />

<xs:attribute name="RootFolderId" type="Guid" />


<xs:attribute name="RootFolderUrl" type="xs:string" use="required" />
<xs:attribute name="ParentWebId" type="Guid" use="required" />
<xs:attribute name="ParentWebUrl" type="xs:string" use="optional" />

<xs:attribute name="BaseType" type="SPBaseType" />


<xs:attribute name="BaseType" type="SPBaseType" />
<xs:attribute name="BaseTemplate" type="SPListTemplateType" use="required" />
</xs:complexType>

<xs:complexType name="SPFieldCollection" mixed="true">


<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="FieldRef" type="SPFieldLink" minOccurs="0" maxOccurs="unbounded"
/>
<xs:element name="Field" type="SPField" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<xs:complexType name="SPField">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any"
processContents="skip" />
</xs:sequence>
<xs:attribute name="ID" type="Guid" />
<xs:attribute name="FieldId" type="Guid" use="optional" />
<xs:attribute name="Name" type="xs:string" />
<xs:attribute name="Value" type="xs:string" />
<xs:attribute name="DisplayName" type="xs:string" />
<xs:attribute name="RowOrdinal" type="xs:int" />
<xs:attribute name="RowOrdinal2" type="xs:int" use="optional" />
<xs:attribute name="Type" type="xs:string" />
<xs:attribute name="ColName" type="xs:string" />
<xs:attribute name="ColName2" type="xs:string" use="optional" />
<xs:attribute name="Title" type="xs:string" use="optional" />
<xs:attribute name="Description" type="xs:string" use="optional" />
<xs:attribute name="DefaultValue" type="xs:string" use="optional" />
<xs:attribute name="DefaultFormula" type="xs:string" use="optional" />
<xs:attribute name="FromBaseType" type="xs:string" use="optional" />
<xs:attribute name="Sealed" type="xs:string" />
<xs:attribute name="CanToggleHidden" type="xs:string" use="optional" />
<xs:attribute name="DisplaySize" type="xs:string" use="optional" />
<xs:attribute name="Required" type="xs:string" use="optional" />
<xs:attribute name="ReadOnly" type="xs:string" use="optional" />
<xs:attribute name="Hidden" type="xs:string" use="optional" />
<xs:attribute name="Direction" type="xs:string" use="optional" />
<xs:attribute name="IMEMode" type="xs:string" use="optional" />
<xs:attribute name="SortableBySchema" type="xs:string" use="optional" />
<xs:attribute name="Sortable" type="xs:string" use="optional" />
<xs:attribute name="FilterableBySchema" type="xs:string" use="optional" />
<xs:attribute name="Filterable" type="xs:string" use="optional" />
<xs:attribute name="FilterableNoRecurrenceBySchema" type="xs:string" use="optional" />
<xs:attribute name="FilterableNoRecurrence" type="xs:string" use="optional" />
<xs:attribute name="Reorderable" type="xs:string" use="optional" />
<xs:attribute name="Format" type="xs:string" use="optional" />
<xs:attribute name="FillInChoice" type="xs:string" use="optional" />
<xs:attribute name="SchemaXml" type="xs:string" use="optional" />
<xs:attribute name="JSLink" type="xs:string" use="optional" />
<xs:attribute name="CAMLRendering" type="xs:string" use="optional" />
<xs:attribute name="ServerRender" type="xs:string" use="optional" />
<xs:attribute name="ListItemMenu" type="xs:string" use="optional" />
<xs:attribute name="ListItemMenuAllowed" type="xs:string" use="optional" />
<xs:attribute name="LinkToItem" type="xs:string" use="optional" />
<xs:attribute name="LinkToItemAllowed" type="xs:string" use="optional" />
<xs:attribute name="CalloutMenu" type="xs:string" use="optional" />
<xs:attribute name="CalloutMenuAllowed" type="xs:string" use="optional" />
<!-- Label definition -->
<xs:attribute name="ListDefaultCompliancetagWrittenTime" type="xs:dateTime" use="optional" />
<xs:attribute name="ListDefaultComplianceTagUserId" type="xs:int" use="optional" />
<!-- ListDefaultComplianceFlags is a Flags dependes on the Label, if the Label has Keep or KeepAndDelete ( that will have the 0x01 bit set). If the Label is a record label, that will have
<xs:attribute name="ListDefaultComplianceFlags" type="xs:int" use="optional" />
<xs:attribute name="ListDefaultComplianceTag" type="xs:string" use="optional" />
<!-- end of Label definition -->
<xs:anyAttribute namespace="##any" processContents="skip" />
</xs:complexType>

<!-- FieldDataCollection definition -->


<xs:complexType name="FieldDataCollection">
<xs:sequence>
<xs:element name="Field" type="DictionaryEntry" minOccurs="0" maxOccurs="unbounded"
/>
</xs:sequence>
</xs:complexType>

<!-- SPEventReceiverDefinitionCollection definition -->


<xs:complexType name="SPEventReceiverDefinitionCollection">
<xs:sequence>
<xs:element name="EventReceiver" type="SPEventReceiverDefinition" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<!-- SPEventReceiverDefinition definition -->


<xs:complexType name="SPEventReceiverDefinition">
<xs:attribute name="Id" type="Guid" use="required" />
<xs:attribute name="Name" type="xs:string" use="required" />
<xs:attribute name="WebId" type="Guid" use="required" />
<xs:attribute name="HostId" type="Guid" use="required" />
<xs:attribute name="HostType" type="SPEventHostType" use="required" />
<xs:attribute name="Synchronization" type="SPEventReceiverSynchronization"
use="optional" />
<xs:attribute name="Type" type="SPEventReceiverType" use="required" />
<xs:attribute name="SequenceNumber" type="xs:int" use="required" />
<xs:attribute name="Url" type="xs:string" use="optional" />
<xs:attribute name="Assembly" type="xs:string" use="optional" />
<xs:attribute name="Class" type="xs:string" use="optional" />
<xs:attribute name="SolutionId" type="Guid" use="optional" />
<xs:attribute name="Data" type="xs:string" use="optional" />
<xs:attribute name="Filter" type="xs:string" use="optional" />
<xs:attribute name="Credential" type="xs:int" use="optional" />
<xs:attribute name="ItemId" type="xs:int" use="optional" />
</xs:complexType>
<!-- ListDeletedContentTypes definition -->
<xs:complexType name="ListDeletedContentTypes">
<xs:sequence>
<xs:element name="DeletedContentType" type="DeletedContentType" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<!-- DeletedContentType definition -->


<xs:complexType name="DeletedContentType">
<xs:attribute name="ContentTypeId" type="xs:string" use="required" />
</xs:complexType>

<!-- SPDocumentLibrary definition -->


<xs:complexType name="SPDocumentLibrary">
<xs:complexContent>
<xs:extension base="SPList">
<xs:attribute name="DocumentTemplateUrl" type="xs:string" />
<xs:attribute name="IsCatalog" type="xs:boolean" />
<xs:attribute name="ThumbnailSize" type="xs:int" />
<xs:attribute name="WebImageHeight" type="xs:int" />
<xs:attribute name="WebImageWidth" type="xs:int" />
</xs:extension>
</xs:complexContent>
</xs:complexType>

<!-- SPFolder definition -->


<xs:complexType name="SPFolder">
<xs:sequence>
<xs:element name="Properties" type="Dictionary" minOccurs="0" />
</xs:sequence>
<xs:attribute name="Id" type="Guid" />
<xs:attribute name="Name" type="xs:string" />
<xs:attribute name="Url" type="xs:string" />
<xs:attribute name="ParentFolderId" type="Guid" />
<xs:attribute name="ParentWebId" type="Guid" />
<xs:attribute name="ParentWebUrl" type="xs:string" use="optional" />
<xs:attribute name="ContainingDocumentLibrary" type="Guid" />
<xs:attribute name="WelcomePageUrl" type="xs:string" use="optional" />
<xs:attribute name="WelcomePageParameters" type="xs:string" use="optional" />
<xs:attribute name="ListItemIntId" type="xs:int" use="optional" />
<xs:attribute name="Author" type="xs:string" use="optional" />
<xs:attribute name="ModifiedBy" type="xs:string" use="optional" />
<xs:attribute name="TimeCreated" type="xs:dateTime" use="optional" />
<xs:attribute name="TimeLastModified" type="xs:dateTime" use="optional" />
<xs:attribute name="ProgId" type="xs:string" use="optional" />
<xs:attribute name="SortBehavior" type="xs:string" use="optional" />
</xs:complexType>

<!-- SPFileVersion Collection definition -->


<xs:complexType name="SPFileVersionCollection">
<xs:sequence>
<xs:element name="File" type="SPFile" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<!-- SPListItemVersion Collection definition -->


<xs:complexType name="SPListItemVersionCollection">
<xs:sequence>
<xs:element name="ListItem" type="SPListItem" minOccurs="1" maxOccurs="unbounded"
/>
</xs:sequence>
</xs:complexType>

<!-- SPFileVersionEvent Collection definition -->


<xs:complexType name="SPFileVersionEventCollection">
<xs:sequence>
<xs:element name="VersionEvent" type="SPFileVersionEvent" minOccurs="1"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<xs:complexType name="SPFileVersionEvent">
<xs:attribute name="Id" type="xs:int" />
<xs:attribute name="UIVersion" type="xs:int" />
<xs:attribute name="Type" type="xs:int" />
<xs:attribute name="Time" type="xs:dateTime" />
<xs:attribute name="UserId" type="xs:int" />
</xs:complexType>

<!-- SPFile definition -->


<xs:complexType name="SPFile">
<xs:sequence>
<xs:element name="Properties" type="Dictionary" minOccurs="0" />
<xs:element name="Versions" type="SPFileVersionCollection" minOccurs="0"
maxOccurs="1" />
<xs:element name="Links" type="SPLinkCollection" minOccurs="0" maxOccurs="1" />
<xs:element name="EventReceivers" type="SPEventReceiverDefinitionCollection"
minOccurs="0" maxOccurs="1" />
<xs:element name="VersionEvents" type="SPFileVersionEventCollection" minOccurs="0"
maxOccurs="1" />
</xs:sequence>

<xs:attribute name="Name" type="xs:string" />


<xs:attribute name="Id" type="Guid" />
<xs:attribute name="Url" type="xs:string" />
<xs:attribute name="ListItemIntId" type="xs:int" />
<xs:attribute name="InDocumentLibrary" type="xs:boolean" />

<xs:attribute name="ParentWebId" type="Guid" />


<xs:attribute name="ParentWebUrl" type="xs:string" />

<xs:attribute name="ParentId" type="Guid" />


<xs:attribute name="ListId" type="Guid" use="optional" />
<!-- Map to file on disk -->
<xs:attribute name="FileValue" type="xs:string" use="optional" />

<xs:attribute name="CheckinComment" type="xs:string" use="optional" />


<xs:attribute name="Version" type="xs:string" use="optional" default="1.0" />

<xs:attribute name="Author" type="xs:string" use="optional" />


<xs:attribute name="ModifiedBy" type="xs:string" use="optional" />
<xs:attribute name="TimeCreated" type="xs:dateTime" use="optional" />
<xs:attribute name="TimeLastModified" type="xs:dateTime" use="optional" />

<!-- Case where it fails at export time but too late to ignore -->
<xs:attribute name="FailureMessage" type="xs:string" use="optional" />

<!-- Setup Path Information -->


<xs:attribute name="IsGhosted" type="xs:boolean" use="optional" />
<xs:attribute name="SetupPath" type="xs:string" use="optional" />
<xs:attribute name="SetupPathUser" type="xs:string" use="optional" />
<!-- Use: 2, 3, 4 OR 15 -->
<xs:attribute name="SetupPathVersion" type="xs:byte" default="15" />

<xs:anyAttribute namespace="##any" processContents="skip" />


</xs:complexType>

<!-- Doc Type of List Item -->


<xs:simpleType name="ListItemDocType">
<xs:restriction base="xs:string">
<xs:enumeration value="File" />
<xs:enumeration value="Folder" />
<xs:enumeration value="Unknown" />
</xs:restriction>
</xs:simpleType>

<!-- SPListItem definition -->


<xs:complexType name="SPListItem">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="5">
<xs:element name="Fields" type="SPFieldCollection" minOccurs="0" maxOccurs="1"
/>
<xs:element name="Versions" type="SPListItemVersionCollection" minOccurs="0"
maxOccurs="1" />
<xs:element name="Attachments" type="SPAttachmentCollection" minOccurs="0"
maxOccurs="1" />
<xs:element name="Links" type="SPLinkCollection" minOccurs="0" maxOccurs="1" />
<xs:element name="EventReceivers" type="SPEventReceiverDefinitionCollection"
minOccurs="0" maxOccurs="1" />
</xs:choice>
</xs:sequence>

<xs:attribute name="Name" type="xs:string" />


<xs:attribute name="DirName" type="xs:string" />
<xs:attribute name="FileUrl" type="xs:string" use="optional" />
<xs:attribute name="Version" type="xs:string" use="optional" default="1.0" />
<xs:attribute name="Id" type="Guid" />
<xs:attribute name="IntId" type="xs:int" />
<xs:attribute name="DocId" type="Guid" use="optional" />

<xs:attribute name="Author" type="xs:string" use="optional" />


<xs:attribute name="ModifiedBy" type="xs:string" use="optional" />
<xs:attribute name="TimeCreated" type="xs:dateTime" use="optional" />
<xs:attribute name="TimeLastModified" type="xs:dateTime" use="optional" />

<xs:attribute name="ParentWebId" type="Guid" />


<xs:attribute name="ParentListId" type="Guid" />
<xs:attribute name="ParentFolderId" type="Guid" use="optional" />

<xs:attribute name="ModerationStatus" type="SPModerationStatusType" use="optional" />


<xs:attribute name="ModerationComment" type="xs:string" use="optional" />
<xs:attribute name="ContentTypeId" type="xs:string" />
<xs:attribute name="ProgId" type="xs:string" use="optional" />
<xs:attribute name="Order" type="xs:float" use="optional" />
<xs:attribute name="ThreadIndex" type="xs:string" use="optional" />
<xs:attribute name="UserSolutionActivated" type="xs:boolean" use="optional" />
<xs:attribute name="DocType" type="ListItemDocType" default="File" />

<!-- UserInfo -->


<xs:attribute name="UserLoginName" type="xs:string" use="optional" />
<xs:attribute name="GroupName" type="xs:string" use="optional" />

<!-- Case where it fails at export time but too late to ignore -->
<xs:attribute name="FailureMessage" type="xs:string" use="optional" />

<xs:anyAttribute namespace="##any" processContents="skip" />


</xs:complexType>

<xs:complexType name="SPFieldLink">
<xs:attribute name="Name" type="xs:string" />
<xs:attribute name="ID" type="Guid" use="optional" />
<xs:attribute name="Customization" type="xs:string" use="optional" />
<xs:attribute name="Default" type="xs:string" use="optional" />
<xs:attribute name="ColName" type="xs:string" use="optional" />
<xs:attribute name="ColName2" type="xs:string" use="optional" />
<xs:attribute name="RowOrdinal" type="xs:int" use="optional" />
<xs:attribute name="RowOrdinal2" type="xs:int" use="optional" />

<xs:attribute name="Hidden" type="TRUEFALSE" use="optional" />


<xs:attribute name="Required" type="TRUEFALSE" use="optional" />
<xs:attribute name="Explicit" type="xs:string" use="optional" />
<xs:attribute name="ShowInNewForm" type="xs:string" use="optional" />
<xs:attribute name="ShowInEditForm" type="xs:string" use="optional" />
<xs:attribute name="DisplayName" type="xs:string" use="optional" />
<xs:attribute name="Node" type="xs:string" use="optional" />

<xs:anyAttribute namespace="##any" processContents="skip" />


</xs:complexType>
<xs:complexType name="SPXmlDocumentCollection">
<xs:sequence >
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any"
processContents="skip" />
</xs:sequence>
<xs:anyAttribute namespace="##any" processContents="skip" />
</xs:complexType>

<xs:complexType name="SPContentType">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any"
processContents="skip" />
</xs:sequence>

<xs:attribute name="ID" type="Guid" />


<xs:attribute name="Name" type="xs:string" />
<xs:attribute name="Scope" type="xs:string" />
<xs:attribute name="NextChildByte" type="xs:short" />
<xs:attribute name="ParentWebId" type="Guid" />
<xs:attribute name="ListId" type="Guid" use="optional" />
<xs:attribute name="Description" type="xs:string" use="optional" />
<xs:attribute name="Hidden" type="TRUEFALSE" use="optional" />
<xs:attribute name="ReadOnly" type="TRUEFALSE" use="optional" />
<xs:attribute name="Group" type="xs:string" use="optional" />
<xs:attribute name="PushDownChanges" type="xs:boolean" use="optional" />
<xs:attribute name="RequireClientRenderingOnNew" type="xs:string" use="optional" />

<xs:anyAttribute namespace="##any" processContents="skip" />


</xs:complexType>

<xs:complexType name="SPContentTypeRef">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any"
processContents="skip" />
</xs:sequence>

<xs:attribute name="ID" type="Guid" />

<xs:anyAttribute namespace="##any" processContents="skip" />


</xs:complexType>

<xs:complexType name="SPContentTypeFolder">
<xs:attribute name="TargetName" type="xs:string" />

<xs:anyAttribute namespace="##any" processContents="skip" />


</xs:complexType>

<xs:complexType name="SPContentTypeCollection">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any"
processContents="skip" />
</xs:sequence>
</xs:complexType>

<!--This defines that the XML can contain 0-N instances of the SPGenericObject element-->
<xs:element name="SPObjects" type="SPGenericObjectCollection"></xs:element>
</xs:schema>

DeploymentRequirements.XSD
There is no change from current published full 2013 package schema.

DeploymentRootObjectMap.XSD
Table 6: Constrained DeploymentRootObjectMap.XSD
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema
targetNamespace="urn:deployment-rootobjectmap-schema"
elementFormDefault="qualified"
xmlns="urn:deployment-rootobjectmap-schema"
xmlns:mstns="urn:deployment-rootobjectmap-schema"
xmlns:xs="http://www.w3.org/2001/XMLSchema">

<!-- Guid SimpleType definition -->


<xs:simpleType name="Guid">
<xs:restriction base="xs:string"></xs:restriction>
</xs:simpleType>

<xs:simpleType name="SPDeploymentObjectType">
<xs:restriction base="xs:string">
<xs:enumeration value="Folder" />
<xs:enumeration value="List" />
<xs:enumeration value="ListItem" />
<xs:enumeration value="File" />
</xs:restriction>
</xs:simpleType>

<xs:complexType name="SPRootObject">
<xs:attribute name="Id" type="Guid" />
<xs:attribute name="Type" type="SPDeploymentObjectType" />
<xs:attribute name="ParentId" type="Guid" />
<xs:attribute name="WebUrl" type="xs:string" />
<xs:attribute name="Url" type="xs:string" />
<xs:attribute name="IsDependency" type="xs:boolean" />
</xs:complexType>

<xs:complexType name="SPRootObjects">
<xs:sequence>
<xs:element
name="RootObject" type="SPRootObject"
minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>

<xs:element name="RootObjects" type="SPRootObjects" />


</xs:schema>

DeploymentSystemData.XSD
There is no change from current published full 2013 package schema.

DeploymentUserGroupMap.XSD
There is no change from current published full 2013 full 2013 package schema.

DeploymentViewFormsList.XSD
There is no change from current published full 2013 package schema.
SPO provided Migration Azure container and queue
6/21/2018 • 2 minutes to read Edit Online

Microsoft’s Migration API requires the use of an Azure container for temporary storage. To simplify the process, you are now provided with a default container while using the migration API.
If you choose, you can still provide your own Azure container.

Encryption is required
For the Migration API to accept a Migration Job coming from a SPO provided Azure container, the data needs to be encrypted at rest. The customer is still allowed to provide their own
Azure account if they prefer to not use encryption.

Advantages
AD V ANTAG E D ES CR IPTIO N

Cost of Azure container goes to SPO Since we are providing the containers, those containers are now part of the basic SharePoint online
Offering. Every tenant who signs up for SharePoint Online will get this for free).

Containers and queues are unique per request and not reused Once a container is given to a customer this container will not be reused or shared.

Containers and queue are automatically deleted As per the standard SharePoint Online Compliance, we will destroy the container within 30 to 90 days
automatically.

Containers and queues are in the customer’s datacenter location We make sure to provision containers that are in the same physical location than their SharePoint online
tenant.

They are obtainable programmatically There is no need to interact with Azure unless the user chooses.

How to use it
Getting Containers
public SPProvisionedMigrationContainersInfo ProvisionMigrationContainers()

The call will return an object that contains two strings containing two SAS tokens for accessing the two required containers and a byte array for the AES256CBC encryption.
This key will need to be used when encrypting the data. We forget the key once we give it out, therefore you must keep it to pass it again for the Submit Migration Job call.

Uri DataContainerUri

Uri MetadataContainer Uri

byte[] EncryptionKey

Getting Queue
public SPProvisionedMigrationQueueInfo ProvisionMigrationQueue()

This method will return a string containing the SAS token for accessing the Azure queue.
The queue can be reused across multiple migration jobs so this call should not be that frequently as the SPProvisionedMigrationContainersInfo() call.

Uri JobQueueUri

After getting the Container and the Queue:


Once those calls have been made, the rest of the flow remains the same for using the Migration API.
OneDrive for Business and SharePoint Online Migration API encryption
6/21/2018 • 2 minutes to read Edit Online

Using the Migration API requires a temporary storage container in Azure. This Azure container is already only openable by someone having a SAS key access to the container. The gGoal of
this feature is to allow to pass eEncrypted content at rest to the API meaning that even if a malicious user has access to the Container he won’t be able to use its content.

What is stored in the Azure blob container


The Migration API requires the Azure Container for content passing and also for log and queue reporting back. It can be split down as a summary into those buckets:
Content
Files
Manifest
Metadata
Permissions
List items
Taxonomy
Logs (created by SharePoint Online to report back on the migration results)
Queue
Real time reportig on the progress

What is the encryption feature?


When using the encryption parameter, everything listed above will be encrypted at rest and the key will need to be preserved in order to read the logs and the real time progress. The main
benefits is making the content useless for a malicious user who would manage to breach into the Azure container.
This comes with a small cost of performance. This feature is optional when using the API and it is recommended to only use it for the most confidential information since it does reduce the
speed of the migration by a small portion. Microsoft destroys the key once the migration job is finished and there is no way to recover the key if lost, not even from support.

As a 3rd party developer how do I take advantage of the Encryption feature?


Calling the API
The method for calling the Migration Job has a different name and an additional parameter at the end. The new name is: CreateMigrationJobEncrypted

The new parameter is: EncryptionOption

For now, it only supports receiving an AES256CBC Encryption Key.


Example:

public Guid CreateMigrationJobEncrypted(


Guid gWebId,
string azureContainerSourceUri,
string azureContainerManifestUri,
string azureQueueReportUri,
EncryptionOption AES256CBCKey)

Extra requirement
For the encryption, each file must be encrypted and have an IV assigned to it. The encryption method should follow the AES CBC 256 Standard. The IV should be different for every file
including the manifests in the package and should be stored as a property on each files.
Name = [IV]
Value = [Base64encoded byte array of the IV]

Reading the queue when encrypted


When using the encryption option, the messages in the queue will also get encrypted.
It is important to remember the Job ID. Without the specific key used for the job, you won’t be able to read the message back.
Here is the JSON content in the queue message

{"Label", "Encrypted"},
{"JobId", "[JobId value]"},
{"IV", "[IV value in base64format]"},
{"Content", "[encrypted message in base64string]"}

Once the messages are decrypted, they will be the same as the API without encryption.
Running Migrations into OneDrive and SharePoint Online: Throttling
6/27/2018 • 2 minutes to read Edit Online

This document is intended for ISVs migrating content into OneDrive and SharePoint only.

Context and Expectations Setting


Migration is critical for SPO and is prioritized alongside service availability. When we detect that service availability may be threatened, 429 response codes are sent back to protect the
experience of end users.
429 is a normal part of any well-functioning cloud system; the expectation is that background tasks will get 429s and all background task callers (both ISVs and Microsoft apps) should ride
through them without direct customer impact to their own end users.
The number of 429s sent back is a function of the current load on the farm, as well as other tenant/farm level variables. Therefore, it is important to focus on migration throughput rather
than the number of 429s themselves.
Set expectations with customers:
Expect to create and manage migration efforts at any time
Expect content migration throughput to be higher during off-peak times and lower during peak times.
Overall throughput over the duration of a day still aligns with our public documentation here.

Best Practices
Below are the key best practices we recommend migration vendors follow.
Interactive flag:
Include an interactive flag in your user agent string for interactive calls such as user login, launch jobs, etc. For example: ISV|VendorName|AppName/Version|Interactive

We allow 300 calls every 5 minutes for handling small migrations and site management that customers expect to complete interactively.
NOTE

Once you have implemented Interactive flag for the system to pick that cue, it may not be instantaneous; allow a few days for it to take effect.
Retry value:
Use the retry value in the http header of the 429 message and do not exponential back-off.
429:
Do not handle 429 as an error condition displayed to the user. When 429 does occur, handle it as a background task retry and do not prompt users to contact support.
If users cannot login or if jobs are not progressing, please escalate.
If you are seeing over 30% of requests getting 429 over 30 minutes, please escalate.
Throughput:
Expect throughput to be lower during peak hours as opposed to off-peak hours. Generally, nights and weekends in the customer’s time zone (the time zone of the region where their SPO
tenant is setup) are off-peak. Customers should be encouraged to move migration to off-peak hours if possible.
If throughput during peak hours is an order of magnitude worse than off-peak hours, that should be escalated.
SPO Migration API: Sharing
6/27/2018 • 3 minutes to read Edit Online

Details on sharing and permissions


The per user sharing model in SharePoint relies on both permissions and “Shared With” data references for an object to be considered shared with an individual. If a user has access to
content, but no “Shared With” references, they will not see the content show up in their Shared With Me view within their OneDrive For Business site.
However, if they are indicated in “Shared With” references but do not have any access to the content, they will either never see the content show up in their Shared With Me view within
their OneDrive For Business site or when they try to use a link from there it will be denied access. To preserve sharing information, both the permissions and “Shared With” references will
need to be correctly set. The permissions can be set at different levels of the content hierarchy using scopes (unique ACLs), that apply to that object and any of its children unless they
themselves have unique permissions.
Using PRIME, content can be migrated in using SPFile/SPFolder objects with a document library followed by SPListItem objects that reference the imported File/Folder objects. During the
ListItem import, the “Shared With” references data can be imported, and then the security can be applied afterward within the same migration package, by setting up scopes (ACLs) and role
assignments (ACEs) for the content hierarchy as needed. Permissions migration is performed using the DeploymentRoleAssignments object with RoleAssignment entries representing
specific scopes and Assignment entries representing assignments of specific roles to specific principals. Since this code ends up breaking inheritance for content and applying the specified
role assignments, it has the same limitations as using other object model approaches to setting permissions in SharePoint.
NOTE

As you enumerate the security information on the source, you need to assess if you are at risk of hitting the SharePoint limits for ACL sizing (5000 max ACEs with recommendation of below
500 ACEs) and the maximum number of scopes - unique ACLs (There is a hard limit of 50,000 unique ACLs with a recommendation of below 5000 unique ACLs per document library). If
you are close to reaching these limits, we recommend that the permission model be simplified on the source before migration.

SharedWithUser column:
SharedWithUsers column (not SharedWithMe) is not created during list creation. It is created during a share event which causes the specific columns to be ensured. If you share an item on a
team site or ODB, you should see it get created. It is technically possible that the column could be explicitly created by code in advance of the migration (or in the migration package if we are
allowing list column additions, which we may not be currently supporting), but we recommend against that in the case the SharedWithUsers column is not created correctly.
For reference purposes, the SharedWithUsers column has a universal hard coded ID and is exported as the following information (note the SourceID value is the web’s ID):

<Field ID="{ef991a83-108d-4407-8ee5-ccc0c3d836b9}" Type="UserMulti" DisplayName="$Resources:core,SharedWithFieldDisplayName;" Mult="TRUE" Name="SharedWithUsers" StaticName="SharedWithUsers" Group

It may be simpler to try sharing a single test item to someone from the target list before importing the rest of the migration package. This way the column is set up before you attempt to
import the rest of the data. It is likely that you will need to verify some data on the target site first, so this could just be an additional preparation step.
Example:
Shared to single person:
In the case of a file shared to a single person, the following data structure highlighted in yellow would be seen. Note that the bolded values have different values depending on the
field/property in question, and although their additional formatting is different between then, that you must ensure the data is consistent between the three fields/properties:

<SPObject …>
<File …>
<Properties>
<Property Name="SharedWithUsers" Type="String" Access="ReadWrite" Value="140;#user1" />
<Property Name="display_urn:schemas-microsoft-com:office:office#SharedWithUsers" Type="String" Access="ReadWrite" Value="user1" />
</Properties>
</File>
</SPObject>
<SPObject …>
<ListItem …>
<Fields>
<Field Name="SharedWithUsers" Value="140;# ;UserInfo" FieldId="ef991a83-108d-4407-8ee5-ccc0c3d836b9" />
</Fields>
</ListItem>
</SPObject>

Shared to multiple people:


In the case of sharing with multiple people, note that for the main SharedWithUsers property and field the separator value (“;#”) is used not only between the user identifier and user’s title
but also between the individual users, whereas for the display url field, only a semicolon is used to separate the display names.

<SPObject …>
<File …>
<Properties>
<Property Name="SharedWithUsers" Type="String" Access="ReadWrite" Value="140;#user1;#10;#Tenant Admin User" />
<Property Name="display_urn:schemas-microsoft-com:office:office#SharedWithUsers" Type="String" Access="ReadWrite" Value="user1;Tenant Admin User" />
</Properties>
</File>
</SPObject>
<SPObject …>
<ListItem …>
<Fields>
<Field Name="SharedWithUsers" Value="140;# ;#10;# ;UserInfo" FieldId="ef991a83-108d-4407-8ee5-ccc0c3d836b9" />
</Fields>
</ListItem>
</SPObject>
SharePoint site design and site script overview
4/23/2018 • 7 minutes to read Edit Online

NOTE

Site designs and site scripts have been released to production and are available for general use.
Use site designs and site scripts to automate provisioning new or existing modern SharePoint sites that use your own custom configurations.
When people in your organization create new SharePoint sites, you often need to ensure some level of consistency. For example, you may need proper branding and theming applied to each
new site. You may also have detailed site provisioning scripts, such as using the PnP provisioning engine, that need to be applied each time a new site is created.
This article describes how you can use site designs and site scripts to provide custom configurations to apply when new sites are created.

How site designs work


Site designs are like a template. They can be used each time a new site is created to apply a consistent set of actions. They can also be applied to existing modern sites (group-connected
Team and Communication sites). Most actions typically affect the site itself, such as setting the theme or creating lists. But a site design can also include other actions, such as recording the
new site URL to a log, or sending a tweet.
You create site designs and register them in SharePoint to one of the modern template sites: the Team site or the Communication site. You can see how this works in the following steps.
1. Go to the SharePoint home page on your developer tenant.
2. Choose Create site.
You'll see the two modern template sites: Team site and Communication site.
3. Choose Communication site.
The Communication site has a Choose a design box, which comes with the following site designs:
Topic
Showcase
Blank
These are the default site designs. For each site design, there is a title, description, and image.

Had you chosen the Team site template, it contains only one default site design named Team site.
For more information about how you can change the default site designs, see Customize a default site design.
When a site design is selected, SharePoint creates the new site, and runs site scripts for the site design. The site scripts detail the work such as creating new lists or applying a theme. When
the actions in the scripts are completed, SharePoint displays detailed results of those actions in a progress pane.

NOTE

Site designs can now be applied to previously created modern site collections. For mor information, see the REST API and PowerShell articles.
Anatomy of a site script
Site scripts are JSON files that specify an ordered list of actions to run when creating the new site. The actions are run in the order listed.
The following example is a script that has two top-level actions. First, it applies a theme that was previously created named Contoso Explorers. It then creates a Customer Tracking list.

{
"$schema": "schema.json",
"actions": [
{
"verb": "applyTheme",
"themeName": "Contoso Explorers"
},
{
"verb": "createSPList",
"listName": "Customer Tracking",
"templateType": 100,
"subactions": [
{
"verb": "SetDescription",
"description": "List of Customers and Orders"
},
{
"verb": "addSPField",
"fieldType": "Text",
"displayName": "Customer Name",
"isRequired": false,
"addToDefaultView": true
},
{
"verb": "addSPField",
"fieldType": "Number",
"displayName": "Requisition Total",
"addToDefaultView": true,
"isRequired": true
},
{
"verb": "addSPField",
"fieldType": "User",
"displayName": "Contact",
"addToDefaultView": true,
"isRequired": true
},
{
"verb": "addSPField",
"fieldType": "Note",
"displayName": "Meeting Notes",
"isRequired": false
}
]
}
],
"version": 1
}

Each action in a site script is specified by a verb value in the JSON. In the previous script, the first action is specified by the applyTheme verb. Next, the createSPList verb creates the list.
Notice that the createSPList verb contains its own set of verbs that run additional actions on only the list.
Available actions include:
Creating a new list or library (or modifying the default one created with the site)
Creating site columns, content types, and configuring other list settings
Applying a theme
Setting a site logo
Adding navigation
Triggering a Microsoft Flow
Installing a deployed solution from the app catalog
Setting regional settings for the site
Setting external sharing capability for the site
For a complete list of available actions and their parameters, see the JSON schema.
Site scripts can be run again on the same site after provisioning. This can only be done programmatically. Site scripts are non-destructive, so when they run again, they ensure that the site
matches the configuration in the script.
For example, if the site already has a list with the same name that the site script is creating, the site script will only add missing fields to the existing list. Also, please note that site scripts are
limited to 30 cumulative actions (across one or more scripts that may be called in a site design). This includes subactions.

Using PowerShell or REST to work with site designs and site scripts
You can create site designs and site scripts by using PowerShell or the REST API. The following example creates a site script and a site design that uses the site script.
C:\> Get-Content 'c:\scripts\site-script.json' `
-Raw | `
Add-SPOSiteScript `
-Title "Contoso theme and list"

Id : 2756067f-d818-4933-a514-2a2b2c50fb06
Title : Contoso theme and list
Description :
Content :
Version : 0

C:\> Add-SPOSiteDesign `
-Title "Contoso customer tracking" `
-WebTemplate "64" `
-SiteScripts "2756067f-d818-4933-a514-2a2b2c50fb06" `
-Description "Creates customer list and applies standard theme"

In the previous example, the Add-SPOSiteScript cmdlet or CreateSiteScript REST API returns a site script id. This is used for the SiteScripts parameter in the subsequent call to the Add-
SPO-SiteDesign cmdlet or CreateSiteDesign REST API.
The WebTemplate parameter set to the value 64 indicates registering this site design with the Team site template. The value 68 would indicate registering with the Communication site
template. The Title and Description parameters are displayed when a user views site designs as they create a new Team site.
NOTE

A site design can run multiple scripts. The script IDs are passed in an array, and they run in the order listed.
For step-by-step information about creating a site design, see Get started creating site designs.

PnP provisioning and customization using Microsoft Flow


One action provided by site scripts is the ability to trigger a Microsoft Flow. This allows you to specify any custom action that you need beyond the actions provided natively in site scripts.
If you use the PnP provisioning engine to automate site creation, you can use a Microsoft Flow to integrate with site designs. You can maintain all your existing provisioning scripts as well as
create new custom provisioning scripts by using this technique.

The process works as follows:


1. The script instantiates your Microsoft Flow using a URL with additional details.
2. The flow sends a message to an Azure storage queue that you have configured.
3. The message triggers a call to an Azure function that you have configured.
4. The Azure function runs your custom script, such as the PnP provisioning engine, to apply your custom configurations.
For a step-by-step tutorial about how to configure your own Microsoft Flow with PnP provisioning, see Build a complete site design using the PnP provisioning engine.

Scoping
You can configure site designs to only appear for specific groups or people in your organization. This is useful to ensure that people only see the site designs intended for them. For example,
you might want the accounting department to only see site designs specifically for them. And the accounting site designs may not make sense to show to anyone else.
By default, a site design can be viewed by everyone when it is created. Scopes are applied by using the Grant-SPOSiteDesignRights cmdlet or the GrantSiteDesignRights REST API. You
can specify the scope by user or a mail-enabled security group.
The following example shows how to add Nestor (a user at the fictional Contoso site) view rights on a site design.

Grant-SPOSiteDesignRights `
-Identity 44252d09-62c4-4913-9eb0-a2a8b8d7f863 `
-Principals "nestorw@contoso.onmicrosoft.com" `
-Rights View

For more information about working with scopes, see Scoping access to site designs.
See also
Get started creating site designs
Apply a scope to your site design
Site design JSON schema
PowerShell cmdlets for SharePoint site designs and site scripts
Site design and site script REST API
Site design examples
Get started creating site designs and site scripts
8/1/2018 • 4 minutes to read Edit Online

You can create site designs to provide reusable lists, themes, layouts, pages, or custom actions so that your users can quickly build new SharePoint sites with the features they need.
This article describes how to build a simple site design that adds a SharePoint list for tracking customer orders. You'll use the site design to create a new SharePoint site with the custom list.
You'll learn how to use SharePoint PowerShell cmdlets to create site scripts and site designs. You can also use REST APIs to perform the same actions. The corresponding REST calls are
shown for reference in each step.

Create the site script in JSON


A site design is a collection of actions that SharePoint runs when creating a new site. Actions describe changes to apply to the new site, such as creating a new list or applying a theme. The
actions are specified in a JSON script, which is a list of all actions to apply. When a script runs, SharePoint completes each action in the order listed.
Each action is specified by the "verb" value in the JSON script. Also, actions can have subactions that are also "verb" values. In the following JSON, the script specifies to create a new list
named Customer Tracking, and then subactions set the description and add several fields to define the list.
1. Download and install the SharePoint Online Management Shell. If you already have a previous version of the shell installed, uninstall it first and then install the latest version.
2. Follow the instructions at Connect to SharePoint Online PowerShell to connect to your SharePoint tenant.
3. Create and assign the JSON that describes the new script to a variable as shown in the following PowerShell code.

$site_script = @'
{
"$schema": "schema.json",
"actions": [
{
"verb": "createSPList",
"listName": "Customer Tracking",
"templateType": 100,
"subactions": [
{
"verb": "SetDescription",
"description": "List of Customers and Orders"
},
{
"verb": "addSPField",
"fieldType": "Text",
"displayName": "Customer Name",
"isRequired": false,
"addToDefaultView": true
},
{
"verb": "addSPField",
"fieldType": "Number",
"displayName": "Requisition Total",
"addToDefaultView": true,
"isRequired": true
},
{
"verb": "addSPField",
"fieldType": "User",
"displayName": "Contact",
"addToDefaultView": true,
"isRequired": true
},
{
"verb": "addSPField",
"fieldType": "Note",
"displayName": "Meeting Notes",
"isRequired": false
}
]
}
],
"bindata": { },
"version": 1
}
'@

The previous script creates a new SharePoint list named Customer Tracking. It sets the description and adds four fields to the list. Note that each of these are considered an action. Site
scripts are limited to 30 cumulative actions (across one or more scripts that may be called in a site design).

Add the site script


Each site script must be registered in SharePoint so that it is available to use. Add a new site design by using the Add-SPOSiteScript cmdlet. The following example shows how to add the
JSON script described previously.

C:\> Add-SPOSiteScript
-Title "Create customer tracking list"
-Content $site_script
-Description "Creates list for tracking customer contact information"

After running the cmdlet, you get a result that lists the site script ID of the added script. Keep track of this ID somewhere because you will need it later when you create the site design.
The REST API to add a new site script is CreateSiteScript.

Create the site design


Next, you need to create the site design. The site design appears in a drop-down list when someone creates a new site from one of the templates. It can run one or more site scripts that have
already been added.
Run the following cmdlet to add a new site design. Replace <ID> with the site script ID from when you added the site script.

C:\> Add-SPOSiteDesign
-Title "Contoso customer tracking"
-WebTemplate "64"
-SiteScripts "<ID>"
-Description "Tracks key customer data in a list"

The previous cmdlet creates a new site design named Contoso customer tracking. The -WebTemplate value selects which base template to associate with. The value "64" indicates Team site
template, and the value "68" indicates the Communication site template.
The JSON response displays the ID of the new site design. You can use it in subsequent cmdlets to update or modify the site design.
The REST API to add a new site design is CreateSiteDesign.

Use the new site design


Now that you've added a site script and site design, you can use it to create new sites through the self-service site creation experience or apply the site design to an existing site using the
Invoke-SPOSiteDesign command in PowerShell.

New site creation


1. Go to the home page of the SharePoint site that you are using for development.
2. Choose Create site.
3. Choose Team site.
4. In the Choose a design drop-down, select your site design customer orders.
5. In Site name, enter a name for the new site Customer order tracking.
6. Choose Next.
7. Choose Finish.
8. A pane indicates that your script is being applied. When it is done, choose View updated site.
9. You will see the custom list on the page.

Apply to an existing site collection


You can also apply a published site design to an existing site collection using the Invoke-SPOSiteDesign cmdlet.
You can already apply to Group-connected Team and Communication sites. By August 2018 you will also be able to apply site designs to the team site not connected to an Office 365 Group,
a classic team site, or a classic publishing site.

See also
SharePoint site design and site script overview
Scoping access to site designs
4/23/2018 • 2 minutes to read Edit Online

Site designs are available to everyone by default. You can also scope site designs so that they are only available to specific users or groups. For example, the accounting apartment may have
specific site designs they use, but it may not make sense to share those site designs with everyone.
This article explains how you can control which users and groups can see specific site designs.

Grant rights to a site design


When a site design is first created, it is available to everyone. You can grant View rights to the site design. After rights are granted, only the users or groups (principals) specified have access.
You can continue granting rights to more principals with subsequent API calls.
NOTE

Scoping is currently only available for mail-enabled security groups and users. We are planning to provide support for Office 365 Groups in the future.

Grant rights to security groups


The following example shows how to scope an existing site design so that only the mail-enabled security group accounting can view and use the site design.

Grant-SPOSiteDesignRights `
-Identity db752673-18fd-44db-865a-aa3e0b28698e `
-Principals ("accounting@contoso.sharepoint.com") `
-Rights View

You might want to create a new site design and grant rights at the same time, as shown in the next example.

Add-SPOSiteDesign `
-Title "Scoped site design" `
-Description "Scoped to only the accounting email security group" `
-SiteScripts 256494cb-bd31-4f60-9eba-285308d7a863 `
-WebTemplate 64 `
-PreviewImageUrl "https://contoso.sharepoint.com/SiteAssets/scope-image.png" `
| Grant-SPOSiteDesignRights `
-Principals ("accounting@contoso.com") `
-Rights View

Grant rights to users


The following example shows how to grant view rights on a site design to Nestor (a user at the fictional Contoso site).

PS C:\> Grant-SPOSiteDesignRights `
-Identity 44252d09-62c4-4913-9eb0-a2a8b8d7f863 `
-Principals "nestorw@contoso.onmicrosoft.com" `
-Rights View

View rights assigned to a site design


To view rights, use the Get-SPOSiteDesignRights cmdlet. The following example shows how to use this cmdlet and a response in the case where only Nestor has view rights.

PS C:\> Get-SPOSiteDesignRights 607aed52-6d61-490a-b692-c0f58a6981a1

DisplayName PrincipalName Rights


----------- ------------- ------
Nestor Wilke i:0#.f|membership|nestorw@contoso.onmicrosoft.com View

Revoke rights from a site design


You can revoke rights for any principal. If you revoke view rights for all principles, the site design will again be available to everyone.
The following example revokes access for the accounting mail-enabled security group and Nestor.

Revoke-SPOSiteDesignRights `
-Identity db752673-18fd-44db-865a-aa3e0b28698e `
-Principals ("accounting@contoso.sharepoint.com","nestorw@spdfcontosodemo2.onmicrosoft.com") `

See also
SharePoint site design and site script overview
Customize a default site design
4/23/2018 • 2 minutes to read Edit Online

SharePoint contains several site designs already available in the SharePoint Online site templates. These are the default site designs. You can modify them by using PowerShell or the REST
APIs to control the entire site provisioning experience. For example, you can ensure that your company theme is applied to every site that gets created, or you can make sure a logging
mechanism always runs regardless of which site design is chosen.

Apply a site design to the default site designs


To customize the default site designs, apply a new one with the PowerShell Add-SPOSiteDesign cmdlet or the CreateSiteDesign REST API. Specify the IsDefault switch to apply the site
design as the default.
The WebTemplate ID for a group-connected Team site is 64; for a Communication site it is 68.
The following example shows how to use the IsDefault switch to apply the Contoso company theme to the default site designs. The site script referenced by ID contains the JSON script to
apply the correct theme.

C:\> Add-SPOSiteDesign `
-Title "Contoso company theme" `
-WebTemplate "68" `
-SiteScripts "89516c6d-9f4d-4a57-ae79-36b0c95a817b" `
-Description "Applies standard company theme to site" `
-IsDefault

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.CreateSiteDesign", {info:{Title:"Contoso company theme", Description:"Applies standard company theme to s

Which default site designs are updated?


In the previous example, the WebTemplate value of "68" refers to the SharePoint Online Communication site template. That template contains the following default site designs:
Topic
Showcase
Blank
When you apply a new site design, it updates all three default site designs at the same time.
The SharePoint Online Team site template contains only one default site design named Team. In this case, when you apply a default site design, only the Team site design is updated.

Restore the default site designs


To restore a site design to the defaults, remove the site design that you applied. In the previous example, if the site design created had the ID db752673-18fd-44db-865a-aa3e0b28698e , you
would remove it as shown in the following example.

C:\> Remove-SPOSiteDesign db752673-18fd-44db-865a-aa3e0b28698e

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.DeleteSiteDesign", {id:"db752673-18fd-44db-865a-aa3e0b28698e"});

NOTE

If you're not sure which site design is the default, run the Get-SPOSiteDesign cmdlet. It will list all site designs, and indicates which ones are defaults.

See also
SharePoint site design and site script overview
Site design JSON schema
7/23/2018 • 15 minutes to read Edit Online

The site design is a list of actions. For more complex actions, such as creating a list, there are also subactions. Each action is specified by a "verb" value. Verb actions are run in the order
they appear in the JSON script. Only the verb actions listed here can be used; otherwise, an "unable to handle action" error will be thrown when trying to upload a site script. More actions
will be added over time.
The overall JSON structure is specified as follows:

{
"$schema": "schema.json",
"actions": [
...
<one or more verb actions>
...
],
"bindata": { },
"version": 1
};

Create a new SharePoint list


Use the createSPList verb to create a new SharePoint list.
JSON values
listName – The name of the list for users to identify it with.
templateType – Which template to apply to the list. Typically you would use value 100. Template type values are documented in SPListTemplateType enumeration.
subactions – An array of actions that run in the order listed to create your list.
Example
{
"verb": "createSPList",
"listName": "Customer Tracking",
"templateType": 100,
"subactions": [
{
"verb": "setDescription",
"description": "List of Customers and Orders"
}
]
}

The subactions array provides additional actions to specify how to construct the list. Subactions are also specified using a verb value.

setTitle
Sets a title which identifies the list in views.
JSON value
title – The title of the new list.
Example
{
"verb": "setTitle",
"title": "Customers and Orders"
}

setDescription
Sets the description of the list.
JSON value
description – The description of the new list.
Example
{
"verb": "setDescription",
"description": "List of Customers and Orders"
}

addSPField
Adds a new field.
JSON values
fieldType – The field type can be set to Text, Note, Number, Boolean, User, or DateTime. For other data types, see the addSPFieldXml action.
displayName – The display name of the field.
internalName – An optional attribute. If provided, specifies the internal name of the field. If not provided, the internal name is based on the display name.
isRequired – True if this field is required to contain information; otherwise, false.
addToDefaultView – True if the field will be added to the default view; otherwise, false.
enforceUnique – An optional attribute that defaults to false. If true, all values for this field must be unique.
Example
{
"verb": "addSPField",
"fieldType": "Text",
"displayName": "Customer Name",
"isRequired": false,
"addToDefaultView": true
}

deleteSPField
Deletes a default field that was provided by the selected template type.
JSON value
displayName – The display name to identify the field to delete.
Example
{
"verb": "deleteSPField",
"displayName": "Modified"
}

addSPFieldXml
Enables defining fields and their elements using Collaborative Application Markup Language (CAML). For reference, see Field element (Field).
Currently these field constructs cannot be designated as site columns nor added to content types. To create site columns with Field XML use the createSiteColumnXml action.
JSON value
schemaXml – The CAML block to define the field.
addToDefaultView – True if the field will be added to the default view; otherwise, false.
Example
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type=\"Choice\" DisplayName=\"Project Category\" Required=\"FALSE\" Format=\"Dropdown\" StaticName=\"ProjectCategory\" Name=\"ProjectCategory\"><Default>Operations</Defau
}

addSPLookupFieldXml
Enables defining lookup fields and their dependent lists element using Collaborative Application Markup Language (CAML). For reference, see Field element (Field).
JSON value
schemaXml – The CAML block to define the field.
targetListName – The name that identifies the list this lookup field is referencing. Provide either this or targetListUrl.
targetListUrl – A web-relative URL that identifies the list this lookup field is referencing. Provide either this or targetListName.
addToDefaultView – True if the field will be added to the default view; otherwise, false.
Example
{
"verb": "addSPLookupFieldXml",
"schemaXml": "<Field Type=\"Lookup\" DisplayName=\"Contoso Project Category\" Required=\"FALSE\" EnforceUniqueValues=\"FALSE\" ShowField=\"Title\" UnlimitedLengthInDocumentLibrary=\"FALSE\" Rel
"targetListName": "Contoso Project Master"
}

addSPView
Defines and adds a view to the list. Use this action to specify the desired columns and how you want the list items displayed (using a CAML query). Action properties allow you to specify
row limits, and whether the view is paged and recurses over items in nested folders. You can also designate your constructed view as the default.
JSON value
name – The name of the view.
viewFields – An array of the internal names of the fields in your view.
query – A CAML query string that contains the where clause for the view's query. See CAML schemas.
rowLimit – The row limit of the view.
isPaged – Specifies whether the view is paged.
makeDefault – If true, the view will be made the default for the list; otherwise, false.
scope – An optional setting to specify the scope of the view. For more details, see SPViewScope enumeration.
Example
{
"verb": "addSPView",
"name": "Contoso Projects by Category",
"viewFields":
[
"ID",
"Title",
"siteColumnUser",
"ProjectCategory"
],
"query": "<OrderBy><FieldRef Name=\"ProjectCategory\" /><FieldRef Name=\"siteColumnUser\" Ascending=\"FALSE\" /></OrderBy>",
"rowLimit": 100,
"isPaged": true,
"makeDefault": true
}
removeSPView
Removes a view from a list. This action can also be used to remove a view applied by the site template.
JSON value
name – The name of the view to remove.
Example
{
"verb": "removeSPView",
"name": "All Items"
}

addContentType
Adds a content type to the list. Currently these are limited to the default content types included in the site template or ones defined in a script by using the createContentType action.
NOTE

Currently we do not support adding enterprise content types.


JSON value
name – The name of the content type to add.
Example
{
"verb": "addContentType",
"name": "name"
}

removeContentType
Removes a content type that was provided by the selected template type.
JSON value
name – The name of the content type to remove.
Example
{
"verb": "removeContentType",
"name": "name"
}

setSPFieldCustomFormatter
Sets column formatting for a field. For more information, see Use column formatting to customize SharePoint.
JSON values
fieldDisplayName – The display name of the field to operate on.
formatterJSON – A JSON object to use as the field CustomFormatter.
Example
In this example, we are formatting a number column as a data bar.
{
"verb": "setSPFieldCustomFormatter",
"fieldDisplayName": "Effort (days)",
"formatterJSON":
{
"debugMode": true,
"elmType": "div",
"txtContent": "@currentField",
"attributes": {
"class": "sp-field-dataBars"
},
"style": {
"width": {
"operator": "?",
"operands": [
{
"operator": ">",
"operands": [
"@currentField",
"20"
]
},
"100%",
{
"operator": "+",
"operands": [
{
"operator": "toString()",
"operands": [
{
"operator": "*",
"operands": [
"@currentField",
5
]
}
]
},
"%"
]
}
]
}
}
}
}

associateFieldCustomizer
Registers field extension for a list field. For more information on these client-side extensions, see Build field customizer tutorial.
JSON values
internalName – The internal name of the field to operate on.
clientSiteComponentId – The identifier (GUID) of the extension in the app catalog. This property value can be found in the manifest.json file or in the elements.xml file.
clientSiteComponentProperties – An optional parameter, which can be used to provide properties for the field customizer extension instance.
Example
{
"verb": "createSPList",
"listName": "Custom List with Slider Extension",
"templateType": 100,
"subactions": [
{
"verb": "SetDescription",
"description": "Custom list to illustrate SharePoint site scripting"
},
{
"verb": "addSPField",
"fieldType": "Text",
"displayName": "Text Field",
"isRequired": false,
"addToDefaultView": true
},
{
"fieldType": "Number",
"displayName": "Number Field",
"internalName": "ElectricSlide",
"addToDefaultView": true,
"isRequired": true
},
{
"verb": "associateFieldCustomizer",
"internalName": "ElectricSlide",
"clientSideComponentId": "35944670-3111-4482-b152-9e9d1sean9f7",
"clientSideComponentProperties": "{\"sampleText\":\"Yes - added by a site design, what?\"}"
}
]
}

associateListViewCommandSet
Associates a ListViewCommandSet to the list
JSON values
title – The title of the extension.
location – A required parameter to specify where the command is displayed. Options are: ContextMenu or CommandBar.
clientSideComponentId – The identifier (GUID) of the extension in the app catalog. This property value can be found in the manifest.json file or in the elements.xml file.
clientSideComponentProperties – An optional parameter, which can be used to provide properties for the extension instance.
Example
{
"verb": "createSPList",
"listName": "CustomList",
"templateType": 100,
"subactions": [
{
"verb": "SetDescription",
"description": "Custom list to illustrate SharePoint site scripting"
},
{
"verb": "addSPField",
"fieldType": "Text",
"displayName": "Text Field",
"isRequired": false,
"addToDefaultView": true
},
{
"verb": "addSPField",
"fieldType": "Number",
"displayName": "Number Field",
"internalName": "ElectricSlide",
"addToDefaultView": true,
"isRequired": true
},
{
"verb": "associateListViewCommandSet",
"title": "HelloWorld",
"location": "CommandBar"
"clientSideComponentId": "13234283-d6c2-408f-a9ef-31a920c8ae78",
"clientSideComponentProperties": "{\"sampleText\":\"added by a site design\"}"
}
]
}

Define a new site column


Use the createSiteColumn verb to define a new site column that can then be associated to a list directly or by using the addContentType action.
JSON value
fieldType – The type of column to add. Supported values - like SPField - are Text, Note, Number, Boolean, User, and DateTime. For other data types, refer to the addSPFieldXml script
action.
internalName – The internal name of the site column.
displayName – The display name of the site column.
isRequired – True if this field is required to contain information; otherwise, false.
group – An optional attribute to designate the column group.
enforceUnique – An optional attribute that defaults to false. If true, all values for this field must be unique.
Example
{
"verb": "createSiteColumn",
"fieldType": "User",
"internalName": "siteColumn4User",
"displayName": "Project Owner",
"isRequired": false
}

Use the createSiteColumnXml verb to define a new site column for those complex data types not supported by createSiteColumn. These columns can then be associated to a list directly or
by using the addContentType action.
JSON value
schemaXml – The CAML block to define the field.
pushChanges – Indicates whether this change should be pushed to lists that already reference this field. Defaults to true.
Example
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type=\"Choice\" DisplayName=\"Project Status\" Required=\"FALSE\" Format=\"Dropdown\" StaticName=\"ProjectStatus\" Name=\"ProjectStatus\"><Default>In Progress</Default><C
}

Define a new content type


Use createContentType to define a new content type that can then be associated to a list by using the addContentType action.
JSON value
NOTE

When referencing the content type ID, only one of the three references are required - ID, parentName, or parentId.
name – The name of the content type to create.
description – The optional description of the content type.
parentName – Name of the parent content type.
parentId – ID of the parent content type.
id – ID of the content type.
hidden – Specifies whether the content type is visible or hidden.
subactions – Specifies subactions to run on the content type. These are used to designate the site columns to add.
Example
{
"verb": "createContentType",
"name": "Contoso Projects",
"description": "custom list content type",
"parentName": "Item",
"hidden": false,
"subactions":
[
{
"verb": "addSiteColumn",
"internalName": "siteColumn1Text"
},
{
"verb": "addSiteColumn",
"internalName": "siteColumn2Number"
},
{
"verb": "addSiteColumn",
"internalName": "siteColumn3Note"
}
]
}

addSiteColumn
Subaction to add a previously defined site column directly to a list or content type (existing or created through the site script).
NOTE

This action can be used to add created site columns to a list or content type.
JSON value
internalName – The internal name of the site column to add.
Example
{
"verb": "addSiteColumn",
"internalName": "siteColumnUser"
}

removeSiteColumn
Subaction to remove a site column from a list or content type.
JSON value
internalName – The internal name of the site column to remove.
Example
{
"verb": "removeSiteColumn",
"internalName": "siteColumnUser"
}

Add a navigation link


Use the addNavLink verb to add a new navigation link to the site.
JSON values
url – The url of the link to add.
displayName – The display name of the link.
isWebRelative – True if the link is web relative; otherwise, false.
Example
NOTE

If you add a link to a nested site item such as a list, be sure to add the path reference from the root.

{
"verb": "addNavLink",
"url": "/Customer Event Collateral",
"displayName": "Event Collateral",
"isWebRelative": true
},
{
"verb": "addNavLink",
"url": "/Lists/Project Activities",
"displayName": "Project Activities",
"isWebRelative": true
}

Remove a navigation link


Use the removeNavLink verb to remove a navigation link from the site.
JSON values
url – The url of the link to add.
displayName – The display name of the link.
isWebRelative – True if the link is web relative; otherwise, false.
Example
NOTE

This action can be used to remove site links added by the collaboration and communication site templates (for example, "home", "documents", "pages", "conversations", etc.).
{
"verb": "removeNavLink",
"displayName": "Home",
"isWebRelative": true
},
{
"verb": "removeNavLink",
"displayName": "Pages",
"isWebRelative": true
},
{
"verb": "removeNavLink",
"displayName": "Conversations",
"isWebRelative": true
},
{
"verb": "removeNavLink",
"url": "/_layouts/15/groupstatus.aspx?Target=TEAM",
"displayName": "Teams",
"isWebRelative": true
}

Apply a theme
Use the applyTheme verb to add a custom theme to the site. For more information about how to construct and upload these themes, see SharePoint site theming. Note that this site action
only works for applying custom themes; to apply one of our in-product SharePoint themes, create a copy as a custom one and reference that one.
JSON value
themeName – The name of the theme to apply.
Example
{
"verb": "applyTheme",
"themeName": "Blue Yonder"
}

Set a site logo


Use the setSiteLogo verb to specify a logo for your site.
NOTE

This action only works on the communication site template (68).


JSON value
url – The url of the logo image to use.
Example
{
"verb": "setSiteLogo",
"url": "/Customer Event Collateral/logo.jpg"
}

Join a hub site


Use the joinHubSite verb to join the site to a designated hub site.
JSON value
hubSiteId – The ID of the hub site to join.
name – An optional string specifying the name of the hub site.
Example
NOTE

Hub sites are a new feature that are just rolling out to customers in Targeted Release in March 2018. This action might not be available for use in your environment. To learn more, see
SharePoint hub sites overview.

{
"verb": "joinHubSite",
"hubSiteId": "e337cc17-b355-45d2-8dd4-e056f1bcf6f6"
}

Install an add-in or solution


Use the installSolution action to install a deployed add-in or SharePoint Framework solution from the tenant app catalog.
JSON values
Example
NOTE

To get the solution ID, sign in to a site by using the Connect-PnPOnline cmdlet, and then run Get-PnPApp. This returns a list of your deployed solutions.

{
"verb": "installSolution",
"id": "d40e4edc-a6da-4cd8-b82d-bba970976803"
}

Register an extension
Use the associateExtension action to register a deployed SharePoint Framework extension from the tenant app catalog.
NOTE

For more details on how to create and configure a SharePoint Framework extension, check out: Overview of SharePoint Framework Extensions.
JSON values
title – The title of the extension in the app catalog.
location – Used to specify the extension type. If it is used to create commands, then where the command would be displayed; otherwise this should be set to
ClientSideExtension.ApplicationCustomizer.
clientSideComponentId – The identifier (GUID) of the extension in the app catalog. This property value can be found in the manifest.json file or in the elements.xml file.
clientSideComponentProperties – An optional parameter, which can be used to provide properties for the extension instance.
registrationId – An optional parameter, which indicates the type of the list the extension is associated to (if it is a list extension).
registrationType – An optional parameter, which should be specified if the extension is associated with a list.
scope – Indicates whether the extension is associated with a Web or a Site.
Example
{
"verb": "associateExtension",
"title": "SPFXApplicationCustomizer Example",
"location": "ClientSideExtension.ApplicationCustomizer",
"clientSideComponentId": "40d64749-a6e5-4691-b440-1e32fb6sean5",
"scope": "Web"
}

Trigger a flow
Use the triggerFlow verb to kick off a custom flow.
JSON values
url – A trigger URL of the flow.
name – The name of the flow.
parameters – An optional set of parameters to pass into the flow.
Example
{
"verb": "triggerFlow",
"url": "<A trigger URL of the Flow.>",
"name": "Record and tweet site creation event",
"parameters": {
"event": "Microsoft Event",
"product": "SharePoint"
}
}

Configure regional settings


Use the setRegionalSettings action to configure the regional settings of the site (/_layouts/15/regionalsetng.aspx).
JSON values
timeZone – A number specifying the time zone. For a list of permissible values, see https://msdn.microsoft.com/library/microsoft.sharepoint.spregionalsettings.timezones.aspx
locale – A number specifying the culture LCID. For a list of permissible values, see https://msdn.microsoft.com/en-us/library/ms912047(v=winembedded.10).aspx
sortOrder – A number specifying the sort order. For a list of permissible values, see https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spregionalsettings.collation.aspx
hourFormat – Specifies whether the site should use 12-hour or 24-hour time format.
Example
{
"verb": "setRegionalSettings",
"timeZone": 2, /* Greenwich Mean Time */
"locale": 1050, /* Croatia */
"sortOrder": 6, /* Croatian */
"hourFormat": "24"
}

Add users (principals) to SharePoint Groups


Use the addPrincipalToGroup action to manage addition of users and groups to select default SharePoint groups. For more information, see Understanding SharePoint Groups. This action
can be used for licensed users, security groups, and Office 365 Groups.
JSON values
principal – A required parameter to specify the name of the principal (user or group) to add to the SharePoint group.
group – A required parameter to specify the SharePoint group to add the principal to.
Example
NOTE

This action currently only supports the Visitors (permission level: read), Members (permission level: contribute or edit, depending on the site template), and Owners (permission level: full
control) groups. Principals must be added individually.
{
"verb": "addPrincipalToSPGroup",
"principal": "sean@contosotravel.onmicrosoft.com", /* user */
"group": "Owners"
},
{
"verb": "addPrincipalToSPGroup",
"principal": "travelops", /* sg */
"group": "Owners"
},
{
"verb": "addPrincipalToSPGroup",
"principal": "itexecutives", /* mail-enabled sg */
"group": "Members"
},
{
"verb": "addPrincipalToSPGroup",
"principal": "Adventure@contosotravel.onmicrosoft.com", /* o365 group */
"group": "Visitors"
}

Manage guest access


Use the setSiteExternalSharingCapability action to manage guest access. For more information, see Manage external sharing for your SharePoint Online environment.
JSON values
capability – A required parameter to specify the sharing option for the site collection. The four options are: Disabled, ExistingExternalUserSharingOnly, ExternalUserSharingOnly,
ExternalUserAndGuestSharing
Example
{
"verb": "setSiteExternalSharingCapability",
"capability": "Disabled"
}

See also
SharePoint site design and site script overview
SharePoint site design: PowerShell cmdlets
4/23/2018 • 2 minutes to read Edit Online

NOTE

Site designs and site scripts have been released to production and are available for general use.
Use PowerShell cmdlets to create, retrieve, update, and remove site designs and site scripts to new and existing modern site collections.

Getting started
To run the PowerShell cmdlets, you'll need to do the following:
1. Download and install the SharePoint Online Management Shell. If you already have a previous version of the shell installed, uninstall it first and then install the latest version.
2. Follow the instructions at Connect to SharePoint Online PowerShell to connect to your SharePoint tenant.
To verify your setup, try using the Get-SPOSiteScript cmdlet to read the current list of site scripts. If the cmdlet runs and returns with no errors, you're ready to proceed.

Site design cmdlets


The following cmdlets are available for managing site designs and site scripts from PowerShell:
Add-SPOSiteDesign
Add-SPOSiteScript
Get-SPOSiteDesign
Get-SPOSiteDesignRights
Get-SPOSiteScript
Grant-SPOSiteDesignRights
Invoke-SPOSiteDesign
Remove-SPOSiteDesign
Remove-SPOSiteScript
Revoke-SPOSiteDesignRights
Set-SPOSiteDesign
Set-SPOSiteScript

See also
JSON schema reference
REST API
Apply a scope to your site design
SharePoint site design and site script overview
Site design and site script REST API
4/23/2018 • 9 minutes to read Edit Online

You can use the SharePoint REST interface to perform basic create, read, update, and delete (CRUD) operations on site designs and site scripts.
The SharePoint Online (and SharePoint 2016 and later on-premises) REST service supports combining multiple requests into a single call to the service by using the OData $batch query
option. For details and links to code samples, see Make batch requests with the REST APIs.

Prerequisites
Before you get started, make sure that you're familiar with the following:
Get to know the SharePoint REST service
Complete basic operations using SharePoint REST endpoints

REST commands
The following REST commands are available for working with site designs and site scripts:
CreateSiteScript – Creates a new site script.
GetSiteScripts – Gets a list of information on existing site scripts.
GetSiteScriptMetadata – Gets information about a specific site script.
UpdateSiteScript – Updates a site script with new values.
DeleteSiteScript – Deletes a site script.
CreateSiteDesign – Creates a site design.
ApplySiteDesign – Applies a site design to an existing site collection.
GetSiteDesigns – Gets a list of information on existing site designs.
GetSiteDesignMetadata – Gets information about a specific site design.
UpdateSiteDesign – Updates a site design with new values.
DeleteSiteDesign – Deletes a site design.
GetSiteDesignRights – Gets a list of principals that have access to a site design.
GrantSiteDesignRights – Grants access to a site design for one or more principals.
RevokeSiteDesignRights – Revokes access from a site design for one or more principals.

Create a function to send REST requests


To work with the REST API, we recommend creating a helper function to make the REST calls. The following RestRequest function calls the REST method specified in the url parameter and
passes the additional parameters in params.

function RestRequest(url,params) {
var req = new XMLHttpRequest();
req.onreadystatechange = function ()
{
if (req.readyState != 4) // Loaded
return;
console.log(req.responseText);
};

// Prepend web URL to url and remove duplicated slashes.


var webBasedUrl = (_spPageContextInfo.webServerRelativeUrl + "//" + url).replace(/\/{2,}/,"/");
req.open("POST",webBasedUrl,true);
req.setRequestHeader("Content-Type", "application/json;charset=utf-8");
req.setRequestHeader("ACCEPT", "application/json; odata.metadata=minimal");
req.setRequestHeader("x-requestdigest", _spPageContextInfo.formDigestValue);
req.setRequestHeader("ODATA-VERSION","4.0");
req.send(params ? JSON.stringify(params) : void 0);
}

CreateSiteScript
Creates a new site script.

Parameters
PAR AME TER D ES CR IPTIO N

Title The display name of the site design.

Content JSON value that describes the script. For more information, see JSON reference.

Examples
The following example creates a new site script that applies a custom theme.
var site_script =
{
"$schema": "schema.json",
"actions": [
{
"verb": "applyTheme",
"themeName": "Contoso Theme"
}
],
"bindata": { },
"version": 1
};

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.CreateSiteScript(Title=@title)?@title='Contoso theme script'", site_script);

Here is an example of the JSON returned after calling CreateSiteScript. It contains the ID of the new site script.

{
"@odata.context": "https://contoso.sharepoint.com/_api/$metadata#Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptMetadata",
"Content": null,
"Description": null,
"Id": "7647d3d6-1046-41fe-a798-4ff66b099d12",
"Title": "Contoso customer list",
"Version": 0
}

GetSiteScripts
Gets a list of information on all existing site scripts.

Parameters
None.

Examples
The following example gets the site script information for all site scripts.

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteScripts");

Here is an example of the JSON returned after calling GetSiteScripts.

{
"@odata.context": "https://contoso.sharepoint.com/_api/$metadata#Collection(Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptMetadata)",
"value": [
{
"Content": null,
"Description": null,
"Id": "6dfedb96-c090-44e3-875a-1c38032715fc",
"Title": "Customer orders",
"Version": 1
},
{
"Content": null,
"Description": null,
"Id": "07702c07-0485-426f-b710-4704241caad9",
"Title": "Contoso theme",
"Version": 1
}
]
}

GetSiteScriptMetadata
Gets information about a specific site script. It also returns the JSON of the script.

Parameters
PAR AME TER D ES CR IPTIO N

id The ID of the site script to get information about.

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteScriptMetadata",
{id:"07702c07-0485-426f-b710-4704241caad9"});

Examples
Here is an example of the JSON returned after calling GetSiteScriptMetadata.
{
"@odata.context": "https://contoso.sharepoint.com/_api/$metadata#Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptMetadata",
"Content": "{\r\n \"$schema\": \"schema.json\",\r\n \"actions\": [\r\n {\r\n \"verb\": \"applyTheme\",\r\n \"themeName\": \"Custom Cyan\"\r\n
"Description": null,
"Id": "07702c07-0485-426f-b710-4704241caad9",
"Title": "Contoso theme",
"Version": 1
}

UpdateSiteScript
Updates a site script with new values. In the REST call, all parameters are optional except the site script Id.

Parameters
PAR AME TER D ES CR IPTIO N

Id The ID of the site script to update.

Title (Optional) The new display name of the site script.

Description (Optional) The new description of the site script.

Version (Optional) The new version number of the site script.

Content (Optional) A new JSON script defining the script actions. For more information, see Site design JSON
schema.

Examples
Here's an example of updating an existing site script with a new JSON script and values.

var updated_site_script =
{
"$schema": "schema.json",
"actions": [
{
"verb": "applyTheme",
"themeName": "Contoso Theme"
}
],
"bindata": { },
"version": 2
};

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.UpdateSiteScript",
{updateInfo:{
Id:"07702c07-0485-426f-b710-4704241caad9",
Title:"New Contoso theme",
Description:"Updated Contoso site script",
Version: 2,
Content: JSON.stringify(updated_site_script)}});

Here is an example of the JSON returned after calling UpdateSiteScript.

{
"@odata.context": "https://contoso.sharepoint.com/_api/$metadata#Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteScriptMetadata",
"Content": "{\"$schema\":\"schema.json\",\"actions\":[{\"verb\":\"applyTheme\",\"themeName\":\"Contoso Theme\"}],\"bindata\":{},\"version\":2}",
"Description": "Updated Contoso site script",
"Id": "07702c07-0485-426f-b710-4704241caad9",
"Title": "New Contoso theme",
"Version": 2
}

DeleteSiteScript
Deletes a site script.

Parameters
PAR AME TER D ES CR IPTIO N

id The ID of the site script to delete.

Examples
Here's an example of deleting a site script.

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.DeleteSiteScript",
{id:"07702c07-0485-426f-b710-4704241caad9"});

CreateSiteDesign
Creates a new site design available to users when they create a new site from the SharePoint home page.

Parameters
PAR AME TER D ES CR IPTIO N

id The ID of the site design to apply.

Title The display name of the site design.

WebTemplate Identifies which base template to add the design to. Use the value 64 for the Team site template, and the
value 68 for the Communication site template.

SiteScripts An array of one or more site scripts. Each is identified by an ID. The scripts will run in the order listed.

Description (Optional) The display description of site design.

PreviewImageUrl (Optional) The URL of a preview image. If none is specified, SharePoint uses a generic image.

PreviewImageAltText (Optional) The alt text description of the image for accessibility.

IsDefault (Optional) True if the site design is applied as the default site design; otherwise, false. For more
information see Customize a default site design.

Examples
Here's an example of creating a new site design.

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.CreateSiteDesign",{
info:{
Title:"Contoso customer tracking",
Description:"Creates customer list and applies standard theme",
SiteScriptIds:["07702c07-0485-426f-b710-4704241caad9"],
WebTemplate:"64",
PreviewImageUrl: "https://contoso.sharepoint.com/SiteAssets/contoso-design.png",
PreviewImageAltText: "Customer tracking site design theme"
}
});

Here is an example of the JSON returned after calling CreateSiteDesign. It contains the ID of the new site design.

{
"@odata.context": "https://contoso.sharepoint.com/_api/$metadata#Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteDesignMetadata",
"Description": "Creates customer list and applies standard theme",
"PreviewImageAltText": "Customer tracking site design theme",
"PreviewImageUrl": "https://contoso.sharepoint.com/SiteAssets/contoso-design.png",
"SiteScriptIds": [ "07702c07-0485-426f-b710-4704241caad9" ],
"Title": "Contoso customer tracking",
"WebTemplate": "64",
"Id": "614f9b28-3e85-4ec9-a961-5971ea086cca",
"Version": 1
}

ApplySiteDesign
Applies a site design to an existing site collection.

Parameters
PAR AME TER D ES CR IPTIO N

id The ID of the site design to apply.

webUrl The URL of the site collection where you want to apply the site design.

Examples
Here's an example of applying a site design to the ProjectGo site collection.

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.ApplySiteDesign", {siteDesignId: "614f9b28-3e85-4ec9-a961-5971ea086cca", "webUrl":"https://contoso.micros

GetSiteDesigns
Gets a list of information about existing site designs.

Parameters
None

Examples
Here's an example of getting all the site designs.

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteDesigns");

Here is an example of the JSON returned after calling GetSiteDesigns.


{
"@odata.context": "https://contoso.sharepoint.com/_api/$metadata#Collection(Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteDesignMetadata)",
"value": [
{
"Description": "Tracks customer orders",
"IsDefault": false,
"PreviewImageAltText": null,
"PreviewImageUrl": null,
"SiteScriptIds": [ "6dfedb96-c090-44e3-875a-1c38032715fc" ],
"Title": "customer orders",
"WebTemplate": "64",
"Id": "bbbd5740-ed97-461b-8b8e-e682f3fa167b",
"Version": 1
},
{
"Description": "Creates customer list and applies standard theme",
"IsDefault": true,
"PreviewImageAltText": "Customer tracking site design theme",
"PreviewImageUrl": "https://contoso.sharepoint.com/SiteAssets/site_design.png",
"SiteScriptIds": [ "07702c07-0485-426f-b710-4704241caad9" ],
"Title": "Contoso customer tracking",
"WebTemplate": "64",
"Id": "614f9b28-3e85-4ec9-a961-5971ea086cca",
"Version": 1
}
]
}

GetSiteDesignMetadata
Gets information about a specific site design.

Parameters
PAR AME TER D ES CR IPTIO N

id The ID of the site design to get information about.

Examples
Here's an example of getting information about a specific site design by ID.

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteDesignMetadata",
{id:"614f9b28-3e85-4ec9-a961-5971ea086cca"});

Here is an example of the JSON returned after calling GetSiteDesignMetadata.

{
"@odata.context": "https://contoso.sharepoint.com/_api/$metadata#Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteDesignMetadata",
"Description": "Creates customer list and applies standard theme",
"IsDefault": true,
"PreviewImageAltText": "Customer tracking site design theme",
"PreviewImageUrl": "https://contoso.sharepoint.com/SiteAssets/site_design.png",
"SiteScriptIds": [ "07702c07-0485-426f-b710-4704241caad9" ],
"Title": "Contoso customer tracking",
"WebTemplate": "64",
"Id": "614f9b28-3e85-4ec9-a961-5971ea086cca",
"Version": 1
}

UpdateSiteDesign
Updates a site design with new values. In the REST call, all parameters are optional except the site script Id.
NOTE

If you had previously set the IsDefault parameter to TRUE and wish it to remain true, you must pass in this parameter again (otherwise it will be reset to FALSE).

Parameters
PAR AME TER D ES CR IPTIO N

Id The ID of the site design to update.

Title (Optional) The new display name of the updated site design.

WebTemplate (Optional) The new template to add the site design to. Use the value 64 for the Team site template, and
the value 68 for the Communication site template.

SiteScripts (Optional) A new array of one or more site scripts. Each is identified by an ID. The scripts run in the order
listed.

Description (Optional) The new display description of the updated site design.

PreviewImageUrl (Optional) The new URL of a preview image.

PreviewImageAltText (Optional) The new alt text description of the image for accessibility.
PAR AME TER D ES CR IPTIO N

IsDefault (Optional) True if the site design is applied as the default site design; otherwise, false. For more
information see Customize a default site design.

Examples
Here's an example that updates every value on an existing site design.

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.UpdateSiteDesign",
{updateInfo:{
Id:"614f9b28-3e85-4ec9-a961-5971ea086cca",
Title:"Contoso customer site",
Description:"Creates site with customer theme and list",
SiteScriptIds:["6b2b79e4-5da3-4352-8565-42a896fabd57","2b997981-258b-4e1e-81ff-f6fbf7235a1f"],
PreviewImageUrl:"https://contoso.sharepoint.com/SiteAssets/customer_site.png",
PreviewImageAltText:"Customer site with list and theme",
WebTemplate:"68",
Version: 7,
IsDefault: false}});

Here is an example of the JSON returned after calling UpdateSiteDesign.

{
"@odata.context": "https://contoso.sharepoint.com/_api/$metadata#Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteDesignMetadata",
"Description": "Creates site with customer theme and list",
"IsDefault": false,
"PreviewImageAltText": "Customer site with list and theme",
"PreviewImageUrl": "https://contoso.sharepoint.com/SiteAssets/customer_site.png",
"SiteScriptIds": [ "6b2b79e4-5da3-4352-8565-42a896fabd57", "2b997981-258b-4e1e-81ff-f6fbf7235a1f" ],
"Title": "Contoso customer site",
"WebTemplate": "68",
"Id": "614f9b28-3e85-4ec9-a961-5971ea086cca",
"Version": 7
}

DeleteSiteDesign
Deletes a site design.

Parameters
PAR AME TER D ES CR IPTIO N

id The ID of the site design to delete.

Examples
Here's an example of deleting a site design.

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.DeleteSiteDesign",
{id:"f9e76746-5076-4bd2-bad3-e611c488fa85"});

GetSiteDesignRights
Gets a list of principals that have access to a site design.

Parameters
PAR AME TER D ES CR IPTIO N

id The ID of the site design to get rights information from.

Examples
Here's an example of getting view rights for a specific site design.

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GetSiteDesignRights",
{id:"dc076f7b-6c15-4d76-8f85-948a17f5dd18"});

Here is an example of the JSON returned after calling GetSiteDesignRights.


{
"@odata.context": "https://contoso.sharepoint.com/_api/$metadata#SiteDesignPrincipals",
"value": [
{
"@odata.type": "#Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteDesignPrincipal",
"@odata.id": "https://contoso.sharepoint.com/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteDesignPrincipalfca62a9f-e43e-49a0-9139-6ae4df212859",
"@odata.editLink": "Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteDesignPrincipalfca62a9f-e43e-49a0-9139-6ae4df212859",
"DisplayName": "Nestor Wilke",
"PrincipalName": "i:0#.f|membership|nestorw@contoso.onmicrosoft.com",
"Rights": 1
},
{
"@odata.type": "#Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteDesignPrincipal",
"@odata.id": "https://contoso.sharepoint.com/_api/Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteDesignPrincipalce4cd6f6-553b-4a55-9364-1d39125be0ef",
"@odata.editLink": "Microsoft.SharePoint.Utilities.WebTemplateExtensions.SiteDesignPrincipalce4cd6f6-553b-4a55-9364-1d39125be0ef",
"DisplayName": "Patti Fernandez",
"PrincipalName": "i:0#.f|membership|pattif@contoso.onmicrosoft.com",
"Rights": 1
}
]
}

GrantSiteDesignRights
Grants access to a site design for one or more principals.

Parameters
PAR AME TER D ES CR IPTIO N

id The ID of the site design to grant rights on.

principalNames An array of one or more principals to grant view rights. Principals can be users or mail-enabled security
groups in the form of "alias" or "alias@<domain name>.com"

grantedRights Always set to 1. This represents the View right.

Examples
Here's an example of granting view rights to a site design for Nestor and Patti (fictional users at Contoso.)

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.GrantSiteDesignRights", {
"id": "dc076f7b-6c15-4d76-8f85-948a17f5dd18",
"principalNames": [ "NestorW@contoso.onmicrosoft.com", "PattiF@contoso.onmicrosoft.com" ],
"grantedRights": 1
});

RevokeSiteDesignRights
Revokes access from a site design for one or more principals.

Parameters
PAR AME TER D ES CR IPTIO N

id The ID of the site design to revoke rights from.

principalNames An array of one or more principals to revoke view rights from. If all principals have rights revoked on the
site design, the site design becomes viewable to everyone.

Examples
Here's an example of revoking view rights from a site design for Patti (fictional user at Contoso.)

RestRequest("/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.RevokeSiteDesignRights",
{id:"5d4756e9-e1f5-42f7-afa7-5fa5aac170aa",
principalNames:["debrab@Contoso.sharepoint.com"] });

See also
SharePoint site design and site script overview
Calling the PnP provisioning engine from a site script
5/11/2018 • 9 minutes to read Edit Online

Site designs offer a great way to standardize the look and feel of your site collections. However, you can't do some things with site designs, such as add a footer to every page. You can use
the PnP provisioning engine to create a template that you can use to provision an Application Customizer to a site. This Application Customizer can then update your page design to register
a footer on every page, for example.
This article describes how to create a site design that applies a PnP provisioning template to a site. The template will add an Application Customizer to render a footer.
The steps in this article use the following components:
A site design and a site script
Microsoft Flow
Azure Queue storage
Azure Functions
A SharePoint Framework (SPFx) solution
A PnP provisioning template
A PnP PowerShell script
An app ID and app secret with administrative rights on your tenant
You'll use these components to trigger the PnP provisioning code after you create the site and apply the site design.

Set up app-only access to your tenant


To set up app-only access, you need to have two different pages on your tenant—one on the regular site, and the other on your SharePoint administration site.
1. Go to following URL in your tenant: https://[yourtenant].sharepoint.com/_layouts/15/appregnew.aspx (you can go to any site, but for now pick the root site).
2. Next to the Client Id and Client Secret fields, choose the Generate button.
3. Enter a title for your app, such as Site Provisioning.
4. In the App Domain box, enter localhost.
5. In the Redirect URI box, enter https://localhost.

6. Choose Create.
7. Copy the values for Client Id and Client Secret because you will need them later.

Next, trust the app, so that it has the appropriate access to your tenant:
1. Go to https://[yourtenant]-admin.sharepoint.com/_layouts/appinv.aspx (notice the -admin in the URL).
2. In the App Id field, paste the Client ID that you copied, and choose Lookup.
3. In the Permission Request XML field, paste the following XML:

<AppPermissionRequests AllowAppOnlyPolicy="true" >


<AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
</AppPermissionRequests>

4. Choose Create.
5. To confirm that you want to trust this app, choose Trust It.

Create the Azure Queue storage


In this section, you will use Azure Queue storage to receive messages from Microsoft Flow. Every time a message shows up in the Queue storage, an Azure function is triggered to run a
PowerShell script.
To set up the Azure Queue storage:
1. Go to the Azure portal and sign in.
2. Choose + New.
3. From the Azure Marketplace listings, select Storage, and in the Featured column, choose Storage account - blob, file, table, queue.
4. Provide values for the required fields. Select Pin to dashboard, and choose Create. It can take a few minutes for the storage account to be created.
5. Open the storage account, and go to Queues.
6. Choose + Queue at the top of the screen.
7. Enter pnpprovisioningqueue for the name, or enter your own value; be sure to follow the naming standard. Make note of the queue name; you will need this value when you create
the Azure function.
8. Go to Access Keys and note the Storage Account Name and the key1 Key value. You will need these values when you create the flow.

Create the flow


To put a message in the queue, you need to create a flow:
1. Go to the Microsoft Flow site, sign in, and choose Create from Blank at the top of the page.
2. Choose Search hundreds of connectors and triggers to select your trigger.
3. Search for Request, and then choose Request - When an HTTP Request is received.
4. Enter the following JSON as your request body:

{
"type": "object",
"properties": {
"webUrl": {
"type": "string"
},
"parameters": {
"type": "object",
"properties": {
"event": {
"type": "string"
},
"product": {
"type": "string"
}
}
}
}
}

5. Select + New Step, and choose Add an action.


6. Search for Azure Queues, and select Azure Queues - Put a message on a queue.
7. Enter a descriptive name for the connection.
8. Enter the storage account name that you copied in the previous section.
9. Enter the storage shared key, which is the value of the Key1 key value field of your storage account.
10. Choose Create.
11. Select pnpprovisioningqueue for the queue name.
12. In the request body, you specified an incoming parameter called webUrl. To put the value of that field in the queue, click in the message field and select webUrl from the Dynamic
Content picker.
13. Choose Save Flow. This generates the URL that you will copy in the next step.
14. Choose the first step in your flow ('When an HTTP request is received') and copy the URL.
15. Save your flow.
Your flow should look like the following.

Test the flow


To test your flow, you have to make a POST request. You can do this via PowerShell, as shown in the following example.
$uri = "[the URI you copied in step 14 when creating the flow]"
$body = "{webUrl:'somesiteurl'}"
Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Body $body

When you go to the main screen of your flow, you will see a run history. If your flow worked correctly, it will show Succeeded .
Now go to the queue you just created in Azure, and choose Refresh. You should see an entry that shows that you correctly invoked the flow.

Provision the SPFx solution


In this section, you'll use an existing SPFx solution, the Regions Footer Application Customizer.
To build and provision the solution, follow the steps in the Readme file in the sample repo.

Create a PnP provisioning template


Copy the following provisioning template XML to a new file and save the file as FlowDemoTemplate.xml.

<?xml version="1.0"?>
<pnp:Provisioning xmlns:pnp="http://schemas.dev.office.com/PnP/2017/05/ProvisioningSchema">
<pnp:Preferences Generator="OfficeDevPnP.Core, Version=2.20.1711.0, Culture=neutral, PublicKeyToken=3751622786b357c2" />
<pnp:Templates ID="CONTAINER-FLOWDEMO">
<pnp:ProvisioningTemplate ID="TEMPLATE-FLOWDEMO" Version="1" BaseSiteTemplate="GROUP#0" Scope="RootSite">
<pnp:CustomActions>
<pnp:WebCustomActions>
<pnp:CustomAction Name="spfx-react-app-customizer" Description="Custom action for Application Customizer" Location="ClientSideExtension.ApplicationCustomizer" Title="spfx-react-app-cust
</pnp:WebCustomActions>
</pnp:CustomActions>
</pnp:ProvisioningTemplate>
</pnp:Templates>
</pnp:Provisioning>

NOTE

The provisioning template adds a custom action to a solution. The ClientSideComponentId is associated with the Regions Footer Application Customizer that you provisioned earlier. If
you run this demo with your own SPFx solution, change the ClientSideComponentId and optionally the ClientSideComponentProperties attribute values in the XML.

Create the Azure function


1. Go to the Azure portal .
2. Search for Function App, and create a new function app. In the Storage field, select Use existing, and then select the storage account that you created earlier. Set the other values as
required.
3. Open the Function app and select Functions > New function.

4. From the Language drop-down box, select PowerShell.


5. Select QueueTrigger - PowerShell.
6. Name the function ApplyPnPProvisioningTemplate.
7. Enter the name of the queue you created earlier.
8. Choose Create. An editor where you can enter PowerShell cmdlets opens.
Next, you'll upload the PnP PowerShell module so that you can use it in the Azure function.

Upload the PnP PowerShell module for your Azure function


You'll need to download the PnP PowerShell module so that you can upload it for your Azure function.
1. Create a temporary folder on your computer.
2. Launch PowerShell and enter the following:

Save-Module -Name SharePointPnPPowerShellOnline -Path [pathtoyourfolder]

The PowerShell module files download to a folder within the folder that you created.

Next, upload the files so that your Azure function can use the module.
1. Go to the main page of your Function app and select Platform features.
2. Select Advanced tools (Kudu).

3. On the main Kudu page, select Debug Console and choose either CMD or PowerShell.
4. Choose the File Explorer on the upper part of the page, and go to site\wwwroot\[nameofyourazurefunction].
5. Create a new folder named modules.

6. In the modules folder, create another folder called SharePointPnPPowerShellOnline, and go to that folder.
7. In File Explorer on your computer, go to the folder where you downloaded the PnP PowerShell module files. Open the SharePointPnPPowerShellOnline\2.20.1711.0 folder (notice
that the version number might be different).
8. Drag and drop all the files from this folder into the folder in Kudu to upload them.

Finish the Azure function


1. Go back to your Azure function and expand the files tab to the right.

2. Select Upload and upload the provisioning template file that you created earlier.
3. Replace the PowerShell script with the following:

$in = Get-Content $triggerInput -Raw


Write-Output "Incoming request for '$in'"
Connect-PnPOnline -AppId $env:SPO_AppId -AppSecret $env:SPO_AppSecret -Url $in
Write-Output "Connected to site"
Apply-PnPProvisioningTemplate -Path D:\home\site\wwwroot\ApplyPnPProvisioningTemplate\FlowDemoTemplate.xml

4. Notice that you're using two environment variables: SPO_AppId and SPO_AppSecret . To set those variables, go to the main Function app page in the Azure portal, select Application
settings, and add two new application settings:
SPO_AppId - Set the value to the Client ID you copied in the first step when you created your app on your tenant.
SPO_AppSecret - Set the value to the Client Secret that you copied in the first step when you created your app on your tenant.

Create the site design


1. Open PowerShell and make sure that you have the SharePoint Online Management Shell installed.
2. Connect to your tenant using Connect-SPOService.

Connect-SPOService -Url https://[yourtenant]-admin.sharepoint.com

3. Now you can get the existing site designs.

Get-SPOSiteDesign

To create a site design, you first need to create a site script. A site design is a container that refers to one or more site scripts.
1. Copy the following JSON code to your clipboard and modify it. Set the url property to the value that you copied when you created the flow. The URL looks similar to the following:
https://prod-27.westus.logic.azure.com:443/workflows/ef7434cf0d704dd48ef5fb6...oke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun

{
"$schema": "schema.json",
"actions": [
{
"verb": "triggerFlow",
"url": "[paste the workflow trigger URL here]",
"name": "Apply Template",
"parameters": {
"event":"",
"product":""
}
}
],
"bindata": {},
"version": 1
}

2. Select the JSON again and copy it again to your clipboard.


3. Open PowerShell and enter the following to copy the script into a variable and create the site script:

$script = Get-Clipboard -Raw


Add-SPOSiteScript -Title "Apply PnP Provisioning Template" -Content $script
Get-SPOSiteScript

4. You will see a list of one or more site scripts, including the site script you just created. Select the ID of the site script that you created, and copy it to the clipboard.
5. Use the following command to create the site design:

Add-SPOSiteDesign -Title "Site with footer" -SiteScripts [Paste the ID of the Site Script here] -WebTemplate "64"

The Add-SPOSiteDesign cmdlet associates the site design with the Team site. If you want to associate the design with a Communication site, use the value "68".

Verify the results


After you created your Azure Queue storage, you created the app ID for app-only access, the Azure function, and the site design. You then triggered the Microsoft Flow from the site design.
To test the results, create a new site. In your SharePoint tenant, select SharePoint > Create Site > Team Site.
Your new site design should show up as a design option. Notice that the site design is applied after the site is created. If you configured it correctly, your flow will be triggered. You can check
the run history of the flow to verify that it ran correctly. Note that the footer might not show up immediately; if you don't see it, wait a minute and reload your site to check again.

See also
SharePoint site design and site script overview
SharePoint site theming
7/6/2018 • 4 minutes to read Edit Online

SharePoint site owners have new options for applying custom styles and colors to sites that make it easier to define and manage themes across site collections.
These new features include:
The ability to define custom themes and make them available to site owners. Themes are defined in a JSON schema that stores color settings and related metadata for each theme.
An online Theme Generator tool that you can use to define new custom themes.
A simplified set of default themes, with six light themes and two dark themes presently available.
An updated color palette, with 12 light colors and 6 dark colors, as well as 16 supplementary themes.
Control over which themes are available for use on pages within your sites. For example, you can define custom themes based on your organization's branding or identity, and make those
the only available themes within your sites.
These capabilities are available to administrators via PowerShell cmdlets, and to developers via the SharePoint client-side object model (CSOM) or the SharePoint REST API.
For general information about working with themes to customize the look of your sites, see Change the look of your SharePoint site.

Default themes
The following predefined themes are available by default:
Blue
Orange
Red
Purple
Green
Gray
Dark Yellow (inverted theme)
Dark Blue (inverted theme)
These themes have been designed for readability, so you might find them to be useful starting points for creating custom themes. For more information about default themes, see SharePoint
site theming: JSON schema.
In addition to the default themes, you can select from supplementary themes. The following customizations are available:
Light themes: Gold, Teal, Dark Blue, Indigo, Plum, Warm Gray
Dark themes: Red, Green, Purple, Gray

Select a modern theme


To select from the available themes for a SharePoint site, choose the gear icon ( ) in the top right corner of the screen, and then select Change the look. You'll be presented with a list of
themes to choose from, which might include default themes and/or custom themes depending on how your site has been configured.
The following image shows how the default themes are presented in the theme picker dialog box.
When you choose a theme in the list, those color settings are instantly applied to the page so that you can see what the selected theme will look like.
After you've found a theme that you want to use, choose Save to save your selection, or choose Cancel to revert to your current theme.

Work with classic themes


You can still use the classic themes by choosing the link to Classic change the look options under the modern themes listed under Change the look. Because the modern SharePoint UI
differs from the classic UI, however, some limitations apply when you use classic themes with modern pages.
When you select a classic theme, a modern theme is generated from the settings in the classic theme, including the isInverted flag, the background image, and the color settings for
ContentAccent1, PageBackground, and BackgroundOverlay. If isInverted is set to True, neutral colors such as NeutralDark and NeutralLight will be reversed.
For the simplest experience, we recommend that you use modern themes with modern pages. If you need to use classic themes with modern pages, test your site carefully to verify that your
content is readable and accessible.

Troubleshoot custom theme issues


The modern site theming experience has been rolled out to classic site templates, too. While the new client-side theming architecture is more performant, if you have customizations on
classic sites that aren’t rendering properly after you change the site’s theme, you can opt the site out of the new theming experience by disabling the feature. Please note, this opt-out only
applies to classic sites where you have custom theme references that aren't rendering properly. By enabling this site-level opt-out you will disable the modern theming - and also lose the fast
theming benefits it provides.
To do this, you must use a Windows PowerShell script with a CSOM (client-side object model) wrapper. We recommend using the PnP enable feature command:
1. Verify that you meet the following minimum requirements:
You are a global administrator.
You have read about Execution Policies.
2. Download the latest PnP PowerShell from https://github.com/SharePoint/PnP-PowerShell/releases.
3. Enter Connect-PnPOnline -Url <SiteUrl> -Credentials getCredentials (replacing <SiteUrl> with the url of the site you wish to opt out of).
4. Enter your credentials when prompted.
5. To opt out of the site, you need to enable a feature:
Enter “Get-PnPFeature -Scope Site -Identity 5138468E-3D76-4F72-9DE4-E029F1245A7B”
Verify that nothing is returned from the previous command (this confirms the feature isn’t enabled yet)
Enter “Enable-PnPFeature -Scope Site -Identity 5138468E-3D76-4F72-9DE4-E029F1245A7B”
Enter “Get-PnPFeature -Scope Site -Identity 5138468E-3D76-4F72-9DE4-E029F1245A7B”
6. Verify that the following is returned:
ClientSideThemingOptOut - 5138468e-3d76-4f72-9de4-e029f1245a7b
7. For more information about Windows PowerShell, see PowerShell.

See also
SharePoint site theming: JSON schema
SharePoint site theming: PowerShell cmdlets
SharePoint site theming: CSOM API
SharePoint site theming: REST API
SharePoint site theming: JSON schema
4/23/2018 • 7 minutes to read Edit Online

The new SharePoint site theming features use a JSON schema to store color settings and other information about each theme. Theme settings are stored in a JSON object that contains the
following keys:
name – The name of the theme, which appears in the theme picker UI and is also used by administrators and developers to refer to the theme in PowerShell cmdlets or calls to the
SharePoint REST API.
isInverted – This value should be false for light themes and true for dark themes; it controls whether SharePoint uses dark or light theme colors to render text on colored
backgrounds.
backgroundImageUri – The URI of an optional background image for the theme (value can be blank if no background image).
theme – The RGB color settings for the theme, stored as a nested JSON object with the following keys:
themePrimary
themeLighterAlt
themeLighter
themeLight
themeTertiary
themeSecondary
themeDarkAlt
themeDark
themeDarker
neutralLighterAlt
neutralLighter
neutralLight
neutralQuaternaryAlt
neutralQuaternary
neutralTertiaryAlt
neutralTertiary
neutralSecondaryAlt
neutralSecondary
neutralPrimaryAlt
neutralPrimary
neutralDark
black
white
primaryBackground
primaryText
bodyBackground
bodyText
disabledBackground
disabledText
error
accent
The colors in the theme element are specified as 6-digit or 3-digit hexadecimal RGB string values.
The following is an example of a JSON object that defines a theme.
{
name: 'Blue',
isInverted: true,
backgroundImageUri: '',
theme: {
themePrimary: "#00bcf2",
themeLighterAlt: "#00090c",
themeLighter: "#001318",
themeLight: "#002630",
themeTertiary: "#005066",
themeSecondary: "#00abda",
themeDarkAlt: "#0ecbff",
themeDark: "#44d6ff",
themeDarker: "#6cdfff",
neutralLighterAlt: "#2e3340",
neutralLighter: "#353a49",
neutralLight: "#404759",
neutralQuaternaryAlt: "#474e62",
neutralQuaternary: "#4c546a",
neutralTertiaryAlt: "#646e8a",
neutralTertiary: "#c8c8c8",
neutralSecondaryAlt: "#d0d0d0",
neutralSecondary: "#dadada",
neutralPrimaryAlt: "#eaeaea",
neutralPrimary: "#ffffff",
neutralDark: "#f4f4f4",
black: "#f8f8f8",
white: "#262a35",
primaryBackground: "#262a35",
primaryText: "#ffffff",
bodyBackground: "#ffffff";
bodyText: "#333333";
disabledBackground: "#f4f4f4";
disabledText: "#c8c8c8";
error: "#ff5f5f";
accent: "#ffb900";
}
}

The SharePoint Framework includes eight built-in themes: six on light backgrounds, and two on dark backgrounds. You might find it useful to create a custom theme by starting from one of
the built-in themes and adjusting it to suit your needs.
Another option is to use the Theme Generator tool to build a custom theme. It provides an interactive UI for selecting theme colors, and automatically generates the JSON, SASS, and
PowerShell definitions for your custom theme.
NOTE

The theme generator definitions do not currently include the "error" or "accent" color slots. These can be manually added to your generated definition before uploading to the tenant.
The following is a summary of the built-in themes, including JSON definitions for the theme colors that you can use as a starting point for customization.

Red theme
The following table shows the color palette used by the Red theme.

themeDarker: #751b1e black: #000000

themeDark: #952226 neutralDark: #212121

themeDarkAlt: #c02b30 neutralPrimary: #333

neutralPrimaryAlt: #3c3c3c

themePrimary: #d13438 neutralSecondary: #666666

neutralTertiary: #a6a6a6

themeSecondary: #d6494d neutralTertiaryAlt: #c8c8c8

themeTertiary: #ecaaac neutralLight: #eaeaea

themeLight: #f6d6d8 neutralLighter: #f4f4f4

themeLighter: #faebeb neutralLighterAlt: #f8f8f8

themeLighterAlt: #fdf5f5 white: #fff


The following code shows how to define a dictionary in PowerShell for the Red theme's color palette.

{
themeDarker: '#751b1e',
themeDark: '#952226',
themeDarkAlt: '#c02b30',
themePrimary: '#d13438',
themeSecondary: '#d6494d',
themeTertiary: '#ecaaac',
themeLight: '#f6d6d8',
themeLighter: '#faebeb',
themeLighterAlt: '#fdf5f5',
black: '#000000',
neutralDark: '#212121',
neutralPrimary: '#333',
neutralPrimaryAlt: '#3c3c3c',
neutralSecondary: '#666666',
neutralTertiary: '#a6a6a6',
neutralTertiaryAlt: '#c8c8c8',
neutralLight: '#eaeaea',
neutralLighter: '#f4f4f4',
neutralLighterAlt: '#f8f8f8',
white: '#fff',
neutralQuaternaryAlt: '#dadada',
neutralQuaternary: '#d0d0d0',
neutralSecondaryAlt: '#767676',
primaryBackground: '#fff',
primaryText: '#333'
}

Orange theme
The following table shows the color palette used by the Orange theme.

themeDarker: #6f2d09 black: #000000

themeDark: #8d390b neutralDark: #212121

themeDarkAlt: #b5490f neutralPrimary: #333

neutralPrimaryAlt: #3c3c3c

themePrimary: #ca5010 neutralSecondary: #666666

neutralTertiary: #a6a6a6

themeSecondary: #e55c12 neutralTertiaryAlt: #c8c8c8

themeTertiary: #f6b28d neutralLight: #eaeaea

themeLight: #fbdac9 neutralLighter: #f4f4f4

themeLighter: #fdede4 neutralLighterAlt: #f8f8f8

themeLighterAlt: #fef6f1 white: #fff

The following code shows how to define a dictionary in PowerShell for the Orange theme's color palette.

{
themeDarker: '#6f2d09',
themeDark: '#8d390b',
themeDarkAlt: '#b5490f',
themePrimary: '#ca5010',
themeSecondary: '#e55c12',
themeTertiary: '#f6b28d',
themeLight: '#fbdac9',
themeLighter: '#fdede4',
themeLighterAlt: '#fef6f1',
black: '#000000',
neutralDark: '#212121',
neutralPrimary: '#333',
neutralPrimaryAlt: '#3c3c3c',
neutralSecondary: '#666666',
neutralTertiary: '#a6a6a6',
neutralTertiaryAlt: '#c8c8c8',
neutralLight: '#eaeaea',
neutralLighter: '#f4f4f4',
neutralLighterAlt: '#f8f8f8',
white: '#fff',
neutralQuaternaryAlt: '#dadada',
neutralQuaternary: '#d0d0d0',
neutralSecondaryAlt: '#767676',
primaryBackground: '#fff',
primaryText: '#333'
}
Green theme
The following table shows the color palette used by the Green theme.

themeDarker: #094c23 black: #000000

themeDark: #0c602c neutralDark: #212121

themeDarkAlt: #0f7c39 neutralPrimary: #333

neutralPrimaryAlt: #3c3c3c

themePrimary: #10893e neutralSecondary: #666666

neutralTertiary: #a6a6a6

themeSecondary: #14a94e neutralTertiaryAlt: #c8c8c8

themeTertiary: #7aefa7 neutralLight: #eaeaea

themeLight: #bff7d5 neutralLighter: #f4f4f4

themeLighter: #dffbea neutralLighterAlt: #f8f8f8

themeLighterAlt: #effdf4 white: #fff

The following code shows how to define a dictionary in PowerShell for the Green theme's color palette.

{
themePrimary: '#10893e',
themeLighterAlt: '#effdf4',
themeLighter: '#dffbea',
themeLight: '#bff7d5',
themeTertiary: '#7aefa7',
themeSecondary: '#14a94e',
themeDarkAlt: '#0f7c39',
themeDark: '#0c602c',
themeDarker: '#094c23',
neutralLighterAlt: '#f8f8f8',
neutralLighter: '#f4f4f4',
neutralLight: '#eaeaea',
neutralQuaternaryAlt: '#dadada',
neutralQuaternary: '#d0d0d0',
neutralTertiaryAlt: '#c8c8c8',
neutralTertiary: '#a6a6a6',
neutralSecondaryAlt: '#767676',
neutralSecondary: '#666666',
neutralPrimary: '#333',
neutralPrimaryAlt: '#3c3c3c',
neutralDark: '#212121',
black: '#000000',
white: '#fff',
primaryBackground: '#fff',
primaryText: '#333'
}

Blue theme
The following table shows the color palette used by the Blue theme.

themeDarker: #004578 black: #000000

themeDark: #005a9e neutralDark: #212121

themeDarkAlt: #106ebe neutralPrimary: #333

neutralPrimaryAlt: #3c3c3c

themePrimary: #0078d7 neutralSecondary: #666666

neutralTertiary: #a6a6a6

themeSecondary: #2b88d8 neutralTertiaryAlt: #c8c8c8

themeTertiary: #71afe5 neutralLight: #eaeaea

themeLight: #c7e0f4 neutralLighter: #f4f4f4


themeLighter: #deecf9 neutralLighterAlt: #f8f8f8

themeLighterAlt: #eff6fc white: #fff

The following code shows how to define a dictionary in PowerShell for the Blue theme's color palette.

{
themePrimary: '#0078d7',
themeLighterAlt: '#eff6fc',
themeLighter: '#deecf9',
themeLight: '#c7e0f4',
themeTertiary: '#71afe5',
themeSecondary: '#2b88d8',
themeDarkAlt: '#106ebe',
themeDark: '#005a9e',
themeDarker: '#004578',
neutralLighterAlt: '#f8f8f8',
neutralLighter: '#f4f4f4',
neutralLight: '#eaeaea',
neutralQuaternaryAlt: '#dadada',
neutralQuaternary: '#d0d0d0',
neutralTertiaryAlt: '#c8c8c8',
neutralTertiary: '#a6a6a6',
neutralSecondaryAlt: '#767676',
neutralSecondary: '#666666',
neutralPrimary: '#333',
neutralPrimaryAlt: '#3c3c3c',
neutralDark: '#212121',
black: '#000000',
white: '#fff',
primaryBackground: '#fff',
primaryText: '#333'
}

Purple theme
The following table shows the color palette used by the Purple theme.

themeDarker: #27268a black: #000000

themeDark: #3230b0 neutralDark: #212121

themeDarkAlt: #5250cf neutralPrimary: #333

neutralPrimaryAlt: #3c3c3c

themePrimary: #6b69d6 neutralSecondary: #666666

neutralTertiary: #a6a6a6

themeSecondary: #7a78da neutralTertiaryAlt: #c8c8c8

themeTertiary: #c1c0ee neutralLight: #eaeaea

themeLight: #e1e1f7 neutralLighter: #f4f4f4

themeLighter: #f0f0fb neutralLighterAlt: #f8f8f8

themeLighterAlt: #f8f7fd white: #fff

The following code shows how to define a dictionary in PowerShell for the Purple theme's color palette.
{
themePrimary: '#6b69d6',
themeLighterAlt: '#f8f7fd',
themeLighter: '#f0f0fb',
themeLight: '#e1e1f7',
themeTertiary: '#c1c0ee',
themeSecondary: '#7a78da',
themeDarkAlt: '#5250cf',
themeDark: '#3230b0',
themeDarker: '#27268a',
neutralLighterAlt: '#f8f8f8',
neutralLighter: '#f4f4f4',
neutralLight: '#eaeaea',
neutralQuaternaryAlt: '#dadada',
neutralQuaternary: '#d0d0d0',
neutralTertiaryAlt: '#c8c8c8',
neutralTertiary: '#a6a6a6',
neutralSecondaryAlt: '#767676',
neutralSecondary: '#666666',
neutralPrimary: '#333',
neutralPrimaryAlt: '#3c3c3c',
neutralDark: '#212121',
black: '#000000',
white: '#fff',
primaryBackground: '#fff',
primaryText: '#333'
}

Gray theme
The following table shows the color palette used by the Gray theme.

themeDarker: #323130 black: #000000

themeDark: #403e3d neutralDark: #212121

themeDarkAlt: #53504e neutralPrimary: #333

neutralPrimaryAlt: #3c3c3c

themePrimary: #5d5a58 neutralSecondary: #666666

neutralTertiary: #a6a6a6

themeSecondary: #6d6a67 neutralTertiaryAlt: #c8c8c8

themeTertiary: #bbb9b8 neutralLight: #eaeaea

themeLight: #dfdedd neutralLighter: #f4f4f4

themeLighter: #efeeee neutralLighterAlt: #f8f8f8

themeLighterAlt: #f7f7f7 white: #fff

The following code shows how to define a dictionary in PowerShell for the Gray theme's color palette.

{
themePrimary: '#5d5a58',
themeLighterAlt: '#f7f7f7',
themeLighter: '#efeeee',
themeLight: '#dfdedd',
themeTertiary: '#bbb9b8',
themeSecondary: '#6d6a67',
themeDarkAlt: '#53504e',
themeDark: '#403e3d',
themeDarker: '#323130',
neutralLighterAlt: '#f8f8f8',
neutralLighter: '#f4f4f4',
neutralLight: '#eaeaea',
neutralQuaternaryAlt: '#dadada',
neutralQuaternary: '#d0d0d0',
neutralTertiaryAlt: '#c8c8c8',
neutralTertiary: '#a6a6a6',
neutralSecondaryAlt: '#767676',
neutralSecondary: '#666666',
neutralPrimary: '#333',
neutralPrimaryAlt: '#3c3c3c',
neutralDark: '#212121',
black: '#000000',
white: '#fff',
primaryBackground: '#fff',
primaryText: '#333'
}

Dark Yellow theme


The following table shows the color palette used by the Dark Yellow theme.

themeDarker: #fff171 black: #f8f8f8

themeDark: #ffed4b neutralDark: #f4f4f4

themeDarkAlt: #ffe817 neutralPrimary: #ffffff

neutralPrimaryAlt: #eaeaea

themePrimary: #fce100 neutralSecondary: #dadada

neutralTertiary: #c8c8c8

themeSecondary: #e3cc00 neutralTertiaryAlt: #6d6d6d

themeTertiary: #6a5f00 neutralLight: #3f3f3f

themeLight: #322d00 neutralLighter: #313131

themeLighter: #191700 neutralLighterAlt: #282828

themeLighterAlt: #0d0b00 white: #1f1f1f

The following code shows how to define a dictionary in PowerShell for the Dark Yellow theme's color palette.

{
themePrimary: '#fce100',
themeLighterAlt: '#0d0b00',
themeLighter: '#191700',
themeLight: '#322d00',
themeTertiary: '#6a5f00',
themeSecondary: '#e3cc00',
themeDarkAlt: '#ffe817',
themeDark: '#ffed4b',
themeDarker: '#fff171',
neutralLighterAlt: '#282828',
neutralLighter: '#313131',
neutralLight: '#3f3f3f',
neutralQuaternaryAlt: '#484848',
neutralQuaternary: '#4f4f4f',
neutralTertiaryAlt: '#6d6d6d',
neutralTertiary: '#c8c8c8',
neutralSecondaryAlt: '#d0d0d0',
neutralSecondary: '#dadada',
neutralPrimaryAlt: '#eaeaea',
neutralPrimary: '#ffffff',
neutralDark: '#f4f4f4',
black: '#f8f8f8',
white: '#1f1f1f',
primaryBackground: '#1f1f1f',
primaryText: '#ffffff',
error: '#ff5f5f'
}

Dark Blue theme


The following table shows the color palette used by the Dark Blue theme.

themeDarker: #6cdfff black: #f8f8f8

themeDark: #44d6ff neutralDark: #f4f4f4

themeDarkAlt: #0ecbff neutralPrimary: #ffffff

neutralPrimaryAlt: #eaeaea

themePrimary: #00bcf2 neutralSecondary: #dadada

neutralTertiary: #c8c8c8

themeSecondary: #00abda neutralTertiaryAlt: #646e8a

themeTertiary: #005066 neutralLight: #404759

themeLight: #002630 neutralLighter: #353a49

themeLighter: #001318 neutralLighterAlt: #2e3340

themeLighterAlt: #00090c white: #262a35


The following code shows how to define a dictionary in PowerShell for the Dark Blue theme's color palette.

{
themePrimary: '#00bcf2',
themeLighterAlt: '#00090c',
themeLighter: '#001318',
themeLight: '#002630',
themeTertiary: '#005066',
themeSecondary: '#00abda',
themeDarkAlt: '#0ecbff',
themeDark: '#44d6ff',
themeDarker: '#6cdfff',
neutralLighterAlt: '#2e3340',
neutralLighter: '#353a49',
neutralLight: '#404759',
neutralQuaternaryAlt: '#474e62',
neutralQuaternary: '#4c546a',
neutralTertiaryAlt: '#646e8a',
neutralTertiary: '#c8c8c8',
neutralSecondaryAlt: '#d0d0d0',
neutralSecondary: '#dadada',
neutralPrimaryAlt: '#eaeaea',
neutralPrimary: '#ffffff',
neutralDark: '#f4f4f4',
black: '#f8f8f8',
white: '#262a35',
primaryBackground: '#262a35',
primaryText: '#ffffff',
error: '#ff5f5f'
}

See also
SharePoint site theming overview
SharePoint site theming: PowerShell cmdlets
SharePoint site theming: CSOM API
SharePoint site theming: REST API
SharePoint site theming: PowerShell cmdlets
3/26/2018 • 2 minutes to read Edit Online

SharePoint tenant administrators can use PowerShell cmdlets to create, retrieve, and remove site themes.
Developers can use the SharePoint REST API to handle theme management tasks.
For information about how themes are defined and stored, see JSON schema reference.

Getting started
To run the PowerShell cmdlets for theme management, you must do the following:
1. Download and install the SharePoint Online Management Shell. If you already have a previous version of the shell installed, uninstall it first and then install the latest version.
2. Follow the instructions at Connect to SharePoint Online PowerShell to connect to your SharePoint tenant.
To verify your setup, try using the Get-SPOHideDefaultThemes cmdlet to read the SPOHideDefaultThemes setting. If the cmdlet runs and returns False with no errors, as shown in the
following example, you're ready to proceed.

Site theme cmdlets


The following cmdlets are available for managing site themes from PowerShell:
Add-SPOTheme – Creates a new custom theme, or overwrites an existing theme to modify its settings.
Get-SPOTheme – Retrieves settings for an existing theme.
Remove-SPOTheme – Removes a theme from the theme gallery.
Set-SPOHideDefaultThemes – Specifies whether the default themes should be available.
Get-SPOHideDefaultThemes – Queries the current SPOHideDefaultThemes setting.

See also
SharePoint site theming overview
SharePoint site theming: CSOM
SharePoint site theming: CSOM development
4/20/2018 • 3 minutes to read Edit Online

The SharePoint client-side object model (CSOM) provides access to the SharePoint object model from code that is running locally or on a different server than SharePoint.

Prerequisites
Before you get started, make sure that you're familiar with the following:
Using the Client Object Model
Common Programming Tasks in the Managed Client Object Model
You also need to reference the Microsoft.SharePointOnline.CSOM NuGet package (version 16.1.6906.1200 or later).

CSOM code example


The following example shows how to create a Microsoft.Online.SharePoint.TenantAdministration.Tenant object and call the GetAllTenantThemes method to return a list of themes.
NOTE

The URL used to create the context object includes the -admin suffix because TenantAdministration methods work with the admin site.
Create a Tenant instance with the Tenant constructor, and then call the methods on that instance.
You can use the same approach to call other theme management methods.

using System.Security;
using Microsoft.SharePoint.Client;
using Microsoft.Online.SharePoint.TenantAdministration;
using Microsoft.Online.SharePoint.TenantManagement;

...

ClientContext ctx = new ClientContext("https://mysite-admin.sharepoint.com/");


var pwd = "mypassword";
var passWord = new SecureString();
foreach (char c in pwd.ToCharArray()) passWord.AppendChar(c);
ctx.Credentials = new SharePointOnlineCredentials("admin@mydomain.com", passWord);
Tenant tenant = new Tenant(ctx);
ClientObjectList<ThemeProperties> themes = tenant.GetAllTenantThemes();

Theme definition example


For methods that take a theme argument, the following code defines an SPOTheme class that you can use to create custom themes.

/// <summary>
/// Properties defining a theme in SharePoint Online.
/// </summary>
public class SPOTheme
{
/// <summary>
/// Specifies the name of the theme. This must uniquely identify the theme.
/// </summary>
public string Name
{
get; private set;
}
/// <summary>
/// Specifies the palette of colors in the theme, as a dictionary of theme slot values.
/// </summary>
public IDictionary<String, String> Palette
{
get; private set;
}
/// <summary>
/// Specifies whether the theme is inverted, with a dark background and a light foreground.
/// </summary>
public bool IsInverted
{
get; private set;
}
}

Applying a theme
There's currently no supported API to programmatically apply a theme to a specific site.

Methods/properties of the Microsoft.Online.SharePoint.TenantAdministration.Tenant class


Use the following methods to customize the set of available themes for a SharePoint tenant administration site. You can add a new custom theme, update an existing theme, or delete a
theme, and you can retrieve a specific theme or all themes. You can also hide or restore the default themes that come with SharePoint.

AddTenantTheme public method


Add a theme to the tenant.
Namespace: Microsoft.Online.SharePoint.TenantAdministration.Tenant
Parameters: string name, string themeJson
Return type: ClientResult

DeleteTenantTheme public method


Delete a theme from the tenant.
Namespace: Microsoft.Online.SharePoint.TenantAdministration.Tenant
Parameters: string name
Return type: void

GetAllTenantThemes public method


Retrieve all the themes that are currently available in the tenant, including any custom themes that have been added. Default themes are only included if the HideDefaultThemes property
is false (the default value).
Namespace: Microsoft.Online.SharePoint.TenantAdministration.Tenant
Parameters: none
Return type: ClientObjectList

GetTenantTheme public method


Retrieve a theme by name.
Namespace: Microsoft.Online.SharePoint.TenantAdministration.Tenant
Parameters: string name
Return type: ThemeProperties

HideDefaultThemes public property


This property indicates whether the default themes are available in the theme picker UI. The default setting is false (the default themes are available), but you might want to set this property
to true after you define custom themes, to allow only specific themes to be used.
Namespace: Microsoft.Online.SharePoint.TenantAdministration.Tenant
Type: Boolean

UpdateTenantTheme public method


Update the settings for an existing theme.
Namespace: Microsoft.Online.SharePoint.TenantAdministration.Tenant
Parameters: string name, string themeJson
Return type: ClientResult

Methods of the Microsoft.Online.SharePoint.TenantManagement.Tenant class


These are alternative APIs to manage your themes at the tenant level.

AddTenantTheme public method


Add a theme to the tenant.
Namespace: Microsoft.Online.SharePoint.TenantManagement.Tenant
Parameters: string name, string themeJson
Return type: ClientResult

GetAllTenantThemes public method


Retrieve all the themes that are currently available in the tenant, including any custom themes that have been added. Default themes are only included if the HideDefaultThemes property
is false (the default value).
Namespace: Microsoft.Online.SharePoint.TenantManagement.Tenant
Parameters: none
Return type: ClientObjectList

GetHideDefaultThemes public method


Read the current setting for whether to hide default themes in the theme picker UI.
Namespace: Microsoft.Online.SharePoint.TenantManagement.Tenant
Parameters: none
Return type: ClientResult

GetTenantTheme public method


Retrieve a theme by name.
Namespace: Microsoft.Online.SharePoint.TenantManagement.Tenant
Parameters: string name
Return type: ThemeProperties

SetHideDefaultThemes public method


Specify whether to hide default themes in the theme picker UI.
Namespace: Microsoft.Online.SharePoint.TenantManagement.Tenant
Parameters: Boolean
Return type: void

UpdateTenantTheme public method


Update the settings for an existing theme.
Namespace: Microsoft.Online.SharePoint.TenantManagement.Tenant
Parameters: string name, string themeJson
Return type: ClientResult

See also
SharePoint site theming overview
SharePoint site theming: JSON schema
SharePoint site theming: PowerShell cmdlets
SharePoint site theming: REST API
SharePoint site theming: REST API
4/20/2018 • 2 minutes to read Edit Online

You can use the the SharePoint REST interface to perform basic create, read, update, and delete (CRUD) operations on site themes.
The SharePoint Online (and SharePoint 2016 and later on-premises) REST service supports combining multiple requests into a single call to the service by using the OData $batch query
option. For details and links to code samples, see Make batch requests with the REST APIs.

Prerequisites
Before you get started, make sure that you're familiar with the following:
Get to know the SharePoint REST service
Complete basic operations using SharePoint REST endpoints

REST commands for site themes


The following REST commands are available for working with site themes:
AddTenantTheme – create a new theme; similar to the Add-SPOTheme SharePoint cmdlet
RemoveTenantTheme – remove a theme from the tenant store; similar to the Remove-SPOTheme PowerShell cmdlet
GetTenantThemingOptions – read theme settings
The URL for theme management REST commands is based on _api/thememanager. For example, the following are the endpoints for the commands:
http://<site url>/_api/thememanager/AddTenantTheme
http://<site url>/_api/thememanager/RemoveTenantTheme
http://<site url>/_api/thememanager/GetTenantThemingOptions

AddTenantTheme
The following JavaScript sample code shows how to add a new theme to a tenant.

function RestRequest(url,params) {
var req = new XMLHttpRequest();
req.onreadystatechange = function ()
{
if (req.readyState != 4) // Loaded
return;
console.log(req.responseText);
};
req.open("POST",url,true);
req.setRequestHeader("Content-Type", "application/json;charset=utf-8");
req.setRequestHeader("ACCEPT", "application/json; odata.metadata=minimal");
req.setRequestHeader("x-requestdigest", _spPageContextInfo.formDigestValue);
req.setRequestHeader("ODATA-VERSION","4.0");
req.send(params ? JSON.stringify(params) : void 0);
}
RestRequest("/_api/thememanager/GetTenantThemingOptions");

var pal = {
"palette" : {
"themePrimary": "#1BF242",
"themeLighterAlt": "#0d0b00",
"themeLighter": "#0b35bc",
"themeLight": "#322d00",
"themeTertiary": "#6a5f00",
"themeSecondary": "#1B22F2",
"themeDarkAlt": "#ffe817",
"themeDark": "#ffed4b",
"themeDarker": "#fff171",
"neutralLighterAlt": "#252525",
"neutralLighter": "#282828",
"neutralLight": "#313131",
"neutralQuaternaryAlt": "#3f3f3f",
"neutralQuaternary": "#484848",
"neutralTertiaryAlt": "#4f4f4f",
"neutralTertiary": "#c8c8c8",
"neutralSecondaryAlt": "#d0d0d0",
"neutralSecondary": "#dadada",
"neutralPrimary": "#ffffff",
"neutralDark": "#eaeaea",
"black": "#f8f8f8",
"white": "#1f1f1f",
"primaryBackground": "#1f1f1f",
"primaryText": "#ffffff",
"error": "#ff5f5f"
}
}
RestRequest("/_api/thememanager/AddTenantTheme", {name:"Sounders Rave Green", themeJson: JSON.stringify(pal)});

RemoveTenantTheme
The following JavaScript sample code shows how to remove a theme.
function RestRequest(url,params) {
var req = new XMLHttpRequest();
req.onreadystatechange = function ()
{
if (req.readyState != 4) // Loaded
return;
console.log(req.responseText);
};
req.open("POST",url,true);
req.setRequestHeader("Content-Type", "application/json;charset=utf-8");
req.setRequestHeader("ACCEPT", "application/json; odata.metadata=minimal");
req.setRequestHeader("x-requestdigest", _spPageContextInfo.formDigestValue);
req.setRequestHeader("ODATA-VERSION","4.0");
req.send(params ? JSON.stringify(params) : void 0);
}

RestRequest("/_api/thememanager/DeleteTenantTheme", { name:"themeName.DarkYellow" });

RestRequest("/_api/thememanager/UpdateTenantTheme", { name:"themeName",
themeJson:""});

GetTenantThemingOptions
The following JavaScript sample code shows how to read theme settings.

function RestRequest(url,params) {
var req = new XMLHttpRequest();
req.onreadystatechange = function ()
{
if (req.readyState != 4) // Loaded
return;
console.log(req.responseText);
};
req.open("POST",url,true);
req.setRequestHeader("Content-Type", "application/json;charset=utf-8");
req.setRequestHeader("ACCEPT", "application/json; odata.metadata=minimal");
req.setRequestHeader("x-requestdigest", _spPageContextInfo.formDigestValue);
req.setRequestHeader("ODATA-VERSION","4.0");
req.send(params ? JSON.stringify(params) : void 0);
}

RestRequest("/_api/thememanager/GetTenantThemingOptions");

See also
SharePoint site theming overview
SharePoint site theming: JSON schema
SharePoint site theming: PowerShell cmdlets
SharePoint site theming: CSOM API
Overview of SharePoint webhooks
7/9/2018 • 4 minutes to read Edit Online

SharePoint webhooks enable developers to build applications that subscribe to receive notifications on specific events that occur in SharePoint. When an event is triggered, SharePoint sends
an HTTP POST payload to the subscriber. Webhooks are easier to develop and consume than Windows Communication Foundation (WCF) services used by SharePoint Add-in remote
event receivers because webhooks are regular HTTP services (web API).
Currently webhooks are only enabled for SharePoint list items. SharePoint list item webhooks cover the events corresponding to list item changes for a given SharePoint list or a document
library. SharePoint webhooks provide a simple notification pipeline so that your application can be aware of changes to a SharePoint list without polling the service. For more information,
see SharePoint list webhooks.

Creating webhooks
To create a new SharePoint webhook, you add a new subscription to the specific SharePoint resource, such as a SharePoint list.
The following information is required for creating a new subscription:
Resource. The resource endpoint URL you are creating the subscription for. For example, a SharePoint List API URL.
Server notification UR. Your service endpoint URL. SharePoint sends an HTTP POST to this endpoint when events occur in the specified resource.
Expiration date. The expiration date for your subscription. The expiration date should not be more than 180 days. By default, subscriptions are set to expire 180 days from when they are
created.
You can also include the following information if needed:
Client State. An opaque string passed back to the client on all notifications. You can use this for validating notifications, tagging different subscriptions, or other reasons.

Handling webhook validation requests


When a new subscription is created, SharePoint validates whether the notification URL supports receiving webhook notifications. This validation is performed during the subscription
creation request. The subscription is only created if your service responds in a timely manner back with the validation token.

Example validation request


When a new subscription is created, SharePoint sends an HTTP POST request to the registered URL in a format similar to the following example:

POST https://contoso.azurewebsites.net/your/webhook/service?validationToken={randomString}
Content-Length: 0

Response
For the subscription to be created successfully, your service must respond to the request by returning the value of the validationToken query string parameter as a plain-text response.

HTTP/1.1 200 OK
Content-Type: text/plain

{randomString}

If your application returns a status code other than 200 , or fails to respond with the value of the validationToken parameter, the request to create a new subscription fails.

Receiving notifications
The notification payload informs your application that an event occurred in a given resource for a given subscription. Multiple notifications to your application may be batched together into a
single request if multiple changes occurred in the resource within the same time period.
The notification payload body also contains your client state if you used it when creating the subscription.

Webhook notification resource


The notification resource defines the shape of the data provided to your service when a SharePoint webhook notification request is submitted to your registered notification URL.
JSON representation
Each notification generated by the service is serialized into a webhookNotifiation instance:

{
"subscriptionId":"91779246-afe9-4525-b122-6c199ae89211",
"clientState":"00000000-0000-0000-0000-000000000000",
"expirationDateTime":"2016-04-30T17:27:00.0000000Z",
"resource":"b9f6f714-9df8-470b-b22e-653855e1c181",
"tenantId":"00000000-0000-0000-0000-000000000000",
"siteUrl":"/",
"webId":"dbc5a806-e4d4-46e5-951c-6344d70b62fa"
}

Because multiple notifications may be submitted to your service in a single request, these are combined together in an object with a single array value:
{
"value":[
{
"subscriptionId":"91779246-afe9-4525-b122-6c199ae89211",
"clientState":"00000000-0000-0000-0000-000000000000",
"expirationDateTime":"2016-04-30T17:27:00.0000000Z",
"resource":"b9f6f714-9df8-470b-b22e-653855e1c181",
"tenantId":"00000000-0000-0000-0000-000000000000",
"siteUrl":"/",
"webId":"dbc5a806-e4d4-46e5-951c-6344d70b62fa"
}
]
}

Properties
PR O PER T Y NAME T YPE D ES CR IPTIO N

resource String Unique identifier of the list where the subscription is registered.

subscriptionId String The unique identifier for the subscription resource.

clientState String - optional An optional string value that is passed back in the notification.
message for this subscription.

expirationDateTime DateTime The date and time when the subscription expires if not updated or
renewed.

tenantId String Unique identifier for the tenant that generated this notification.

siteUrl String Server relative URL of the site where the subscription is registered.

webId String Unique identifier of the web where the subscription is registered.

Example notification
The body of the HTTP request to your service notification URL contains a webhook notification. The following example shows a payload with one notification:

{
"value":[
{
"subscriptionId":"91779246-afe9-4525-b122-6c199ae89211",
"clientState":"00000000-0000-0000-0000-000000000000",
"expirationDateTime":"2016-04-30T17:27:00.0000000Z",
"resource":"b9f6f714-9df8-470b-b22e-653855e1c181",
"tenantId":"00000000-0000-0000-0000-000000000000",
"siteUrl":"/",
"webId":"dbc5a806-e4d4-46e5-951c-6344d70b62fa"
}
]
}

The notification doesn't include any information about the changes that triggered it. Your application is expected to use the GetChanges API on the list to query the collection of changes
from the change log and store the change token value for any subsequent calls when the application is notified.

Event types
SharePoint webhooks only support asynchronous events. This means that webhooks are only fired after a change happened (similar to -ed events), and thus synchronous (-ing events) are
not possible.

Error handling
If an error occurs while sending the notification to your application, SharePoint retries up to 5 times to deliver the notification. Any response with an HTTP status code outside of the 200-299
range, or that times out, is attempted again 5 minutes later. If the request is not successful after 5 attempts, the notification is dropped. Future notifications will still be attempted to your
application.

Expiration
Webhook subscriptions are set to expire after 180 days by default if an expirationDateTime value is not specified.
You need to set an expiration date when creating the subscription. The expiration date should be less than 180 days. Your application is expected to handle the expiration date according to
your application's needs by updating the subscription periodically.

Retry mechanism
If an event occurs in SharePoint and your service endpoint is not reachable (for example, due to maintenance) SharePoint retries sending the notification. SharePoint performs a retry of 5
times with a 5-minute wait time between the attempts. If for some reason your service is down for a longer time, the next time it's up and gets called by SharePoint, the call to the
GetChanges() recovers the changes that were missed when your service was not available.
Get started with SharePoint webhooks
3/26/2018 • 11 minutes to read Edit Online

This article describes how to build an application that adds and handles SharePoint webhook requests. You will learn how to use Postman client to construct and execute SharePoint
webhook requests quickly while interacting with a simple ASP.NET Web API as the webhook receiver.
You will use plain HTTP requests, which is useful for helping you understand how webhooks work.
To complete the step-by-step instructions in this article, download and install the following tools:
Google Chrome Browser
Postman
Visual Studio Community Edition
ngrok (to install ngrok, see Download and Installation)
An Office 365 developer subscription with SharePoint Online. If you are new to Office 365, you can also sign up for an Office 365 developer subscription through the Office 365
Developer Program. See the Office 365 Developer Program documentation for step-by-step instructions about how to join the Office 365 Developer Program and sign up and configure
your subscription.

Step 1: Register an Azure AD application for Postman client


In order for the Postman client to communicate with SharePoint, you need to register a Microsoft Azure Active Directory (Azure AD) app in your Azure AD tenant associated with your Office
365 tenant.
1. Ensure that you register the application as a Web Application.
2. To access SharePoint Online, it's important to grant the Azure AD app permissions to the Office 365 SharePoint Online application and select the read and write items and lists
in all site collections permission.
NOTE

For more information about adding an Azure AD application and granting permissions to applications, see Adding an application.
3. Enter the following endpoint as the Reply (Redirect) URL for the app. This is the endpoint to which Azure AD will send the authentication response, including the access token, if
authentication was successful.

https://www.getpostman.com/oauth2/callback

4. Generate a Key, which will be the client secret.


5. The following properties are required in later steps, so copy them to a safe place:
Client Id
Client Secret

Step 2: Build a webhook receiver


For this project, use the Visual Studio Web API project to build the webhook receiver.

Create a new ASP.NET Web API project


1. Open Visual Studio.
2. Select File > New > Project.
3. In the Templates pane, select Installed Templates, and expand the Visual C# node.
4. Under Visual C#, select Web.
5. In the list of project templates, select ASP.NET Web Application.
6. Name the project SPWebhooksReceiver, and select OK.
7. In the New ASP.NET Project dialog, select the Web API template from the ASP.NET 4.5. group.
8. Change the authentication to No Authentication by selecting the Change Authentication button.
9. Select OK to create the Web API project.
NOTE

You can clear the Host in the cloud check box because this project will not be deployed to the cloud.
Visual Studio creates your project.

Build the webhook receiver


Install NuGet packages
Use ASP.NET Web API Tracing to log the requests coming from SharePoint. The following steps install the tracing package:
1. Go to Solution Explorer in Visual Studio.
2. Open the context menu (right-click) for the project, and select Manage NuGet Packages.
3. In the search box, enter Microsoft.AspNet.WebApi.Tracing.
4. In the search results, select the Microsoft.AspNet.WebApi.Tracing package, and then select Install to install the package.
Build SPWebhookNotification model
Each notification generated by the service is serialized into a webhookNotification instance. You need to build a simple model that represents this notification instance.
1. Go to Solution Explorer in Visual Studio.
2. Open the context menu (right-click) for the Models folder, and select Add > Class.
3. Enter SPWebhookNotification as the class name and select Add to add the class to your project.
4. Add the following code to the body of the SPWebhookNotification class:

public string SubscriptionId { get; set; }

public string ClientState { get; set; }

public string ExpirationDateTime { get; set; }

public string Resource { get; set; }

public string TenantId { get; set; }

public string SiteUrl { get; set; }

public string WebId { get; set; }

Build SPWebhookContent model


Because multiple notifications can be submitted to your webhook receiver in a single request, they are combined together in an object with a single array value. Build a simple model that
represents the array.
1. Go to Solution Explorer in Visual Studio.
2. Open the context menu (right-click) for the Models folder, and select Add > Class.
3. Enter SPWebhookContent as the class name, and select Add to add the class to your project.
4. Add the following code to the body of the SPWebhookContent class:

public List<SPWebhookNotification> Value { get; set; }

Add SharePoint webhook client state


Webhooks provide the ability to use an optional string value that is passed back in the notification message for your subscription. This can be used to verify that the request is indeed coming
from the source you trust, which in this case is SharePoint.
Add a client state value with which the application can verify the incoming requests.
1. Go to Solution Explorer in Visual Studio.
2. Open the web.config file, and add the following key as the client state to the <appSettings> section:

<add key="webhookclientstate" value="A0A354EC-97D4-4D83-9DDB-144077ADB449"/>

Enable tracing
In the web.config file, enable tracing by adding the following key inside the <system.web> element in the <configuration> section:

<trace enabled="true"/>

A trace writer is required, so you must add a trace writer to the controller configuration (in this case use the one from System.Diagnostics).
1. Go to Solution Explorer in Visual Studio.
2. Open WebApiConfig.cs in the App_Start folder.
3. Add the following line inside the Register method:

config.EnableSystemDiagnosticsTracing();

Build SharePoint webhook controller


Now build the webhook receiver controller that handles the incoming requests from SharePoint and take action accordingly.
1. Go to Solution Explorer in Visual Studio.
2. Open the context menu (right-click) for the Controllers folder, and select Add > Controller.
3. In the Add Scaffold dialog, select Web API 2 Controller - Empty.
4. Select Add.
5. Name the controller SPWebhookController, and select Add to add the API controller to your project.
6. Replace the using statements with the following code:

using Newtonsoft.Json;
using SPWebhooksReceiver.Models;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.Tracing;

7. Replace the code in the SPWebhookController class with the following code:
[HttpPost]
public HttpResponseMessage HandleRequest()
{
HttpResponseMessage httpResponse = new HttpResponseMessage(HttpStatusCode.BadRequest);
var traceWriter = Configuration.Services.GetTraceWriter();
string validationToken = string.Empty;
IEnumerable<string> clientStateHeader = new List<string>();
string webhookClientState = ConfigurationManager.AppSettings["webhookclientstate"].ToString();

if (Request.Headers.TryGetValues("ClientState", out clientStateHeader))


{
string clientStateHeaderValue = clientStateHeader.FirstOrDefault() ?? string.Empty;

if (!string.IsNullOrEmpty(clientStateHeaderValue) && clientStateHeaderValue.Equals(webhookClientState))


{
traceWriter.Trace(Request, "SPWebhooks",
TraceLevel.Info,
string.Format("Received client state: {0}", clientStateHeaderValue));

var queryStringParams = HttpUtility.ParseQueryString(Request.RequestUri.Query);

if (queryStringParams.AllKeys.Contains("validationtoken"))
{
httpResponse = new HttpResponseMessage(HttpStatusCode.OK);
validationToken = queryStringParams.GetValues("validationtoken")[0].ToString();
httpResponse.Content = new StringContent(validationToken);

traceWriter.Trace(Request, "SPWebhooks",
TraceLevel.Info,
string.Format("Received validation token: {0}", validationToken));
return httpResponse;
}
else
{
var requestContent = Request.Content.ReadAsStringAsync().Result;

if (!string.IsNullOrEmpty(requestContent))
{
SPWebhookNotification notification = null;

try
{
var objNotification = JsonConvert.DeserializeObject<SPWebhookContent>(requestContent);
notification = objNotification.Value[0];
}
catch (JsonException ex)
{
traceWriter.Trace(Request, "SPWebhooks",
TraceLevel.Error,
string.Format("JSON deserialization error: {0}", ex.InnerException));
return httpResponse;
}

if (notification != null)
{
Task.Factory.StartNew(() =>
{
//handle the notification here
//you can send this to an Azure queue to be processed later
//for this sample, we just log to the trace

traceWriter.Trace(Request, "SPWebhook Notification",


TraceLevel.Info, string.Format("Resource: {0}", notification.Resource));
traceWriter.Trace(Request, "SPWebhook Notification",
TraceLevel.Info, string.Format("SubscriptionId: {0}", notification.SubscriptionId));
traceWriter.Trace(Request, "SPWebhook Notification",
TraceLevel.Info, string.Format("TenantId: {0}", notification.TenantId));
traceWriter.Trace(Request, "SPWebhook Notification",
TraceLevel.Info, string.Format("SiteUrl: {0}", notification.SiteUrl));
traceWriter.Trace(Request, "SPWebhook Notification",
TraceLevel.Info, string.Format("WebId: {0}", notification.WebId));
traceWriter.Trace(Request, "SPWebhook Notification",
TraceLevel.Info, string.Format("ExpirationDateTime: {0}", notification.ExpirationDateTime));

});

httpResponse = new HttpResponseMessage(HttpStatusCode.OK);


}
}
}
}
else
{
httpResponse = new HttpResponseMessage(HttpStatusCode.Forbidden);
}
}

return httpResponse;
}

8. Save the file.

Step 3: Debug the webhook receiver


1. Select F5 to debug the webhook receiver.
2. When you have the browser open, copy the port number from the address bar. For example: http://localhost:<_port-number_>

Step 4: Run ngrok proxy


1. Open a console terminal.
2. Go to the extracted ngrok folder.
3. Enter the following with the port number URL from the previous step to start ngrok:

./ngrok http port-number --host-header=localhost:port-number

You should see ngrok running.


4. Copy the Forwarding HTTPS address. You will use this address as the service proxy for SharePoint to send requests.

Step 5: Add webhook subscription using Postman


Get new access token
Postman makes it really simple to work with APIs. The first step is to configure Postman to authenticate with Azure AD so you can send API requests to SharePoint. You will use the Azure
AD app that you registered in Step 1.
1. Open Postman. You are presented with a Sidebar and Request Editor.
2. Select the Authorization tab in the Request Editor.
3. Select OAuth 2.0 in the Type list.
4. Select the Get New Access Token button.
5. In the dialog window, enter the following:
Auth URL:
https://login.microsoftonline.com/common/oauth2/authorize?resource=https%3A%2F%2F<_your-sharepoint-tenant-url-without-https_>
Replace your-sharepoint-tenant-url-without-https with your tenant url without the https prefix.
Access Token URL: https://login.microsoftonline.com/common/oauth2/token
Client Id: Client Id of the app you registered previously in Step one.
Client Secret: Client Secret of the app you registered previously in Step one.
Token name: sp_webhooks_token
Grant type: Authorization Code
6. Select the Request Token to sign in, consent, and get the token for the session.
7. When the token is successfully retrieved, you should see access_token variable added to the Authorization tab.
8. Select the option to Add token to header.
9. Double-click the access_token variable to add the token to the header for the request.

Get Documents list Id


You need to manage webhooks for the default document library, which is provisioned in your default site collection under the name Documents. Get the Id of this list by issuing a GET
request:
1. Enter the following request URL:

https://site-collection/_api/web/lists/getbytitle('Documents')?$select=Title,Id

2. Replace site-collection with your site collection.


Postman executes your request and if successful, you should see the result.
3. Copy the Id from the results. Later you will use the Id to make webhook requests.

Add webhook subscription


Now that you have the required information, construct the query and the request to add a webhook subscription. Use the request editor for the following steps:
1. Change the request to POST from GET.
2. Enter the following as the request URL:

https://site-collection/_api/web/lists('list-id')/subscriptions

3. Replace site-collection with your site collection.


4. Go to the Headers tab.
5. Make sure you still have the Authorization header. If not, you need to request a new access token.
6. Add the following header key > value pairs:
Accept > application/json;odata=nometadata
Content-Type > application/json
7. Go to the Body tab and select raw format.
8. Paste the following JSON as the body:

{
"resource": "https://site-collection/_api/web/lists('list-id')",
"notificationUrl": "https://ngrok-forwarding-address/api/spwebhook/handlerequest",
"expirationDateTime": "2016-10-27T16:17:57+00:00",
"clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449"
}

9. Make sure the expirationDateTime is at most 6 months from today.


10. Make sure you are debugging the webhook receiver as in Step 4.
11. Select Send to execute the request.
If the request is successful, you should see the response from SharePoint that provides the subscription details. The following example shows a response for a newly created
subscription:

{
"clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449",
"expirationDateTime": "2016-10-27T16:17:57Z",
"id": "32b95d9-4d20-4a17-bfa3-2957cb38ead8",
"notificationUrl": "https://85557d4b.ngrok.io/api/spwebhook/handlerequest",
"resource": "c34420f9-2ad7-4e54-94c9-b67798d2299b"
}

12. Copy the subscription id. You will need it for the next set of requests.
13. Go to the webhook receiver project in Visual Studio and examine the Output window. You should see the trace logs that look similar to the following trace, along with other messages:

iisexpress.exe Information: 0 : Message='Received client state: A0A354EC-97D4-4D83-9DDB-144077ADB449'


iisexpress.exe Information: 0 : Message='Received validation token: daf2803c-43cf-44c7-8dff-7066eaa40f13'

The trace indicates that the webhook received initially received a validation request. If you look at the code, you'll see that it returns the validation token immediately so that
SharePoint can validate the request:

if (queryStringParams.AllKeys.Contains("validationtoken"))
{
httpResponse = new HttpResponseMessage(HttpStatusCode.OK);
validationToken = queryStringParams.GetValues("validationtoken")[0].ToString();
httpResponse.Content = new StringContent(validationToken);

traceWriter.Trace(Request, "SPWebhooks",
TraceLevel.Info,
string.Format("Received validation token: {0}", validationToken));
return httpResponse;
}
Step 6: Get subscription details
Now you'll run queries in Postman to get the subscription details.
1. Open the Postman client.
2. Change the request to GET from POST.
3. Enter the following as the request:

https://site-collection/_api/web/lists('list-id')/subscriptions

4. Replace site-collection with your site collection.


5. Select Send to execute the request.
If successful, you should see SharePoint return the subscriptions for this list resource. Because we just added one, you should at least see one subscription returned. The following
example shows a response with one subscription:

{
"value": [
{
"clientState": "A0A354EC-97D4-4D83-9DDB-144077ADB449",
"expirationDateTime": "2016-10-27T16:17:57Z",
"id": "32b95add-4d20-4a17-bfa3-2957cb38ead8",
"notificationUrl": "https://85557d4b.ngrok.io/api/spwebhook/handlerequest",
"resource": "c34420f9-2a67-4e54-94c9-b67798229f9b"
}
]
}

6. Run the following query to get details of the specific subscription:

https://site-collection/_api/web/lists('list-id')/subscriptions('subscription-id')

7. Replace subscription-id with your subscription id.

Step 7: Test webhook notification


Now add a file to the Documents library and test if you get a notification from SharePoint in the webhook receiver.
1. Go to Visual Studio.
2. In the SPWebhookController, place a breakpoint on the following line of code:

var requestContent = Request.Content.ReadAsStringAsync().Result;

3. Go to the Documents library. It is named Shared Documents library in your default site collection.
4. Add a new file.
5. Go to Visual Studio and wait for the breakpoint to be hit.
The wait time may vary from a few seconds to up to five minutes. When the breakpoint is hit, the webhook receiver has just received a notification from SharePoint.
6. Select F5 to continue.
7. To see the notification data, look in the Output window for the following entries, since you added the notification data into the trace log:

iisexpress.exe Information: 0 : Message='Resource: c34420f9-2a67-4e54-94c9-b6770892299b'


iisexpress.exe Information: 0 : Message='SubscriptionId: 32b95ad9-4d20-4a17-bfa3-2957cb38ead8'
iisexpress.exe Information: 0 : Message='TenantId: 7a17cb7d-6898-423f-8839-45f363076f06'
iisexpress.exe Information: 0 : Message='SiteUrl: /'
iisexpress.exe Information: 0 : Message='WebId: 62b80e0b-f889-4974-a519-cc138413be40'
iisexpress.exe Information: 0 : Message='ExpirationDateTime: 2016-10-27T16:17:57.0000000Z'

This project only writes the information to the trace log. However, in your receiver, you send this information into a table or a queue that can process the received data to get information
from SharePoint.
With this data, you can construct the URL and use the GetChanges API to get the latest changes.

Next steps
In this article, you used Postman client and a simple web API to subscribe and receive webhook notifications from SharePoint.
Next, take a look at SharePoint webhooks sample reference implementation, which shows an end-to-end sample that uses Azure Storage Queues to process the information, get changes
from SharePoint, and push those changes back into a SharePoint list.
SharePoint webhooks sample reference implementation
4/20/2018 • 9 minutes to read Edit Online

The SharePoint Patterns and Practices (PnP) reference implementation shows how you can use SharePoint webhooks in your application. The webhooks are implemented in an enterprise
ready manner using various Microsoft Azure components such as Azure Web Jobs, Azure SQL Server, and Azure Storage Queues for asynchronous web job notification handling.
The reference implementation only works with SharePoint list webhooks.
You can also follow these steps by watching the video on the SharePoint PnP YouTube Channel:

https://www.youtube-nocookie.com/embed/P4a1_EWokwM

Applies to Office 365 Multi Tenant (MT).


Microsoft Azure is used to host the various components needed to implement Azure webhooks.
Source code and other materials for the reference implementation are available in two flavors:
A SharePoint provider-hosted application version
An Office 365 Azure AD application, which can be found in the SharePoint developer samples GitHub repository.

Deploy the reference implementation


The application shows you how to manage webhooks, specifically for a SharePoint list. It also contains a reference implementation of a webhook service endpoint that you can reuse in your
webhook projects.

Deployment guides
The SharePoint web hooks reference implementation deployment guide lists the deployment steps used to deploy the SharePoint provider-hosted reference implementation.
To deploy the Office 365 Azure AD application, use the steps described at SharePoint web hooks Azure AD reference implementation deployment guide, which shows you how to use
a Web API function as webhook service.
If you're more interested in using Azure Functions, see the Azure Functions guide for more details on how to use Azure Functions in this reference implementation.

Introduction to webhooks
Webhooks notify your application about changes in SharePoint that the application needs to monitor. There's no need for your application to regularly poll for changes anymore. With
webhooks, your application is notified (push model) whenever there's a change. Webhooks are not specific to Microsoft. They are a universal web standard that's also being adopted by other
vendors (for example, WordPress, GitHub, MailChimp, and others).
Add a webhook to your SharePoint list
The reference implementation works with a SharePoint list. To add a webhook to a SharePoint list, your application first creates a webhook subscription by sending a
POST /_api/web/lists('list-id')/subscriptions request. The request includes the following items:

A payload that identifies the list that you're adding the webhook for.
The location of your webhook service URL to send the notifications.
The expiration date of the webhook.
After you've requested SharePoint to add your webhook, SharePoint validates that your webhook service endpoint exists. It sends a validation string to your service endpoint. SharePoint
expects that your service endpoint returns the validation string within 5 seconds. If this process fails, the webhook creation is canceled. If you've deployed your service, this works and
SharePoint returns an HTTP 201 message on the POST request that the application initially sent. The payload in the response contains the ID of the new webhook subscription.

Take a look at the reference implementation, and you'll see that all webhook CRUD operations are consolidated in the WebHookManager class of the SharePoint.WebHooks.Common
project. Adding a webhook is done by using the AddListWebHookAsync method:

/// <summary>
/// This method adds a webhook to a SharePoint list. Note that you need your webhook endpoint being passed into this method to be up and running and reachable from the internet
/// </summary>
/// <param name="siteUrl">Url of the site holding the list</param>
/// <param name="listId">Id of the list</param>
/// <param name="webHookEndPoint">Url of the webhook service endpoint (the one that will be called during an event)</param>
/// <param name="accessToken">Access token to authenticate against SharePoint</param>
/// <param name="validityInMonths">Optional webhook validity in months, defaults to 3 months, max is 6 months</param>
/// <returns>subscription ID of the new webhook</returns>
public async Task<SubscriptionModel> AddListWebHookAsync(string siteUrl, string listId, string webHookEndPoint, string accessToken, int validityInMonths = 3)
{
// webhook add code...
}

When making a call to SharePoint, you need to provide authentication information, and in this case you're using a Bearer authentication header with an access token. To obtain the access
token, intercept the token via an ExecutingWebRequest event handler:

ClientContext cc = null;

// Create SharePoint ClientContext object...

// Add ExecutingWebRequest event handler


cc.ExecutingWebRequest += Cc_ExecutingWebRequest;

// Capture the OAuth access token since we want to reuse that one in our REST requests
private void Cc_ExecutingWebRequest(object sender, WebRequestEventArgs e)
{
this.accessToken = e.WebRequestExecutor.RequestHeaders.Get("Authorization").Replace("Bearer ", "");
}

SharePoint calls out to your webhook service


When SharePoint detects a change in a list for which you've created a webhook subscription, your service endpoint is called by SharePoint. When you look at the payload from SharePoint,
notice that the following properties are important:

PR O PER T Y D ES CR IPTIO N

subscriptionId The ID of the webhook subscription. If you want to update the webhook subscription (for example, you
prolong the webhook expiration), you need this ID.

resource The ID of the list for which the change happened.

siteUrl The server relative URL of the site holding the resource for which the change happened.
NOTE

SharePoint only sends a notification that a change happened, but the notification does not include what actually changed. Because you get information about the web and list that were
changed, this means that you can use the same service endpoint to handle webhook events from multiple sites and lists.
When your service is called, it's important that your service replies with an HTTP 200 message in under 5 seconds. Later in this article you'll learn more about the response time, but
essentially this requires that you asynchronously handle the notifications. In this reference implementation, you'll do this by using Azure Web Jobs and Azure Storage Queues.
Grab the changes your service needs to act upon
In the previous step, your service endpoint was called, but SharePoint only provided information about where the change happened, not what actually changed. To understand what was
changed, you'll need to use the SharePoint GetChanges() API, as shown in the following image.

You can learn more about the GetChanges() implementation in the ProcessNotification method in the ChangeManager class of the SharePoint.WebHooks.Common project.
To avoid getting the same change repeatedly, it's important that you inform SharePoint from which point you want the changes. This is done by passing a changeToken, which also implies
that your service endpoint needs to persist the last used changeToken so that it can be used the next time the service endpoint is called.
The following are some key things to note about changes:
SharePoint does not call your service in real-time: when a change happens on a list that has a webhook, SharePoint queues a webhook callout. Once each minute, this queue is read
and the appropriate service endpoints are called. This batching of requests is important. For example, if a bulk upload of 1000 records occurred at once, batching prevents SharePoint
from calling your endpoint 1000 times. So your endpoint is only called once, but when you call the GetChanges() method, you get 1000 change events that you need to process.
To guarantee an immediate response, regardless of the number of changes there, it's important that the workload of your service endpoint runs asynchronously. In the reference
implementation, we leveraged the power of Azure: the service serializes the incoming payload and stores it in an Azure Storage queue while there's an Azure web job that runs
continuously and checks for messages in the queue. When there are messages in the queue, the web job processes them and also executes your logic asynchronously.

Complete end-to-end flow


The following diagram describes the complete end-to-end webhook flow.

1. Your application creates a webhook subscription. When it does, it gets the current changeToken from the list it created the webhook for.
2. Your application persists the changeToken in a persistent storage, such as SQL Azure in this case.
3. A change in SharePoint occurs, and SharePoint calls your service endpoint.
4. Your service endpoint serializes the notification request and stores it in a storage queue.
5. Your web job sees the message in the queue and starts your message processing logic.
6. Your message processing logic retrieves the last used change token from the persistent storage.
7. Your message processing logic uses the GetChanges() API to determine what changed.
8. The returned changes are processed and now your application performs what it needs to do based on the changes.
9. Finally, the application persists the last retrieved changeToken so that next time it does not receive changes that were already processed.

Work with webhook renewal


Webhook subscriptions are set to expire 6 months by default or at the specified date when they are created. Often you need the webhook to be available for a longer time. The patterns
described in the following sections are good for increasing the lifetime of a webhook subscription. The first pattern is lightweight and the second one is slightly more complex and requires an
additional web job to be hosted.

Basic model
When your service receives a notification, it also gets information about the subscription lifetime. If the subscription is about to expire, inside your notification processing logic you simply
extend the lifetime of the subscription. This model is implemented in this reference implementation and works fine for most cases. However, in a case where there's no change for 6 months
on the list that you've created a webhook subscription for, the webhook subscription is never prolonged and is deleted.

Reliable but more complex model


Create a web job that on a weekly basis reads all the subscription IDs from the persistent storage. One-by-one extend the found subscriptions each time.
NOTE

This web job is not part of this reference implementation.


The actual renewal of a SharePoint list webhook can be done by using a PATCH /_api/web/lists('list-id')/subscriptions(‘subscriptionID’) REST call.
In the reference implementation, updating of webhooks is implemented in the WebHookManager class of the SharePoint.WebHooks.Common project.
Updating a webhook is done by using the UpdateListWebHookAsync method:

/// <summary>
/// Updates the expiration datetime (and notification URL) of an existing SharePoint list webhook
/// </summary>
/// <param name="siteUrl">Url of the site holding the list</param>
/// <param name="listId">Id of the list</param>
/// <param name="subscriptionId">Id of the webhook subscription that we need to update</param>
/// <param name="webHookEndPoint">Url of the webhook service endpoint (the one that will be called during an event)</param>
/// <param name="expirationDateTime">New webhook expiration date</param>
/// <param name="accessToken">Access token to authenticate against SharePoint</param>
/// <returns>true if successful, exception in case something went wrong</returns>
public async Task<bool> UpdateListWebHookAsync(string siteUrl, string listId, string subscriptionId, string webHookEndPoint, DateTime expirationDateTime, string accessToken)
{
// webhook update code...
}

Debugging webhooks
Because SharePoint is calling out to your webhook service endpoint, your endpoint needs to be reachable by SharePoint. This makes development and debugging slightly more complex. The
following are some strategies that you can use to make your life easier:
During initial development, you provide your own serialized payload to your service processing logic. This makes it possible to completely test your processing logic without
deploying the service endpoint (and even without configuring a webhook).
If you have access to Azure resources, you can deploy your endpoint to Azure by using a debug build and configuring the Azure App Service for debugging. This allows you to set a
remote breakpoint and do remote debugging using Visual Studio.
If you do not want to deploy your service during development time, you need to use a secure tunnel for your service. The idea is that you tell SharePoint that the notification service is
located on a shared public endpoint. In the client, you install a component that connects to that shared public service, and whenever a call is made to the public endpoint, the client
component is notified and it pushes the payload to your service running on localhost. ngrok is an implementation of such a secure tunnel tool that you can use to debug your
webhook service locally.

See also
Overview of SharePoint webhooks
Using Azure Functions with SharePoint webhooks
3/26/2018 • 5 minutes to read Edit Online

Azure Functions offers an easy way to host your SharePoint webhooks: you can simply add your webhook C# or JavaScript code via the browser, and Azure takes care of the hosting and
scaling of your function. This guide shows how to set up and use Azure Functions for your webhooks.

Create an Azure Function App


The first step you need to do is create an Azure Function App, which is a special kind of Azure Web App focused on hosting Azure Functions.
1. Navigate to https://portal.azure.com, select New, and then search for Function App.

2. Select Function App, and then complete the information needed to create the Function App:

Create an Azure Function


1. Now that the app to host the functions is ready, you can continue with creating your first Azure Function by selecting the New Function link.

This offers you to start your function from a template; in the case of SharePoint webhooks, we need an HTTP triggered function, and because we are writing C# code in our sample,
this means we're using the HttpTrigger-CSharp function template. Given that SharePoint webhook services need to be anonymously callable, it's important to switch the
Authorization level to Anonymous.
NOTE

Using the GenericWebHook template does not yet work for SharePoint webhooks, but the SharePoint product team is aware of this problem and will address it.
If you get "Failed to validate the notification URL" errors when using your Azure function-based webhook, you might be able to resolve this by setting the Authorization level to
Function and defining your function for anonymous access.

The result is a "default" Azure Function written in C#.

2. In our case, we want this Azure Function to behave as a SharePoint webhook service, so we need to implement the following in C#:
Return the validationtoken if specified as a URL parameter to the call. This is needed as described at Create a new subscription, and SharePoint expects the reply to happen within 5
seconds.
Process the JSON webhook notification. In the following sample, we've opted to store the JSON in a storage queue so that an Azure Web Job can pick it up and process it
asynchronously. Depending on your needs, you could also process the notification directly in your webhook service, but keep in mind that all webhook service calls need to
complete in 5 seconds; hence, using an asynchronous model is recommended.
3. You can achieve this by replacing the default code with the following code (please enter your storage account connection string and update the queue name if you're using a different
one):

#r "Newtonsoft.Json"
#r "Microsoft.WindowsAzure.Storage"

using System;
using System.Net;
using Newtonsoft.Json;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;
public static async Task<object> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info($"Webhook was triggered!");

// Grab the validationToken URL parameter


string validationToken = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "validationtoken", true) == 0)
.Value;

// If a validation token is present, we need to respond within 5 seconds by


// returning the given validation token. This only happens when a new
// web hook is being added
if (validationToken != null)
{
log.Info($"Validation token {validationToken} received");
var response = req.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(validationToken);
return response;
}

log.Info($"SharePoint triggered our webhook...great :-)");


var content = await req.Content.ReadAsStringAsync();
log.Info($"Received following payload: {content}");

var notifications = JsonConvert.DeserializeObject<ResponseModel<NotificationModel>>(content).Value;


log.Info($"Found {notifications.Count} notifications");

if (notifications.Count > 0)
{
log.Info($"Processing notifications...");
foreach(var notification in notifications)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("<YOUR STORAGE ACCOUNT>");
// Get queue... create if does not exist.
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
CloudQueue queue = queueClient.GetQueueReference("sharepointlistwebhookeventazuread");
queue.CreateIfNotExists();

// add message to the queue


string message = JsonConvert.SerializeObject(notification);
log.Info($"Before adding a message to the queue. Message content: {message}");
queue.AddMessage(new CloudQueueMessage(message));
log.Info($"Message added :-)");
}
}

// if we get here we assume the request was well received


return new HttpResponseMessage(HttpStatusCode.OK);
}

// supporting classes
public class ResponseModel<T>
{
[JsonProperty(PropertyName = "value")]
public List<T> Value { get; set; }
}

public class NotificationModel


{
[JsonProperty(PropertyName = "subscriptionId")]
public string SubscriptionId { get; set; }

[JsonProperty(PropertyName = "clientState")]
public string ClientState { get; set; }

[JsonProperty(PropertyName = "expirationDateTime")]
public DateTime ExpirationDateTime { get; set; }

[JsonProperty(PropertyName = "resource")]
public string Resource { get; set; }

[JsonProperty(PropertyName = "tenantId")]
public string TenantId { get; set; }

[JsonProperty(PropertyName = "siteUrl")]
public string SiteUrl { get; set; }

[JsonProperty(PropertyName = "webId")]
public string WebId { get; set; }
}

public class SubscriptionModel


{
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Id { get; set; }

[JsonProperty(PropertyName = "clientState", NullValueHandling = NullValueHandling.Ignore)]


public string ClientState { get; set; }

[JsonProperty(PropertyName = "expirationDateTime")]
public DateTime ExpirationDateTime { get; set; }

[JsonProperty(PropertyName = "notificationUrl")]
public string NotificationUrl {get;set;}

[JsonProperty(PropertyName = "resource", NullValueHandling = NullValueHandling.Ignore)]


public string Resource { get; set; }
}

Configure your Azure Function


Because we've chosen the correct template to start from, our configuration is almost complete. The only thing you still need to do is to switch the Allowed HTTP methods to Selected
methods, and then only allow the POST HTTP method. Also cross-check that Mode is equal to Standard, and Authorization level is set to Anonymous.

Test your Azure Function


You're now all set for your first Azure Function test.
1. Navigate to the Develop screen.
2. Select the Test icon to open the test pane on the right, and add a URL parameter "validationtoken" with a random string as value.
3. Using this setup, we're mimicking the behavior of SharePoint by calling your web hook service when validating a new webhook addition. Select Run to test...if everything goes well,
you'll see in the logs section that your service was called and that it returned the passed value with an HTTP 200 response.

Grab the webhook URL to use in your implementation


We'll need to let SharePoint know what webhook URL we're using. To do so, let's start by copying the Azure Function URL.

To avoid unathorized usage of your Azure Function, the caller needs to specify a code when calling your function. This code can be retrieved via the Manage screen.
So in our case the webhook URL to use is the following:

See also
Overview of SharePoint webhooks
SharePoint list webhooks
3/26/2018 • 2 minutes to read Edit Online

The SharePoint list webhooks cover the events corresponding to list item changes for a given SharePoint list or a document library. SharePoint webhooks provide a simple notification
pipeline so your application can be aware of changes to a SharePoint list without polling the service.

Tasks
TAS K HT TP ME THO D

Create a new subscription POST /_api/web/lists('list-guid')/subscriptions

Get subscriptions GET /_api/web/lists('list-guid')/subscriptions

Delete a subscription DELETE /_api/web/lists('list-guid')/subscriptions('id')

Update a subscription PATCH /_api/web/lists('list-guid')/subscriptions('id')

List event types


Notifications are sent to your application for the following asynchronous list item events in SharePoint:
ItemAdded
ItemUpdated
ItemDeleted
ItemCheckedOut
ItemCheckedIn
ItemUncheckedOut
ItemAttachmentAdded
ItemAttachmentDeleted
ItemFileMoved
ItemVersionDeleted
ItemFileConverted
Synchronous events are not supported in webhooks.

See also
Overview of SharePoint webhooks
Create a new subscription
3/26/2018 • 2 minutes to read Edit Online

Creates a new webhook subscription on a SharePoint list.

Permissions
The application must have at least edit permissions to the SharePoint list where the subscription will be created.

If your application is a Microsoft Azure Active Directory (Azure AD ) application


You must grant the Azure AD app the permissions specified in the following table:

APPLICATIO N PER MIS S IO N

Office 365 SharePoint Online Read and write items and lists in all site collections.

If your application is a SharePoint Add-in


You must grant the SharePoint Add-in the following permission(s) or higher:

S CO PE PER MIS S IO N R IG HTS

List Manage

HTTP request
POST /_api/web/lists('list-id')/subscriptions

Request body
Include the following properties in the request body.

NAME T YPE D ES CR IPTIO N

resource string The URL of the list to receive notifications from.

notificationUrl string The service URL to send notifications to.

expirationDateTime date The date the notification will expire and be deleted.

client-clientState string Optional. Opaque string passed back to the client on all
notifications.
You can use this for validating notifications or tagging different
subscriptions.

Example
POST /_api/web/lists('5C77031A-9621-4DFC-BB5D-57803A94E91D')/subscriptions
Accept: application/json
Content-Type: application/json

{
"resource": "https://contoso.sharepoint.com/_api/web/lists('5C77031A-9621-4DFC-BB5D-57803A94E91D')",
"notificationUrl": "https://91e383a5.ngrok.io/api/webhook/handlerequest",
"expirationDateTime": "2016-04-27T16:17:57+00:00"
}

Response
If the subscription is added, a 201 Created response is returned that includes the newly created subscription object.

Example
HTTP/1.1 201 Created
Content-Type: application/json

{
"id": "a8e6d5e6-9f7f-497a-b97f-8ffe8f559dc7",
"expirationDateTime": "2016-04-27T16:17:57Z",
"notificationUrl": "https://91e383a5.ngrok.io/api/webhook/handlerequest",
"resource": "5c77031a-9621-4dfc-bb5d-57803a94e91d"
}

URL validation
Before a new subscription is created, SharePoint sends a request with a validation token in the body of the request to the service URL provided. Your service must respond to this request by
returning the validation token.
If your service fails to validate the request in this way, the subscription is not created.

See also
SharePoint list webhooks
Overview of SharePoint webhooks
Update a subscription
3/26/2018 • 2 minutes to read Edit Online

Updates a webhook subscription on a SharePoint list.

Permissions
The application must have at least edit permissions to the SharePoint list where the subscription will be updated.

If your application is a Microsoft Azure Active Directory (Azure AD ) application


You must grant the Azure AD application the permissions specified in the following table. A subscription can only be updated by the Azure AD application that created it.

APPLICATIO N PER MIS S IO N

Office 365 SharePoint Online Read and write items and lists in all site collections.

If your application is a SharePoint Add-in


You must grant the SharePoint Add-in the following permission(s) or higher. A subscription can only be updated by the SharePoint Add-in that created it.

S CO PE PER MIS S IO N R IG HTS

List Manage

HTTP request
PATCH _api/web/lists('list-id')/subscriptions('id')

Example
PATCH _api/web/lists('5C77031A-9621-4DFC-BB5D-57803A94E91D')/subscriptions('6D77031A-2345-5GRT-BV3D-55234B56FR43')
Content-Type: application/json

{
"notificationUrl": "https://contoso.azurewebsites.net/api/v2/webhook-receiver",
"expirationDateTime": "2016-01-03T11:23:00.000Z"
}

Request body
Include the following properties in the request body.

NAME T YPE D ES CR IPTIO N

notificationUrl string The service URL to send notifications to.

expirationDateTime date The date the notification will expire and be deleted.

client-clientState string Optional. Opaque string passed back to the client on all
notifications.
You can use this for validating notifications or tagging different
subscriptions.

Response
If the subscription is found and successfully updated, a 204 No Content response is returned.

Example
HTTP/1.1 204 No Content

See also
SharePoint list webhooks
Overview of SharePoint webhooks
Delete a subscription
3/26/2018 • 2 minutes to read Edit Online

Deletes a webhook subscription from a SharePoint list. After deleting the subscription, notifications are no longer delivered.

Permissions
The application must have at least edit permissions to the SharePoint list where the subscription will be deleted.

If your application is a Microsoft Azure Active Directory (Azure AD ) application


You must grant the Azure AD app the permissions specified in the following table. A subscription can only be deleted by the Azure AD application that created it.

APPLICATIO N PER MIS S IO N

Office 365 SharePoint Online Read and write items and lists in all site collections.

If your application is a SharePoint Add-in


You must grant the SharePoint Add-in the following permission(s) or higher. A subscription can only be deleted by the SharePoint Add-in that created it.

S CO PE PER MIS S IO N R IG HTS

List Manage

HTTP request
DELETE _api/web/lists('list-id')/subscriptions('id')

Example
DELETE _api/web/lists('5C77031A-9621-4DFC-BB5D-57803A94E91D')/subscriptions('6D77031A-2345-5GRT-BV3D-55234B56FR43')

Request body
Do not supply a request body for this method.

Response
If the subscription is found and successfully deleted, a 204 No Content response is returned.

Example
HTTP/1.1 204 No Content

See also
SharePoint list webhooks
Overview of SharePoint webhooks
Get subscriptions
3/26/2018 • 2 minutes to read Edit Online

Gets one or more webhook subscriptions on a SharePoint list.

Permissions
Get a single subscription
The application must have at least edit permissions to the SharePoint list where the subscription will be retrieved.
If your application is a Microsoft Azure Active Directory (Azure AD) application
You must grant the Azure AD application the permissions specified in the following table. A subscription can only be retrieved by the Azure AD application that created it.

APPLICATIO N PER MIS S IO N

Office 365 SharePoint Online Read and write items and lists in all site collections.

If your application is a SharePoint Add-in


You must grant the SharePoint Add-in the following permission(s) or higher. A subscription can only be retrieved by the SharePoint Add-in that created it.

S CO PE PER MIS S IO N R IG HTS

List Manage

Get all subscriptions


The application must have manage list permissions to the SharePoint list where the subscription will be retrieved.
If your application is an Azure AD application
You must grant the Azure AD app the permissions specified in the following table.

APPLICATIO N PER MIS S IO N

Office 365 SharePoint Online Have full control of all site collections.

If your application is a SharePoint Add-in


You must grant the SharePoint Add-in the following permission(s) or higher.

S CO PE PER MIS S IO N R IG HTS

List Full control

HTTP request
Get a single subscription
List webhook
GET _api/web/lists('list-id')/subscriptions('id')

E X A M P LE

GET _api/web/lists('5C77031A-9621-4DFC-BB5D-57803A94E91D')/subscriptions('6D77031A-2345-5GRT-BV3D-55234B56FR43')

Request body
Do not supply a request body for this method.
Response
This returns the subscription viewable by the calling application.

HTTP/1.1 200 OK
Content-Type: application/json

{
"odata.metadata": "https://contoso.sharepoint.com/_api/$metadata#SP.ApiData.Subscriptions/@Element",
"odata.type": "Microsoft.SharePoint.Webhooks.Subscription",
"odata.id": "https://contoso.sharepoint.com/_api/web/lists('5C77031A-9621-4DFC-BB5D-57803A94E91D')/subscriptions('a8e6d5e6-9f7f-497a-b97f-8ffe8f559dc7')",
"odata.editLink": "web/lists('5C77031A-9621-4DFC-BB5D-57803A94E91D')/subscriptions('a8e6d5e6-9f7f-497a-b97f-8ffe8f559dc7')",
"expirationDateTime": "2016-04-30T16:17:57Z",
"id": "a8e6d5e6-9f7f-497a-b97f-8ffe8f559dc7",
"notificationUrl": "https://contoso.azurewebistes.net/api/webhook/handlerequest",
"resource": "5c77031a-9621-4dfc-bb5d-57803a94e91d"
}

Get all subscriptions


List webhook
GET _api/web/lists('list-id')/subscriptions

E X A M P LE

GET _api/web/lists('5C77031A-9621-4DFC-BB5D-57803A94E91D')/subscriptions
Request body
Do not supply a request body for this method.
Response
This returns a collection of all subscriptions on a SharePoint resource.

HTTP/1.1 200 OK
Content-Type: application/json

{
"odata.metadata": "https://a830edad9050849295j16032914.sharepoint.com/_api/$metadata#SP.ApiData.Subscriptions",
"value": [
{
"odata.type": "Microsoft.SharePoint.Webhooks.Subscription",
"odata.id": "https://contoso.sharepoint.com/_api/Microsoft.SharePoint.Webhooks.Subscriptionc3175b9c-1491-454f-b5da-980431e36146",
"odata.editLink": "Microsoft.SharePoint.Webhooks.Subscriptionc3175b9c-1491-454f-b5da-980431e36146",
"clientState": "{A0A354EC-97D4-4D83-9DDB-144077ADB449}",
"expirationDateTime": "2016-04-30T16:17:57Z",
"id": "a8e6d5e6-9f7f-497a-b97f-8ffe8f559dc7",
"notificationUrl": "https://contoso.azurewebsites.net/api/webhook/handlerequest",
"resource": "5c77031a-9621-4dfc-bb5d-57803a94e91d"
}
]
}

See also
SharePoint list webhooks
Overview of SharePoint webhooks
Application Lifecycle Management (ALM) APIs
7/12/2018 • 7 minutes to read Edit Online

ALM APIs provide simple APIs to manage deployment of your SharePoint Framework solutions and add-ins across your tenant. ALM APIs support the following capabilities:
Add SharePoint Framework solution or SharePoint Add-in to tenant or site collection app catalog.
Remove SharePoint Framework solution or SharePoint Add-in from tenant or site collection app catalog.
Enable SharePoint Framework solution or SharePoint Add-in to be available for installation in tenant or site collection app catalog.
Disable SharePoint Framework solution or SharePoint Add-in not to be available for installation in tenant or site collection app catalog.
Install SharePoint Framework solution or SharePoint Add-in from tenant or site collection app catalog to a site.
Upgrade SharePoint Framework solution or SharePoint Add-in to a site, which has a newer version available in the tenant or site collection app catalog.
Uninstall SharePoint Framework solution or SharePoint Add-in from the site.
List all and get details about SharePoint Framework solutions or SharePoint Add-ins in the tenant or site collection app catalog.
ALM APIs can be used to perform exactly the same operations that are available from a UI perspective. When these APIs are used, all typical actions are performed. Following are some of
the characteristics of ALM APIs:
Install and UnInstall events are being fired for provider-hosted add-ins when corresponding operations occur.
ALM APIs support app-only-based operations.
ALM APIs are natively provided by using REST APIs, but there are additional CSOM extensions, PowerShell cmdlets, and the cross-platform Office 365 CLI available through SharePoint
PnP Community channels.

REST API
 T IP

ALM APIs are also supported for the site collection app catalog. URLs for the site collection app catalog operations are exactly the same, but you can change the tenantappcatalog to
sitecollectionappcatalog . Notice also that you will need to enable the site collection app catalog in your site collection or you will get an exception when trying to use these APIs.

Add solution package to the app catalog


This API is designed to be executed in the context of the app catalog site.

url: /_api/web/tenantappcatalog/Add(overwrite=true, url='test.txt')


method: POST
Authorization: Bearer <access token>
X-RequestDigest: <form digest>
Accept: 'application/json;odata=nometadata'
binaryStringRequestBody: true
body: 'byte array of the file'

Deploy solution packages in the app catalog


This enables the solution to be available to install to specific sites. This API is designed to be executed in the context of the app catalog site.

url: /_api/web/tenantappcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx')/Deploy
method: POST
Authorization: Bearer <access token>
X-RequestDigest: <form digest>
Accept: 'application/json;odata=nometadata'
Content-Type: 'application/json;odata=nometadata;charset=utf-8'

NOTE

This operation is required to be completed after Add, before you can install packages to specific sites.

Retract solution packages in the app catalog


This retracts the solution to be available from the sites. This API is designed to be executed in the context of the app catalog site.

url: /_api/web/tenantappcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx')/Retract
method: POST
Authorization: Bearer <access token>
X-RequestDigest: <form digest>
Accept: 'application/json;odata=nometadata'

NOTE

If you run this operation after you have installed solutions to the site, they stop working because the solution is disabled from the tenant level.

Remove solution packages from the app catalog


This API is designed to be executed in the context of the app catalog site.

url: /_api/web/tenantappcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx')/Remove
method: POST
Authorization: Bearer <access token>
Accept: 'application/json;odata=nometadata'

NOTE

If the Retract operation is not performed before the Remove operation, the solution is automatically retracted.

List available packages from the app catalog


Use this REST API for getting a list of available SharePoint Framework solutions or add-ins in the app catalog.
url: /_api/web/tenantappcatalog/AvailableApps
method: GET
Authorization: Bearer <access token>
Accept: 'application/json;odata=nometadata'

Get details about individual solution packages in the app catalog


Use this REST API for getting details about individual SharePoint Framework solutions or add-ins available in the app catalog.

url: /_api/web/tenantappcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx')
method: GET
Authorization: Bearer <access token>
Accept: 'application/json;odata=nometadata'

Install solution package from the app catalog to a SharePoint site


Install a solution package with a specific identifier from the app catalog to the site based on URL context. This REST call can be executed in the context of the site where the install operation
should happen.

url: /_api/web/tenantappcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx')/Install
method: POST
Authorization: Bearer <access token>
X-RequestDigest: <form digest>
Accept: 'application/json;odata=nometadata'

Upgrade solution packages on the SharePoint site


Upgrade a solution package from the site to a newer version available in the app catalog. This REST call can be executed in the context of the site where the upgrade operation should
happen.

url: /_api/web/tenantappcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx')/Upgrade
method: POST
Authorization: Bearer <access token>
X-RequestDigest: <form digest>
Accept: 'application/json;odata=nometadata'

Uninstall solution packages from the SharePoint site


This REST call can be executed in the context of the site where the uninstall operation should happen.

url: /_api/web/tenantappcatalog/AvailableApps/GetById('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx')/Uninstall
method: POST
Authorization: Bearer <access token>
X-RequestDigest: <form digest>
Accept: 'application/json;odata=nometadata'

NOTE

When you use the REST API to uninstall a solution package from the site, it is not relocated to the recycle bin.

SharePoint PnP PowerShell cmdlets


By using PnP PowerShell, you can automate deploying, publishing, installing, upgrading, and retracting your apps.
NOTE

Support for scope option was released on the April 2018 release of PnP PowerShell.

Add and publish your app to the app catalog


Adding your app (.sppkg file, .app file) to the app catalog is a prerequisite to making your app available for use on your SharePoint sites. You can do this by using the following cmdlet:

Add-PnPApp -Path ./myapp.sppkg -Scope Tenant

Once added, you need to continue with publishing your app, effectively making the app available to be used by the users of your tenant. The following PnP PowerShell cmdlet shows how
this can be done:

Publish-PnPApp -Identity <app id> -SkipFeatureDeployment -Scope Tenant

NOTE

Use the SkipFeatureDeployment flag to allow an app that was developed for tenant-wide deployment to be actually available as a tenant-wide deployed app.

Remove the app from the app catalog


To remove an app added earlier, use the following cmdlet:

Remove-PnPApp -Identity <app id> -Scope Tenant

Use apps on your site


After the app is added to the app catalog and published, you can install the app to your site:

Install-PnPApp -Identity <app id> -Scope Tenant

To upgrade the app:

Update-PnPApp -Identity <app id> -Scope Tenant

To uninstall the app from your site:


Uninstall-PnPApp -Identity <app id> -Scope Tenant

NOTE

When you uninstall an app from your site, the app is completely deleted, so it does not end up in the site's recycle bin.

Know which apps are there for you to use


You can get a list of apps that can be added to the site by using:

Get-PnPApp -Scope Tenant

Office 365 CLI commands to add, deploy, and manage SharePoint apps cross-platform
Using the Office 365 CLI, you can automate deploying, publishing, installing, upgrading, and retracting your apps. The Office 365 CLI is a cross-platform command-line interface that can be
used on any platform, including Windows, MacOS, and Linux. To learn more about these commands, see the following sections.

Add and publish your app to the app catalog


Adding your app (.sppkg file, .app file) to the tenant app catalog is a prerequisite to making your app available for use on your SharePoint sites. Use the add command to do this:

spo app add --filePath ./spfx.sppkg

Once added, you need to continue with publishing your app, effectively making the app available to be used by the users of your tenant. Use the deploy command to do this:

spo app deploy --id <app id> --skipFeatureDeployment

NOTE

Use the SkipFeatureDeployment flag to allow an app that was developed for tenant-wide deployment to be actually available as a tenant-wide deployed app.

Remove the app from the app catalog


You may want to remove an app that you added earlier, and you can do this by using the remove command:

spo app remove --id <app id>

Use apps on your site


After the app is added to the app catalog and published, you can install the app to your site by using the install command:

spo app install --id <app id> --siteUrl <url>

To upgrade the app, use the upgrade command:

spo app upgrade --id <app id> --siteUrl <url>

To uninstall the app from your site, use the uninstall command:

spo app uninstall --id <app id> --siteUrl <url>

NOTE

When you uninstall an app from your site, the app is completely deleted, so it will not end up in the site's recycle bin.

List and get apps in the app catalog


You can see what apps have been added to the app catalog by using the list command:

spo app list

You can get a single app's details by using the get command:

spo app get --id <app id>

See also
Get to know the SharePoint REST service
Use column formatting to customize SharePoint
8/13/2018 • 20 minutes to read Edit Online

You can use column formatting to customize how fields in SharePoint lists and libraries are displayed. To do this, you construct a JSON object that describes the elements that are displayed
when a field is included in a list view, and the styles to be applied to those elements. The column formatting does not change the data in the list item or file; it only changes how it’s displayed
to users who browse the list. Anyone who can create and manage views in a list can use column formatting to configure how view fields are displayed.
For example, a list with the fields Title, Effort, Assigned To, and Status with no customizations applied might look like this:

A list with the appearance of the Effort, Assigned To, and Status fields customized via column formatting might look like this:

 T IP

Samples demonstrated in this article and numerous other community samples are available from a GitHub repository dedicated for open-sourced column formatting definitions. You can
find these samples from the sp-dev-column-formatting repository at SharePoint GitHub organization.

How is column formatting different than the Field Customizer?


Both column formatting and SharePoint Framework Field Customizer extensions enable you to customize how fields in SharePoint lists are displayed. The Field Customizer is more powerful
because you can use it to write any code that you want to control how a field is displayed.
Column formatting is more easily and broadly applied. However, it is less flexible, because it does not allow for custom code; it only allows for certain predefined elements and attributes.
The following table compares column formatting and the Field Customizer.

FIELD T YPE CO LU MN FO R MAT TING FIELD CU S TO MIZER

Conditional formatting based on item values and value ranges Supported Supported

Action links Support for static hyperlinks that do not launch script Support for any hyperlink, including those that invoke custom script

Data visualizations Support for simple visualizations that can be expressed using HTML Support for arbitrary data visualizations
and CSS

If you can accomplish your scenario by using column formatting, it’s typically quicker and easier to do that than to use a Field Customizer. Anyone who can create and manage views in a list
can use column formatting to create and publish customizations. Use a Field Customizer for more advanced scenarios that column formatting does not support.

Get started with column formatting


To open the column formatting pane, open the drop-down menu under a column. Under Column Settings, choose Format this column.
If no one has used column formatting on the column you selected, the pane will look like the following.
A field with no formatting specified uses the default rendering. To format a column, enter the column formatting JSON in the box.
To preview the formatting, select Preview. To commit your changes, select Save. When you save, anyone who views the list will see the customization that you applied.
The easiest way to use column formatting is to start from an example and edit it to apply to your specific field. The following sections contain examples that you can copy, paste, and edit for
your scenarios. There are also several samples available in the SharePoint/sp-dev-column-formatting repository.

Display field values (basic)


The simplest column formatting is one that places the value of the field inside a <div /> element. This example works for number, text, choice, and date fields:

{
"elmType": "div",
"txtContent": "@currentField"
}

Some field types require a bit of extra work to retrieve their values. Person fields are represented in the system as objects, and a person’s display name is contained within that object’s title
property. This is the same example, modified to work with the person field:

{
"elmType": "div",
"txtContent": "@currentField.title"
}

Lookup fields are also represented as objects; the display text is stored in the lookupValue property. This example works with a lookup field:

{
"elmType": "div",
"txtContent": "@currentField.lookupValue"
}

Apply conditional formatting


You can use column formatting to apply styles, classes, and icons to fields, depending on the value inside those fields.

Conditional formatting based on a number range (basic)


The following image shows an example of conditional formatting applied to a number range.

This example uses an Excel-style conditional expression ( =if ) to apply a class ( sp-field-severity--warning ) to the parent <div /> element when the value in the current field is less than or
equal to 70. This causes the field to be highlighted when the value is less than or equal to 70, and appear normally if it's greater than 70.
{
"$schema": "http://columnformatting.sharepointpnp.com/columnFormattingSchema.json",
"debugMode": true,
"elmType": "div",
"attributes": {
"class": "=if(@currentField <= 70,'sp-field-severity--warning', '')"
},
"children": [
{
"elmType": "span",
"style": {
"display": "inline-block",
"padding": "0 4px"
},
"attributes": {
"iconName": "=if(@currentField <= 70,'Error', '')"
}
},
{
"elmType": "span",
"txtContent": "@currentField"
}
]
}

Conditional formatting based on the value in a text or choice field (advanced)


The following image shows an example of conditional formatting applied to a text or choice field:

You can apply conditional formatting to text or choice fields that might contain a fixed set of values. The following example applies different classes depending on whether the value of the
field is Done, In Review, Blocked, or another value. This example applies a CSS class (
sp-field-severity--low, sp-field-severity--good, sp-field-severity--warning, sp-field-severity--blocked ) to the <div /> based on the field's value. It then outputs a <span /> element
with an IconName attribute. This attribute applies another CSS class to that <span /> that shows an Office UI Fabric icon inside that element. Finally, another <span /> element is output
that contains the value inside the field.
This pattern is useful when you want different values to map to different levels of urgency or severity. You can start from this example and edit it to specify your own field values and the
styles and icons that should map to those values.

{
"$schema": "http://columnformatting.sharepointpnp.com/columnFormattingSchema.json",
"debugMode": true,
"elmType": "div",
"attributes": {
"class": "=if(@currentField == 'Done', 'sp-field-severity--good', if(@currentField == 'In progress', 'sp-field-severity--low' ,if(@currentField == 'In review','sp-field-severity--warning', if
},
"children": [
{
"elmType": "span",
"style": {
"display": "inline-block",
"padding": "0 4px"
},
"attributes": {
"iconName": "=if(@currentField == 'Done','CheckMark', if(@currentField == 'In progress', 'Forward', if(@currentField == 'In review', 'Error', if(@currentField == 'Has issues','Warning',''
}
},
{
"elmType": "span",
"txtContent": "@currentField"
}
]
}

Apply formatting based on date ranges


Because dates are often used to track deadlines and key project timelines, a common scenario is to apply formatting based on the value in a date/time field. To apply formatting based on the
value in a date/time field, apply the following patterns.

Formatting an item when a date column is before or after today's date (advanced)
The following image shows a field with conditional date formatting applied:
This example colors the current field red when the value inside an item's DueDate is before the current date/time. Unlike some of the previous examples, this example applies formatting to
one field by looking at the value inside another field. Note that DueDate is referenced using the [$FieldName] syntax. FieldName is assumed to be the internal name of the field. This
example also takes advantage of a special value that can be used in date/time fields - @now , which resolves to the current date/time, evaluated when the user loads the list view.
NOTE

If you have spaces in the field name, those are defined as _x0020_ . For example, a field named "Due Date" should be referenced as $Due_x0020_Date .

{
"$schema": "http://columnformatting.sharepointpnp.com/columnFormattingSchema.json",
"elmType": "div",
"debugMode": true,
"txtContent": "@currentField",
"style": {
"color": "=if([$DueDate] <= @now, '#ff0000', ''"
}
}

Formatting items based on arbitrary dates (advanced)


To compare the value of a date/time field against a date that's not @now , follow the pattern in the following example. The following example colors the current field red if the due date was <=
tomorrow. This is accomplished using date math. You can add milliseconds to any date and the result will be a new date. For example, to add a day to a date, you'd add (24*60*60*1000 =
86,400,000).
This example demonstrates an alternate syntax to express a conditional expression, using the ternary ( ? ) operator inside an abstract syntax tree.

{
"elmType": "div",
"txtContent": "@currentField",
"style": {
"color": {
"operator": "?",
"operands": [
{
"operator": "<=",
"operands": [
"[$DueDate]",
{
"operator": "+",
"operands": [
"@now",
86400000
]
}
]
},
"#ff0000",
""
]
}
}
}

To compare a date/time field value against another date constant, use the Date() method to convert a string to a date. The following example colors the current field red if the value in the
DueDate field is before 3/22/2017.

{
"elmType": "div",
"txtContent": "@currentField",
"style": {
"color": {
"operator": "?",
"operands": [
{
"operator": "<=",
"operands": [
"[$DueDate]",
{
"operator": "Date()",
"operands": [
"3/22/2017"
]
}
]
},
"#ff0000",
""
]
}
}
}

Create clickable actions


You can use column formatting to provide hyperlinks that go to other webpages, or start custom functionality. This functionality is limited to static links that can be paramaterized with values
from fields in the list. You can't use column formatting to output links to protocols other than http:// , https:// , or mailto: .

Turn field values into hyperlinks (basic)


This example shows how to turn a text field that contains stock ticker symbols into a hyperlink that targets the Yahoo Finance real-time quotes page for that stock ticker. The example uses a
+ operator that appends the current field value to the static hyperlink http://finance.yahoo.com/quote/. You can extend this pattern to any scenario in which you want users to view
contextual information related to an item, or you want to start a business process on the current item, as long as the information or process can be accessed via a hyperlink parameterized
with values from the list item.

{
"elmType": "a",
"txtContent": "@currentField",
"attributes": {
"target": "_blank",
"href": "='http://finance.yahoo.com/quote/' + @currentField"
}
}

Add an action button to a field (advanced)


The following image shows action buttons added to a field.

You can use column formatting to render quick action links next to fields. The following example, intended for a person field, renders two elements inside the parent <div /> element:
A <span /> element that contains the person’s display name.
An <a /> element that opens a mailto: link that creates an email with a subject and body populated dynamically via item metadata. The <a /> element is styled using the ms-Icon ,
ms-Icon—Mail , and ms-QuickAction Fabric classes to make it look like a clickable email icon.

{
"elmType": "div",
"children": [
{
"elmType": "span",
"style": {
"padding-right": "8px"
},
"txtContent": "@currentField.title"
},
{
"elmType": "a",
"attributes": {
"iconName": "Mail",
"class": "sp-field-quickAction",
"href": {
"operator": "+",
"operands": [
"mailto:",
"@currentField.email",
"?subject=Task status&body=Hey, how is your task coming along?.\r\n---\r\n",
"@currentField.title",
"\r\nClick this link for more info. http://contoso.sharepoint.com/sites/ConferencePrep/Tasks/Prep/DispForm.aspx?ID=",
"[$ID]"
]
}
}
}
]
}

Create simple data visualizations


Use column formatting to combine conditional and arithmetical operations to achieve basic data visualizations.

Format a number column as a data bar (advanced)


The following image shows a number column formatted as a data bar.
This example applies background-color and border-top styles to create a data bar visualization of @currentField , which is a number field. The bars are sized differently for different values
based on the way the width attribute is set - it's set to 100% when the value is greater than 95, and (@currentField * 100 / 95)% otherwise. To fit this example to your number column, you
can adjust the boundary condition ( 20 ) to match the maximum anticipated value inside the field, and change the equation to specify how much the bar should grow depending on the value
inside the field.

{
"debugMode": true,
"elmType": "div",
"txtContent": "@currentField",
"attributes": {
"class": "sp-field-dataBars"
},
"style": {
"width": "=if(@currentField > 95, '100%', toString(@currentField * 100 / 95) + '%'"
}
}

Show trending up/trending down icons (advanced)


The following image shows a list with trending up/trending down icons added:

This example relies on two number fields, Before and After , for which the values can be compared. It shows the appropriate trending icon next to the After field, depending on that field's
value compared to the value in Before . sp-field-trending--up is used when After 's value is higher; sp-field-trending--down is used when After 's value is lower.
{
"debugMode": true,
"elmType": "div",
"children": [
{
"elmType": "span",
"attributes": {
"class": {
"operator": "?",
"operands": [
{
"operator": ">",
"operands": [
"[$After]",
"[$Before]"
]
},
"sp-field-trending--up",
"sp-field-trending--down"
]
},
"iconName": {
"operator": "?",
"operands": [
{
"operator": ">",
"operands": [
"[$After]",
"[$Before]"
]
},
"SortUp",
{
"operator": "?",
"operands": [
{
"operator": "<",
"operands": [
"[$After]",
"[$Before]"
]
},
"SortDown",
""
]
}
]
}
}
},
{
"elmType": "span",
"txtContent": "[$After]"
}
]
}

Create a button to launch a Flow


The following screenshot shows a list with a Flow button added to the Action column:

You can use column formatting to create buttons that, when selected, run Flows on the corresponding list item. If the Flow is configured to gather data from the end user before running, the
Flow Launch Panel will be displayed after choosing the button. Otherwise, the Flow will just run.
To use the sample below, you must substitute the ID of the Flow you want to run. This ID is contained within the customRowAction attribute inside the button element. To obtain a Flow's ID:
1. Choose Flow > See your flows in the SharePoint list where the Flow is configured.
2. Choose the Flow you want to run.
3. Copy the ID from the end of the URL.
{
"$schema": "https://developer.microsoft.com/json-schemas/sp/column-formatting.schema.json",
"elmType": "span",
"style": {
"color": "#0078d7"
},
"children": [
{
"elmType": "span",
"attributes": {
"iconName": "Flow"
}
},
{
"elmType": "button",
"style": {
"border": "none",
"background-color": "transparent",
"color": "#0078d7",
"cursor": "pointer"
},
"txtContent": "Send to Manager",
"customRowAction": {
"action": "executeFlow",
"actionParams": "{\"id\": \"183bedd4-6f2b-4264-855c-9dc7617b4dbe\"}"
}
}
]
}

Supported column types


The following column types support column formatting:
Single line of text
Number
Choice
Person or Group
Yes/No
Hyperlink
Picture
Date/Time
Lookup
Title (in Lists)
The following are not currently supported:
Managed Metadata
Filename (in Document Libraries)
Calculated
Retention Label

Style guidelines
Predefined classes
You can use the following predefined classes for several common scenarios.

CL AS S NAME S CR EENS HO T

sp-field-customFormatBackground Specifies the padding and margins for all classes that use backgrounds.

sp-field-severity--good

sp-field-severity--low

sp-field-severity--warning

sp-field-severity--severeWarning

sp-field-severity--blocked

sp-field-dataBars
CL AS S NAME S CR EENS HO T

sp-field-trending--up

sp-field-trending--down

sp-field-quickAction

Predefined icons
You can use predefined icons from Office UI Fabric. For details, see the Fabric website.

Creating custom JSON


Creating custom column formatting JSON from scratch is simple if you understand the schema. To create your own custom column formatting:
1. Download Visual Studio Code. It's free and fast to download.
2. In Visual Studio Code, create a new file, and save the empty file with a .json file extension.
3. Paste the following lines of code into your empty file.

{
"$schema": "https://developer.microsoft.com/json-schemas/sp/column-formatting.schema.json"
}

You now have validation and autocomplete to create your JSON. You can start adding your JSON after the first line that defines the schema location.
 T IP

At any point, select Ctrl+Space to have Visual Studio Code offer suggestions for properties and values. For more information, see Editing JSON with Visual Studio Code.

Detailed syntax reference


elmType
Specifies the type of element to create. Valid elements include:
div
span
a
img
svg
path
button
Any other value will result in an error.
button elements
Button elements can be used to launch a specific action on the parent item. Every button element has a requred property, customRowAction , that specifies an action that's taken when the
button is clicked. This action must be one of the following values:
defaultClick: buttons with this action will do the same thing as clicking the list item in an uncustomized view. Below is an example of a button that, when clicked, simulates a click on the
item, which results in the details pane being opened.

{
"elmType": "button",
"txtContent": "Open this item",
"customRowAction": {
"action": "defaultClick"
}
}

share: Clicking the button will open the sharing dialog. Below is an example of this type of button.

{
"elmType": "button",
"txtContent": "Share this item",
"customRowAction": {
"action": "share"
}
}

delete: Clicking the button will open the delete confirmation dialog.
editProps: Clicking the button will open the item properties page in edit mode.
executeFlow: Clicking the button will launch the specified Flow, specified by ID inside the actionParams attribute. For an example of this, see the Create a button to launch a Flow section
in this document.

txtContent
An optional property that specifies the text content of the element specified by elmType . The value of this property can either be a string (including special strings) or an Expression object.

style
An optional property that specifies style attributes to apply to the element specified by elmType . This is an object with name-value pairs that correspond to CSS names and values. The
values of each property in the style object can either be a string (including special strings) or an Expression object. The following style attributes are allowed.

'background-color'
'fill'
'background-image'
'border'
'border-bottom'
'border-bottom-color'
'border-bottom-style'
'border-bottom-width'
'border-color'
'border-left'
'border-left-color'
'border-left-style'
'border-left-width'
'border-right'
'border-right-color'
'border-right-style'
'border-right-width'
'border-style'
'border-top'
'border-top-color'
'border-top-style'
'border-top-width'
'border-width'
'outline'
'outline-color'
'outline-style'
'outline-width'
'border-bottom-left-radius'
'border-bottom-right-radius'
'border-radius'
'border-top-left-radius'
'border-top-right-radius'
'box-decoration-break'
'box-shadow'
'box-sizing'

'overflow-x'
'overflow-y'
'overflow-style'
'rotation'
'rotation-point'

'opacity'

'height'
'max-height'
'max-width'
'min-height'
'min-width'
'width'

'align-items'
'box-align'
'box-direction'
'box-flex'
'box-flex-group'
'box-lines'
'box-ordinal-group'
'box-orient'
'box-pack'

'font'
'font-family'
'font-size'
'font-style'
'font-variant'
'font-weight'
'font-size-adjust'
'font-stretch'

'grid-columns'
'grid-rows'

'margin'
'margin-bottom'
'margin-left'
'margin-right'
'margin-top'

'column-count'
'column-fill'
'column-gap'
'column-rule'
'column-rule-color'
'column-rule-style'
'column-rule-width'
'column-span'
'column-width'
'columns'

'padding'
'padding-bottom'
'padding-left'
'padding-right'
'padding-top'

'bottom'
'clear'
'clip'
'display'
'float'
'left'
'overflow'
'position'
'right'
'top'
'visibility'
'z-index'

'border-collapse'
'border-spacing'
'caption-side'
'empty-cells'
'table-layout'

'color'
'direction'
'letter-spacing'
'line-height'
'text-align'
'text-decoration'
'text-indent'
'text-transform'
'unicode-bidi'
'vertical-align'
'white-space'
'word-spacing'
'hanging-punctuation'
'punctuation-trim'
'text-align-last'
'text-justify'
'text-outline'
'text-shadow'
'text-wrap'
'word-break'
'word-wrap'

The following example shows the value of a style object. In this example, two style properties ( padding and background-color ) will be applied. The padding value is a hard-coded string
value. The background-color value is an Expression that is evaluated to either red ( #ff0000 ) or green ( #00ff00 ) depending on whether the value of the current field (specified by
@currentField ) is less than 40. For more information, see the Expression object section.

{
"padding": "4px",
"background-color": {
"operator": "?",
"operands": [
{
"operator": "<",
"operands": [
"@currentField",
40
]
},
"#ff0000",
"#00ff00"
]
}
}

attributes
An optional property that specifies additional attributes to add to the element specified by elmType . This is an object with name-value pairs. Attribute names must be one of the following:
href
rel
src
class
target
title
role
iconName
d
aria
Any other attribute name will result in an error. Attribute values can either be Expression objects or strings. The following example adds two attributes ( target and href ) to the element
specified by elmType . The target attribute is hard-coded to a string. The href attribute is an expression that will be evaluated at runtime to http://finance.yahoo.com/quote/ + the value of
the current field ( @currentField ).

{
"target": "_blank",
"href": "='http://finance.yahoo.com/quote/' + @currentField"
}

children
An optional property that specifies child elements of the element specified by elmType . The value is specified as an array of elm objects. There can be an arbitrary level of nesting. If an
element has the txtContent property, the child properties are ignored.

debugMode
An optional property that is meant for debugging. It outputs error messages and logs warnings to the console.

Expressions
Values for txtContent , style properties, and attribute properties can be expressed as expressions, so that they are evaluated at runtime based on the context of the current field (or row).
Expression objects can be nested to contain other Expression objects.
Excel-style expressions
All Excel-style expressions begin with an equal ( = ) sign.
This simple conditional expression evaluates to none if @me is not equal to [$Author.email] , and evaluates to `` otherwise:

=if(@me != [$Author.email], 'none', '')

More complex if/else statements can be written like this:

=if([$Sentiment] <= 0.3, 'sp-field-severity--blocked', if([$Sentiment] < 0.9,'sp-field-severity--warning','sp-field-severity--good'))

Non-conditional operators that take one or two operands can be written like this:

=[$foo] * -7

=sin(@currentField)

=toString(60 + (sin(6.2831853 * @currentField) * 60))

Abstract Syntax Tree expressions


The following example contains an Expression object that performs the following expression:
(@currentField > 40) ? '100%' : (((@currentField * 2.5).toString() + '%')

{
"operator": "?",
"operands": [
{
"operator": ">",
"operands": [
"@currentField",
"40"
]
},
"100%",
{
"operator": "+",
"operands": [
{
"operator": "toString()",
"operands": [
{
"operator": "*",
"operands": [
"@currentField",
2.5
]
}
]
},
"%"
]
}
]
}

Operators
Operators specify the type of operation to perform. The following operators are valid values:
+
-
/
*
<
>
==
!=
<=
>=
||
&&
toString()
Number()
Date()
cos
sin
?
toLocaleString()
toLocaleDateString()
toLocaleTimeString()
Binary operators - The following are the standard arithmetic binary operators that expect two operands:
+
-
/
*
<
>
<=
>=
Unary operators - The following are standard unary operators that expect only one operand:
toString()
Number()
Date()
cos
sin
toLocaleString()
toLocaleDateString()
toLocaleTimeString()
Conditional operator - The conditional operator is:
?
This is to achieve an expression equivalent to a ? b : c, where if the expression a evaluates to true, then the result is b, else the result is c.

operands
Specifies the parameters, or operands for an expression. This is an array of Expression objects or base values.

Special string values


The values for txtContent , styles, and attributes can be either strings or Expression objects. A few special string patterns for retrieving values from the fields in the list and the user's context
are supported.
"@currentField"
Will evaluate to the value of the current field.
Some field types are represented as objects. To output a value from an object, refer to a particular property inside that object. For example, if the current field is a person/group field, specify
@currentField.title to retrieve the person's name, which is normally displayed in list views. The following are the field types that are represented as objects with a list their properties.

NOTE

The @currentField.title returns a person's name by default. However, if the person field's Show Field has been adjusted, it may change the value of the title property. For example, a
person field with the Show Field configured as Department will have the person's department for the title property.
People fields
The people field object has the following properties (with example values):

{
"id": "122",
"title": "Kalya Tucker",
"email": "kaylat@contoso.com",
"sip": "kaylat@contoso.com",
"picture": "https://contoso.sharepoint.com/kaylat_contoso_com_MThumb.jpg?t=63576928822"
}

Date/Time fields
The value of Date/Time fields can be retrieved a few different ways, depending on the date format you'd like to display. The following methods for converting date values to specific formats
are supported:
toLocaleString() - Displays a date type fully expanded with date and time.
toLocaleDateString() - Displays a date type with just the date.
toLocaleTimeString() - Displays a date type with just the time.

For example, the following JSON will display the current field (assuming it's a date field) as a date and time string.

{
"elmType": "div",
"txtContent": {
"operator": "toLocaleString()",
"operands" : ["@currentField"]
}
}

Lookup fields
The lookup field object has the following properties (with example values):

{
"lookupId": "100",
"lookupValue": "North America",
}
The following example shows how a lookup field might be used on a current field.

{
"elmType": "a",
"txtContent": "@currentField.lookupValue",
"attributes": {
"href": {
"operator": "+",
"operands": [
"https://contoso.sharepoint.com/teams/Discovery/Lists/Regions/DispForm.aspx?ID=",
"@currentField.lookupId"
]
},
"target": "_blank"
}
}

Hyperlink fields
The hyperlink field object has the following property (with example value):

{
"desc": "SharePoint Patterns and Practices",
}

To reference the URL value, use @currentField .


The following example shows how a hyperlink field might be used on a current field.

{
"elmType": "a",
"txtContent": "@currentField.desc",
"attributes": {
"href": "@currentField",
"target": "_blank"
}
}

"[$FieldName]"
The column is formatted within the context of the entire row. You can use this context to reference the values of other fields within the same row by specififying the internal name of the
field surrounded by square brackets and preceeded by a dollar sign: [$InternalName] . For example, to get the value of a field with an internal name of "MarchSales", use [$MarchSales] .
If the value of a field is an object, the object's properties can be accessed. For example, to access the "Title" property of a person field named "SalesLead", use "[$SalesLead.title]".
"@me"
This will evaluate to the email address of the current logged in user.
This field can be used to display the current user's email address, but more likely it will be used within conditions. The following is an example of setting the color for a person field to red
when it is equal to the current logged in user and blue otherwise:

{
"elmType": "div",
"txtContent": "@currentField.title",
"style": {
"color": {
"operator": "?",
"operands": [
{
"operator": "==",
"operands": [
"@me",
"@currentField.email"
]
},
"red",
"blue"
]
}
}
}

"@now"
This will evaluate to the current date and time.
"@window.innerHeight"
This will evaluate to a number equal to the height of the browser window (in pixels) when the list was rendered.
"@window.innerWidth"
This will evaluate to a number equal to the width of the browser window (in pixels) when the list was rendered.

See also
Column formatting
Create SharePoint Communication site using REST
4/23/2018 • 2 minutes to read Edit Online

This topic assumes that you are already familiar with the following topics:
Get to know the SharePoint REST service
Complete basic operations using SharePoint REST endpoints
This topic does not provide code snippets.
The following REST commands are available for creating a modern SharePoint Communication site:
Create. Create a new SharePoint Communication site.
Status. Get the status of a SharePoint Communication site.
The URL for Communication site REST commands is based on _api/sitepages/communicationsite . For example, these are the endpoints for the REST commands listed earlier:
http:///_api/sitepages/communicationsite/create
http:///_api/sitepages/communicationsite/status

Create Communication site


url: /_api/sitepages/communicationsite/create
method: POST
body:
{
"request":{
"__metadata":{
"type":"SP.Publishing.CommunicationSiteCreationRequest"
},
"AllowFileSharingForGuestUsers":false,
"Classification":"LBI",
"Description":"Description",
"SiteDesignId":"6142d2a0-63a5-4ba0-aede-d9fefca2c767",
"Title":"Comm Site 1",
"Url":"https://vesku.sharepoint.com/sites/commsite132",
"lcid":1033
}
}

IM P O R T A N T

The lcid parameter is not currently supported with this API. You can currently only create English sites.
New in this API is the concept of SiteDesignID . Much like the in-product site creation flow, the SiteDesignID parameter maps to the included site designs. They are:
Topic: null
Showcase: 6142d2a0-63a5-4ba0-aede-d9fefca2c767
Blank: f6cc5403-0d63-442e-96c0-285923709ffc

Response
If successful, this method returns a 200, OK response code and simple JSON object in the response body with the following details.

{
"d":{
"Create":{
"__metadata":{"type":"SP.Publishing.CommunicationSiteCreationResponse"},
"SiteStatus":2,
"SiteUrl":"https://contoso.sharepoint.com/sites/comm1"
}
}
}

Get Communication site status


The REST API for getting the status of a modern SharePoint Communication site:

url: /_api/sitepages/communicationsite/status?url='https%3A%2F%2Fcontoso.sharepoint.com%2Fsites%2Fcomm1'
method: GET
body: none

Response
If successful, this method returns a 200, OK response code and simple JSON object in the response body with the following details.
If the site exists, the response returns the site status and site URL:

{
"d":{
"Status":{
"__metadata":{"type":"SP.Publishing.CommunicationSiteCreationResponse"},
"SiteStatus":2,
"SiteUrl":"https://contoso.sharepoint.com/sites/comm1"
}
}
}

If the site does not exist, the response returns a site status of 0 with no URL.
{
"d":{
"Status":{
"__metadata":{"type":"SP.Publishing.CommunicationSiteCreationResponse"},
"SiteStatus":0,
"SiteUrl":
}
}
}

See also
Get to know the SharePoint REST service
Shorter share link format in OneDrive and SharePoint
4/20/2018 • 2 minutes to read Edit Online

Links to shared files and folders in OneDrive and SharePoint are now shorter and have a new format. For example, the following shows the old and new format for a OneDrive link that
works for anyone inside the organization.

O LD LINK FO R MAT NE W LINK FO R MAT

https://contoso-my.sharepoint.com/personal/john_contoso_com/_layouts/15/guestaccess.aspx? https://contoso-
share=ERGZUIZ8E0pAuC1oJtwz4dQB23IabPgbMtiVe0OLPtMybw my.sharepoint.com/:w:/p/john/ERGZUIZ8E0pAuC1oJtwz4dQB23IabPgbMtiVe0OLPtMybw
NOTE

Links that were shared before this change was introduced are not affected by the change and will continue to work.
The new link format might affect applications or services that inspect or take dependencies on OneDrive or SharePoint URL structures, especially if those applications or services parse the
site URL or specific strings. The new short links are compatible with all APIs that work with guestaccess.aspx links.
The following are some scenarios that are affected by this change:
Applications that parse a URL input by an end user to get the site URL in order to construct SharePoint REST API requests such as GetFileByUrl or GetSharingLinkData.
Applications that take URL input from an end user and use CSOM to attempt to query file information.
Applications that parse a URL input by an end user to determine whether it is an anonymous or an internal-only sharing link.
Apps that use Microsoft Graph to interact with SharePoint links will continue to work. For more information, see Accessing shared DriveItems.

SharePoint REST API


The SharePoint REST API does not have a supported way to interact with user input links. We recommend that you migrate to the Microsoft Graph shares API if possible.
If you’re unable to migrate to Microsoft Graph, you can use the following workaround. Note that this workaround is not supported.
1. Determine the base URL. This is now the hostname of the link.
2. Construct the API request by concatenating the base URL, SP.RemoteWeb , and a specific API method, as shown.
{hostname}/_api/SP.RemoteWeb(@a)/web/{specific_api_here}?@a='{url_encoded_link}'

For example, for the following input URL:


https://contoso-my.sharepoint.com/personal/john_contoso_com/_layouts/15/guestaccess.aspx?share=ERGZUIZ8E0pAuC1oJtwz4dQB23IabPgbMtiVe0OLPtMybw

This is the original API request:


https://contoso-my.sharepoint.com/personal/john_contoso_com/_api/web/GetFileByUrl(@url)?@url='https%3A%2F%2Fcontoso-
my.sharepoint.com%2Fpersonal%2Fjohn_contoso_com%2F_layouts%2F15%2Fguestaccess.aspx%3Fshare%3DERGZUIZ8E0pAuC1oJtwz4dQB23IabPgbMtiVe0OLPtMybw

This is the new API request:


https://contoso-my.sharepoint.com/_api/SP.RemoteWeb(@url)/web/GetFileByUrl(@url)?@url='https%3A%2F%2Fcontoso-
my.sharepoint.com%2Fpersonal%2Fjohn_contoso_com%2F_layouts%2F15%2Fguestaccess.aspx%3Fshare%3DERGZUIZ8E0pAuC1oJtwz4dQB23IabPgbMtiVe0OLPtMybw

To determine the specific type of link, inspect the IsSharingLink and IsAnonymous fields in the response for the GetSharingLinkData API (replace GetFileByUrl with GetSharingLinkData
in the examples). Use this method instead of parsing URLs for tokens such as guestaccess.aspx .

SharePoint CSOM
CSOM does not have a supported way to interact with user input links. Some applications open a ClientContext and query the file metadata by successively truncating path segments from
the SharePoint link until the ClientContext constructor succeeds. This approach no longer works with the new URL format.
To work around this:
1. Open a ClientContext on the root site (scheme://hostname).
2. Call Web.WebUrlFromPageUrlDirect() to get the web URL of the link.
3. Open a new ClientContext using this web URL to make additional requests.
NOTE

This approach is not supported.


SharePoint development overview
7/12/2018 • 3 minutes to read Edit Online

SharePoint is a development platform for SharePoint Framework, SharePoint Add-ins and farm solutions. Get acquainted with the capabilities and features of SharePoint to start your
development.

Introducing the SharePoint development platform


SharePoint is a versatile development platform for building client-side components, add-ins and solutions with varying scopes that address a wide range of needs. The SharePoint developer
documentation guides you through the features, technologies, capabilities, and models for development that distinguish SharePoint as a development platform.

What kinds of development can you do with SharePoint?


For SharePoint Framework
The following article can help you get acquainted with SharePoint Framework and determine whether they are a good option for you.
Overview of the SharePoint Framework
For SharePoint Add-ins development
The following article can help you get acquainted with SharePoint Add-ins and determine whether they are a good option for you.
SharePoint Add-ins compared with SharePoint solutions
For SharePoint solutions and add-ins for mobility features development
The following sections describe how to create mobile solutions for SharePoint.
Build Windows Phone apps that access SharePoint
How to: Build search-driven mobile apps with the Navigation and Event Logging REST interfaces
The following sections provide information about SharePoint features that are available for farm solutions.
Build sites for SharePoint
Add SharePoint capabilities

Set up your development environment and start developing


For SharePoint Framework
Table 1 shows the resources for setting up a development environment and beginning to take advantage of the new capabilities for building SharePoint Framework customizations.
Table 1. Resources to help you get started with SharePoint Framework solutions

TO PIC D ES CR IPTIO N

Set up your SharePoint Framework development environment Contains step-by-step instructions on how to install the components of a SharePoint Framework
development environment.

Build your first SharePoint client-side web part Describes how to build your first client-side web part using SharePoint Framework

Build your first SharePoint Framework Extension Describes how to build your first SharePoint Framework Extension

For SharePoint solutions and add-ins for mobility features development


Table 2 shows the resources for setting up a development environment and beginning to take advantage of the new capabilities for building farm solutions with SharePoint.
Table 2. Resources to help you get started with SharePoint farm solutions development

TO PIC D ES CR IPTIO N

Set up a general development environment for SharePoint Contains step-by-step instructions on how to install the components of a SharePoint development
environment.

Choose the right API set in SharePoint Describes the several sets of APIs that are provided in SharePoint, including the server object model and
the various client-side object models, and the REST/OData web service.

Programming models in SharePoint Provides a quick overview of the different kinds of SharePoint development projects that you can create
with SharePoint.

Add SharePoint capabilities Provides a gateway to detailed information about using the capabilities of SharePoint in your solutions.

For SharePoint Add-ins development


If you want to get started development SharePoint Add-ins, first think about the kinds of add-ins that you might want to build, the technologies that you want to include, and the hosting
options that you want to use.
When you know the kinds of SharePoint Add-in that you want to create, we provide guidance to help you match them to the appropriate development environment. Table 3 shows the
resources for setting up your SharePoint development environment and beginning to create your add-ins.
Table 3. Resources to help you get started with SharePoint Add-ins development

TO PIC D ES CR IPTIO N
TO PIC D ES CR IPTIO N

Set up a development environment for SharePoint Add-ins on Office 365 Explains how to sign up for and use an Office 365 Developer Site for developing SharePoint Add-ins.

Set up an on-premises development environment for SharePoint Add-ins Explains how to set up a local, on-premises installation of SharePoint and configure it for developing
SharePoint Add-ins.

Get started creating provider-hosted SharePoint Add-ins Contains step-by-step instructions on how to create a basic SharePoint Add-in that is hosted separately
from a SharePoint site.

Get started creating SharePoint-hosted SharePoint Add-ins Contains step-by-step instructions on how to create a basic SharePoint Add-in that is hosted on a
SharePoint site.

See also
Accessibility in SharePoint
Protocol handler error due to deprecated interface in SharePoint 2016
.NET server API reference for SharePoint
.NET client API reference for SharePoint Online
SharePoint glossary
SharePoint Server 2019 development platform
8/13/2018 • 2 minutes to read Edit Online

This article contains preliminary details around supported development capabilities in the SharePoint 2019.
IM P O R T A N T

This list is still subject to change until actual official release of SharePoint 2019. This page will be updated accordingly when there are changes in the supportability statements.
Supported capabilities
Modern and classic pages
Modern sites - modern team and communication site
Classic sites are also supported
Column formatting
SharePoint Framework client-side web parts
SharePoint Framework extensions in modern experiences
Webhooks for list items
Asset packaging and automatic JavaScript file hosting from app catalog
"Tenant" scoped deployment of SharePoint Framework solutions
ALM APIs for add-in and SharePoint Framework solution management
Not supported capabilities
Site Designs and Site Scripts
Hub sites
Site collection app catalog
"Tenant" properties
Custom modern themes for communication site or modern team site
Supported SharePoint Framework version for the SharePoint 2019 will be SharePoint Framework v1.4.1 (except Microsoft Graph APIs). SharePoint Framework Yeoman generator will be
updated to have this option included in the version selection.
NOTE

If you need to write SharePoint Framework components for SharePoint 2019 before Yeoman generator is updated, you can install SharePoint Framework 1.4.1 and use that as the generator
for your SharePoint 2019 components. You should use the 'Online' option in this case, when the environment question is asked in the Yeoman solution flow.

See also
Introduction to SharePoint Server 2019 Preview development platform
Introduction to SharePoint Server 2019 Preview development platform YouTube video
SharePoint glossary
5/3/2018 • 24 minutes to read Edit Online

Find definitions for terms used in SharePoint developer documentation.

Glossary
TER M D EFINITIO N

access control entry An entry in either a securable object's discretionary access control list (DACL) or an object's system
access control list (SACL). In a DACL, the entry grants or denies permissions to a user or group. In a
SACL, the entry specifies which security events to audit for a particular user or group or controls the
Windows Integrity Level for the object.

access control list In Windows-based systems, a list of access control entries (ACE) that apply to an entire object, a set of
the object's properties, or an individual property of an object, and that define the access granted to one
or more security principals.

access URL The internal URL that is used by a crawler to identify and access an item.

ACE An entry in either a securable object's discretionary access control list (DACL) or an object's system
access control list (SACL). In a DACL, the entry grants or denies permissions to a user or group. In a
SACL, the entry specifies which security events to audit for a particular user or group or controls the
Windows Integrity Level for the object.

ACL In Windows-based systems, a list of access control entries (ACE) that apply to an entire object, a set of
the object's properties, or an individual property of an object, and that define the access granted to one
or more security principals.

activity feed A feed that provides information, notifications and updates based on people, documents, and tags you
are following.

activity flow A running instance of a workflow that consists of a sequence of action instances and/or activity model
instances. Action instances and activity model instances can be sequenced in any order to create a single
activity flow.

activity model A predefined sequence of actions.

after event An asynchronous event whose handler runs only after the action that raised the event is complete.

alert subscription A request to receive an Internet message automatically when user-defined criteria are met. Such
messages are generated automatically when items such as documents, webpages, list items, sites, or
other resources on a server are changed.

alternate account An additional user account that is in a different domain, but within the same forest as the primary
account.

app catalog A SharePoint document library that administrators can use to distribute apps for Office and SharePoint
to their end users.

app custom action A type of custom action that is added to a host site by a SharePoint Add-in (formerly an app for
SharePoint) and that links to more functionality that is contained by the add-in.

app for SharePoint A cloud-enabled app that integrates rich, scenario-focused content and services into a SharePoint
environment. Now known as "SharePoint Add-in."

app part A component of a SharePoint Add-in (formerly an app for SharePoint) that can be embedded on a site
page to expose the functionality of the add-in.

app web A sub website to which the SharePoint components of an add-in are deployed when the add-in is
installed on a host web.

application directory The directory on an index server or a query server where all files are stored for the purpose of creating a
full-text index catalog or performing queries on a full-text index catalog.

application session The period of time when an application is running. When an application starts, the session starts. When
an application quits, the session ends.

AppSource Formerly known as Office Store. An Internet site that provides a collection of products and services
developed by Microsoft partners for Microsoft Office users.

audience identifier A GUID or string that is used to uniquely identify an audience.

audience rule A set of logical conditions that determine whether a user profile can be a member of an audience.

authoritative page A webpage that a site collection administrator has designated as more relevant than other webpages.
This is typically the URL of the home page for the intranet of an organization. The higher the authority
level assigned to a page, the higher the page appears in search results. Also referred to as authoritative
page.

authority level A floating-point number that designates that a specific webpage is more relevant than other webpages.
Allowed values are 0, 1, or 2. Zero (0) signifies the most valuable authoritative page level.
TER M D EFINITIO N

authority page A webpage that a site collection administrator has designated as more relevant than other webpages.
This is typically the URL of the home page for the intranet of an organization. The higher the authority
level assigned to a page, the higher the page appears in search results. Also referred to as authoritative
page.

autohost To deploy the components of an add-in on appropriate hosts and establish add-in isolation
automatically.

available site template An XML-based collection of predefined or user-defined settings that are stored as a site definition
configuration or a site template, and can be used when creating a site.

backward signing A condition of a handwritten signature, in an image or .ink file, that specifies the direction of the
characters in the signature, right-to-left or left-to-right.

base view identifier An integer that uniquely identifies a view definition for a list.

basic page A web parts page that contains only one web part zone and, by default, a Content Editor web part.

BCS A feature that enables users to interact with back-end (LOB) data from within the Office Suite and
SharePoint.

BCS solution deployment BCS server to client solution deployment that is based on ClickOnce technology.

before event A synchronous event whose handler runs completely before the action that raised the event starts.

blank site A site that was created by using the "Blank" site template.

Business Connectivity A feature that enables users to interact with back-end (LOB) data from within the Office Suite and
SharePoint.

Business Connectivity Services A feature that enables users to interact with back-end (LOB) data from within the Office Suite and
SharePoint.

CAML An XML-based language that is used to describe various elements, such as queries and views, in sites
that are based on SharePoint products and technologies.

Central Administration site A special SharePoint site where an administrator can manage all sites and servers in a farm that is
running SharePoint products and technologies.

chrome control An HTML and JavaScript based control that renders the top chrome, which is available to use in apps for
SharePoint.

Collaborative Application Markup Language An XML-based language that is used to describe various elements, such as queries and views, in sites
that are based on SharePoint products and technologies.

content migration package A package of XML-formatted files that is used to migrate content between site collections, sites, and
lists.

content placeholder A region within a page layout that is populated dynamically with the value of the publishing page field to
which it is bound.

content type group A named category of content types that is used to organize content types of a similar purpose.

content type identifier A unique identifier that is assigned to a content type.

content type order The sequence in which content types are displayed.

content type resource folder A folder that stores the resource files that are associated with a content type.

content type schema An XML definition that describes the contents of a content type.

content type specific view A view that is associated with a particular content type that is associated with a folder.

context site A site that corresponds to the context of the current request.

context type A GUID that is used as a classification for an event receiver.

contextual search scope A system-defined restriction that can optionally be added to a query to restrict the query results to
items that are from a specific site or list.

crawl log A set of properties that provides information about the results of crawling a display URL. The
information includes whether the crawl was successful, the content source to which the display URL
belongs, and the level, message, time, and identifier for any errors that occur.

crawl queue A data structure that stores the list of items to crawl next.

crawled property A type of metadata that can be discovered during a crawl and applied to one or more items. It can be
mapped to a managed property.

cross-domain library A JavaScript library available in apps for SharePoint to allow cross-domain client-level communication.

custom action A dropdown menu item or ribbon component that is added to a site page.
TER M D EFINITIO N

Data View web part A web part that is used to display items in a list.

declarative workflow association A code-free binding of a declarative workflow to a specific list or content type using XAML (Extensible
Application Markup Language).

default list view The view of a list that is defined by the owner of the list to appear when users browse to the list without
specifying a view.

default mobile list view The view of a list that is defined by the owner of the list to appear when users browse to the list from a
mobile device without specifying a view.

default search scope The search scope that is assigned automatically to a search scope display group.

default user store A user store supplied as a starting point for expanding group membership when a user store is not
already specified in FAST Search Authorization.

deployment system object An object that is created as part of a site or site collection. Examples of deployment system objects are
root folders, catalogs, default pages, and galleries that are created during site or site collection creation.
A deployment system object is not part of a template.

descendant content type Any content type that inherits from another content type.

dynamic rank A component of the rank that depends on how well query text matches an indexed item.

excluded item An item that is excluded from a crawl by the administrator of the host site or the search administrator of
the crawler.

extracted definition The definition that is obtained by an index server during a crawl, to identify if any sentences in the item
match the pattern for defining a term.

extracted term A term that an extracted definition applies to.

Farm Administrators group A group of users that has permission to manage all the servers in a server farm. Members of the Farm
Administrators group can perform command-line operations and all the administrative tasks in Central
Administration for the server or server farm.

farm solution A custom solution that can be deployed to a farm by a farm administrator. A farm solution has full access
to system resources and other sites in the farm.

feature definition An XML fragment that defines a feature and its attributes.

feature identifier A GUID that identifies a feature.

feature property A property that is associated with an active feature at a particular scope.

feature scope The scope at which a feature can be activated.

federated location A source that returns a set of search results for a given search query. The source can be a search service
in the local server farm or another server farm, or another search engine that is compliant with the
OpenSearch protocol.

federated location definition The configuration settings that describe how to issue a query for a given federated location and display
the search results.

field internal name A string that uniquely identifies a field in a content type or a SharePoint list.

first-stage Recycle Bin A container for items that are deleted. Items in this container are visible to users with the appropriate
permissions and to site collection administrators.

FSA Manager The Windows service that provides administration functionality for FAST Search Authorization.

FSA worker The Windows service that generates user search security filters in FAST Search Authorization.

full-text index component A set of files that contain all index keys that are extracted from a set of items.

generic list A list whose base type is Generic List.

Group Approval document identifier A string that uniquely identifies a document that is subject to the policies defined for a Group Approval
workflow. The string is generated and assigned automatically to a document by a protocol server.

high confidence property A managed property from the metadata index that the administrator identifies as a good indicator of a
highly relevant item. It is used to produce a high confidence result.

high confidence result A search result that is considered to be highly relevant because of a precise match between a high
confidence property value and the tokens in the query text.

high-trust app An app that uses the server-to-server (S2S) protocol, where the app is responsible for creating the user
portion of the access token, and therefore is trusted to assert any user identity.

host web A SharePoint site to which an add-in is installed.

item identifier An integer that uniquely identifies an item in a SharePoint list.


TER M D EFINITIO N

keyword consumer A site collection that uses a particular set of keywords, synonyms, and Best Bets.

keyword synonym An alternate phrasing of a particular keyword. When a user types a keyword synonym, search returns
the same Best Bet result as the keyword.

language auto-detection A process that automatically determines the language code identifier (LCID) for text in a document.

list folder A folder that is contained within a SharePoint list. A list folder can contain documents or list items, and it
retains the characteristics of other items in the list, such as a customizable schema.

list form A page that allows users to create, view, or edit an item in a list.

List Form web part A web part that is used to display, edit, or view an item in a list.

list identifier A GUID that is used to identify a list in a site collection.

list item attachment A file contained within a list item that is stored in a folder in the list with the segment "Attachments."

list item identifier An integer that uniquely identifies an item in a SharePoint list.

list server template A value that identifies the template that is used for a list.

list template An XML-based definition of list settings, including fields and views, and optionally list items. List
templates are stored in .stp files in the content database.

list template identifier A GUID that is used to identify a list template.

list view page A web part page that displays a view of a list.

List View web part A reusable component that generates HTML-based views of items in a SharePoint list.

log level The amount of information that is stored in a log file for a transaction. Log levels can be represented by
numbers or by words from the most to the least verbose.

managed keyword A word or phrase that is added to a SharePoint item, either as a value in the Managed Keyword column
or as a social tag.

member group A group of users that is specific to the User Profile service.

member group source A qualified domain name, such as domain.corp.microsoft.com, that identifies the source of a member
group.

Members group A default group of users on a SharePoint site. By default, the Members group is assigned the Contribute
permission level.

membership group record identifier A unique identifier for a member group record.

metadata index A data structure on a back-end database server that stores properties that are associated with each
item, and attributes of those properties.

metadata schema A schema that is used to manage information about an item.

Microsoft Business Connectivity Services A feature that enables users to interact with back-end (LOB) data from within the Office Suite and
SharePoint.

moderated object An object for which a moderator reviews and either approves or rejects additions or changes to that
object. New objects and changes to existing objects can be seen by other users only after they have
been approved by the moderator.

moderation status A content approval status of an item in a list.

multivalue property A property that can contain multiple values of the same variant type.

navigation structure A hierarchical organization of links between related content, such as lists within a site.

new form A form that allows for the creation of a list item.

Office SharePoint Server Search service The farm-wide service that either responds to query requests from front-end web servers or crawls
items.

Office Store Now known as AppSource. An Internet site that provides a collection of products and services developed
by Microsoft partners for Microsoft Office users.

Open Item permission An authorization that allows a user to retrieve an entire file.

Open web permission A requisite permission during the import or export of a SharePoint site.

operator account The account of the user who is managing the import process for a deployment package.

organization identifier An integer that uniquely identifies an organization.


TER M D EFINITIO N

orphaned object A content database object that lacks a requisite relationship to a corresponding object.

paged view A view that supports one or more visual pages. A paged view is used to break up large sets of data into
smaller sets for increased performance and manageability.

parent farm A farm that crawls content from another farm and also responds to query requests from that farm.

parent list A list that contains a list item or list folder.

PerformancePoint Data Connections Library A SharePoint document library that contains PerformancePoint data sources.

personal site A type of SharePoint site that is used by an individual user for personal productivity. The site appears to
the user as My Site.

portal content The main search catalog, which contains content sources and settings that are related to a crawl.

principal aliasing The process of mapping a user or a group in one user store to a user or a group in another user store
for the purpose of returning all documents that the user or group has rights to view, regardless of which
user store the user or group is authenticated to.

privacy level A setting that specifies the category of users who are allowed to view the personal information of other
users, such as user profile properties, colleagues, or memberships.

provisioned A condition of an object that was created and deployed successfully.

public filter The search security filter in FSA that finds documents that all users have access to.

publish to server A process that facilitates saving a document or portions of a document to a web server.

published version The version of a list item that is approved and can be seen by all users. The user interface (UI) version
number for a published version is incremented to the next positive major version number and the minor
version is zero.

publishing level An integer that is assigned to a document to indicate the publishing status of that version of the
document.

publishing page A document that binds to a page layout to generate an HTML page for display to a reader. Publishing
pages have specific fields that contain the content that is displayed in an HTML page.

query independent rank A system to rank items that uses features that do not vary with different queries.

query table A two-dimensional table that presents data from an external data source.

ranking parameter A value that is used to influence the algorithm that determines the rank of an item.

role identifier An integer that uniquely identifies a role definition within a site.

role type A predefined role definition.

root document A document in the root folder of a site.

scheduled A status that is applied to a list item or document that specifies a time when the item or document will
be published or unpublished.

schema version An integer value that represents the version number of the schema for a deployment package.

search application A unique group of search settings that is associated, one-to-one, with a shared service provider.

search catalog All the crawl data that is associated with a given search application. A search catalog provides
information that is used to generate query results.

search database A database that stores search-related information, including stored procedures and tables that are used
for crawler data, document metadata, and administration information.

search query log A record of information about user searches, such as search terms and time of access.

search scope consumer A site collection that uses a particular search scope display group.

search scope display group An ordered set of search scopes, defined by an administrator or programmatically, and used for
returning groups of search scopes. Search scope display groups are saved for each search scope
consumer and search scopes can be in multiple search scope display groups.

search scope index A specialized component of a full-text index catalog that is built on the values of scoped properties for
optimized queries.

search scope rule An attribute that specifies which items are included in a given search scope.

search service account A user account under which the search service runs.

search shared application object An instance of a shared application for search that holds search-specific settings.
TER M D EFINITIO N

second-stage Recycle Bin A container for items that have been deleted from a first-stage Recycle Bin. Items in a second-stage
Recycle Bin are visible only to site collection administrators.

server-to-server protocol An authentication protocol between two servers or services.

Shared Documents library A document library that is included by default in the Team Site site template.

shared view A view of a list or web part page that every user who has the appropriate permissions can see.

SharePoint Add-in Formerly "app for SharePoint." A cloud-enabled add-in that integrates rich, scenario-focused content and
services into a SharePoint environment.

SharePoint Search SQL syntax The rules that govern the construction of an enterprise search SQL query.

single sign-on ticket A token that contains the encrypted identity of a single sign-on (SSO) user in the form of a security
identifier string and a nonce.

site collection administrator A user who has administrative permissions for a site collection.

site collection flag A 4-byte unsigned integer bit mask that specifies the properties that are global to a site collection. One
or more values can be set for this bit mask.

site collection identifier A GUID that identifies a site collection. In stored procedures, the identifier is typically @SiteId or
@webSiteId. In databases, the identifier is typically SiteId/tp_SiteId.

site collection quota An option for a site collection that allows administrators to set levels for maximum storage allowed,
maximum number of users allowed, and warnings that are associated with the maximum levels.

site column A field that can be associated with a content type or list within a site or site collection.

site content type A named and uniquely identifiable collection of settings and fields that store metadata for lists within
individual sites.

site definition A family of site definition configurations. Each site definition specifies a name and contains a list of the
site definition configurations.

site definition configuration An XML-based definition of lists, features, modules, and other data, that collectively define a type of
SharePoint site. Site definition configurations are stored in the ONET.xml file.

site definition version A zero-based integer that indicates the version number of the site definition. Every time a site definition
is updated, it is suggested that the version number be increased.

site flag A 4-byte unsigned integer bit mask that specifies properties that are unique to a site.

site identifier A GUID that is used to identify a site in a SharePoint site collection.

site membership The status of being a member of a site and having a defined set of user rights for accessing or managing
content on that site.

site property A name/value pair of strings that serves as metadata for a site, such as the title or default language.

site solution A deployable, reusable package that contains a set of features, site definitions, and assemblies that apply
to sites, and that can be enabled or disabled individually.

site template An XML-based definition of site settings, including formatting, lists, views, and elements such as text,
graphics, page layout, and styles. Site templates are stored in .stp files in the content database.

start address A URL that identifies a point at which to start a crawl. Administrators specify start addresses when they
create or edit a content source.

static rank The component of a rank that does not depend on the search query. It represents the perceived
importance of an item and may be related to the origin of the item and relationships between the item
and other items or business rules that are defined in the search application.

trusted authentication A mechanism whereby a user account or a process account can be used to perform operations on behalf
of the current user.

trusted subsystem A method of communication in which two-way trust is established between two server components.
Each server component communicates with the other component by using an account that is authorized
to perform privileged actions such as retrieving files and settings.

UI culture The language that is used to display strings and other graphical elements in a user interface.

user display name A user profile property that can contain the preferred name of a user.

user profile change entry log A repository that logs all the changes that take place in a user profile.

user profile change event An event that occurs when a property of any user profile is changed.

user profile import The process of importing records from a directory service to the user profile store.

user profile record identifier An integer that uniquely identifies a user profile record.
TER M D EFINITIO N

user profile store A database that stores information about each user profile.

user search security filter The user search security filter that specifies group and user permissions for a specific FAST Search user.
FAST Search Authorization (FSA) filters out inappropriate search results by intersecting the user's query
with the user's search security filter, and checking each document's access control list to determine if the
user has permission to view that document. The user search security filter is FSA's primary means of
enforcing document-level security ("security trimming"), which helps to ensure that search results display
only documents that the user has permissions to read.

user store A logical grouping of users, groups, and content permissions for a third-party security or content system
that is accessed by FAST Search Authorization.

visible scope A search scope that is displayed to site collection administrators and users.

Visitors group A default group of users on a SharePoint site. By default, the Visitors group is assigned the Read
permission level.

web application identifier A GUID that identifies a web application.

web control A server-side component that encapsulates user interface and related functionality.

web discussion comment An individual comment that is added within a web discussion.

web identifier A GUID that is used to identify a site in a SharePoint site collection.

web part cache A hash table of key/value pairs that is used to cache and locate internal information for web parts.

web part chrome state The condition of a web part and the web part chrome surrounding it. Possible values are zero (0) for
normal state or one (1) for minimized state.

web part connection An element in a web parts page that defines a provider-consumer data relationship between two web
parts. When a web parts page is rendered, data provided by one web part can affect how and what is
rendered by the other web part.

web part identifier A GUID that identifies a web part.

web part property A configurable characteristic of a web part that determines the behavior of the web part.

web part type identifier A unique 16-byte value that is assigned to each web part type.

web part zone identifier A string that identifies a web part zone on a web parts page.

web part zone index An integer that specifies the relative position of a web part in a web part zone. web parts are positioned
from the smallest to the largest zone index. If two or more web parts have the same zone index, they are
positioned adjacent to each other in an undefined order.

web proxy A method exposed in a client object model to issue requests from SharePoint to a remote service that
developers can use in apps for SharePoint.

web service method A procedure that is exposed to web service clients as an operation that can be called on the web service.

work item process A process that runs a work item.

work item type identifier A GUID that is used to identify a work item type.

workflow association An association of a workflow template to a specific list or content type.

workflow configuration file An implementation-specific file that is a part of a workflow. The workflow configuration file contains
information that is necessary to create a workflow template from the specified workflow markup and
rules files, and to associate it to a specific list.

workflow history item A list item that stores information about the current status of, and past actions for, a document or item
that is associated with a workflow.

workflow history list A list that stores the history of actions or tasks for a business process.

workflow identifier A GUID that is used to identify a workflow.

workflow markup file A file that contains markup to specify the functional behavior of a workflow.

workflow task An action or task in a sequence that is related to a built-in or user-defined business process.

workflow task list A list that stores the sequence of actions or tasks for a business process.

zero-based index An index in which the first item has an index of zero.
Protocol handler error due to deprecated interface in SharePoint 2016
3/26/2018 • 2 minutes to read Edit Online

Protocol handler implementations using the interfaces listed in this article in the srchprth.h header file are now deprecated in SharePoint 2016. Specifically, the protocol handler for
deprecated interfaces generates the error "The protocol handler cannot be loaded".

Symptom
You see the following error message when you load the protocol handler:

The protocol handler <name of custom protocol handler> cannot be loaded. Error description: No such interface supported.

Cause
You are using the srchprth.h header file in your protocol handler implementation. This file contains interfaces deprecated in SharePoint 2016.

Resolution
Replace the deprecated interfaces in your protocol handler implementation with those that are currently supported:
srchprth.h (updated)
urlaccsdk.h (new)

Deprecated Interfaces
The deprecated interfaces include the following:
interface ISearchProtocol : IUnknown

HRESULT Init([in] TIMEOUT_INFO *pTimeoutInfo,


[in] IProtocolHandlerSite *pProtocolHandlerSite,
[in] PROXY_INFO *pProxyInfo);

HRESULT CreateAccessor([in] LPCWSTR pcwszURL,


[in] AUTHENTICATION_INFO *pAuthenticationInfo,
[in] INCREMENTAL_ACCESS_INFO *pIncrementalAccessInfo,
[in] ITEM_INFO *pItemInfo,
[out] IUrlAccessor **ppAccessor);

HRESULT CloseAccessor([in] IUrlAccessor *pAccessor);


HRESULT ShutDown();
}

TIMEOUT_INFO
{
DWORD dwSize;
DWORD dwConnectTimeout;
DWORD dwDataTimeout;
}

PROXY_INFO
{
DWORD dwSize;
LPCWSTR pcwszUserAgent;
PROXY_ACCESS paUseProxy;
BOOL fLocalBypass;
DWORD dwPortNumber;
LPCWSTR pcwszProxyName;
LPCWSTR pcwszBypassList;
}

AUTHENTICATION_INFO
{
DWORD dwSize;
AUTH_TYPE atAuthenticationType;
LPCWSTR pcwszUser;
LPCWSTR pcwszPassword;
}

INCREMENTAL_ACCESS_INFO
{
DWORD dwSize;
FILETIME ftLastModifiedTime;
}

IProtocolHandler: public IUnknown


{
public:
HRESULT Init(
/* [in] */ LPCWSTR pwszUserAgent,
/* [in] */ DWORD dwUseProxy,
/* [in] */ DWORD dwConnectTimeout,
/* [in] */ DWORD dwDataTimeout,
/* [in] */ DWORD dwLocalByPassProxy,
/* [in] */ DWORD dwPortNumber,
/* [in] */ LPCWSTR pcwszProxyName,
/* [in] */ LPCWSTR pcwszByPassList,
/* [in] */ LPCWSTR pcwszProxyUserName,
/* [in] */ LPCWSTR pcwszProxyPassword,
/* [in] */ IProtocolHandlerSite *pProtocolHandlerSite) = 0;

HRESULT CreateAccessor(
/* [in] */ AccessorInitParams *pParams,
/* [out] */ IUrlAccessor **ppAccessor) = 0;

HRESULT CloseAccessor(
/* [in] */ IUrlAccessor *pAccessor) = 0;

HRESULT SetProcessMemorySize(
/* [in] */ DWORD dwFltrDmnMemoryQuota) = 0;
};

struct AccessorInitParameters
{
LPCWSTR pwszUrl;
LPCWSTR pwszCrawlTarget;
BOOL fUseSSLWithCT;
BOOL fUseCTForIntranet;
DWORD eAuthenticationType;
LPCWSTR pwszUser;
LPCWSTR pwszPassword;
LPCWSTR pwszHttpFrom;
FILETIME ftIfModifiedSince;
DWORD dwCrawlId;
DWORD dwMiniCrawlID;
DWORD dwDeletedCount;
DWORD dwDeletedCountSync;
BOOL fDeletedCountValid;
LPCWSTR pwszAppName;
LPCWSTR pwszCatName;
DWORD dwFilterPipeFlags;
LPCWSTR pwszContentClass;
LPCWSTR pwszSearchPropertyMappingUrl;
BYTE *pbChangeLogCookie;
DWORD cbChangeLogCookieLength;
BYTE *pbChangeLogCookieEnd;
DWORD cbChangeLogCookieEndLength;
LPCWSTR pwszFormsAuthURL;
LPCWSTR pwszFormsAuthPost;
BYTE *pbCachedBlob;
DWORD cbCachedBlobLength;
DWORD dwPHFlags;
LPCWSTR pwszSecurityId;
LPCWSTR pwszCorrelationId;
CLSID *pTenantID;
HANDLE hImpersonationToken;

} AccessorInitParams;

AccessorInitParams contains many parameters, some of which may be optional. These parameters are mostly an expansion of previous deprecated structs.

See also
For more information, see Enterprise Search Protocol Handlers.
Programming models in SharePoint
5/3/2018 • 3 minutes to read Edit Online

You can develop applications for the SharePoint platform in many ways. These applications can be usefully categorized into the following groups based on the tools used to create them, the
programming models used to develop them, the methods by which they are packaged and deployed, the methods by which they are marketed, and the devices on which they run.
SharePoint Framework
SharePoint Add-ins
SharePoint publishing sites
SharePoint farm solutions
Mobile add-ins for SharePoint
Reusable components for SharePoint
These categories are not mutually exclusive. For example, you can develop a publishing site as an SharePoint Add-in. The following sections define these categories and guide you to the
documentation for each.

SharePoint Framework
The SharePoint Framework (SPFx) is a page and web part model that provides full support for client-side SharePoint development, easy integration with SharePoint data, and support for
open source tooling. With the SharePoint Framework, you can use modern web technologies and tools in your preferred development environment to build productive experiences and apps
that are responsive and mobile-ready from day one. The SharePoint Framework works for SharePoint Online and soon also for on-premises (SharePoint 2016 Feature Pack 2). For more
information, see Overview of the SharePoint Framework.

Add-ins for SharePoint


A SharePoint Add-in is similar to an add-in on a mobile device. It is a stand-alone productivity solution that does a small number of related tasks, installs easily, and uninstalls cleanly. Users
can discover and download SharePoint Add-ins from a public SharePoint add-in store or from their organization's corporate add-in catalog. A SharePoint Add-in can include classic
SharePoint components such as lists, custom website pages, web parts, workflows, and content types. But an SharePoint Add-in can also surface a remote web application and remote data in
SharePoint. A SharePoint Add-in can also include both SharePoint and remote components. SharePoint Add-ins are very safe applications whose custom logic is always shifted "up" to the
cloud or "down" to the client computers. It never runs on the SharePoint servers.
For an introduction to the model for SharePoint Add-ins, see SharePoint Add-ins. For more information, see SharePoint Add-ins compared with SharePoint solutions, and Choose the right
API set in SharePoint.

SharePoint publishing sites


SharePoint publishing sites provide large-scale content publishing with a high degree of maintainability and regulation compliance. They also provide management of documents, records,
taxonomy, and content types. For more information, see Build sites for SharePoint.

SharePoint farm solutions


SharePoint farm solutions are trusted SharePoint extensions whose custom logic calls the SharePoint server object model and runs with full trust on the SharePoint servers. These solutions
are primarily for custom administrative extensions of SharePoint, such as timer jobs, custom Windows PowerShell commands, and extensions of Central Administration. Farm solutions are
distributed as SharePoint solution packages that farm administrators upload to a farm-wide storage location from which they can be deployed. Components in farm solutions can have farm,
web application, site collection, or website scope. For more information, see Build farm solutions in SharePoint.

Mobile add-ins for SharePoint


Windows Phone apps, and apps built on non-Microsoft mobile platforms, can access SharePoint websites and data. Tools for building Windows Phone apps that interact with SharePoint are
available for installation on Visual Studio 2010 and Visual Studio 2012. A SharePoint client managed API just for use on Windows Phone devices is available. Mobile devices, including non-
Microsoft devices, can also access SharePoint data through SharePoint REST/OData endpoints. For more information, see Build Windows Phone apps that access SharePoint.

Reusable components for SharePoint


The SharePoint platform and Visual Studio 2012 enable encapsulation and reuse of application elements, including elements created with code, script, and XML markup. For more
information, see Build reusable components for SharePoint.

In this section
Build sites for SharePoint
Build farm solutions in SharePoint
Build Windows Phone apps that access SharePoint
Build reusable components for SharePoint

See also
Set up your SharePoint Framework development environment
Set up a general development environment for SharePoint
Add SharePoint capabilities
Accessibility in SharePoint
SharePoint Add-ins compared with SharePoint solutions
5/3/2018 • 13 minutes to read Edit Online

Learn about when to develop your SharePoint extension as a SharePoint Add-in and when to develop it as a SharePoint farm solution or a no-code sandboxed solution.
This article compares the use cases of SharePoint Add-ins, farm solutions, and no-code sandboxed solutions (NCSSs).
New SharePoint Add-ins are self-contained extensions that may include cloud-based logic and data, SharePoint components, and client-side scripts, but not custom managed code
that runs on SharePoint servers. They are installed from either the Office Store or an organization add-in catalog, and can be installed on either on-premises farms or Microsoft
SharePoint Online. For an overview of SharePoint Add-ins, see SharePoint Add-ins.
SharePoint farm solutions are packages of SharePoint components that are uploaded to a farm-wide gallery from where they can be installed. They cannot be distributed through the
Office Store, and they cannot be installed on SharePoint Online. They can include custom managed code that runs on the SharePoint farm servers. For more information about the
basics of farm solutions, see Solutions Overview and Farm Solutions in SharePoint 2010.
NCSSs are also packages of SharePoint components; but they are uploaded to a site collection gallery from where they can be installed. They can be installed to either on-premise
farms or to SharePoint Online, but they cannot be distributed through the Office Store. They can include the almost the same kinds of descriptive components as SharePoint Add-ins
and, like add-ins, they can have JavaScript, but they do not contain custom managed code that runs on the SharePoint servers. Differences in the deployment systems of add-ins and
NCSSs make NCSSs a better development option for a short list of scenarios. For information about sandboxed solutions, see Sandboxed Solutions in SharePoint 2010.

Important: While developing sandboxed solutions that contain only declarative markup and JavaScript -- which we call no-code sandboxed solutions (NCSS)-- is still viable, we have
deprecated the use of custom managed code within the sandboxed solution. We have introduced the new SharePoint Add-in model as a replacement to those scenarios that required the
use of managed code. The add-in model decouples the SharePoint core product from the add-in runtime, and this enables much more flexibility and gives you the ability to run the code
in the environment of your choice. We realize that our customers have made investments in coded sandboxed solutions and we will phase them out responsibly. Existing coded
sandboxed solutions will continue to work in on-premise SharePoint farms for the foreseeable future. Given the dynamic nature of online services, we will determine support needs for
coded sandboxed solutions in SharePoint Online based on customer demand. NCSSs continue to be supported. All future investments will go to making the new SharePoint Add-in
model richer and more powerful. Accordingly, we recommend that all new development should use the new add-in model whenever possible. In scenarios where you have to develop a
farm solution or coded sandboxed solution, we recommend that you design it so that it can easily evolve toward a more loosely coupled development model.

Develop an add-in whenever you can


The most important guidance we can give you is to develop a SharePoint Add-in instead of a farm solution or NCSS whenever you can. SharePoint Add-ins have the following advantages
over classic solutions:
Provide users with the easiest discovery, purchase, and installation process.
Give administrators the safest SharePoint extensions.
Provide you with the simplest marketing and sales system based on a Microsoft online add-in store.
Maximize your flexibility in developing future upgrades.
Maximize your ability to take advantage of your existing non-SharePoint programming skills.
Integrate cloud-based resources in smoother and more flexible ways.
Enable your extension to have permissions that are distinct from the permissions of the user who is running the add-in.
Enable you to use cross-platform standards, including HTML, REST, OData, JavaScript, and OAuth.
Enable you to take advantage of the SharePoint cross-domain JavaScript library to access SharePoint data. Alternatively, you can use a Microsoft-provided secure token service that is
OAuth-compatible or use digital certificates to get authorization to SharePoint data.

Design add-ins or NCSSs for end users and design farm solutions for administrators
SharePoint Add-ins and NCSSs use one of the SharePoint client object models or REST endpoints to access SharePoint content and components. These client APIs enable SharePoint
extensions that are designed for end users. ("End users" in this context are site-collection administrators, website owners, and website members.) The server object model has additional APIs
that enable programmatic extensions of SharePoint management, configuration, and security. These include extensions of Central Administration, custom Windows PowerShell commands,
timer jobs, and custom backups. For more information about the kinds of administrative extensions that you can develop, see Windows SharePoint Services Administration. These
administrative extensions are deployed in SharePoint Features that have farm, web application, or site-collection scope. SharePointfarm solutions are also installed by farm administrators,
although add-ins and NCSSs can be installed by tenant and site collection administrators.
The server object model also has APIs for create, read, update, and delete (CRUD) operations on lists, libraries, and websites, and for operations on other SharePoint components. This
means that the server object model can be used for extensions that are intended for end users, but for reasons given in the previous section, farm solutions are not usually the best choice for
such extensions. Thus, it is no surprise that farm solutions cannot be installed on Microsoft SharePoint Online. Because Microsoft handles all the management of SharePoint Online, there is
no need for administrative extensions. For more information about the different sets of APIs in SharePoint and where they overlap, see Choose the right API set in SharePoint.
The client object models and REST endpoints do not duplicate the administrative-oriented APIs of the server object model. Moreover, because neither a SharePoint Add-in nor an NCSS can
contain custom code that runs on the SharePoint servers, they cannot call these administrative APIs. In addition, all Features in SharePoint Add-ins must have website scope; and Features in
NCSSs have either site collection or website scope. Thus, an administrative-oriented SharePoint extension is not really possible with a SharePoint Add-in or NCSS. So, the second principle,
but not an absolute rule, is that add-ins and NCSSs are for end users, and farm solutions are for administrators.

Design NCSSs for branding and template-like extensions


You may encounter one of the small number of SharePoint development scenarios for which the add-in model is not well-suited, but which you cannot implement with a farm solution either,
perhaps because the solution needs to be installable on SharePoint Online or needs to be installable by a site collection administrator. There are two broad, and overlapping, categories of
such scenarios.
Branding: SharePoint users often want to give their SharePoint sites, including their SharePoint Online sites, a custom appearance with their own colors, styles, layouts, and logos.
This is generally easier to do with NCSSs than with SharePoint Add-ins. A SharePoint Add-in has declarative control over the appearance of only its own add-in web. For the host
web, it can declaratively add only ribbon buttons and menu items (and add-in parts). Any other changes to a host web or its parent site collection, tenancy, or on-premisesSharePoint
web application has to be done with code or script that uses one of the SharePoint's client object models. For example, new icons or CSS files would have to be programmatically
deployed. This code could be run from the add-in itself after it is installed, or it could run in the add-in installation event handler. But it would take a considerable amount of work to
create this code. In addition, the add-in would need site collection-scoped permissions to change any websites outside its own add-in web and host web, and it would need tenant-
scoped permissions to change more than just its parent site collection. A branding NCSS, however, can be deployed and activated to any site collection; and it could consist of only a
few purely declarative components.
NOTE

Note that SharePointfarm solutions are potentially more powerful than either NCSSs or SharePoint Add-ins for branding, but they are not an option on SharePoint Online.
"Template-like" extensions: Suppose that you need to create a crisis management extension for SharePoint for the collaborative analysis and solution of business crises. Your
extension includes several custom list types, no-code workflows, and other SharePoint components, all combined into a custom WebTemplate. Suppose you package and deploy the
extension as an NCSS. After the Feature in the solution has been activated, users can create a crisis management subweb of their SharePoint website whenever a crisis occurs. They
can populate the website with data that is specific to the crisis. On the other hand, you could implement the same extension as a SharePoint Add-in using exactly the same set of
SharePoint components. When the add-in is installed on the team site, the subweb (known as the "add-in web") is immediately created. Again, users populate the website with relevant
data.
Now, what happens when a second crisis occurs? If you implemented the extension as an NCSS, your users can merely create another subweb from your custom WebTemplate.
However, if you implemented the extension as a SharePoint Add-in, your users have a problem. They cannot install a second instance of the same add-in on the parent website. Only
one instance of any add-in can be installed on a host web. The best that you can do is create a subsite of the parent website to serve as a location for another instance of the add-in to
be installed. When the add-in is installed, a new add-in web, which is a sub-subweb of the parent website, is created for the add-in components. This comparison shows a general, but
not absolute, principle: SharePoint extensions that have a "template-like" character - that is, a reusable collection of components that must be configured for each specific use case, but
which naturally have multiple instances associated with the same SharePoint website - fit better with the NCSS development model than with the add-in model. In this example, the
variable element is the crisis, but it is easy to imagine template-like SharePoint extensions in which the instances vary by region, date, or any number of other characteristics.
For information about how to expand the possibilities of SharePoint Add-ins, see Use add-in event handlers conservatively and Add-ins that create extensions.

Doing things the add-in way


As noted earlier, custom code that runs on the SharePoint servers is not allowed in SharePoint Add-ins. This is not a significant limitation. It simply means that your custom business logic
moves either "down" to the client device or "up" to the cloud. In either case, you can use the SharePoint REST/OData service to accessSharePoint sites, lists, and other data. You can also
remotely access SharePoint data through the SharePoint JavaScript, Silverlight, or .NET Framework client object models. Finally, on Windows Phones, you can access SharePoint through the
SharePointWindows Phone object model. For more information about the various sets of APIs in SharePoint, see Choose the right API set in SharePoint.
A similar point is that Features in SharePoint Add-ins cannot have site collection, web application, or farm scope. However, you don't have to give up any user interface (UI) elements or
functionality. It means that the implementation of the component moves out ofSharePoint and onto a client or remote web application or remote database.
The following table lists the SharePoint components that cannot be deployed in a SharePoint Add-in, and describes the "add-in way" of getting the same functionality.

IF YO U W ANT THE FU NCTIO NALIT Y O F ... ... TR Y THES E APPR O ACHES .

Custom web parts A SharePoint Add-in can have remote pages that contain custom web parts. Another option is to expose
a page from a remote web application in an add-in part on a SharePoint site page. The remote page can
have basically the same UI controls and functionality as a web part. For more information, see Create
add-in parts to install with your SharePoint Add-in.

Event receivers and Feature receivers A SharePoint Add-in can contain functionally equivalent remote event receivers. For more information,
see Handle events in SharePoint Add-ins.

Custom field (column) types An add-in can deploy a new field (column) that is based on one of the existing field types. The Calculated
and Computed field types are especially flexible. Another option is to present your data in a remote
webpage by using customized controls or grids.

Custom web services built on the SharePoint Service Application Framework You can develop your custom web services as remote services.

Application pages A SharePoint Add-in can include remote webpages that are available from every website on which the
add-in is installed. An add-in can also use any of the built-in SharePoint web parts on site pages.

Some SharePoint components, listed below, are used in end-user scenarios, but have no equivalents in the SharePoint Add-in model, and cannot be deployed in NCSSs. For these, you must
use farm solutions.
Custom site definitions But custom WebTemplates, which are functionally similar to site definitions, are available in both NCSSs and SharePoint Add-ins. For more information, see
Working with Site Templates and Definitions.
Delegate controls For more information, see Delegate Control (Control Templatization).
Custom themes
Custom action groups and custom action hiding
User controls (.ascx files) No scenario actually requires these.

Use add-in event handlers conservatively


You can overcome some of the limitations of SharePoint Add-ins by creating handlers for the add-in installed, add-in updated, and add-in uninstalling events. These handlers are web
services that are hosted on web servers outside the SharePoint farm, possibly in the cloud. They can use the SharePoint client object model, or the REST APIs, to perform CRUD operations
on SharePoint components, including components in the host web. In theory, you could use such handlers to overcome some deployment restrictions in the Branding and Template-like
extensions items, discussed earlier. However, we recommend that you use such handlers only as a last resort, when there is no other way to give customers the functionality your use case
requires. When deciding whether to create a handler, consider the following:
Programmatic deployment to the host web requires that the add-in request Full Control permission to the host web. Add-ins that require this level of permission cannot be sold
through the Office Store.
Deployment of components to the host web tends to undermine the security advantages of putting SharePoint components in an add-in web with its own domain.
Extensive deployment code is a lot of work to create and debug compared with the descriptive deployment markup that can be used for add-in web components and in NCSSs.
There are some critical best practices that must be followed in creating add-in event handlers. Your code must include rollback logic to undo everything it has done if it encounters an
error. It must also alert the SharePoint infrastructure of the error, so that the infrastructure can roll back everything that it has done.
Add-in event handlers are not possible with the type of SharePoint Add-in known as SharePoint-hosted.
For more information about add-in event handlers, see the SDK node Handle events in SharePoint Add-ins. For information about rollback logic, see the Add rollback logic to the handler
section of the topic Create a handler for the update event in SharePoint Add-ins The latter topic is written in the context of the add-in updated event, but the basic principles apply to all add-
in event handlers.
Add-ins that create extensions
Another way to use the SharePoint client object model -- or its REST APIs -- to resolve component deployment issues with SharePoint Add-ins, is to have CRUD code inside the add-in itself,
instead of in an add-in event handler. The add-in then becomes a kind of factory for a type of custom extension. For example, a SharePoint-hosted add-in could use the SharePointJavaScript
object model to perform deployment and other CRUD operations on the host web or elsewhere in the tenancy or web application. For another example, see the Quick introduction to
remote provisioning section of Site provisioning techniques and remote provisioning in SharePoint, which describes how a provider-hosted SharePoint Add-in is used to provide subweb
provisioning a lot like SharePoint's in-the-box subweb provisioning. There is, however, a lot of wheel-reinvention, and hence a lot of work in creating a factory SharePoint Add-in. In addition,
this kind of add-in cannot be sold through the Office Store because the add-in requires Full Control of the host web.

See also
Programming models in SharePoint
Using Solutions in SharePoint Foundation
Build farm solutions in SharePoint
3/26/2018 • 3 minutes to read Edit Online

Get an overview of our documentation about developing, packaging, and deploying administrative extensions to SharePoint using farm solutions.

What are farm solutions?


SharePoint has its own system for installing extensions to SharePoint administrative functions that is different from other Windows applications and platforms. No MSI file or ClickOnce
technology is involved. Instead, the assemblies, XML, and other files in the extension are bundled into a single file, which is called a solution package. A solution package has a .cab-based
format but a .wsp file extension. The package can contain SharePoint Features and all their child components in addition to certain kinds of components that are not deployed in Features.
Farm administrators upload the packages to a farm-wide storage location from where they can be deployed and their Features activated.
Unlike SharePoint Add-ins, farm solutions contain code that is deployed to the SharePoint servers and makes calls to the SharePoint server object model. These assemblies always run with
full trust. Moreover, the Features in farm solutions can have scope as wide as the site collection, web application, or whole farm, in addition to the website scope of Features in SharePoint
Add-ins. These aspects of farm solutions sometimes make farm administrators reluctant to install them, unless they come from a well-known and trusted source. For this reason, SharePoint
extensions that are primarily for use by end users should be developed as SharePoint Add-ins, not farm solutions. Farm solutions should be used for customizations of SharePoint
administrative functions, such as custom timer jobs, custom Windows PowerShell cmdlets, and extensions of Central Administration. For more on the advantages of SharePoint Add-ins and
the uses of farm solutions, see SharePoint Add-ins compared with SharePoint solutions.

Guide to the developer documentation for farm solutions


Development of farm solutions has changed very little since SharePoint 2010, so this section contains links to the SharePoint 2010 SDK. To avoid confusion, keep the following points in
mind at all times when using the SharePoint 2010 SDK to develop against SharePoint:
You will see many references to "sandboxed solutions" in the SharePoint 2010 SDK. Sandboxed solutions with custom code are deprecated in SharePoint. "no code" sandboxed
solutions are still viable.
Our recommendation that farm solutions be used primarily for administrative extensions did not apply in SharePoint 2010. Therefore, many of the samples and other documentation
in the SharePoint 2010 SDK may be about end-user extensions that are deployed as farm solutions.
The terms "server-side" or "server code" in the SharePoint 2010 SDK refer to code that calls the SharePoint server object model. These terms do not refer to code that runs on remote
web servers (that is, web servers external to the SharePoint farm). Code that calls SharePoint from remote web servers, in both SharePoint 2010 and SharePoint, always uses one of
the SharePoint client object models. In the SharePoint 2010 SDK, such code would be called "client-side" or "client code."
The assemblies in a farm solution in SharePoint 2010 could be deployed with Custom Access Security (CAS) policies. Such policies are ignored in SharePoint; all assemblies in farm
solutions in SharePoint run with full trust.

Packaging and deployment


The basics of packaging, installing, updating, and localizing farm solutions are explained in Solutions Overview and the node Farm Solutions in SharePoint 2010. Development of particular
SharePoint components for inclusion in a farm solution is explained in the relevant nodes of SharePoint 2010 SDK. Most of the components in a farm solution should be encapsulated in one
or more custom SharePoint Features. For information about designing and creating Features, see the Working with Features node of the SharePoint 2010 SDK.

Administrative extensions
Guidance about extending the administrative functions in a SharePoint farm is in the Windows SharePoint Services Administration node of the SharePoint 2010 SDK. There you can find
explanations about extending Central Administration, creating custom Windows PowerShell cmdlets, customizing upgrades and migration, customizing backups, and customizing SharePoint
event logging. One section explains how to customize the SharePoint farm health and performance measuring system. For instructions about creating a custom timer job, see How to: Run
Code on All Web Servers.

In this section
The topics in this section describe the ways in which development of SharePoint solutions has changed.
How to: Customize a field type using client-side rendering
URLs and tokens in SharePoint
Virtual directories in SharePoint solutions

See also
Programming models in SharePoint
Customize a field type using client-side rendering
7/12/2018 • 6 minutes to read Edit Online

Learn how to customize a field type by using the client-side rendering technology in SharePoint. Client-side rendering provides a mechanism that you can use to produce your own output
for a set of controls that are hosted in a SharePoint page. This mechanism enables you to use well-known technologies, such as HTML and JavaScript, to define the rendering logic of custom
field types. In client-side rendering you can specify your own JavaScript resources and host them in the data storage options available to your farm solution, such as the _layouts folder.

Prerequisites for using the examples in this article


To follow the steps in this example, you need the following:
Microsoft Visual Studio 2012
Office Developer Tools for Visual Studio 2012
A SharePoint development environment
For information about setting up your SharePoint development environment, see Set up a general development environment for SharePoint.

Core concepts to help you understand client-side rendering for field types
The following table lists useful articles that can help you understand the concepts and steps that are involved in a custom action scenario.
Table 1. Core concepts for client-side rendering for field types

AR TICLE TITLE D ES CR IPTIO N

Build farm solutions in SharePoint Learn about developing, packaging, and deploying administrative extensions to SharePoint using farm
solutions.

Custom Field Types Learn about creating custom field types. As you store your business information in SharePoint, there
may be times when your data does not conform to the field types that are available in SharePoint
FoundationOr, you might just want to customize those field types. Custom fields can include custom
data validation and custom field rendering.

Code example: Customize the rendering process for a custom field type in a view form
Follow these steps to customize the rendering process for a custom field type:
1. Create the farm solution project.
2. Add a class for the custom field type.
3. Add an XML definition for the custom field type.
4. Add a JavaScript file for the rendering logic of the custom field type.
Figure 1 shows a view form with a custom-rendered field type.
Figure 1. Custom client-side rendered field in a view form

To create the farm solution project


1. Open Visual Studio 2012 as administrator (right-click the Visual Studio 2012 icon in the Start menu, and then choose Run as administrator ).
2. Create a new project using the SharePoint Project template
Figure 2 shows the location of the SharePoint Project template in Visual Studio 2012, under Templates, Visual C#, Office SharePoint, SharePoint Solutions.
Figure 2. SharePoint project Visual Studio template
1. Provide the URL of the SharePoint website that you want to use for debugging.
2. Select the Deploy as a farm solution option.

To add a class for the custom field type


1. Right-click the farm solution project and add a new class. Name the class file FavoriteColorFieldType.cs.
2. Copy the following code and paste it in the FavoriteColorFieldType.cs file. The code performs the following tasks:
Declares a FavoriteColorField class that inherits from SPFieldText.
Provides two constructors for the FavoriteColorField class.
Overrides the JSLink property.
NOTE

The JSLink property is not supported on Survey or Events lists. A SharePoint calendar is an Events list.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

// Additional references for this sample.


using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;

namespace Microsoft.SDK.SharePoint.Samples.WebControls
{
/// <summary>
/// The FavoriteColorField custom field type
/// inherits from SPFieldText.
/// Users can input the color in the field
/// just like in any other text field.
/// But the field will provide additional
/// rendering logic when displaying
/// the field in a view form.
/// </summary>
public class FavoriteColorField : SPFieldText
{
// The solution deploys the JavaScript
// file to the CSRAssets folder
// in the WFE's layouts folder.
private const string JSLinkUrl =
"~site/_layouts/15/CSRAssets/CSRFieldType.js";

// You have to provide constructors for SPFieldText.


public FavoriteColorField(
SPFieldCollection fields,
string name) :
base(fields, name)
{

}
public FavoriteColorField(
SPFieldCollection fields,
string typename,
string name) :
base(fields, typename, name)
{

/// <summary>
/// Override the JSLink property to return the
/// value of our custom JavaScript file.
/// </summary>
public override string JSLink
{
get
{
return JSLinkUrl;
}
set
{
base.JSLink = value;
}
}
}
}

To add an XML definition for the custom field type


1. Right-click the farm solution project, and add a SharePoint mapped folder. In the dialog box, select the {SharePointRoot}\Template\XML folder.
2. Right-click the XML folder created in the last step, and add a new XML file. Name the XML file fldtypes_FavoriteColorFieldType.xml.
3. Copy the following markup, and paste it in the XML file. The markup performs the following tasks:
Provides type name for the field type.
Specifies the full class name for the field type. This is the class you created in the previous procedure.
Provides additional attributes for the field type.

<?xml version="1.0" encoding="utf-8" ?>


<FieldTypes>
<FieldType>
<Field Name="TypeName">FavoriteColorField</Field>
<Field Name="TypeDisplayName">Favorite color field</Field>
<Field Name="TypeShortDescription">Favorite color field</Field>
<Field Name="FieldTypeClass">Microsoft.SDK.SharePoint.Samples.WebControls.FavoriteColorField, $SharePoint.Project.AssemblyFullName$</Field>
<Field Name="ParentType">Text</Field>
<Field Name="Sortable">TRUE</Field>
<Field Name="Filterable">TRUE</Field>
<Field Name="UserCreatable">TRUE</Field>
<Field Name="ShowOnListCreate">TRUE</Field>
<Field Name="ShowOnSurveyCreate">TRUE</Field>
<Field Name="ShowOnDocumentLibrary">TRUE</Field>
<Field Name="ShowOnColumnTemplateCreate">TRUE</Field>
</FieldType>
</FieldTypes>

To add a JavaScript file for the rendering logic of the custom field type
1. Right-click the farm solution project, and add the SharePoint Layouts mapped folder. Add a new CSRAssets folder to the recently added Layouts folder.
2. Right-click the CSRAssets folder that you created in the last step, and add a new JavaScript file. Name the JavaScript file CSRFieldType.js.
3. Copy the following code and paste it in the JavaScript file. The code performs the following tasks:
Creates a template for the field when it is displayed in a view form.
Registers the template.
Provides the rendering logic for the field type when used displayed in a view form.

(function () {
var favoriteColorContext = {};

// You can provide templates for:


// View, DisplayForm, EditForm and NewForm
favoriteColorContext.Templates = {};
favoriteColorContext.Templates.Fields = {
"FavoriteColorField": {
"View": favoriteColorViewTemplate
}
};

SPClientTemplates.TemplateManager.RegisterTemplateOverrides(
favoriteColorContext
);
})();

// The favoriteColorViewTemplate provides the rendering logic


// the custom field type when it is displayed in the view form.
function favoriteColorViewTemplate(ctx) {
var color = ctx.CurrentItem[ctx.CurrentFieldSchema.Name];
return "<span style='background-color : " + color +
"' >&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;</span>&amp;nbsp;" + color;
}

To build and run the solution


1. Press the F5 key.
NOTE

When you press F5, Visual Studio builds the solution, deploys the solution, and opens the SharePoint website where the solution is deployed.
2. Create a custom list and add a new Favorite color field column.
3. Add one item to the list, and provide a value for the favorite color column.
4. Figure 3 shows the create column page with the new custom field type.
Figure 3. Creating a new custom field type column
PR O B LEM S O LU TIO N

Field type FavoriteColorField is not installed properly. Go to the list settings page to delete this field. Execute the following command from an elevated command prompt: iisreset /noforce.
Caution: If you are deploying the solution to a production environment, wait for an appropriate time to
reset the web server using iisreset /noforce.

Next steps
This article demonstrated how to customize the rendering process for a custom field type. As a next step, you can learn more details about custom field types. To learn more, see the
following:
How to: Create a Custom Field Type
Walkthrough: Creating a Custom Field Type
Customize a list view in SharePoint Add-ins using client-side rendering

See also
Set up a general development environment for SharePoint
Build sites for SharePoint
Add SharePoint capabilities
Build farm solutions in SharePoint
URLs and tokens in SharePoint
3/26/2018 • 4 minutes to read Edit Online

Learn how to formulate URLs and how to use URL tokens in SharePoint.

Types of URLs in SharePoint


SharePoint parses URL strings to determine the form of URL based on a specified protocol (for example, http:) or on the placement of a forward slash (/) within the string. Depending on the
particular member, you can use the following URL forms:
An absolute URL specifies a full path and begins with a protocol. For example, http:// domain_or_server/[ sites/ ] Web_Site/ Lists / List_Title/ AllItems.aspx .
A domain-relative URL is based on the domain (which might be the name of a server) address and always begins with a forward slash. It specifies a complete path from top-level
website to file name. For example, /[ sites/ ] Web_Site/ Lists / List_Title/ AllItems.aspx .
A website-relative URL is based on the address of a website object ( SPWeb ). It does not begin with a forward slash, and it specifies a complete path from the website address to
the file name. For example, Lists/ List_Title/ AllItems.aspx .
A URL relative to a file or folder is based on the folder containing the file. It does not contain any forward slashes. It simply specifies the name of the file. For example,
AllItems.aspx .

NOTE

There is no concept of a "site collection-relative URL"; passing such a URL may cause the code to fail.

Good practice for image URLs


When you create a URL to an image file that is located in the %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\TEMPL ATE\L AYOUTS\1033\IMAGES directory,
specify a path that uses the root website of the site collection, but that does not include a subsite within the path. For example, use /_layouts/images/MyImage.gif for an image file, not
/MySubsite/_layouts/images/MyImage.gif. This is because subsite URLs are resolved in different ways depending on where they are used. You can ignore these variations if you always use
the root website-relative URL.

URL tokens in SharePoint


SharePoint supports the tokens listed in the following tables for use in either SharePoint Add-ins or farm solutions. In addition, some tokens are usable only in apps. For more information
about them, see URL strings and tokens in SharePoint Add-ins.
The tokens in the tables of this section can be used in URLs in a wide variety of situations in SharePoint development, such as in custom actions and in links on custom pages. In some
contexts, some of these tokens cannot be used. Three of the most important places where only a restricted list of tokens can be used are the start page of an app, a custom action on the host
web, and the Src property of an app part. These are called out in separate columns, but these three are not an exhaustive list of places where tokens can be used.
The StartPage column specifies whether the token can be used in the StartPage element of an app manifest. The Custom Action column specifies whether the token can be used in the
URL of a custom action on a host web. The App Part column specifies whether the token can be used in the Src property of the app part.
Tokens that can be used at the beginning of a URL

TO K EN R ES O LV ES TO S TAR TPAG E CU S TO M ACTIO N APP PAR T R EMAR K S

~controlTemplates The URL of the No No No


ControlTemplates virtual folder
for the current website.

~layouts The URL of the Layouts virtual No No No


folder for the current website.

~site The URL of the current website. No No Yes

~sitecollection The URL of the parent site No No Yes


collection of the current
website.

Except where indicated otherwise, none of these tokens in the next table can be used in the path portion of the Src property value of the app part. The App Part column refers to their use in
the query string portion of the value.
Tokens that can be used inside a URL

TO K EN R ES O LV ES TO S TAR TPAG E CU S TO M ACTIO N APP PAR T R EMAR K S

{ControlTemplates} The URL of the No No No


ControlTemplates virtual folder
for the current website.

{ItemId} The ID of an item in a list or No Yes No


library (an integer).

{ItemUrl} The URL of the item being No Yes No


acted upon.

{Layouts} The URL of the Layouts virtual No No No


folder for the current website.

{ListId} The ID of the current list (a No Yes No


GUID).
TO K EN R ES O LV ES TO S TAR TPAG E CU S TO M ACTIO N APP PAR T R EMAR K S

{RecurrenceId} The recurrence index of a No Yes No This token is not supported for
recurring event. use in the context menus of list
items.

{Site} The URL of the current website. No Yes Yes

{SiteCollection} The URL of the parent site of No Yes Yes


the current website.

{SiteUrl} The URL of the current website. No Yes No

{Source} The HTTP Request URL. No Yes No

See also
Build farm solutions in SharePoint
Advanced Extranet Support
Getting References to Sites, Web Applications, and other Key Objects
Working with List Objects and Collections
Sample Object Model Tasks
Virtual directories in SharePoint solutions
3/26/2018 • 2 minutes to read Edit Online

Learn about how changes in the virtual directory system affect how you create farm solutions in SharePoint.

Make your solutions compatible with the new UI mode system


When you are using the Microsoft SharePoint 2010 Software Development Kit (SDK), but developing for SharePoint, there is a change in the virtual directory system that you need to
consider as you work. The change is a side effect of the new SharePoint feature that enables a site collection to run in either SharePoint 2010 mode or SharePoint mode. The modes are
sometimes called compatibility levels orUI versions. For files in the virtual folders _layouts or _controltemplates , SharePoint needs to use the version of the files in
%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\ (sometimes called the 15 hive) or in the corresponding 14 hive, depending on the mode of the site collection.
SharePoint adds "/15" into the virtual directory path just after the virtual directory name to signal that the SharePoint files should be used. The absence of that extra string indicates that
SharePoint 2010 files should be used.
This new system has implications for you as you develop SharePoint solutions and apps, particularly when you are using the SharePoint 2010 SDK. In any SharePoint Add-in (which only
run in SharePoint mode) and in any SharePoint solution that you know is only going to be used in site collections that run in SharePoint mode, you need to add the "/15" yourself to all the
_layouts and _controltemplates virtual paths you create in your solution/app. (unless the path is pointing to an *.aspx file), even though this string does not appear in any instructions you
read in the SharePoint 2010 SDK. For example, if the SharePoint 2010 SDK instructs you to use ~/_layouts/images/myimage.png , you should use ~/_layouts/15/images/myimage.png when you
are developing for SharePoint.
If you need to make your solution compatible with site collections of either mode, you need branching logic to determine the mode of the current site collection and construct the virtual path
accordingly. The CompatibilityLevel property, which is also available in all the SharePoint client object models and the REST interface, is one place where your code can check for the mode.
The SPUtility class also has several new properties to aid in managing compatibility level in your solutions. These are not available in the client object models. Finally, there are several
controls in SharePoint that expose a UIVersion property that your code can also use to find the current compatibility level.
NOTE

If the file in the virtual path is *.aspx, SharePoint will automatically detect the mode of the current site collection and return the file from the appropriate hive. So you do not have to insert the
"/15" into the virtual path.

See also
Build farm solutions in SharePoint
Planning Deployment of Farm Solutions for SharePoint
SPUtility properties
Access SharePoint from mobile and native device apps
5/3/2018 • 2 minutes to read Edit Online

Learn how to access SharePoint from mobile apps and other native device apps, and from external web applications. SharePoint Add-ins, farm solutions, and "no code" sandboxed solutions
are all run from within SharePoint, but apps on other platforms can also access SharePoint client APIs.
IM P O R T A N T

To test and debug on any platform, you need a developer account on Office 365. More info: Set up a development environment for SharePoint Add-ins on Office 365 or Create a
developer site on an existing Office 365 subscription.

Non-Microsoft mobile and native device apps


Non-Microsoft device apps, including mobile apps, use SharePoint REST/OData APIs for CRUD operations on SharePoint data.
See Get to know the SharePoint REST service for the basics.
See REST API reference for SharePoint for a complete reference.
For more information about how to create mobile apps for any platform, see Build mobile apps for other platforms using SharePoint.

Windows Phone apps that access SharePoint


Windows Phone apps can use one of the following:
The .NET SharePoint client-side object model (CSOM) version specifically for Windows Phone devices.
The SharePoint REST/OData APIs.
These mobile apps can take advantage of the support in SharePoint for the Microsoft Push Notification service and a new geolocation field type.
For more about creating Windows Phone apps that access SharePoint, see Build Windows Phone apps that access SharePoint.

Web applications that don't start from SharePoint


Web applications that don't start from SharePoint are not strictly "SharePoint Add-ins," although they're sometimes counted as SharePoint Add-ins in MSDN and other docs. These apps
include, among others, ones that run from the Office 365 app launcher and Office Add-ins, as well as any web applications that are run directly from a browser.
You can build these apps on the ASP.NET platform or a non-Microsoft stack. If you build your web application on a non-Microsoft stack, it does CRUD operations with the REST/OData
APIs, just as a non-Microsoft device app. If you build it on ASP.NET it can use the SharePoint CSOM or the REST/OData APIs.
These apps gain authorized access to SharePoint data by using access tokens that are issued by the Azure Control Service (ACS) in compliance with the OAuth Authentication Code
flow. For more, see Authorization Code OAuth flow for SharePoint Add-ins.
IM P O R T A N T

Azure Access Control (ACS), a service of Azure Active Directory (Azure AD), will be retired on November 7, 2018. This retirement does not impact the SharePoint Add-in model, which uses
the https://accounts.accesscontrol.windows.net hostname (which is not impacted by this retirement). For more information, see Impact of Azure Access Control retirement for SharePoint
Add-ins.
Build Windows Phone apps that access SharePoint
4/20/2018 • 7 minutes to read Edit Online

SharePoint provides an exciting opportunity for developers to build mobile apps that travel with users, are interactive and attractive, and are available whenever and wherever users want to
work with them. You can combine Windows Phone 8 and Windows Phone 7 applications with on-premises SharePoint services and applications, or with remote SharePoint services and
applications that run in the cloud (such as those that use SharePoint Online) to create powerful applications that extend the functionality beyond the traditional desktop or laptop and into a
truly portable and much more accessible environment.
The new mobility features offered by SharePoint are built on existing Microsoft tools and technologies, such as SharePoint, Windows Phone, Visual Studio, and Silverlight. Developers who
are already familiar with those technologies and their related tools will be able to create SharePoint-powered mobile apps for Windows Phone without a steep learning curve. In this section,
we explore some of the types of SharePoint-powered mobile apps you can build for Windows Phone 8 and Windows Phone 7 and the most common ways to customize those applications.
SharePoint provides a framework and tools for developers, including Visual Studio 2010 project templates, to create mobile solutions that interact with SharePoint data both in on-premises
SharePoint installations and in the cloud by using SharePoint Online. Figure 1 shows how a simple list application could look on Windows Phone.
Figure 1. SharePoint list items in a Windows Phone app

What skills do you need to create mobile apps?


In this section, we assume that you're familiar with SharePoint, the .NET Framework, the Visual Studio development system, and Visual C#. It's also good to have some experience with
Windows Phone 8 or Windows Phone 7 application development using Silverlight, and it helps to be familiar with XAML, the StackPanel and Pivot controls for Windows Phone, and
concepts such as tombstoning, Silverlight data binding, and so on. If you are new to Windows Phone application development using Silverlight, we recommend that you check out the
following resources.
Developing a Windows Phone Application from Start to Finish
User interface for Windows Phone
Quickstart: Creating a user interface with XAML for Windows Phone
Pivot control architecture for Windows Phone

Development overview for mobile apps using SharePoint


You can build a wide variety of mobile apps using SharePoint. This section describes what's new or changed in the SharePoint release that makes mobile app development simple for
developers.

Windows Phone SharePoint Application template


This is the simplest type of mobile app you can build to bring a regular list to the phone. SharePoint offers a Visual Studio template to enable you to quickly and easily create SharePoint list
applications for the Windows Phone. For example, you can build a "To Do List"-type Windows Phone application that brings your task list from SharePoint into the Windows Phone and
enables the you to use your phone to update the status of a task on the go. Another example is having the product catalog for an inventory list in SharePoint available on the phone for the
sales people.
Installing the Windows Phone SharePoint SDK makes two Windows Phone SharePoint Application templates available to you in Visual Studio 2010 or Visual Studio 2010 Express for
Windows Phone (see How to: Set up an environment for developing mobile apps for SharePoint).
Using the Windows Phone SharePoint List Application template, you can follow the steps of a wizard to create a functional Windows Phone app that can access and manipulate data in a
SharePoint list.

New and enhanced mobility object model in SharePoint


SharePoint adds several new classes to both the server and client object models to enable the SharePoint mobility scenarios that we described earlier in this article.
To enable location-aware apps, there is a new native field type class, SPFieldGeoLocation, along with several associated classes for structuring the value of location fields and rendering
them. These classes are also callable in the SharePoint client object model for Silverlight. The new field type also has a definition added to the standard SharePoint fldtypes.xml file and new
user controls for rendering the field on the Display, Edit, and New forms. For an overview, see Integrating location and map functionality in SharePoint.
To enable SharePoint authentication for Windows Phone users, the client object model includes a new Authenticator class and several associated classes. For an overview, see Overview of
the SharePoint mobile client authentication object model.
To enable automatic notifications to Windows Phone users of events on a SharePoint farm, the server object model includes several new classes, each of which is also callable from the client
object model. These classes include methods that enable phone apps to register with SharePoint server apps for notifications about specified types of events. There are also methods that the
server apps use to send notifications to registered subscribers. For an overview, see Create a Windows Phone SharePoint list app to receive push notifications.
With SharePoint, you're not limited to mobile app development just for Windows Phone 8 and Windows Phone 7. With the JavaScript programming interface and the new Representational
State Transfer (REST) programming interface provided by SharePoint, you can create applications for non-Windows Phone mobile devices; you can interact with SharePoint sites by using
JavaScript that executes as scripts in the browser, or remotely by using any technology that supports standard REST capabilities. The following section provides an overview of the REST and
JavaScript programming interfaces.
ECMAScript (JavaScript, JScript) object model architecture
SharePoint Foundation 2010 introduced the client object models, which enabled developers to perform remote communication with SharePoint by using the web programming technology
of their choice: the .NET Framework, Silverlight, or JavaScript.
In SharePoint Foundation 2010, the client object models provide APIs that enable developers to interact with SharePoint sites from script that executes in the browser, from code (based on
the .NET Framework 3.5 or later) that executes in a .NET Framework-managed application, or from code that executes in a Silverlight 2.0 application. The proxy .js and managed .dll files that
compose the client object models are built on the client.svc web service, and handle the effective batching, serialization of requests, and parsing of replies. Figure 2 shows a high-level view of
the SharePoint client object model architecture.
Figure 2. SharePoint client object model architecture

To learn how to use the JavaScript client object model against SharePoint data, see the ECMAScript Client Object Model video.
REST endpoints in SharePoint
To use the REST capabilities that are built into SharePoint, you can construct a RESTful HTTP request using the Open Data Protocol (OData) standard that corresponds to the desired client
object model API. The client.svc web service handles the HTTP request and serves the appropriate response, in either Atom or JavaScript Object Notation (JSON) format. The client
application must then parse that response. Figure 3 shows a high-level view of the SharePoint REST architecture.
Figure 3. SharePoint REST architecture

Currently, the REST service in SharePoint is read-only. That is, only REST endpoints that represent an HTTP GET operation are available
By default, the SharePoint REST service responses are formatted using the Atom protocol, according to the OData specification. In addition, the REST service supports HTTP Accept headers
that enable developers to specify that the response is returned in JSON format. To learn more about REST services in SharePoint, see Use OData query operations in SharePoint REST
requests.
The SharePoint REST service supports the following OData query operators:
Filter
Take
Expand

Start developing mobile apps for SharePoint


The following how-tos and overviews delve into the specific information you need to start your mobile app development:
How to: Set up an environment for developing mobile apps for SharePoint
Overview of Windows Phone SharePoint application templates in Visual Studio
Architecture of the Windows Phone SharePoint List Application template
How to: Create a Windows Phone SharePoint list app
How to: Store and retrieve SharePoint list items on a Windows Phone
How to: Implement business logic and data validation in a Windows Phone app for SharePoint
How to: Support and convert SharePoint field types for Windows Phone apps
How to: Customize list item queries and filter data for Windows Phone apps
How to: Customize the user interface of a SharePoint list app for Windows Phone
How to: Use multiple SharePoint lists in a Windows Phone app
How to: Configure and use push notifications in SharePoint apps for Windows Phone
Integrating location and map functionality in SharePoint
How to: Create a mobile app in SharePoint that contains data from an external data source
How to: Integrate maps with Windows Phone apps and SharePoint lists
How to: Build search-driven mobile apps with the Navigation and Event Logging REST interfaces

See also
Programming models in SharePoint
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
About Expression Blend
Set up an environment for developing mobile apps for SharePoint
3/26/2018 • 5 minutes to read Edit Online

Learn about the system requirements and configuring a development environment for SharePoint mobility projects. A minimal configuration for working with SharePoint mobility projects
requires a server running SharePoint (or a SharePoint Online account) and a development environment on a separate client operating system. Installing SharePoint on client operating
systems (such as Windows 7) is not supported, and installing the tools necessary for Windows Phone development is not supported on server operating systems (such as Windows Server
2008).

Windows Phone development projects and SharePoint Server


To create and test Windows Phone apps that interact with SharePoint, you need access to a server running SharePoint or a SharePoint Online account, and you need sufficient permissions
on the sites and lists you intend to use in your solutions. We recommend that you use an installation of SharePoint Server that is dedicated to testing and development as a target server
while you develop your projects. Use SharePoint Server in a production environment as your target server only after your developed solution has undergone sufficient testing.
For information on installing and configuring SharePoint, see the documentation in the SharePoint Products section of the Microsoft TechNet Library. For information on using SharePoint
Online in your development solutions, visit the SharePoint Online Developer Resource Center.
For the code samples in this documentation, it is assumed that a developer working with the sample has or can obtain sufficient permissions on SharePoint sites and lists to be able to add,
edit, and delete data.

Configure a client development environment for SharePoint mobility projects


To develop SharePoint Add-ins for use on Windows Phone devices, you need to set up your development tools on a computer that is running a client operating system, not a server
operating system.

Configuring Windows Phone SDK 8.0


To develop SharePoint Add-ins for use on Windows Phone 8, you need to set up your development tools on a computer that is running Windows 8 64-bit (x64) client versions or Windows 8
Pro. The Windows Phone 8 Emulator requires Windows 8 Pro, and requires a processor that supports Second Level Address Translation (SL AT).
1. On a computer with a supported client operating system, install Windows Phone SDK 8.0. The Windows Phone Software Development Kit (SDK) 8.0 provides you with the tools that
you need to develop apps and games for Windows Phone 8 and Windows Phone 7.5.
The Windows Phone SDK 8.0 is a full-featured development environment to use for building apps and games for Windows Phone 8.0 and Windows Phone 7.5. The Windows Phone
SDK provides a stand-alone Visual Studio Express 2012 edition for Windows Phone or works as an add-in to Visual Studio 2012 Professional, Premium or Ultimate editions. With the
SDK, you can use your existing programming skills and code to build managed or native code apps. In addition, the SDK includes multiple emulators and additional tools for profiling
and testing your Windows Phone app under real-world conditions.
NOTE

If your computer meets the hardware and operating system requirements, but does not meet the requirements for the Windows Phone 8 Emulator, the Windows Phone SDK 8.0 will
install and run. However, the Windows Phone 8 Emulator will not function and you will not be able to deploy or test apps on the Windows Phone 8 Emulator. For information about
the system requirements for running the Windows Phone Emulator, see Setup and System Requirements for Windows Phone Emulator.
2. Install Microsoft SharePoint SDK for Windows Phone 8.
The SharePoint SDK for Windows Phone installs two Silverlight for Windows Phone templates (in addition to those installed by the Windows Phone SDK): the Windows Phone
Empty SharePoint Application template and the Windows Phone SharePoint List Application template. The SDK also installs SharePoint CSOM libraries, an authentication library, and
Windows Phone project templates, and it now supports NTLM authentication. You can use the bundled APIs and templates to build Windows Phone 8 applications against
SharePoint.
Additionally, the SharePoint SDK for Windows Phone installs several supporting run-time assemblies (in
%ProgramFiles(x86)%\\Microsoft SDKs\\SharePoint\\v15.0\\Phone\\v8.0\\Libraries for a standard installation).

Microsoft.SharePoint.Client.Phone.dll
Microsoft.SharePoint.Client.Phone.Runtime.dll
Microsoft.SharePoint.Client.Phone.Auth.UI
Microsoft.SharePoint.Phone.Application.dll

> [!NOTE]
> The templates in the SharePoint SDK for Windows Phone are currently available for C# projects only.

For more information about the templates in SharePoint SDK for Windows Phone, see Overview of Windows Phone SharePoint application templates in Visual Studio.

Configuring Windows Phone SDK 7.1


To develop SharePoint Add-ins for use on Windows Phone 7, you need to set up your development tools on a computer that is running Windows 7 (32-bit or 64-bit) or Windows Vista
Service Pack 2 (32-bit or 64-bit). The Windows Phone Software Development Kit (SDK) 7.1 is not supported on Windows Server 2008 or on Windows XP.
1. On a computer with a supported client operating system, install Windows Phone SDK 7.1.
NOTE

An earlier version of the Windows Phone SDK was named the Windows Phone Developer Tools.
The Windows Phone SDK installs Microsoft Visual Studio 2010 Express for Windows Phone, the Windows Phone Emulator, XNA Game Studio, and Microsoft Expression Blend for
Windows Phone. Visual Studio 2010 Express for Windows Phone is a suitable development environment for most Windows Phone solutions. You can also use Visual Studio 2010
Professional as your preferred development environment, but you still need to install the Windows Phone SDK, which installs the necessary add-ins to Visual Studio. (The Windows
Phone SDK is not currently supported for use with Visual Studio 2012.)
For information on additional system requirements and instructions for installing the Windows Phone SDK, see Installing the Windows Phone SDK. For information about the system
requirements for running the Windows Phone Emulator, see Setup and System Requirements for Windows Phone Emulator.
2. Install Microsoft SharePoint SDK for Windows Phone 7.1.
The SharePoint SDK for Windows Phone installs two Silverlight for Windows Phone templates (in addition to those installed by the Windows Phone SDK): the Windows Phone
Empty SharePoint Application template and the Windows Phone SharePoint List Application template.
Additionally, the SharePoint SDK for Windows Phone installs several supporting run-time assemblies (in
%ProgramFiles(x86)%\\Microsoft SDKs\\SharePoint\\v15.0\\Phone\\v7.1\\Libraries for a standard installation).

Microsoft.SharePoint.Client.Phone.dll
Microsoft.SharePoint.Client.Phone.Runtime.dll
Microsoft.SharePoint.Client.Phone.Auth.UI
Microsoft.SharePoint.Phone.Application.dll

> [!NOTE]
> The templates in the SharePoint SDK for Windows Phone are currently available for C# projects only.

For more information about the templates in SharePoint SDK for Windows Phone, see Overview of Windows Phone SharePoint application templates in Visual Studio.

See also
Build Windows Phone apps that access SharePoint
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Overview of Windows Phone SharePoint application templates in Visual Studio
3/26/2018 • 6 minutes to read Edit Online

Learn about the Visual Studio templates installed by the Windows Phone SharePoint Software Development Kit for mobile app development.

Templates installed by the Windows Phone SharePoint Software Development Kit


After you set up your development environment and install the Windows Phone SharePoint Software Development Kit (SDK), two additional Silverlight for Windows Phone templates are
available for projects:
The Windows Phone Empty SharePoint Application template
The Windows Phone SharePoint List Application template
Currently, these templates are designed to be used only in C# projects. They are not available for Visual Basic projects. The templates are available, however, for use in Visual Studio 2012
and Visual Studio Express 2012 for Windows Phone 8 and in Visual Studio 2010 and Visual Studio 2010 Express for Windows Phone 7.
NOTE

Windows Phone SharePoint templates don't appear in the New Project menu of Expression Blend. However, you can edit a project in Expression Blend by choosing Open in Expression
Blend from a shortcut menu in Visual Studio.
When you create a project based on either one of these templates, you are not given the option of choosing a target Windows Phone platform. As for projects created from Visual Studio
Express 2012 using these templates target Windows Phone 8 applications against SharePoint ; And projects created from Visual Studio 2010 Express using these templates target Windows
Phone OS version 7.1 by default That is, the AppPlatformVersion attribute of the Deployment element in the WMAppManifest.xml file has a value of 7.1.

<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment" AppPlatformVersion="7.1">

NOTE

For more information about settings in the WMAppManifest.xml file, see Application Manifest File for Windows Phone.

Starting a project based on the Windows Phone Empty SharePoint Application template
If you create a Visual Studio project based on the Windows Phone Empty SharePoint Application template, the starting project is similar to a project created by using the basic Windows
Phone Application template (installed by the Windows Phone SDK 7.1), with the addition of references to DLLs installed by the Windows Phone SharePoint SDK
(Microsoft.SharePoint.Client.Phone.dll, Microsoft.SharePoint.Client.Phone.Auth.UI, and Microsoft.SharePoint.Client.Phone.Runtime.dll as shown in Figure 1) and a few other
reconfigurations.
NOTE

The same templates are available for Windows Phone 8 in Visual Studio Express 2012.
Figure 1. Files in a Windows Phone Empty SharePoint Application project

The files in a project based on the Windows Phone Empty SharePoint Application template are the standard files of a Silverlight Windows Phone app. The MainPage.xaml file contains XAML
declarations that constitute the user interface (UI) of the app. A code-behind file, MainPage.xaml.cs, is associated with the MainPage.xaml file by using the mechanism of partial classes, as are
the other code-behind files in the project. (See Code-Behind and Partial Classes.) The MainPage.xaml.cs file contains procedural code to implement logic to support operations and events in
the UI. The App.xaml file represents the overall Windows app. The associated code-behind file, App.xaml.cs, includes procedural code to handle life-cycle events for the app.

Starting a project based on the Windows Phone SharePoint List Application template
The Windows Phone SharePoint List Application template is considerably more powerful than the Windows Phone Empty SharePoint Application template. This template was designed to
help you create Windows Phone apps to handle a likely scenario in mobile application development for SharePoint: accessing and manipulating data stored in a SharePoint list from a
Windows Phone. When you create a Visual Studio project based on this template, a wizard guides you through the necessary configuration steps and generates solution files for a functional
Windows Phone app that can work with SharePoint list data. You can build and deploy the app from the generated files with little or no modification.
NOTE

The same templates are available for Windows Phone 8 in Visual Studio Express 2012.

Understanding the solution files in a Windows Phone SharePoint List Application project
The files generated for a Visual Studio project using the Windows Phone SharePoint List Application template are shown in Figure 2. (References to other assemblies—not shown in Figure 2
—such as System.Runtime.Serialization.dll and Microsoft.Phone.Controls.dll are additional to those references included by the Windows Phone Empty SharePoint Application template.
These additional assemblies support the management of SharePoint list data and the visual controls to represent that data.)
Figure 2. Files in a Windows Phone SharePoint List Application project

The project files for are described in Table 1.


Table 1. Windows Phone SharePoint List Application project files

FILE D ES CR IPTIO N

App.xaml Represents the overall Windows Phone application. Includes declarations of elements related to the
application (instead of to individual pages within the application), such as application life-cycle events like
Application_Deactivated and Application_Closing.

App.xaml.cs The code-behind file associated with App.xaml (using the partial-class mechanism, as is the case for the
other code-behind files in the project). Includes procedural code to handle the operations in the life-cycle
events, such as Application_Deactivated and Application_Closing. You write code in this file to
manage offline (local) storage of data.

ListDataProvider.cs Contains code for accessing data on the SharePoint Server and provides access to the query syntax on
which the various list views of the application are based.

List.xaml Defines the UI elements for the default view form in the phone application; analogous to the All Items
(or All Tasks, All Contacts, or similar) view in SharePoint. The List.xaml file contains the Pivot control that
constitutes the primary container for visual elements in the application, including the PivotItem controls
that render the list views chosen by the developer to be included in the Windows Phone app.

List.xaml.cs The code-behind file associated with List.xaml. Includes code to implement the methods and handlers for
the buttons on the form, such as New and Refresh.

DisplayForm.xaml Defines the UI elements for the Display Item form (or page) in the application; analogous to the View
Item form in SharePoint. In the Windows Phone app, the fields are rendered in a vertical "stack" by using
a StackPanel control contained in a Silverlight Pivot control.

DisplayForm.xaml.cs The code-behind file associated with DisplayForm.xaml. Includes code to implement the methods and
handlers for the buttons on the form, such as Edit and Delete.

EditForm.xaml Defines the UI elements for the Edit Item form in the phone application; analogous to the Edit Item
form in SharePoint. As with the Display Item form, fields are rendered in a StackPanel control.

EditForm.xaml.cs The code-behind file associated with EditForm.xaml. Includes code to implement the methods and
handlers for the buttons on the form, such as Submit and Cancel.

NewForm.xaml Defines the UI elements for the New Item form in the phone application; analogous to the New Item
form in SharePoint. Fields are rendered in a StackPanel control.

NewForm.xaml.cs The code-behind file associated with NewForm.xaml. Includes code to implement the methods and
handlers for the buttons on the form, such as Submit and Cancel.

DisplayItemViewModel.cs Serves as the data source for the DisplayForm.xaml file.

EditItemViewModel.cs Serves as the data source for the EditForm.xaml file. You write code in this file to validate data entered by
users when editing a list item.

ListViewModel.cs Serves as the data source for the List.xaml file.

NewItemViewModel.cs Serves as the data source for the NewForm.xaml file. You write code in this file to validate data entered
by users when adding a new list item.

For the details of the steps involved in creating a Windows Phone app by using the Windows Phone SharePoint List Application template, see How to: Create a Windows Phone SharePoint
list app.
See also
Build Windows Phone apps that access SharePoint
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Windows Phone Development
Architecture of the Windows Phone SharePoint List Application template
3/26/2018 • 10 minutes to read Edit Online

Understand the design pattern of projects created from the Windows Phone SharePoint List Application template. The Windows Phone SharePoint List Application template installed by the
Windows Phone SharePoint Software Development Kit has been designed to generate Windows Phone apps based on a pattern that separates parts of the project into different
components. The template does the work of creating the classes and files to establish the pattern, allowing developers to focus on extending generated projects based on their particular
requirements, business logic, and data.

The Windows Phone SharePoint List Application template and the MVVM design pattern
The Windows Phone SharePoint List Application template generates a Visual Studio 2010 project for a Silverlight-based Windows Phone app developed according to a software design
pattern known as the View-Model-ViewModel (MVVM) pattern. The MVVM pattern is a way of organizing and compartmentalizing code in a project into manageable layers, which can be
independently developed, tested, and modified. It is a particularly effective development pattern for Windows Presentation Foundation (WPF) and Silverlight projects because, among other
benefits, the pattern allows for the presentation layer of a given application to have a less rigid dependency on the structure of underlying data, freeing developers to adapt the presentation
layer for different contexts (as, for instance, Web browsers, mobile device interfaces, or desktop applications) while retaining the same underlying data structures.
As opposed to a simpler approach of, say, writing all of your data-management code in the code-behind files associated with particular XAML files in a Silverlight application, organizing a
project according to the MVVM pattern involves an additional initial investment of effort to plan and develop the necessary classes, the inheritance model, and the methods of
communication between the components of the pattern. The Windows Phone SharePoint List Application template takes care of this initial configuration and development work to set up the
pattern for you, allowing you to customize and extend the project to develop a functional MVVM application quickly.
The three main components or layers of the MVVM pattern are the View, the Model, and the ViewModel. In projects based on the Windows Phone SharePoint List Application template,
these components are implemented by various project files, as shown in Figure 1.
Figure 1. Windows Phone SharePoint List Application files in the MVVM pattern

The following sections explain some of the details related to the implementation of these components in the Windows Phone SharePoint List Application template.

The Model component


The Model component in the MVVM pattern refers to the classes and structures used to represent the data for an application. For an app based on a SharePoint list, the list and its items
serve as the underlying data. In the Windows Phone SharePoint List Application, the ListDataProvider class handles the standard SharePoint client object model operations for connecting
to a SharePoint list; for example, creating an instance of the ClientContext class and setting its properties. The exact implementation details of the ListDataProvider class in the template
depend on the options specified in the steps of the SharePoint Phone Application Wizard when you create a project based on the template.
The base class, ListDataProviderBase (in the Microsoft.SharePoint.Phone.Application.dll), from which the ListDataProvider class is derived implements a caching mechanism for
SharePoint list data. When list items are retrieved from the server, they are cached by the ListDataProvider class in the local memory allocated to the phone app and when those items are
needed in the app, the cache is checked first in order to conserve resources and reduce trips to the server.
If you want to filter the data retrieved from the SharePoint list or specify exactly what data to retrieve, you can modify the code in the ListDataProvider class (in the ListDataProvider.cs file).
The parts of the file you would most likely modify for these purposes are the LoadDataFromServer method and the implementation of the static CamlQueryBuilder class. You can also
derive your own class from the ListDataProviderBase class. If you do so, be sure to implement the abstract methods from the base class, LoadData and LoadItem, and also implement
the Context property member of the base class, providing a suitable get accessor method.

The View component


The View component in the MVVM pattern refers to the user interface (UI) of an app. In Silverlight-based Windows Phone app, the View component is constituted by XAML files for
declaring and qualifying UI elements and code-behind files associated with those XAML files that implement event handlers and other code to determine how users interact with the UI
elements.
It is important to distinguish between two senses of the word "view" in the context of developing SharePoint list apps for Windows Phone. A SharePoint list is associated with one or more
views, as, for example, the default All Items view for a list, or the Current Events view for a list based on the Calendar list template. These views represent ways of organizing and displaying
list items in a SharePoint list. Depending on the kind of SharePoint list (and on whether custom views have been added to the list) you target for your app, the views associated with the list,
such as All Tasks or Current Events, are made available for you to choose to include in your app in the SharePoint Phone Application Wizard when you create a project from the template. If
you include a given view, the template generates a PivotItem control (contained within a Pivot control) to render the view of the list.
This sense of the word "view" is to be distinguished from the sense of the word as it applies to the Views in the template. In a project based on the Windows Phone SharePoint List
Application template, the Views (implemented as XAML files in the Views folder of the project) refer conceptually to the View component of the MVVM pattern. That is, the Views in the
project represent the presentation layer for the data (or, Model) of a given entity. In this case, the entity is either a SharePoint list or a SharePoint list item.
Although the List form (List.xaml) in the project can be said to correspond to the default view associated with a SharePoint list, the conceptual distinction between the default view of a
SharePoint list and the View as represented by the List form should still be maintained, because the List form in the project doesn't necessarily map to the default view of the list on the
server. If, for example, you modify the default list view on the server (by, say, specifying a given sort order or displaying certain fields and not others), the modifications will not be
represented in the XAML that constitutes the List form in the project. You set the order of the items as they are shown in the List form in your app based on your choices in the SharePoint
Phone Application Wizard (or based on your subsequent customizations of the List form), regardless of the order configured for the default view associated with the SharePoint list on the
server.
The List form represents the View (or presentation layer) for the SharePoint list. The other three View files pertain to individual list items, and they can be said to correspond to the forms
available (generally) from the list item menu for a list item in SharePoint.
The Display form (DisplayForm.xaml) corresponds to the View Item form (DispForm.aspx) for a SharePoint list. This form presents a View for an individual item in a SharePoint list.
The Edit form (EditForm.xaml) corresponds to the Edit Item form (EditForm.aspx) for a SharePoint list. This form presents a View for a given item as it is exposed for editing.
The New form (NewForm.xaml) file corresponds to the New Item form (NewForm.aspx) for a SharePoint list. This form presents a View for a given item that is to be created and
added to the list.
The List form is always included by default in a project based on the Windows Phone SharePoint List Application template. The XAML files for the other forms in the Views folder of the
project are generated based on the list operations (New, Display, or Edit) selected in the SharePoint Phone Application Wizard.

The ViewModel component


The ViewModel component in the MVVM pattern is intended to serve as a kind of broker to facilitate the interactions between the View component and the Model component, while
decoupling the View component from the Model component so it is easier to change one or the other without adversely affecting the other. Strictly speaking, the ViewModel component
could be considered part of the presentation layer, because it often includes logic for "shaping" underlying data for presentation in the View component. In projects based on the Windows
Phone SharePoint List Application template, the ViewModels implement the code for binding SharePoint list data retrieved from the Model component (that is, from an object of the
ListDataProvider class) to UI controls in a part of the View component (for example, the Edit form). Depending on the kind of control used to display the data from the list and the type of
data (that is, whether the field type for the list item is text or numerical data or something like a SharePoint Choice field), the ViewModel first processes or converts the data such that it can
be bound to a given UI control.
In particular, the ViewModel classes in the project (as, for example, the EditItemViewModel class) are derived from a base class, ViewModelBase (in the
Microsoft.SharePoint.Phone.Application.dll), which implements the INotifyPropertyChanged interface so that the Silverlight controls constituting the user interface of the app can be
updated when values in the underlying data change, and (going in the other direction) changes to the values stored in UI controls can be applied to the underlying data (if bi-directional, or
"two-way", binding is configured for a control).
Figure 2 shows a simplified representation of the class inheritance hierarchy for the EditItemViewModel class and the binding for a given UI control in the Edit form with the
corresponding field in the ViewModel.
Figure 2. The EditItemViewModel and EditForm classes

The EditForm class (which represents the View component from the MVVM pattern) is defined and implemented by two files, the EditForm.xaml file and its associated code-behind file,
EditForm.xaml.cs. In the EditForm.xaml.cs file, the EditItemViewModel class (representing the ViewModel component of the MVVM pattern) is bound to the View in the EditForm.xaml.cs
file by setting the DataContext property of the EditForm class to an object of the EditItemViewModel class.
Software designs based on the MVVM pattern often confine business logic and validation routines to the Model component of the pattern. In projects based on the Windows Phone
SharePoint List Application template, however, some operations that are typically considered part of the Model component have been implemented in the ViewModel component to make it
more convenient for developers to extend the projects, at the cost of slightly blurring the conceptual distinction between the data layer (Model) and the presentation layer (ViewModel). For
example, the ViewModel classes for editing and creating list items (that is, the EditItemViewModel and NewItemViewModel classes) expose a Validate method that developers can
override to implement validation of data entered by users. (For information on implementing data validation with these ViewModels, see How to: Implement business logic and data
validation in a Windows Phone app for SharePoint..md)
NOTE

The ListDataProvider object only loads the data from server. Other operations, such as Add, Update, and Delete, are performed in the ViewModel itself, followed by a refresh call to
update the ViewModel data from the server. This design reduces cluttering of the code.

The App.xaml file and the Silverlight application model


The App.xaml file and its associated code-behind file, App.xaml.cs, are standard components of a managed Silverlight application. Applications that use the managed API for Silverlight must
include a class derived from the Silverlight Application class, in order to implement the Silverlight application model. The Application class supports application life-cycle events and
facilities for managing resources like images, strings, and XAML templates.
For information about the kinds of modifications you might make to the App.xaml.cs file in your projects, see How to: Store and retrieve SharePoint list items on a Windows Phone on
implementing event handlers in the App.xaml.cs file to preserve application state information, and How to: Use multiple SharePoint lists in a Windows Phone app on instantiating and
configuring additional ListDataProvider objects in App.xaml.cs.

See also
Using the Model-View-ViewModel Pattern
Pivot Control Architecture for Windows Phone
Silverlight Application Model
Developing a Windows Phone Application using the MVVM Pattern
WPF Apps With The Model-View-ViewModel Design Pattern
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Microsoft SharePoint SDK for Windows Phone 7.1
Create a Windows Phone SharePoint list app
3/26/2018 • 8 minutes to read Edit Online

Create a Windows Phone app in Visual Studio based on the Windows Phone SharePoint List Application template. Installing the Windows Phone SharePoint SDK makes two Windows
Phone SharePoint Application templates available to you in Visual Studio 2010 or Visual Studio 2010 Express for Windows Phone. (See How to: Set up an environment for developing
mobile apps for SharePoint.) Using the Windows Phone SharePoint List Application template, you can follow the steps of a wizard to create a functional Windows Phone app that can access
and manipulate data in a SharePoint list.

Important: If you are developing an app for Windows Phone 8, you must use Visual Studio Express 2012 instead of Visual Studio 2010 Express. Except for the development
environment, all information in this article applies to creating apps for both Windows Phone 8 and Windows Phone 7. > For more information, see How to: Set up an environment for
developing mobile apps for SharePoint.

Create the Windows Phone SharePoint list application


In your Windows Phone SharePoint list app, you can access most of the lists that are available in SharePoint Add-ins. For the purposes of this sample Windows Phone app, we use
SharePoint lists with sample data from a fictitious company named Contoso, Ltd. For the steps to create the first iteration of this SharePoint list app, we use a SharePoint Contacts list that
contains information about members of a marketing team at Contoso, as shown in Figure 1.
Figure 1. Contacts list for Contoso marketing team

To create a Windows Phone SharePoint list app


1. Start Visual Studio 2010 by using the Run as Administrator option.
2. Choose File, New, Project.
The New Project dialog box appears.
3. In the New Project dialog box, expand the Visual C# node, and then choose the Silverlight for Window Phone node. (Ensure that the target .NET Framework version is set to 4.)
NOTE

The templates installed by the Windows Phone SharePoint SDK work only in C# projects. The templates are not available for Visual Basic projects.
4. In the Templates pane, choose the Windows Phone SharePoint List Application template and give the project a name, such asContosoSPListApp.
5. While running the SharePoint Phone Application Wizard, the error shown in Figure 2 can occur. This error occurs because the account the developer is using while running the
SharePoint Phone Application Wizard has insufficient permissions.
Figure 2. SPList wizard error message

You can resolve this error by giving sufficient privileges to the account with which the developer is running the SPList wizard. Rerun **Splist wizard** after sufficient rights are given.
1. Choose the OK button. The SharePoint Phone Application Wizard appears. You use this wizard to choose a SharePoint list and configure properties of that list to determine how it
appears in your Windows Phone app.
2. Specify the URL of a target SharePoint site on your network (that is, an on-premises installation of SharePoint Server).
3. Choose Find Lists. If the account under which you are running Visual Studio has access to the specified target site, the SharePoint Phone Application Wizard displays the lists that
are available on that site.
4. Select one of the available lists, such as a Contacts list (shown with sample data in a customized view in Figure 1).
5. Choose Next. The wizard displays the available views associated with the selected list.
The views displayed by the wizard are those views that have been created by users (or provisioned by SharePoint Server) and associated with a given list on the server. Some
SharePoint lists have only one view associated with them by default. A Contacts list, by default, is associated with an All Contacts view. An Announcements list, by default, is associated
with an All Items view. A Tasks lists, by default, is associated with six views, including an All Tasks view and an Active Tasks view. For each view that you select at this stage in the
wizard, a PivotItem control is created and added to the Pivot control in the XAML that defines the UI of the Windows Phone app.
6. Select the check box next to each view you want to include in your Windows Phone app.
7. Choose Next. The wizard displays the available actions for the selected list in your Windows Phone app.
The choices are New, Display, Edit, and Delete. If you want to be able to edit or delete list items in your app, you must choose the Display operation at this stage in the wizard. (The
check boxes for the Edit and Delete operations are disabled unless the Display operation is selected.)
8. Select the check box next to each action you want to have available for the selected list in your Windows Phone app.
9. Choose Next. The wizard displays the fields associated with the selected list on the SharePoint site.
NOTE

A custom field will not be available to select from the SharePoint List wizard for mobile devices. However, you can write custom code to access any custom field. A field cannot be
associated with its content type. However if multiple content types are enabled for the list, all the fields will be available for developers to consume in their phone apps.
10. Select the check box next to each field you want to include in the list as it will appear in your Windows Phone app.
NOTE

List fields that are designated in SharePoint Server as requiring information are selected already; they can't be cleared in the wizard.
11. Choose Next. The wizard gives you the opportunity to order the fields you selected in the previous step.
12. Order the fields according to your needs by selecting individual fields and moving them higher or lower in the order by choosing the up or down arrows.
13. Choose Finish. Visual Studio creates the necessary files for the project and opens the List.xaml file for editing.

Run the Windows Phone app generated by the SharePoint Phone Application Wizard
The project generated by the SharePoint Phone Application Wizard can be built as it is to create a simple but functional Windows Phone SharePoint list app. We can modify and develop
the app further, but, for now, a user can tap (or, in the Windows Phone Emulator, click) a given list item and the app displays all the fields associated with that item (those fields that you
selected in the wizard to include in the app). A user can also add new list items, delete list items, and edit the field values for list items. Multiple-user logon in a single app is not supported.
However, a developer can write code that logs off the current user when another user tries to log on to the same mobile app.
The deployment target for the solution is set to Windows Phone Emulator by default. You can run the project in Visual Studio as it is (either by pressing F5 to start the project in the context
of the debugger or by pressing CTRL+F5 to start the project without debugging). The Windows Phone Emulator is launched, the Windows Phone operating system is loaded, and your app
is deployed to the emulator and started. If you start with the code as it is generated by the wizard, when your SharePoint list app runs in the emulator, you're asked for credentials for the
specified SharePoint list on the target site. Provide the credentials for an account that has sufficient permissions to access the list and choose Log On in the emulator. The main page of the
Windows Phone app (defined by the List.xaml file in the project) is displayed in the emulator. Depending on the fields you chose and the order you specified for those fields in the previous
steps, you should see items from the specified list. Based on the data in the list represented by Figure 1, you would see a list of items in the emulator as shown in Figure 3.
Figure 3. SharePoint list items in a Windows Phone app

While running a Windows Phone app, the authentication error shown in Figure 4 can occur. This happens because the SharePoint mobile app requires Basic Form Authentication; this isn't
enabled by default.
Figure 4. Windows Phone app authentication error
You can resolve this error by choosing Basic form authentication from Central Administration.

To enable Basic form authentication


1. Navigate to Central Administration; ensure you have admin rights on server.
2. Choose Manage Web Applications under Application Management.
3. Choose your web application (on which you have your SharePoint site, which you are accessing from your mobile app).
4. Choose Authentication Providers from the ribbon.
5. Choose Authentication Providers from the ribbon.
6. In the Authentication Provider dialog box, choose Default to Edit Authentication.
7. In the Edit Authentication model window, choose Basic Authentication under Claims Authentication types.
If you based your Windows Phone app on the data from a Contacts list, as shown in Figure 1, you can choose a particular list item and the app presents a page with a view of the item
(defined by DisplayForm.xaml in the project) showing all the fields available for the item in the app, as in Figure 5. (For this example, all the fields associated with a SharePoint Contacts list
were selected in the SharePoint Phone Application Wizard and the default order of those fields was retained.)
Figure 5. DisplayForm view of a Contacts list item

Notice the Edit and Delete buttons on the Application Bar in this page of the app. These operations are implemented for you by methods in Microsoft.SharePoint.Phone.Application.dll
(which is one of the libraries installed by the Windows Phone SharePoint SDK). If you choose the Edit button, a Windows Phone Page control (that is, an object instantiated from a class that
inherits from the Microsoft.Phone.Controls.PhoneApplicationPage class) is displayed. If you edit any of the fields and choose the Submit button on that page in the app, the underlying
UpdateItem method of the EditItemViewModelBase class is executed (which, ultimately, executes the Update method of a ListItem object from the SharePoint Silverlight client object
model) to save your changes to the SharePoint list.

See also
Build Windows Phone apps that access SharePoint
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Store and retrieve SharePoint list items on a Windows Phone
3/26/2018 • 20 minutes to read Edit Online

Learn about the Windows Phone application life cycle and storing network data locally. One of the most important considerations in the development of Windows Phone apps is the
management of state information, both for the overall application and for individual pages or data items within the application. If you're developing Windows Phone apps, you must take into
account that users of your apps might lose connectivity to network resources (such as SharePoint lists). The development infrastructure for Windows Phone apps provides mechanisms for
handling state information at various stages in the life cycle of an app.

Important: If you are developing an app for Windows Phone 8, you must use Visual Studio Express 2012 instead of Visual Studio 2010 Express. Except for the development
environment, all information in this article applies to creating apps for both Windows Phone 8 and Windows Phone 7. > For more information, see How to: Set up an environment for
developing mobile apps for SharePoint.

Store SharePoint list data locally on a Windows Phone


On a Windows Phone, only one app runs at a time, and when a user switches to another app on the phone (by pressing the Start button on the phone, for example), the app currently
running is deactivated, or, in the terms of Windows Phone development,tombstoned. If the user switches back to the deactivated app (by pressing the Back button), the app can be
reactivated, but unless you provide logic to handle application state information over the course of the app life cycle, that state information is not preserved by default in the transition from
activation to deactivation and back again. (For more information about the application life cycle for Windows Phone apps, see Execution Model Overview for Windows Phone.)
For Windows Phone apps, the PhoneApplicationService class exposes standard life-cycle events that can be used to manage application state. In projects created from the Windows
Phone SharePoint List Application template (as with projects created from all Silverlight for Windows Phone templates), these standard Windows Phone application life-cycle events are
declared in the App.xaml file and associated with event handlers in the code-behind file, App.xaml.cs. The declarations in the App.xaml file for your SharePoint list apps should look like the
following markup.

<Application.ApplicationLifetimeObjects>
<!--Required object that handles lifetime events for the application-->
<shell:PhoneApplicationService
Launching="Application_Launching" Closing="Application_Closing"Activated="Application_Activated" Deactivated="Application_Deactivated"/>
</Application.ApplicationLifetimeObjects>

The Application_Activated and Application_Deactivated event handlers declared in the App.xaml file are implemented in the App.xaml.cs code-behind file with default logic that caches
application state information for use in the phone app as long as the app is not terminated. The implementation of the handlers for these events uses the State property (which provides
access to a Dictionary object) of the PhoneApplicationService class to store data. Data stored in this State property is transient. That is, it is preserved when the app is deactivated or
tombstoned, but not when the app is terminated. It is important to keep in mind as you handle application life-cycle events in your projects that if a Windows app is deactivated when a user
switches to another app, that deactivated app is subject to termination by the Windows Phone operating system, depending on circumstances. Any data on the phone that isn't saved to
persistent storage is lost, even if that data was saved to transient storage by using the State property of the PhoneApplicationService.
In a Windows Phone app that gets data from a SharePoint list, the data used on the phone from session to session can of course be retrieved from the server running SharePoint Server, if
the server is available. But continuous connectivity to a SharePoint Server may not be available for a Windows Phone device, owing to variations in service coverage by location and other
factors. To provide users of your app with access to data in the event of lost connectivity with the server running SharePoint Server, or simply to save data to persistent storage between
sessions of the app regardless of server availability, you can take advantage of the Closing and Launching events of the PhoneApplicationService class.
The Application_Launching and Application_Closing handlers for these events are declared in App.xaml and defined in the App.xaml.cs file, but they are not implemented. To handle
storing and retrieving application state information in the context of app termination, you can provide an implementation for the Application_Closing event handler to store data in the
isolated storage designated for the app so that the data persists between sessions of the app, and you can provide an implementation for the Application_Launching event handler to
retrieve data from isolated storage when a new session of the app is started (when the app is launched), even if connectivity to the server running SharePoint Server that is the original
source of the data is not available.

Tip: Data should be encrypted before you save it to a local device. For more information about how to encrypt the data, see How to: Encrypt Data in a Windows Phone Application

To implement event handlers for storing and retrieving application state


1. Create a Windows Phone app by using the Windows Phone SharePoint List Application template in Visual Studio by following the steps in How to: Create a Windows Phone
SharePoint list app.
2. In Solution Explorer, choose the App.xaml file.
3. Press F7 to open the code-behind file, App.xaml.cs, for editing.
4. Locate the (empty) implementation of the Application_Launching event handler and replace the event handler with the following code.

private void Application_Launching(object sender, LaunchingEventArgs e)


{
if (IsolatedStorageSettings.ApplicationSettings.Contains(DataProvider.ListTitle))
{
App.MainViewModel = (ListViewModel)IsolatedStorageSettings.ApplicationSettings
[DataProvider.ListTitle];
App.MainViewModel.Initialize();
}
}

1. Locate the (empty) implementation of the Application_Closing event handler and replace that event handler with the following code.
private void Application_Closing(object sender, ClosingEventArgs e)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(DataProvider.ListTitle))
{
IsolatedStorageSettings.ApplicationSettings[DataProvider.ListTitle] = App.MainViewModel;
}
else
{
IsolatedStorageSettings.ApplicationSettings.Add(DataProvider.ListTitle, App.MainViewModel);
}
IsolatedStorageSettings.ApplicationSettings.Save();
}

1. Save the file.


With these implementations in place, run your app to initialize the main ViewModel in the app with data from the server running SharePoint Server. Exit the app on the phone (by pressing
the Back button to navigate past the first page of the app) to trigger the Application_Closing event. If you then run your app without connectivity to the server, the ViewModel that was
saved to the IsolatedStorageSettings Dictionary object (in the Application_Closing event) is retrieved and initialized. The SharePoint list items that were saved to isolated storage in a
previous session of the app are displayed in the List form (List.xaml) of the app.

Implement a mechanism for editing list items offline


If you follow the procedure in the previous section to implement handlers for the Closing and Launching events in your app, SharePoint list data that was retrieved from the server when
connectivity was available can be displayed in your app even if connectivity to the server is lost in a subsequent session of the app, because the list items are retrieved from local persistent
storage on the phone. Based on the implementation in the previous section, however, the list items made available in this way for display while offline can't be edited and saved back to the
server unless connectivity is restored. In the following procedure, you'll add a mechanism to your app to provide for storing edited versions of list items locally when connectivity is
unavailable. When connectivity to the server is available again, you can retrieve these edited list items and save your changes back to the server.
For the procedures in this section, we assume you're working in the context of a Windows Phone app project created from the Windows Phone SharePoint List Application template and that
your app is based on a Product Orders list created from the Custom List template on the server and contains the columns and field types shown in Table 1.
Table 1. Sample Product Orders list

CO LU MN T YPE R EQ U IR ED

Product (for example, Title) Single line of text (Text) Yes

Description Single line of text (Text) No

Quantity Number Yes

Order Date Date and Time (DateTime) No

Fulfillment Date Date and Time (DateTime) No

Contact Number Single line of text (Text) No

To implement a class to support editing items while offline


1. Starting with a Visual Studio project that was created based on the Product Orders list represented by Table 1, in Solution Explorer, choose the node that represents the project (for
example, SPListAppLocalStorage).
2. On the Project menu, choose Add Class.
The Add New Item dialog box appears with the C# Class template selected.
3. Name the class file DraftItemStore.cs, and then choose Add.
The class file is added to the project and opened for editing.
4. Replace the contents of the class file with the following code.
using System;
using System.Net;
using System.Windows;
using System.Collections.Generic;
using System.IO.IsolatedStorage;

namespace SPListAppLocalStorage // Based on project name by default.


{
public class DraftItemStore
{
const string DraftsKey = "Drafts";

public static void AddDraftItem(string id, EditItemViewModel model)


{
Dictionary<string, EditItemViewModel> draftCollection = GetDraftItemCollection();
draftCollection[id] = model;
SaveDrafts(draftCollection);
}

public static void RemoveDraftItem(string id)


{
Dictionary<string, EditItemViewModel> draftCollection = GetDraftItemCollection();
draftCollection.Remove(id);
SaveDrafts(draftCollection);
}

public static void SaveDrafts(Dictionary<string, EditItemViewModel> draft)


{
if (IsolatedStorageSettings.ApplicationSettings.Contains(DraftsKey))
{
IsolatedStorageSettings.ApplicationSettings[DraftsKey] = draft;
}
else
{
IsolatedStorageSettings.ApplicationSettings.Add(DraftsKey, draft);
}
}

public static List<EditItemViewModel> Drafts


{
get
{
Dictionary<string, EditItemViewModel> draftCollection = GetDraftItemCollection();

List<EditItemViewModel> modelCollection = new List<EditItemViewModel>();


foreach (KeyValuePair<string, EditItemViewModel> entry in draftCollection)
{
modelCollection.Add(entry.Value);
}

return modelCollection;
}
}

public static Dictionary<string, EditItemViewModel> GetDraftItemCollection()


{
Dictionary<string, EditItemViewModel> draftCollection = null;
if (IsolatedStorageSettings.ApplicationSettings.Contains(DraftsKey))
draftCollection = (Dictionary<string,
EditItemViewModel>)IsolatedStorageSettings.ApplicationSettings[DraftsKey];

if (draftCollection == null)
draftCollection = new Dictionary<string, EditItemViewModel>();

return draftCollection;
}

public static EditItemViewModel GetDraftItemById(string id)


{
Dictionary<string, EditItemViewModel> draftCollection = GetDraftItemCollection();
return !draftCollection.ContainsKey(id) ? null : draftCollection[id];
}
}
}

The namespace specified in this code is based on the name of the project (SPListAppLocalStorage in this case). You might want to specify a different namespace, based on the name of your project.

1. Save the file.


A specific instance of the EditItemViewModel class represents a SharePoint list item that is being edited on the phone. You can consider a list item that was edited as a "draft item" before
changes to the item are saved to the server. In the code in this class, the AddDraftItem method adds a specific instance of the EditItemViewModel class (that is, a draft item) as a value to
a Dictionary object, associating the EditItemViewModel in the Dictionary with a key based on the identifier for the given list item. (An identifier is assigned by SharePoint Server to each
item in a list. In a project based on the Windows Phone SharePoint List Application template, that identifier is stored in the ID property of the given ViewModel class, such as
EditItemViewModel or DisplayItemViewModel, which represents the list item.) The RemoveDraftItem method removes an EditItemViewModel from the Dictionary object based
on a specified identifier. Both of these methods use the GetDraftItemCollection method to retrieve the Dictionary object containing the EditItemViewModel objects from isolated
storage and both methods use the SaveDrafts method to save the modified Dictionary object (with a draft item either added to it or removed from it) back to isolated storage. The
GetDraftItemCollection method first determines whether a "Drafts" Dictionary object has been saved to isolated storage. If so, the method returns that Dictionary object; otherwise, the
method initializes and returns a new Dictionary object. The Drafts property of the class provides access to the Dictionary of draft items by returning a list (that is, an object based on the
List generic) of draft items as EditItemViewModel objects. The GetDraftItemById method returns a given draft item from the Dictionary object based on a specified identifier value.
Now you can add elements to the user interface of the phone app and configure them to use the DraftItemStore class for editing list items offline. In the following procedures, you will:
Add and configure a Windows Phone page to display all list items that were saved as draft items to isolated storage on the phone.
Add and configure another page, bound to an EditItemViewModel, for editing an individual draft item, analogous to the Edit form (EditForm.xaml) for list items.
Add a method, SaveAsDraft, to the EditItemViewModel class that executes the AddDraftItem method of the DraftItemStore class implemented in the previous procedure.
Add an ApplicationBar button to the EditForm.xaml file to call the SaveAsDraft method.
Add an ApplicationBar button to the List.xaml file to navigate to the page that displays all list items saved as drafts.

To add a page for displaying all draft items saved on the phone
1. In Solution Explorer, choose the Views folder.
2. On the Project menu, choose Add New Item.
The Add New Item dialog box opens.
3. In the Add New Item dialog box, under the Visual C# node, choose the Silverlight for Windows Phone node.
4. In the Templates pane, choose the Windows Phone Portrait Page template.
5. Name the file Drafts.xaml, and then choose Add.
The file is added to the project under the Views node and opened for editing.
6. In the XAML pane of the designer, replace the contents of the file with the following XAML.

<phone:PhoneApplicationPage
x:Class="SPListAppLocalStorage.Views.Drafts"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="696" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">

<!--LayoutRoot is the root grid where all page content is placed-->


<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<!--TitlePanel contains the name of the application and page title-->


<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="Product Orders"
Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Draft Items" Margin="9,-7,0,0"
Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>

<!--ContentPanel - place additional content here-->


<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox x:Name="lstBoxDraftItems" ItemsSource="{Binding}"
SelectionChanged="lstBoxDraftItems_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding [Title]}" Style="
{StaticResource PhoneTextTitle2Style}"></TextBlock>
<TextBlock Text="{Binding [Description]}" Style="
{StaticResource PhoneTextNormalStyle}"></TextBlock>
<TextBlock Text="{Binding [Contact_x0020_Number]}" Style="
{StaticResource PhoneTextNormalStyle}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>

<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="btnCancel"
IconUri="/Images/appbar.cancel.rest.png" Text="Cancel" Click="OnCancelButtonClick" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

</phone:PhoneApplicationPage>

The value of the namespace designation `<x:Class>` in this code ("SPListAppLocalStorage.Views.Drafts") will vary depending on the name of your project.

1. With the Drafts.xaml file selected in Solution Explorer, press F7 to open the associated code-behind file, Drafts.xaml.cs, for editing.
2. Replace the contents of the file with the following code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace SPListAppLocalStorage.Views
{
public partial class Drafts : PhoneApplicationPage
{
public Drafts()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Drafts_Loaded);
}

private void lstBoxDraftItems_SelectionChanged(object sender, SelectionChangedEventArgs e)


{
ListBox lstBox = sender as ListBox;
if (lstBox.SelectedIndex == -1)
return;

EditItemViewModel selectedDraftItem = lstBox.SelectedItem as EditItemViewModel;


NavigationService.Navigate(new Uri(string.Format("/Views/DraftItemEditForm.xaml?ID={0}",
selectedDraftItem.ID), UriKind.Relative));

lstBox.SelectedIndex = -1;
}

void Drafts_Loaded(object sender, RoutedEventArgs e)


{
this.DataContext = DraftItemStore.Drafts;
}

private void OnCancelButtonClick(object sender, EventArgs e)


{
// Navigate back to initial List View form.
NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative));
}
}
}

1. Save the files.

To add a page for editing individual draft items


1. In Solution Explorer, choose the Views folder.
2. On the Project menu, choose Add New Item.
The Add New Item dialog box opens.
3. In the Add New Item dialog box, under the Visual C# node, choose the Silverlight for Windows Phone node.
4. In the Templates pane, choose the Windows Phone Portrait Page template.
5. Name the file DraftItemEditForm.xaml, and then choose Add.
The file is added to the project under the Views node and opened for editing.
6. In the XAML pane of the designer, replace the contents of the file with the following XAML.

<phone:PhoneApplicationPage
x:Class="SPListAppLocalStorage.DraftItemEditForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True" x:Name="DraftItemEditPage">

<!--LayoutRoot is the root grid where all page content is placed-->


<Grid x:Name="LayoutRoot" Background="Transparent"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=
Microsoft.Phone.Controls">
<StackPanel>
<ProgressBar Background="Red" x:Name="progressBar" Opacity="1"
HorizontalAlignment="Center" VerticalAlignment="Top"
Height="15" Width="470" IsIndeterminate="{Binding IsBusy}"
Visibility="{Binding ShowIfBusy}" />
<ScrollViewer HorizontalScrollBarVisibility="Auto" Height="700">
<Grid x:Name="ContentPanel" Width="470">
<StackPanel Margin="0,5,0,5">
<StackPanel Orientation="Vertical" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Product*</TextBlock>
<TextBox Style="{StaticResource TextValidationTemplate}"
<TextBox Style="{StaticResource TextValidationTemplate}"
FontSize="{StaticResource PhoneFontSizeNormal}" Width="470"
HorizontalAlignment="Left" Name="txtTitle" Text="{Binding [Title],
Mode=TwoWay,ValidatesOnNotifyDataErrors=True,NotifyOnValidationError=True}"
TextWrapping="Wrap" />
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Description</TextBlock>
<TextBox Style="{StaticResource TextValidationTemplate}"
FontSize="{StaticResource PhoneFontSizeNormal}" Width="470"
HorizontalAlignment="Left" Name="txtDescription"
Text="{Binding [Description],
Mode=TwoWay, ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True}"
TextWrapping="Wrap" />
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">
Product Category</TextBlock>
<ListBox MaxHeight="400" Width="Auto" x:Name="lstBoxProduct_x0020_Category"
ItemsSource="{Binding [Product_x0020_Category]}">
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton FontSize="{StaticResource PhoneFontSizeNormal}"
HorizontalAlignment="Left" GroupName="Product_x0020_Category"
Content="{Binding Name}"
IsChecked="{Binding IsChecked, Mode=TwoWay}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Quantity*</TextBlock>
<TextBox Style="{StaticResource TextValidationTemplate}"
FontSize="{StaticResource PhoneFontSizeNormal}" Width="470"
HorizontalAlignment="Left" Name="txtQuantity" Text="{Binding [Quantity],
Mode=TwoWay, ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True}"
TextWrapping="Wrap" />
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Order Date</TextBlock>
<TextBox Height="Auto" Style="{StaticResource TextValidationTemplate}"
FontSize="{StaticResource PhoneFontSizeNormal}" Width="470"
HorizontalAlignment="Left" Name="txtOrder_x0020_Date"
Text="{Binding [Order_x0020_Date], Mode=TwoWay, ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True}" TextWrapping="Wrap" />
<TextBlock FontSize="16" TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextSubtleStyle}"
Text="{Binding DateTimeFormat}" />
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Fulfillment Date</TextBlock>
<TextBox Height="Auto" Style="{StaticResource TextValidationTemplate}"
FontSize="{StaticResource PhoneFontSizeNormal}" Width="470"
HorizontalAlignment="Left" Name="txtFulfillment_x0020_Date"
Text="{Binding [Fulfillment_x0020_Date], Mode=TwoWay,
ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}"
TextWrapping="Wrap" />
<TextBlock FontSize="16" TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding
DateTimeFormat}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Rush
:</TextBlock>
<CheckBox Name="txtRush" FontSize="{StaticResource PhoneFontSizeNormal}"
HorizontalAlignment="Left" IsChecked="{Binding [Rush], Mode=TwoWay,
ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}" />
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Contact Number</TextBlock>
<TextBox Style="{StaticResource TextValidationTemplate}"
FontSize="{StaticResource PhoneFontSizeNormal}" Width="470"
HorizontalAlignment="Left" Name="txtContact_x0020_Number"
Text="{Binding [Contact_x0020_Number],
Mode=TwoWay, ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True}"
TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
</Grid>
</ScrollViewer>
</StackPanel>
</Grid>

<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="btnSubmit"
IconUri="/Images/appbar.save.rest.png"
Text="Submit" Click="OnSubmitButtonClick"/>
<shell:ApplicationBarIconButton x:Name="btnBack"
IconUri="/Images/appbar.back.rest.png"
Text="Back to List" Click="OnBackButtonClick"/>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

</phone:PhoneApplicationPage>
The XAML for defining this page is similar to that of the EditForm.xaml file. You can copy the EditForm.xaml file to use as a basis for DraftItemEditForm.xaml, making the modifications to the fil

1. With the DraftItemEditForm.xaml file chosen in Solution Explorer, press F7 to open the associated code-behind file, DraftItemEditForm.xaml.cs, for editing.
2. Replace the contents of the file with the following code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.SharePoint.Client;
using Microsoft.Phone.Tasks;
using System.Device.Location;
using Microsoft.Phone.Shell;
using Microsoft.SharePoint.Phone.Application;

namespace SPListAppLocalStorage
{
public partial class DraftItemEditForm : PhoneApplicationPage
{
EditItemViewModel viewModel;

/// <summary>
/// Constructor for Draft Item Edit Form.
/// </summary>
public DraftItemEditForm()
{
InitializeComponent();
}

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)


{
// Include initialization of ViewModel here rather than in constructor to be able to use QueryString value.
if (viewModel == null)
{
viewModel = DraftItemStore.GetDraftItemById(NavigationContext.QueryString["ID"].ToString());
}

viewModel.Initialize();
this.DataContext = viewModel;

base.OnNavigatedTo(e);
viewModel.ItemUpdated += new EventHandler<ItemUpdatedEventArgs>(OnItemUpdated);
}

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)


{
base.OnNavigatedFrom(e);
viewModel.ItemUpdated -= new EventHandler<ItemUpdatedEventArgs>(OnItemUpdated);
}

private void OnViewModelInitialization(object sender, InitializationCompletedEventArgs e)


{
this.Dispatcher.BeginInvoke(() =>
{
// If initialization has failed show error message and return.
if (e.Error != null)
{
MessageBox.Show(e.Error.Message, e.Error.GetType().Name, MessageBoxButton.OK);
return;
}

// Set Page's DataContext to current ViewModel instance.


this.DataContext = (sender as EditItemViewModel);
});
}

private void OnCancelButtonClick(object sender, EventArgs e)


{
NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative));
}

private void OnSubmitButtonClick(object sender, EventArgs e)


{
viewModel.UpdateItem();
}

private void OnItemUpdated(object sender, ItemUpdatedEventArgs e)


{
this.Dispatcher.BeginInvoke(() =>
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message, e.Error.GetType().Name, MessageBoxButton.OK);
return;
}

// Remove Draft Item from local storage if update to server succeeds.


DraftItemStore.RemoveDraftItem(viewModel.ID.ToString());
this.NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative));
});
}

private void OnBackButtonClick(object sender, EventArgs e)


{
NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative));
}
}
}
As you can see, the namespace used in this file is based on the name of the project (SPListAppLocalStorage).

1. Add the appbar.back.rest.png image to your project for the ApplicationBar button (btnBack) declared in the DraftItemEditForm.xaml file. In Solution Explorer, choose the Images
folder node in the project.
2. On the Project menu, choose Add Existing Item.
3. In the browser that opens, navigate to the folder in which the standard Windows Phone icon images were installed by the Windows Phone SDK 7.1.
NOTE

The images with a light foreground and a dark background are in %PROGRAMFILES%(x86)\\Microsoft SDKs\\Windows Phone\\v7.1\\Icons\\dark in a standard installation of the SDK.
4. Choose the image file named appbar.back.rest.png, and choose Add. The image is added to the project under the Images node.
5. In Solution Explorer, choose the image file you just added, and in the Properties Window for the file, set the Build Action property for the image file to Content, and set the
Copy to Output Directory property to Copy if newer.
6. Save the files.

To add an ApplicationBar button to the Edit Form for saving an item as a draft
1. In Solution Explorer, choose the EditItemViewModel.cs file under the ViewModels node in the project. Press F7 to open the file for editing.
2. Within the code block (demarcated by opening and closing braces) that implements the EditItemViewModel class, add the following public method to the file.

public void SaveAsDraft()


{
DraftItemStore.AddDraftItem(this.ID.ToString(), this);
}

1. In Solution Explorer, under the Views node in the project, double-click the EditForm.xaml file.
The file is opened for editing in the designer.
2. In the XAML pane of the designer, add another button to the <shell:ApplicationBar> tag (in addition to the existing Submit and Cancel buttons), as shown in the following XAML.

<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="btnSubmit"
IconUri="/Images/appbar.save.rest.png"
Text="Submit" Click="OnBtnSubmitClick"/>
<shell:ApplicationBarIconButton x:Name="btnSaveDraft" IconUri="/Images/appbar.save.rest.png" Text="Save Draft" Click="OnSaveDraftButtonClick"/>
<shell:ApplicationBarIconButton x:Name="btnCancel"
IconUri="/Images/appbar.cancel.rest.png"
Text="Cancel" Click="OnCancelButtonClick"/>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

1. With the EditForm.xaml file chosen in Solution Explorer, press F7 to open the associated code-behind file, EditForm.xaml.cs, for editing.
2. Within the code block (demarcated by opening and closing braces) that implements the EditForm partial class, add the following event handler to the file.

private void OnSaveDraftButtonClick(object sender, EventArgs e)


{
viewModel.SaveAsDraft();
}

1. Save the files.

To add an ApplicationBar button to the List View Form to display all draft items
1. In Solution Explorer, under the Views node, double-click the List.xaml file.
The file is opened for editing in the designer.
2. In the XAML pane of the designer, add another button to the <shell:ApplicationBar> tag (in addition to the existing New and Refresh buttons), as shown in the following XAML
markup.

<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="btnNew"
IconUri="/Images/appbar.new.rest.png" Text="New"
Click="OnNewButtonClick"/>
<shell:ApplicationBarIconButton x:Name="btnRefresh"
IconUri="/Images/appbar.refresh.rest.png"
Text="Refresh" IsEnabled="True" Click="OnRefreshButtonClick"/>
<shell:ApplicationBarIconButton x:Name="btnDrafts" IconUri="/Images/appbar.folder.rest.png" Text="View Drafts" IsEnabled="True" Click="OnDraftsButtonClick
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

1. Add an icon image to your project for the Drafts button. In Solution Explorer, choose the Images folder node in the project.
2. On the Project menu, choose Add Existing Item.
3. In the browser that opens, navigate to the folder in which the standard Windows Phone icon images were installed by the Windows Phone SDK 7.1.
NOTE

The images with a light foreground and a dark background are in %PROGRAMFILES%(x86)\\Microsoft SDKs\\Windows Phone\\v7.1\\Icons\\dark in a standard installation of the SDK.
4. Choose the image file named appbar.folder.rest.png, and then choose Add.
The image is added is added to the project under the Images node.
5. In Solution Explorer, choose the image file you just added and in the Properties Window, set the Build Action property for the image file to Content and set the Copy to
Output Directory property to Copy if newer.
6. In Solution Explorer, choose the List.xaml file under the Views node and press F7. The associated code-behind file, List.xaml.cs, is opened for editing.
7. Add the following event handler to the file, within the code block (demarcated by opening and closing braces) that implements the ListForm partial class.

private void OnDraftsButtonClick(object sender, EventArgs e)


{
NavigationService.Navigate(new Uri("/Views/Drafts.xaml", UriKind.Relative));
}

1. Save all the files in the solution and press F6 to compile the solution.
If you start the project and deploy it to a Windows Phone Emulator, you see a View Drafts button on the ApplicationBar of the List form (Figure 1), which brings up all list items stored as
drafts.
Figure 1. Modified List Form with View Drafts button

At first, because no drafts are saved, the page to display drafts will be empty. Choose an item from the List form (to show the Display form (DisplayForm.xaml) for an item), and then choose
the Edit button to display the Edit form. If you should lose connectivity with the SharePoint Server, you can then choose the Save Draft button on the Edit Form (Figure 2) to save any
changes you've made to the list item to isolated storage.
Figure 2. Modified Edit Form with Save Draft button

When the server becomes available again, you can choose the View Drafts button on the List form to display the Drafts page (Figure 3).
Figure 3. Drafts page displaying items saved as drafts to isolated storage
If you choose an item on the Drafts page, the Draft Item Edit form (DraftItemEditForm.xaml) is displayed (Figure 4) and you can make any additional changes, and then click the Submit
button to save the edited item to the server. At that point, the item is removed from isolated storage because it's no longer treated as a draft item after it's saved with its changes to the server.
Figure 4. Draft Item Edit Form

Notice the similarity between the Draft Item Edit form (Figure 4) and the standard Edit form (Figure 2) in this app. The editing experience for items as draft items should be about the same
as the editing experience for items in the context of the Edit form.

See also
Build Windows Phone apps that access SharePoint
Local Data Storage for Windows Phone
How to: Preserve and Restore Application State for Windows Phone
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Implement business logic and data validation in a Windows Phone app for SharePoint
3/26/2018 • 11 minutes to read Edit Online

Implement data validation in a Windows Phone app created by using the Windows Phone SharePoint List Application template. In a Windows Phone app intended for production use, you
likely need to validate data entered by users to, for example, enforce business logic relevant to your particular circumstances, or to ensure appropriate formatting of entered values, or simply
to catch mistakes before saving values to a SharePoint list. Projects based on the Windows Phone SharePoint List Application template include default data validation logic, but such projects
also provide a mechanism for developers to implement custom data validation.

Important: If you are developing an app for Windows Phone 8, you must use Visual Studio Express 2012 instead of Visual Studio 2010 Express. Except for the development
environment, all information in this article applies to creating apps for both Windows Phone 8 and Windows Phone 7. > For more information, see How to: Set up an environment for
developing mobile apps for SharePoint.

Default data validation rules


Some data types for fields in SharePoint lists are associated by default with simple formatting or data validation. If you enter an invalid URL for a field based on the Hyperlink or Picture field
type in a SharePoint list and attempt to save your changes, you see a message indicating that the address you entered is invalid. If you enter a customer name as a value for a field based on
the Date and Time field type, you receive a message directing you to enter a date within a valid range for the field.
NOTE

Date input validation is with respect to SharePoint date format. If the date format of the phone locale is required, customize the field and add validations accordingly.
Some of these basic validation rules are also enforced by default in a Windows Phone app created from the Windows Phone SharePoint List Application template. If you enter anything
other than a date value in a field that is bound to a SharePoint field of Date and Time type in the Edit form of a Windows Phone app based on a SharePoint list, you see a validation error
message when the focus shifts from the TextBox control associated with the field. (See Figure 1.)
Figure 1. Validation error cue in a Windows Phone app

The text box labeled "Start Time" in the Edit form is bound to a Date and Time field in the SharePoint list on which this sample app is based. The validation error cue (in red text) shown in
Figure 1 appears if an invalid date is entered in the text box (and the text box subsequently loses focus) because the ValidatesOnNotifyDataErrors property of the Binding object
associated with the Text property of the TextBox control is set to True in the XAML declaration that defines the TextBox in the EditForm.xaml file.

<StackPanel Orientation="Vertical" Margin="0,5,0,5">


<TextBlock TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Start Time*
</TextBlock>
<TextBox Height="Auto" Style="{StaticResource TextValidationTemplate}"
FontSize="{StaticResource PhoneFontSizeNormal}" Width="470"
HorizontalAlignment="Left" Name="txtEventDate"
Text="{Binding [EventDate], Mode=TwoWay, ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True}"
TextWrapping="Wrap" />
<TextBlock FontSize="16" TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding DateTimeFormat}" />
</StackPanel>

(If the ValidatesOnNotifyDataErrors property is set to False, the user has no indication that the entered data is invalid until the Save button is chosen. At that point, the user sees an error
message regarding validation errors, because format validation on entered date values is still carried out by the base class from which the EditItemViewModel class is derived.)
But some fields may not provide any notification for invalid data in the Windows Phone app. And well-designed Visual Studio project templates are necessarily generalized to be used as a
starting point for many different applications. The Windows Phone SharePoint List Application template can't include validation rules relevant to specific contexts and yet retain its value as a
generalized template. Depending on your needs and the circumstances in which your particular Windows Phone app will be used, you likely will want to implement your own custom data-
validation rules.

Implement custom data-validation rules


You can validate data entered by users of your Windows Phone app in several ways. A project created by using the Windows Phone SharePoint List Application template includes classes
that serve as intermediaries between the forms (that is, the views) of the data in the Windows Phone app (for example, the EditForm.xaml file) and the data itself in the SharePoint list on
which the app is based. These classes can be considered implementations of the ViewModel component of the Model-View-ViewModel design pattern (Figure 2). (For more information
about how the Windows Phone SharePoint List Application template conforms to the MVVM software design pattern, see Architecture of the Windows Phone SharePoint List Application
template.)
NOTE

The SharePoint list templates do not include default validations (such as percentage complete in a SharePoint task list, post check for a team discussion list, and SP decimal field type
validation), but you can implement such validations.
Figure 2. Template files in ViewModel component

In applications designed based on the MVVM pattern, data validation is often handled in the data layer (that is, in the Model component). In projects created from the Windows Phone
SharePoint List Application template, an extensible mechanism for data validation has been "pushed up" a layer and implemented in the ViewModel component, to make it easier for
developers to manage data validation. In projects based on the template, therefore, the most suitable place for custom code that validates user input or otherwise manages data is in these
ViewModel classes. In terms of data validation, the EditItemViewModel class and the NewItemViewModel class (the classes associated with the forms most likely to involve editing and
updating list data) both provide an open implementation of a validation method (named Validate) that overrides the base validation method in the class from which these two classes are
derived.

public override void Validate(string fieldName, object value)


{
base.Validate(fieldName, value);
}

This method provides a convenient mechanism to the developer for adding custom validation logic that targets individual fields. The general approach is to check the value of the fieldName
argument passed to the Validate method to identify the field you want to associate with your custom validation code. You can, for example, use a switch statement in your implementation
of this method to supply validation logic specific to various fields in the Edit form (EditForm.xaml) of your Windows app.
For the following code example, assume that an installation of SharePoint Server has a Product Orders list created from the Custom List template. The list has been created with the columns
and field types shown in Table 1.
Table 1. Product Orders list

CO LU MN T YPE R EQ U IR ED

Product (i.e., Title) Single line of text (Text) Yes

Description Single line of text (Text) No

Quantity Number Yes

Order Date Date and Time (DateTime) No

Fulfillment Date Date and Time (DateTime) No

Contact Number Single line of text (Text) No

Again, for the purposes of this example, assume that the following simple validation rules are to be enforced, based on the business logic employed at the fictitious company Contoso, Ltd.,
for a given product ordering system:
Fulfillment dates for orders must be later than the date on which the order was placed.
If a customer wants to place an order for a product named Fuzzy Dice, the dice must be ordered in pairs. According to the peculiar rules at Contoso, Ltd., there is simply no such thing
as a Fuzzy Die.
In the Product Orders list, the field type for phone numbers is "Single line of text" (that is, Text), which can be any text (up to 255 characters by default). For this sample, a formatting
validation rule will be enforced that requires entered data to be in one of the common phone number formats; for example, "(555) 555-5555".

To implement custom validation rules


1. Assuming you have created a SharePoint list based on the Custom List template that includes the columns and types specified in Table 1, create a Windows Phone app by using the
Windows Phone SharePoint List Application template in Visual Studio by following the steps detailed in How to: Create a Windows Phone SharePoint list app.
2. In Solution Explorer, in the ViewModels folder for the project, double-click the EditItemViewModel.cs file (or choose the file and press F7) to open the file for editing.
3. Add the following using directives to the list of directives at the top of the file.

using System.Globalization;
using System.Text.RegularExpressions;

1. Replace the default implementation of the Validate method in the file with the following code.
public override void Validate(string fieldName, object value)
{
string fieldValue = value.ToString();
if (!string.IsNullOrEmpty(fieldValue)) //Allowing for blank fields.
{
bool isProperValue = false;

switch (fieldName)
{
case "Quantity":
// Enforce ordering Fuzzy Dice in pairs only.
int quantityOrdered;
isProperValue = Int32.TryParse(fieldValue, out quantityOrdered);
if (isProperValue)
{
if ((quantityOrdered % 2) != 0) // Odd number of product items ordered.
{
if ((string)this["Title"] == "Fuzzy Dice")
{
AddError("Item[Quantity]", "Fuzzy Dice must be ordered in pairs.
No such thing as a Fuzzy Die!");
}
else
{
// Restriction on ordering in pairs doesn't apply to other products.
RemoveAllErrors("Item[Quantity]");
}
}
else
{
RemoveAllErrors("Item[Quantity]");
}
}
break;
case "Fulfillment_x0020_Date":
// Determine whether fulfillment date is later than order date.
DateTime fulfillmentDate;
isProperValue = DateTime.TryParse(fieldValue, CultureInfo.CurrentCulture,
DateTimeStyles.AssumeLocal, out fulfillmentDate);
if (isProperValue)
{
DateTime orderDate;
isProperValue = DateTime.TryParse((string)this["Order_x0020_Date"],
CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal, out orderDate);

if (fulfillmentDate.CompareTo(orderDate) > 0)
{
RemoveAllErrors("Item[Fulfillment_x0020_Date]");
}
else
{
AddError("Item[Fulfillment_x0020_Date]",
"Fulfillment Date must be later than Order Date.");
}
}
break;
case "Contact_x0020_Number":
// Check that contact number is in an appropriate format.
Regex rx = new Regex(@"^\\(?([0-9]{3})\\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$");
if (rx.IsMatch(fieldValue))
{
RemoveAllErrors("Item[Contact_x0020_Number]");
}
else
{
//Specified Contact Number is not a valid phone number.
AddError("Item[Contact_x0020_Number]", "Specified Contact Number is invalid.");
}
break;
default:
// Not adding custom validation for other fields.
break;
}
}

//And then proceed with default validation from base class.


base.Validate(fieldName, value);
}

Keep in mind that the field names specified in this code sample are based on properties of the sample Product Orders list specified in Table 1. (Notice that in the XML schema for list fields in S

1. Save the file.


The custom validation code in this sample is executed only if the value argument passed to the Validate method is not a null or empty string. As indicated in Table 1, the Fulfillment Date
and Contact Number fields are not required to contain data (as the list is defined for the purposes of this sample in SharePoint Server), so we want to allow these fields to be blank. A simple
check to determine whether the value argument is null is not sufficient, because the value passed could be a zero-length string (which doesn't equate to a null value), and for this sample we
don't want to invalidate zero-length strings for fields that can be blank. The validation logic for the Quantity and Fulfillment Date fields includes additional checks of the values passed in to
ensure that they are of the appropriate type. If the initial check here (before the switch statement) confirmed only that the value passed in were not null (instead of checking against the
narrower condition of being a zero-length string), those validations would still not execute if the value were a zero-length string, but the logic to validate data for the Contact Number field
would still execute if the value passed were a zero-length string. And in this sample we want to allow for the Contact Number field to be blank (a zero-length string), especially when a user
starts editing a list item by opening the Edit form.
If you build the project and deploy it to Windows Phone Emulator to run it, you can test your validation logic by entering data that violates your business rules into the fields of the list in the
Edit form of the app. (See Figure 3.)
Figure 3. Custom validation error cues
The code in this sample, if it is included in the EditItemViewModel.cs file only, enforces these validation rules for data entered by users only on the Edit Form. If you want to enforce the
validation rules both when users add new items as well as when they edit them, you must include the same validation logic in the Validate method in the NewItemViewModel.cs file (or,
preferably, create a separate class file with a function that includes this validation logic and call that same function from the Validate methods in both the EditItemViewModel.cs file and the
NewItemViewModel.cs file).
The validation logic in this sample enforces given business rules by indicating to the user that entered data is not in a format permitted by the rules, but the entered data is not intercepted
and changed by this code. To intercept and, for example, format phone numbers in a consistent way before saving the data to the SharePoint list, you can implement custom data conversion
for entered phone numbers. For an explanation of custom data conversion for list item fields, see How to: Support and convert SharePoint field types for Windows Phone apps.

See also
Build Windows Phone apps that access SharePoint
Silverlight Data Binding
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Support and convert SharePoint field types for Windows Phone apps
3/26/2018 • 18 minutes to read Edit Online

Implement data-conversion logic to support SharePoint field types in Windows Phone apps. In projects based on the Windows Phone SharePoint List Application template, the data of many
SharePoint field types is processed and coordinated by default conversion logic to be suitable for display and manipulation in the Silverlight user interface of a Windows Phone, but
developers can also implement their own custom data handling routines.

Important: If you are developing an app for Windows Phone 8, you must use Visual Studio Express 2012 instead of Visual Studio 2010 Express. Except for the development
environment, all information in this article applies to creating apps for both Windows Phone 8 and Windows Phone 7. > For more information, see How to: Set up an environment for
developing mobile apps for SharePoint.

SharePoint field types in Windows Phone apps


SharePoint lists are constituted by fields of data (arranged in columns), and a given field is designated to contain data of a certain type (that is, data structured in a certain way). These types
are called field types. (Such types may also be called column types, because when you add a column to a SharePoint list, you are adding a column of fields associated with a certain type of
data.) These fields are defined by an XML schema. The schema for a field called "Order Date" with a DateTime data type (represented as a Date and Time field in the user interface of a
Microsoft SharePoint Server) might look like the following.

<Field Type="DateTime" DisplayName="Order Date" Required="FALSE"


EnforceUniqueValues="FALSE" Indexed="FALSE" Format="DateOnly"
FriendlyDisplayFormat="Disabled" Name="Order_x0020_Date">
<Default>[today]</Default>
<DefaultFormulaValue>2012-01-10T00:00:00Z</DefaultFormulaValue>
</Field>

Notice in particular the value of the Type attribute of the Field element in this schema, specified here as "DateTime". List fields created to contain data structured in other ways might be
designated with a Type value of, say, "Choice" or "Text" or "Boolean".
SharePoint field types cannot be bound directly to Silverlight controls in a Windows Phone app. The data as it is in the SharePoint list must be prepared or processed in a certain way (or, in
the standard terminology of Silverlight data binding, converted) in order to be bound to the controls in the app and this preparation and coordination is handled by the ViewModels in
projects created from the Windows Phone SharePoint List Application template. Projects based on this template are designed to include default conversion logic to support the binding and
display of SharePoint data in a Windows Phone app for a number of standard SharePoint field types (or for custom fields created based on one of these standard types). The field types
supported with default conversion logic are listed in Table 1.
Table 1. Field types with provisions for default conversion

S HAR EPO INT FIELD T YPE S ILV ER LIG HT D ATA T YPE

Attachments File

Boolean Boolean

Calculated (for display only) String

Choice String

Currency Numeric

DateTime Date (represented according to locale on the phone)

URL Link

Integer Numeric

Location GeoCoordinate

Lookup String

MultiChoice String

Note String

Number Numeric

OutcomeChoice String

Picture Link

Text String

User String

Other SharePoint field types, such as Guid fields, can be used in Windows Phone apps, but developers need to provide custom conversion logic to support binding and displaying values for
those field types for which no default conversion logic has been provided. (See Custom conversion logic to provision unsupported field types in this article.)
For the purpose of illustrating how the template provides default conversion and support for certain field types, assume a SharePoint list includes a column of fields named "Product
Category" designated with a type of Choice and associated with several options, such as "Recreation" and "Culinary". The schema for such a field on the server might resemble the following
markup.
<Field Type="Choice" DisplayName="Product Category" Required="FALSE"
EnforceUniqueValues="FALSE" Indexed="FALSE" Format="Dropdown"
FillInChoice="TRUE"
Name="Product_x0020_Category">
<Default>Recreation</Default>
<CHOICES>
<CHOICE>Culinary</CHOICE>
<CHOICE>Recreation</CHOICE>
<CHOICE>Sartorial</CHOICE>
<CHOICE>Travel</CHOICE>
<CHOICE>Other</CHOICE>
</CHOICES>
</Field>

This Choice field has to be processed in order to be suitable for display in the Windows Phone interface. In this case, the data in the field is represented as a string (for example, "Recreation")
within a collection of string values (specifically, as one of the values of the FieldValuesAsText property of a ListItem object). The conversion logic for Choice fields extracts this string to
display it in the phone's user interface. The string might be bound to and displayed in a TextBlock control in a form. If the value is presented for editing, the default conversion logic for
Choice fields extracts the available options for the field ("Culinary", "Recreation", "Sartorial", etc.) from the XML schema that defines the field and represents those available options a
collection (specifically, as a kind of collection based on the ObservableCollection(T) class) of objects that themselves include the specific option (for example, "Culinary") and whether that
option has been selected. These operations are all handled in the ViewModel layer of the app. In the View (or Presentation) layer (that is, in the XAML file generated for the Edit form by the
Windows Phone SharePoint List Application template), these options are rendered by default as Silverlight RadioButton controls within a ListBox control.

Custom conversion for SharePoint field types


In Visual Studio projects that are based on the Windows Phone SharePoint List Application template, the mechanism for handling the coordination and conversion of data between
SharePoint and the Windows Phone Silverlight user interface has been designed to be flexible and extensible.
Depending on the design intentions for your particular application, you may want to provide conversion logic to support binding and displaying SharePoint field types that are not provided
with conversion logic by default, or you may want to display data for a supported field in a way that differs from the default implementation.
Projects based on the Windows Phone SharePoint List Application template implement a static Converter class that includes routines for registering methods for handling data conversion
operations specific to given data types. The project includes and registers data conversion routines for certain data types by default. The registration mechanism uses delegates to allow for
extensibility. Developers can therefore write their own functions to provide the logic for data conversions and these custom functions can be called when the delegates are invoked instead of
the default functions. In order to arrange for custom functions to be called for data conversion operations, register your functions with the Converter class using the registration methods of
the class. The registration methods are specific to each ViewModel, to accommodate the possibility that you may want to implement and register different functions to process data
differently depending on, for example, whether the data will presented for editing or for viewing only (without editing).

Tip: The currency symbol shown in the display form is from SharePoint locale, even if the Windows Phone locale is different. Developers can customize this behavior by using
Converter objects.

To register data conversion functions for the Display form (DisplayForm.xaml), use the RegisterDisplayFieldValueConverter method of the Converter class. To register functions for the
Edit form (EditForm.xaml), use the RegisterEditFieldValueConverter method, and for the New form (NewForm.xaml), use the RegisterNewFieldValueConverter method.
You can register conversion functions that process data as it comes from the list to be presented in the user interface (that is, functions that determine how to get data) and you can register
functions that process data from the user interface as its saved to the list on the server (functions that determine how to set data).
The get functions must match the signature of the following delegate declaration in the Converter class.

public delegate object GetConvertedFieldValue(string fieldName,


ListItem item, ConversionContext context);

The set functions must match the signature of the following delegate declaration.

public delegate void SetConvertedFieldValue(string fieldName,


object fieldValue, ListItem item, ConversionContext context);

The RegisterDisplayFieldValueConverter method accepts a get function only, because the DisplayItemViewModel class, as designed, is intended to display but not edit data. The
RegisterEditFieldValueConverter and the RegisterNewFieldValueConverter methods are overloaded to accept a get function, a set function, or both.
In How to: Implement business logic and data validation in a Windows Phone app for SharePoint, a validation routine was developed to verify the format or phone numbers provided by the
user of a Windows Phone app. To demonstrate custom data conversion, in the following code sample, we'll implement get and set functions to handle phone number data in a particular way
and register those functions to be used in the Edit and New forms with the Converter class.
Assume for the purposes of the following code example that you have created a Windows Phone SharePoint list app based on a Product Orders list created using the Custom List template
on the server. Assume that the list has a field named "Contact Number" and that this field is designated as a Text field in the list. In the default configuration of a list field designated as a Text
type on a SharePoint Server, a user can enter any text characters (up to 255 characters). The template provides default conversion logic for displaying and editing data from Text fields in
SharePoint, but a Text field (by default) is not structured to impose or display any specific formatting, such as might be conventionally applied to phone numbers. In your Windows Phone
app, you may want phone numbers to be displayed to users in a consistent way and, when saved to the list on the server, formatted in a particular way, even though the underlying field type
( Text) is not associated with specific formatting rules. To apply your particular formatting rules, you can implement your own custom data conversion logic in place of the default logic for a
supported field type.

To implement custom data conversion


1. Assuming you have created a list on a SharePoint Server that includes a Text field named "Contact Number" (like the Product Orders sample list used in How to: Implement business
logic and data validation in a Windows Phone app for SharePoint), create a Windows Phone app using the Windows Phone SharePoint List Application template in Visual Studio by
following the steps detailed in How to: Create a Windows Phone SharePoint list app.
2. In Solution Explorer, choose the node representing the project (named, for example, ContosoSPListApp).
3. On the Project menu in Visual Studio (or Visual Studio Express for Windows Phone), choose Add Class. The Add New Item dialog box opens with the C# Class template already
chosen.
4. Specify a name for the class file (such as ContosoConverter.cs) and choose Add. The class file is added to the project and opened for editing.
5. Replace the contents of the file with the following code.
using System;
using Microsoft.SharePoint.Client; // Added for ListItem.
using Microsoft.SharePoint.Phone.Application; // Added for ConversionContext.
using System.Text.RegularExpressions;

// Specify a namespace appropriate for your particular project.


namespace ContosoSPListApp
{
public static class ContosoConverter
{
static Regex StandardNumberFormat =
new Regex(@"^\\(?([0-9]{3})\\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$", RegexOptions.Compiled);

public static object GetConvertedTextFieldValue(string fieldName,


ListItem item, ConversionContext context)
{
if (item == null) return null;

if (fieldName == "Contact_x0020_Number")
{
string contactNumber = string.Empty;
try
{
contactNumber = item.FieldValuesAsText[fieldName];
}
catch (PropertyOrFieldNotInitializedException)
{
object itemValue = item[fieldName];
if (itemValue != null)
{
contactNumber = itemValue.ToString();
}
}

// Regularize the formatting of phone number for display in UI.


if (StandardNumberFormat.IsMatch(contactNumber))
{
// Phone number is in an acceptable format, but formatting it
// in a specific way for visual consistency in the UI.
string properlyFormattedNumber =
StandardNumberFormat.Replace(contactNumber, "($1) $2-$3");
return properlyFormattedNumber;
}
else
{
// Return a representation of the data adorned in such a way
// as to designate its invalidity.
if (!contactNumber.Contains("Invalid Number"))
{
return string.Format("Invalid Number: {0}", contactNumber);
}
else
{
// Assume data is already adorned with an invalidity designation.
return contactNumber;
}
}
}
else
{
return item[fieldName];
}
}

public static void SetConvertedTextFieldValue(string fieldName,


object fieldValue, ListItem item, ConversionContext context)
{
if (fieldValue == null) return;

if (fieldName == "Contact_x0020_Number")
{
// Conventional formats (e.g., 555-555-5555) are acceptable,
// but formatting phone numbers consistently here for storage in list on Server.
string contactNumber = (string)fieldValue;

if (StandardNumberFormat.IsMatch(contactNumber))
{
string properlyFormattedNumber = StandardNumberFormat.Replace
(contactNumber, "($1) $2-$3");
item[fieldName] = properlyFormattedNumber;
}
else
{
if (!contactNumber.Contains("Invalid Number"))
{
item[fieldName] = string.Format("Invalid Number: {0}", contactNumber);
}
else
{
// Assume data is already adorned with an invalidity designation.
item[fieldName] = contactNumber;
}
}
}
else
{
// Allow values for other Text fields to be passed on to list without modification.
item[fieldName] = fieldValue;
}
}
}
}
1. Save the file.
The GetConvertedTextFieldValue function here determines whether string data from a field intended to contain a phone number (named "Contact Number" in this example) is formatted
according to standard conventions for phone numbers (in North America) and, if so, converts the number into a specific format for display, "(XXX) XXX-XXXX". If the data is not formatted as
a standard phone number, it is prefixed with a designator. This function doesn't actually change the data in the list. The SetConvertedTextFieldValue function, on the other hand, proceeds
in the opposite direction. It checks the value of data supplied for a field by a user to determine whether the supplied data matches the pattern for standard phone numbers or not. If so, the
supplied value is converted into a specific format to be saved to the list on the server. If the supplied value is not in a standard format, the value is prefixed with a designator and that prefixed
value is then saved to the server.
It remains now to register these data-conversion functions with the Converter class for use on the Edit and New forms. You can register the converters in several places. In the following
procedure, the converters are registered in the OnNavigatedTo event of the List form (List.xaml). The List form is created and navigated to before the Edit and New forms are instantiated in
the app, so the converters registered in this event in the List form will take effect for text fields in all the forms.

To register the data-conversion functions


1. In Solution Explorer for the same project in which you created the class in the previous procedure, choose the List.xaml file under the Views node.
2. Press F7 to open the associated code-behind file, List.xaml.cs, for editing.
3. Add the following private variable declaration to the top of the code block that implements the ListForm partial class, after the opening brace in the code block and before the
ListForm() constructor.

private bool _isConversionRegistered;

1. Add the following method, RegisterTextFieldValueConverters, to the file, within the code block (demarcated by opening and closing braces) that implements the ListForm partial class.

private void RegisterTextFieldValueConverters()


{
Converter.RegisterEditFieldValueConverter(FieldType.Text,
ContosoConverter.GetConvertedTextFieldValue,
ContosoConverter.SetConvertedTextFieldValue);

Converter.RegisterNewFieldValueConverter(FieldType.Text,
ContosoConverter.GetConvertedTextFieldValue,
ContosoConverter.SetConvertedTextFieldValue);
}

This method simply calls the appropriate registration methods of the **Converter** class. It is assumed for this code that the custom class containing the **get** and **set** functions created in

1. Modify the implementation of the OnNavigatedTo event handler in the file by adding a check for the value of the _isConversionRegistered flag and a call to the
RegisterTextFieldValueConverters function added in the previous step. The modified handler should be as follows.

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)


{
base.OnNavigatedTo(e);

App.MainViewModel.ViewDataLoaded +=
new EventHandler<ViewDataLoadedEventArgs>(OnViewDataLoaded);
App.MainViewModel.InitializationCompleted +=
new EventHandler<InitializationCompletedEventArgs>(OnViewModelInitialization);

// The OnNavigatedTo event can fire more than once, but the converters only need
// to be registered once, so checking the conversion flag first.
if (_isConversionRegistered == false)
{
// Register converters.
RegisterTextFieldValueConverters();
_isConversionRegistered = true;
}
}

1. Save the file.


Note that the data conversion functions are registered for all fields associated with a Text data type in the Edit and New forms. It is for this reason that the get and set functions
implemented for the ContosoConverter class created in the preceding procedure include conditional checks to process the data for a particular field only (named, in this case,
"Contact_x0020_Number"), allowing the data to "pass through" for other Text fields.

Custom conversion logic to provision unsupported field types


Even if you don't provide conversion logic in your app for Text fields, such fields can still be displayed and edited. Providing your own conversion logic for fields that are already provided
with default conversion logic gives you a greater degree of control over the format or the structure of the data in those fields if the default logic is not suited to your design intentions. For
fields with certain other data types, like Guid fields, conversion logic is not provided by default, but if you understand the mechanism (described in the preceding section) by which
conversion logic is provided for fields, it may be fairly simple to provide your own conversion logic to support field types in your app that are not supported with default logic by the
Windows Phone SharePoint List Application template.
Assume you are creating a Windows Phone app based on a SharePoint list named Product Identifiers, which includes a field with a Guid data type. For the purpose of the following code
sample, assume the list has a Product (or Title) field (of type Text) and an Identifier field (of type Guid).
NOTE

SharePoint lists with Guid fields must be created programmatically or from a list template that includes Guid fields.
In a Windows Phone app created using the template and based on this simple list, the data in Guid fields is not displayed by default. (In place of that data, a message like the following will be
displayed: "No Converter for field type 'Guid' is registered.") In the following procedure, you will include conversion logic to support Guid fields for a Windows Phone app. You add a class
that contains methods to register field value converters to display GUIDs and to generate new GUID values for added list items.

To provide conversion logic for an unsupported field type


1. In a project (named, for instance, SPListAppGuidConversion) created from the Windows Phone SharePoint List Application and based on the Product Identifiers list mentioned above,
choose the node representing the project in Solution Explorer.
2. On the Project menu, choose Add Class. The Add New Item dialog box appears with the C# Class template already selected.
3. Specify GuidConversion.cs as the name of the file and choose Add. The class file is added to the solution and opened for editing
4. Replace the contents of the file with the following code.

using System;
using Microsoft.SharePoint.Phone.Application;
using Microsoft.SharePoint.Client;

namespace SPListAppGuidConversion
{
public class GuidConversion
{
/// <summary>
/// Registers a GET converter to prepare GUID values for display.
/// </summary>
static public void RegisterDisplayFieldGuidConverter()
{
// Register GET converter to display GUID values.
Converter.RegisterDisplayFieldValueConverter(FieldType.Guid,
getConvertedFieldValue: (string fieldName, ListItem item, ConversionContext context) =>
{
string guidValue = string.Empty;

try
{
guidValue = item.FieldValuesAsText[fieldName];
}
catch (PropertyOrFieldNotInitializedException)
{
object itemValue = item[fieldName];
if (itemValue != null)
{
guidValue = itemValue.ToString();
}
}

if (string.IsNullOrWhiteSpace(guidValue))
{
return string.Format("{{{0}}}", Guid.Empty);
}
else
{
Guid g = new Guid();

if (Guid.TryParse(guidValue, out g))


{
guidValue = string.Format("{{{0}}}", g.ToString().ToUpper());
return guidValue;
}
else
{
return "Invalid Identifier (GUID)";
}
}
});
}

/// <summary>
/// Registers GET and SET converters for GUID value of new (i.e., added) list items.
/// </summary>
public static void RegisterNewFieldGuidConverter()
{
Converter.RegisterNewFieldValueConverter(FieldType.Guid,
getConvertedFieldValue: (string fieldName, ListItem item,
ConversionContext context) => Guid.NewGuid().ToString(),
setConvertedFieldValue: (string fieldName, object fieldValue,
ListItem item, ConversionContext context) =>
{
if (fieldValue == null)
{
item[fieldName] = Guid.Empty.ToString();
}
else
{
item[fieldName] = fieldValue;
}
});
}
}
}

In this custom class, the **RegisterDisplayFieldValueConverter** and the **RegisterNewFieldValueConverter** methods of the **Converter** class are called using anonymous functions (defined by a s

This approach, involving lambda expressions, is an alternative to passing named functions as parameters to the converter registration functions, which was demonstrated in an earlier procedure des

1. Save the file.


2. In Solution Explorer, choose the App.xaml file.
3. Press F7 to open the associated code-behind file, App.xaml.cs, for editing.
4. Locate the implementation of the Application_Launching event handler (which is empty in a new project created from the Windows Phone SharePoint List Application template)
and replace it with the following code.
private void Application_Launching(object sender, LaunchingEventArgs e)
{
// Register converters for GUID fields. Converters can be
// registered just once for the app.
GuidConversion.RegisterDisplayFieldGuidConverter();
GuidConversion.RegisterNewFieldGuidConverter();
}

1. For the converter logic to work for new list items (that is, to generate GUID values when items are added to the list), you need to ensure that the Identifier field of the
NewItemViewModel is bound to the New form. One way of doing this is by adding a hidden TextBlock control to NewForm.xaml with a Binding declaration for its Text property set
to the Identifier field. You can add the TextBlock control to the StackPanel container control that includes the TextBox control for the Title field, as in the following section of the markup
in the NewForm.xaml file.

...
<Grid x:Name="LayoutRoot" Background="Transparent"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;
assembly=Microsoft.Phone.Controls">
<StackPanel>
<ProgressBar Background="Red" x:Name="progressBar"
Opacity="1" HorizontalAlignment="Center" VerticalAlignment="Top"
Height="15" Width="470" IsIndeterminate="{Binding IsBusy}"
Visibility="{Binding ShowIfBusy}" />
<ScrollViewer HorizontalScrollBarVisibility="Auto" Height="700">
<Grid x:Name="ContentPanel" Width="470">
<StackPanel Margin="0,5,0,5">
<StackPanel Orientation="Vertical" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap"
HorizontalAlignment="Left" Style="{StaticResource PhoneTextNormalStyle}">
Title*</TextBlock>
<TextBox Style="{StaticResource TextValidationTemplate}"
FontSize="{StaticResource PhoneFontSizeNormal}" Width="470"
HorizontalAlignment="Left" Name="txtTitle" Text="{Binding [Title],
Mode=TwoWay, ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True}" TextWrapping="Wrap" />
<TextBlock Name="txtIdentifier" Text="{Binding [Identifier]}" Visibility="Collapsed"/>
</StackPanel>
</StackPanel>
</Grid>
</ScrollViewer>
</StackPanel>
</Grid>
...

Save the file.

If you start the project and deploy the app to the Windows Phone Emulator to run it, data in the Identifier field is displayed in the List form (List.xaml) if the corresponding field in the
SharePoint list contains a GUID value. (See Figure 1.)
Figure 1. Displaying Guid fields

In projects based on the Windows Phone SharePoint List Application template, Silverlight controls may not be added to forms and bound to field types that are not supported with default
conversion logic in the template. For the Identifiers field of the Product Identifiers list used in the preceding procedure, you could add markup to the DisplayForm.xaml file to define
additional controls to display GUID values, such as a TextBlock control and a TextBox control in a StackPanel control, which is itself contained within the Grid control of the user interface.
The markup for the added StackPanel control could resemble the following.
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal"
Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Identifier:</TextBlock>
<TextBlock Width="310" HorizontalAlignment="Left" Name="txtIdentifier"
Text="{Binding [Identifier]}" TextWrapping="Wrap" Style="
{StaticResource PhoneTextSubtleStyle}" />
</StackPanel>

Now the Identifier field is shown on the Display form as well as on the List form.

See also
Build Windows Phone apps that access SharePoint
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Customize list item queries and filter data for Windows Phone apps
3/26/2018 • 7 minutes to read Edit Online

Customize the data queries on which the views in a Windows Phone app are based. With projects created from the Windows Phone SharePoint List Application template, developers can
take advantage of a design pattern implemented in the template that allows them to customize parts of the data layer for a Windows Phone app. A view of a SharePoint list in a Windows
Phone app can be configured in Microsoft SharePoint Server and included as is in the app on the phone, or a custom view can be created for the app.

Important: If you are developing an app for Windows Phone 8, you must use Visual Studio Express 2012 instead of Visual Studio 2010 Express. Except for the development
environment, all information in this article applies to creating apps for both Windows Phone 8 and Windows Phone 7. > For more information, see How to: Set up an environment for
developing mobile apps for SharePoint.

Configure list views on the server for use in Windows Phone apps
When you create a SharePoint list app for a Windows Phone by using the Windows Phone SharePoint List Application template, you can choose to include in your app any existing views
that are associated with the target SharePoint list. One of the ways to filter items in a SharePoint list as the list appears on the phone, then, is to configure a filtered view for the list on the
server and then to select that view to be included in your Windows Phone app. The Windows Phone SharePoint List Application template wizard generates a Collaborative Application
Markup Language (CAML) query for the selected view that includes the filtering conditions configured for the view on the server. You might, for example, have a list on the server that is
based on the Tasks list template. You can create a view for the list named "Holiday Party" that includes only items related to, for example, planning a company holiday party by adding a filter
condition to show list items only when the Description field contains the words "holiday" or "party". In the Windows Phone app, the CAML markup generated for the view would resemble
the following (depending on the fields chosen to be included in your app).

<View>
<Query>
<Where>
<Or>
<Contains>
<FieldRef Name='Body' />
<Value Type='Note'>holiday</Value>
</Contains>
<Contains>
<FieldRef Name='Body' />
<Value Type='Note'>party</Value>
</Contains>
</Or>
</Where>
</Query>
<RowLimit>30</RowLimit>
<ViewFields>
<FieldRef Name='Title'/>
<FieldRef Name='Body'/>
<FieldRef Name='AssignedTo'/>
<FieldRef Name='Status'/>
<FieldRef Name='PercentComplete'/>
<FieldRef Name='StartDate'/>
<FieldRef Name='DueDate'/>
<FieldRef Name='Checkmark'/>
</ViewFields>
</View>

As with other existing views for the Tasks list that you choose to include in your Windows Phone app when you create your project, a PivotItem control corresponding to the chosen view is
added to the Pivot control that constitutes the main user interface (UI) element in the app.

Customize list view queries in the Windows Phone app


For one reason or another, it may not be possible or reasonable to configure views that meet all of your design needs for a given list on the server. In a Microsoft Visual Studio project created
from the Windows Phone SharePoint List Application template, aspects of what may be called the data layer are made available to developers, primarily through the ListDataProvider.cs file
in the project. You can modify the CAML defined for an existing view, or you can add CAML queries for new views in the ListDataProvider.cs file.

The ListDataProvider.cs file


In a project based on the Windows Phone SharePoint List Application template, the ListDataProvider.cs file defines objects that provide for accessing and configuring a SharePoint list as a
data source for the views in the Windows Phone app. In the List.xaml file, which defines the main application page for the app, a Pivot control (itself containing the child PivotItem controls)
is declared with an event handler assigned to its LoadedPivotItem event. The LoadDataFromServer method in the ListDataProvider.cs file is ultimately called when a PivotItem control
(which is used as the rendering container for list items in the Windows Phone app) is loaded on the main application page of the app.
1. The PivotItem associated with a given list view is loaded in the UI.
2. In the List.xaml.cs file, the handler for the LoadedPivotItem event calls the LoadData method implemented in the ListViewModel.cs file, passing the name of the PivotItem control
that has finished loading. (In the design of projects based on the Windows Phone SharePoint List Application template, the name of a given PivotItem control is set to be the same as
the key value for the CAML query string for the view associated with that control in the ViewXmls Dictionary type defined in the CamlQueryBuilder class in ListViewModel.cs.)
3. The LoadData method in ListViewModel.cs calls the LoadData method implemented in the ListDataProvider.cs file.
4. The LoadData method in ListDataProvider.cs calls the LoadDataFromServer method also implemented in that same file. The LoadDataFromServer method then does the
following:
5. Gets the CAML query string associated with a given view.

CamlQuery query = CamlQueryBuilder.GetCamlQuery(ViewName);

1. Registers with the client object model the list to be retrieved.

ListItemCollection items = Context.Web.Lists.GetByTitle(ListTitle).GetItems(query);

1. Indicates to the client object model that it should return the list items and the fields of those list items (as text values).
Context.Load(items);
Context.Load(items, listItems => listItems.Include(item => item.FieldValuesAsText));

1. Calls ExecuteQueryAsync to send the requests to SharePoint Server and retrieve the data (asynchronously).

Add a custom list view query and corresponding UI elements


In your own projects, you can take advantage of the way the data layer is designed to add your own custom CAML query strings and list views.
For the following code sample, assume again that the target installation of SharePoint Server has a Product Orders list created from the Custom List template, configured with the fields and
types indicated in Table 1 in the topic How to: Implement business logic and data validation in a Windows Phone app for SharePoint. Create a project based on the Windows Phone
SharePoint List Application template that uses a list like the Product Orders list as a source (as described in How to: Create a Windows Phone SharePoint list app). For the purposes of this
example, we add a custom view to the Windows Phone app (not to the list on the server.md) that is filtered to display only those product orders in which the quantity ordered is 100 or more.

To add a custom query and view


1. In Solution Explorer, double-click the ListDataProvider.cs file (or choose the file and press F7) to open the file for editing.
2. Update the definition of the ViewXmls Dictionary type in the static CamlQueryBuilder class to include an additional CAML query, with a WHERE clause stipulating the
appropriate filtering condition.

static Dictionary<string, string> ViewXmls = new Dictionary<string, string>()


{
{"View1", @"<View><Query><OrderBy><FieldRef Name='ID'/>
</OrderBy></Query><RowLimit>30</RowLimit><ViewFields>{0}</ViewFields></View>"},
{"View2", @"<View><Query><OrderBy><FieldRef Name='ID' /></OrderBy>
<Where><Geq><FieldRef Name='Quantity' />
<ValueType='Number'>100</Value>
</Geq></Where>
</Query><RowLimit>30</RowLimit>
<ViewFields>{0}</ViewFields></View>"}
};

1. Double-click the List.xaml file to open the file for editing.


2. Add markup to define an additional child PivotItem control within the main Pivot control. The Grid element in which the UI elements that define the main application page are
declared should resemble the following code.

<Grid x:Name="LayoutRoot" Background="Transparent"


xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls">
<!--Pivot Control-->
<ProgressBar x:Name="progressBar" Opacity="1" HorizontalAlignment="Center"
VerticalAlignment="Top" Height="30" Width="470" IsIndeterminate="{Binding IsBusy}"
Visibility="{Binding ShowIfBusy}" />
<Grid x:Name="ContentPanel" Grid.Row="0" Width="470">
<controls:Pivot Name="Views" Title="Product Orders" LoadedPivotItem="OnPivotItemLoaded">
<!--Pivot item-->
<controls:PivotItem Name="View1" Header="All Items">
<!--Double line list with text wrapping-->
<ListBox x:Name="lstBox1" Margin="0,0,-12,0" SelectionChanged="OnSelectionChanged"
ItemsSource="{Binding [View1]}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="10">
<TextBlock Name="txtTitle" Text="{Binding [Title]}"
TextWrapping="NoWrap" Style="{StaticResource PhoneTextTitle2Style}" />
<TextBlock Name="txtDescription" Text="{Binding [Description]}"
TextWrapping="NoWrap" Style="{StaticResource PhoneTextNormalStyle}" />
<TextBlock Name="txtQuantity" Text="{Binding [Quantity]}"
TextWrapping="NoWrap" Style="{StaticResource PhoneTextNormalStyle}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PivotItem>

<!--Added PivotItem control for customized view--><controls:PivotItem Name="View2" Header="Big Orders"><!--Double line list with text wrapping--><ListBox x:Name="lstBox2" Margin="0,0,
SelectionChanged="OnSelectionChanged" ItemsSource="{Binding [View2]}"><ListBox.ItemTemplate><DataTemplate><StackPanel Orientation="Vertical" Margin="10"><TextBlock Name="txtTitle
TextWrapping="NoWrap" Style="{StaticResource PhoneTextTitle2Style}" /><TextBlock Name="txtDescription" Text="{Binding [Description]}"
TextWrapping="NoWrap" Style="{StaticResource PhoneTextNormalStyle}" /><TextBlock Name="txtQuantity" Text="{Binding [Quantity]}"
TextWrapping="NoWrap" Style="{StaticResource PhoneTextNormalStyle}" /></StackPanel></DataTemplate></ListBox.ItemTemplate></ListBox></controls:PivotItem>

</controls:Pivot>
</Grid>
</Grid>

> [!NOTE]
> In particular that the value of the **Name** attribute ("View2") of the **PivotItem** control is the same as the key value of the entry added to the **Dictionary** type defined in step 2. This

When you start your project (by pressing F5), the Pivot control for the app includes the two PivotItem controls and the data retrieved by the CAML queries associated with their respective
views. The default All Items view displays all the orders, as shown in Figure 1 (with sample data).
Figure 1. All orders (list items) in a sample list
And the custom view, as defined in the preceding procedure, displays a filtered list of items that includes only those orders for which a quantity of 100 or more is specified, as shown in
Figure 2.
Figure 2. Only the big orders

You can make many other customizations both to the CAML queries on which views are based and to the UI elements associated with views.

See also
Build Windows Phone apps that access SharePoint
Introduction to Collaborative Application Markup Language (CAML)
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Customize the user interface of a SharePoint list app for Windows Phone
3/26/2018 • 15 minutes to read Edit Online

Customize the Windows Phone user interface generated by the Windows Phone SharePoint List Application template. SharePoint list apps created from the Windows Phone SharePoint List
Application template are based on the Silverlight for Windows Phone framework. All of the capabilities provided by the Silverlight platform on a Windows Phone are available to developers
for customizing the user interface (UI) of a SharePoint list app designed for a Windows Phone.

Important: If you are developing an app for Windows Phone 8, you must use Visual Studio Express 2012 instead of Visual Studio 2010 Express. Except for the development
environment, all information in this article applies to creating apps for both Windows Phone 8 and Windows Phone 7. > For more information, see How to: Set up an environment for
developing mobile apps for SharePoint.

Create a SharePoint list app for user interface customizations


For the following procedures, assume a server running SharePoint Server has a Product Orders list created from the Custom List template, similar to the sample Product Orders list used in
How to: Implement business logic and data validation in a Windows Phone app for SharePoint. For the sample Windows Phone app used in this topic, the Product Orders list on which the
app is based has been modified to include additional fields. The modified Product Orders list used for the purposes of the examples in this topic has been created with the columns and field
types shown in Table 1.
Table 1. Modified Product Orders list

CO LU MN T YPE R EQ U IR ED

Product (i.e., Title) Single line of text (Text) Yes

Description Single line of text (Text) No

Product Category Choice No

Quantity Number Yes

Order Date Date and Time (DateTime) No

Fulfillment Date Date and Time (DateTime) No

Rush Boolean No

Contact Number Single line of text (Text) No

Follow the procedures in How to: Create a Windows Phone SharePoint list app to use the Windows Phone SharePoint List Application template to generate a SharePoint list app as a
starting point for the following UI customizations. Specify as the target SharePoint list for the app a list that has a schema similar to what is represented in Table 1.

Replace TextBox controls with DatePicker controls


Based on the project as generated by the template, fields in the list designated as DateTime fields (as, for example, the Order Date field in the sample Product Orders list) are bound by
default to TextBox controls in the Edit form (EditForm.xaml) and the New form (NewForm.xaml) in the app. The first improvement you will make to the user interface is to facilitate entering
date values for such fields by replacing their associated TextBox controls with DatePicker controls from the Silverlight for Windows Phone Toolkit. You can install Silverlight for Windows
Phone Toolkit from the CodePlex Website, a hosting site for open-source software projects.

To replace TextBox controls with DatePicker controls


1. In Microsoft Visual Studio 2010, if the project is not opened already, open the project you created in the preceding section, based on the Windows Phone SharePoint List Application
template and using a SharePoint list like the Product Orders list represented in Table 1.
2. On the Project menu in Visual Studio, click Add Reference. The Add Reference dialog box appears.
3. On the Browse tab, navigate to the Microsoft.Phone.Controls.Toolkit.dll assembly installed by the Silverlight for Windows Phone Toolkit.
NOTE

The Microsoft.Phone.Controls.Toolkit.dll assembly can be found in %PROGRAMFILES%(x86)\Microsoft SDKs\Windows Phone\v7.1\Toolkit\< MonthYear >\Bin in a standard
installation of the Toolkit, where < MonthYear > may be something like "Oct11", depending on the version of the Toolkit installed. (Or you can find the assemblies installed by the
Toolkit on your system by clicking the Start button, pointing to All Programs, expanding the Microsoft Silverlight for Windows Phone Toolkit item in the Programs menu, and
clicking Binaries.)
4. In Solution Explorer, select the EditForm.xaml file under the Views node.
5. Press SHIFT + F7 (or double-click the file) to open the file in the designer.
6. In the XAML pane of the designer, add a namespace declaration for distinguishing the controls in the Toolkit assembly to the <phone:PhoneApplicationPage> tag.

<phone:PhoneApplicationPage
x:Class="ContosoSPListApp.EditForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True" x:Name = "EditPage">
The only change to the default markup generated by the template is the addition of the "xmlns:toolkit" namespace designation. Also note that the value of the **Class** attribute here is based on

1. In the EditForm.xaml file, locate the StackPanel control in the markup that contains the controls associated with the Order Date field (designated as "Order_x0020_Date" in the XML
schema for the field). By default, the template generates a TextBox control and two TextBlock controls for DateTime fields. The markup for the StackPanel control and the controls it
contains should resemble the following markup.

<StackPanel Orientation="Vertical" Margin="0,5,0,5">


<TextBlock TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Order Date</TextBlock>
<TextBox Height="Auto" Style="{StaticResource TextValidationTemplate}"
FontSize="{StaticResource PhoneFontSizeNormal}" Width="470"
HorizontalAlignment="Left" Name="txtOrder_x0020_Date"
Text="{Binding [Order_x0020_Date], Mode=TwoWay, ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True}" TextWrapping="Wrap" />
<TextBlock FontSize="16" TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding DateTimeFormat}" />
</StackPanel>

1. Replace that StackPanel control and the controls it contains with the following markup.

<StackPanel Orientation="Vertical" Margin="0,5,0,5">


<toolkit:DatePicker Header="Order Date" Value="{Binding [Order_x0020_Date], Mode=TwoWay}">
</toolkit:DatePicker>
</StackPanel>

1. Next, locate (also in EditForm.xaml) the StackPanel control in the markup that contains the controls associated with the Fulfillment Date field (designated as "Fulfillment_x0020_Date" in
the schema for the field). The markup for the StackPanel and the controls it contains should resemble the following markup.

<StackPanel Orientation="Vertical" Margin="0,5,0,5">


<TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextNormalStyle}">Fulfillment Date</TextBlock>
<TextBox Height="Auto" Style="{StaticResource TextValidationTemplate}"
FontSize="{StaticResource PhoneFontSizeNormal}" Width="470" HorizontalAlignment="Left"
Name="txtFulfillment_x0020_Date" Text="{Binding [Fulfillment_x0020_Date],
Mode=TwoWay, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True}"
TextWrapping="Wrap" />
<TextBlock FontSize="16" TextWrapping="Wrap" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding DateTimeFormat}" />
</StackPanel>

1. Replace that StackPanel control and the controls it contains with the following markup.

<StackPanel Orientation="Vertical" Margin="0,5,0,5">


<toolkit:DatePicker Header="Fulfillment Date" Value="{Binding [Fulfillment_x0020_Date], Mode=TwoWay}"></toolkit:DatePicker>
</StackPanel>

1. Finally, you can add user interface icon images from the Silverlight for Windows Phone Toolkit to your project. In Solution Explorer, select the node representing the project (named,
for example, "ContosoSPListApp").
2. On the Project menu in Visual Studio, click New Folder. A new folder is added under the project node. Name the folder "Toolkit.Content".
3. In Solution Explorer, select the folder you created in the preceding step.
4. On the Project menu, click Add Existing Item. A File Browser window opens.
5. Navigate to the folder where the supporting icon images, ApplicationBar.Cancel.png and ApplicationBar.Check.png, were installed by the Silverlight for Windows Phone Toolkit.
NOTE

The images are in %PROGRAMFILES%(x86)\Microsoft SDKs\Windows Phone\v7.1\Toolkit\< MonthYear >\Bin\Icons in a standard installation of the Toolkit, where < MonthYear >
may be something like "Oct11", depending on the version of the Toolkit installed.
6. Select both images and click Add. The image files are added to the project under the Toolkit.Content folder node.

Important: For the components of the Silverlight for Windows Phone Toolkit to be able to use the icon images, they must be placed in the location in your projected as specified
in the preceding steps.

7. In Solution Explorer, select both image files under the Toolkit.Content folder.
8. In the Properties Window, set the Build Action property for the images to "Content" and set the Copy to Output Directory property to "Copy if newer".
NOTE

If the Properties Window is not visible, press CTRL + W and then P to display the window in Visual Studio.
If you start the project (by pressing F5) to deploy it to the Windows Phone Emulator, you can navigate to the Edit form for an item (by clicking an item in the main List View page and
then clicking the Edit button on the Application Bar in the app). The DateTime fields in the form are now associated with the DatePicker control, as shown in Figure 1.
Figure 1. Edit form with DatePicker control
The DatePicker control (highlighted for the Order Date field in Figure 1) looks very much like a TextBox control with an associated TextBlock as a label, except that when you click the
DatePicker control (or tap it on a Windows Phone device), the control displays a separate page with controls for selecting dates using gestures, as shown in Figure 2.
Figure 2. Date chooser page

Clicking the Done button transfers the chosen date to the DatePicker control on the Edit form. If you then click the Save button on that form, the values of the DateTime fields associated
with the DatePicker controls are updated in the SharePoint list on the server, because the Value properties of the controls were bound to the appropriate fields in the EditForm.xaml file in
the procedure above. If you wanted to replace TextBox controls with DatePicker controls in the New form as well, you would repeat Steps 4 through 10 of the procedure for the
NewForm.xaml file in the project.

Add controls to support custom fill-in options for Choice fields


Fields designated with the Choice field type in a SharePoint list can be configured on a SharePoint Server to allow users to specify custom (or "fill-in") choice values for a field, in addition to
any declared choice values that may be assigned to a Choice field when it is defined on the server. In projects created from the Windows Phone SharePoint List Application template, Choice
fields are not rendered by default to include UI support for entering "fill-in" options. In the procedures in this section, you will add UI controls and code to your app to support entering
custom choice values for the Product Category field.
In the following procedures, you will:
Add a class ( ContosoConverter) with conversion logic to process data to be saved to the Product Category Choice field.
Add a property member ( OtherCategoryValue) to the EditItemViewModel class that provides access to a string representing the "fill-in" value for the Choice field. This property
member will serve as the source in a Binding declaration for an added TextBox control on the Edit form.
Add a RadioButton control and a TextBox control to the Edit form for users to be able to specify a "fill-in" choice value for the Product Category field.
Modify the code-behind file, EditForm.xaml.cs, associated with the Edit form to register an edit field value converter set function for Choice fields and implement event handlers for
the controls added to the Edit form.
NOTE

For more information about field value converters, see How to: Support and convert SharePoint field types for Windows Phone apps.

To add a class to support data conversion for Choice fields


1. In Solution Explorer, select the node representing the project (named, for example, ContosoSPListApp).
2. On the Project menu in Visual Studio (or Visual Studio Express for Windows Phone), click Add Class. The Add New Item dialog box opens with the C# Class template already
selected.
3. Specify a name for the class file (as, for example, ContosoConverter.cs) and click Add. The class file is added to the project and opened for editing.
4. Replace the contents of the file with the following code.

using System;
using System.Net;
using System.Windows;
using System.Collections.ObjectModel;
using Microsoft.SharePoint.Phone.Application;
using Microsoft.SharePoint.Client;

namespace SPListAppUICustomization
{
public class ContosoConverter
{
// Edit Field Value Converter SET function for Choice fields.
public static void SetConvertedChoiceEditFieldValue(string fieldName, object fieldValue,
ListItem item, ConversionContext context, string customCategory)
{
ObservableCollection<ChoiceFieldViewModel> choices = fieldValue as
ObservableCollection<ChoiceFieldViewModel>;
bool isCustomValue = true;

string specifiedChoice = string.Empty;

if (choices != null)
{
foreach (ChoiceFieldViewModel choiceItem in choices)
{
if ((choiceItem.IsChecked == true) || (choiceItem.Name.Equals(customCategory,
StringComparison.CurrentCultureIgnoreCase)))
{
specifiedChoice = choiceItem.Name;
isCustomValue = false;
break;
}
}

if (isCustomValue == true)
{
specifiedChoice = customCategory;
}
}
else
{
specifiedChoice = customCategory;
}

item[fieldName] = specifiedChoice;
}
}
}

1. Save the file.


The SetConvertedChoiceEditFieldValue function here is used for the implementation of the edit field value converter set function delegate registered for Choice fields in the app. The
function iterates through the collection of ChoiceFieldViewModel objects passed as the fieldValue argument. ChoiceFieldViewModel objects are used to represent individual values for
Choice fields in projects based on the Windows Phone SharePoint List Application template. Each object has a Name property that represents a given choice and a Boolean property (
IsChecked) indicating whether a given choice value (of those values available for a field as was defined) is the value specified for the field. The SetConvertedChoiceEditFieldValue
function determines whether a ChoiceFieldViewModel object in the collection is checked or whether the Name property of an object matches a specified custom value for the Product
Category field. If so, the Name property of that ChoiceFieldViewModel object is used to set the value of the field. Otherwise, a specified custom value (from the customCategory
argument) is set as the value of the field.
Next you will add a property member to the EditItemViewModel class that provides access to the "fill-in" value for a Choice field (or an empty string if the specified value of the Choice
field is one of the available choices defined for the field on the server).

To add a property member to the EditItemViewModel class


1. In Solution Explorer, under the ViewModels folder node, select the EditItemViewModel.cs file.
2. Press F7 (or double-click the file) to open the file for editing.
3. After the default using directives in the file, add the following directive.

using System.Collections.ObjectModel;

1. Add the following implementation of a property member (named OtherCategoryValue) to the file, within the code block (demarcated by opening and closing braces) that implements
the EditItemViewModel class.
public string OtherCategoryValue
{
get
{
string specifiedCategory = string.Empty;

// See if specified Choice field value is one of the available values


// from the List ViewModel. If it is, return an empty string.
ObservableCollection<ChoiceFieldViewModel> choicesCollection = this["Product_x0020_Category"] as
ObservableCollection<ChoiceFieldViewModel>;
if (choicesCollection != null &amp;&amp; choicesCollection.Any(choice => choice.IsChecked))
{
return specifiedCategory;
}

// If Choice field value is not one of the values from the List ViewModel,
// get the value from the underlying list item and return value as string.
specifiedCategory = SharePointListItem.FieldValuesAsText["Product_x0020_Category"];
return specifiedCategory;
}
}

1. Save the file.


Next, you will add controls to the Edit form and configure those controls to support entering custom values for the Product Category field.

To add and configure UI controls for entering custom Choice field values
1. In Solution Explorer, select the EditForm.xaml file under the Views folder node.
2. Press SHIFT + F7 (or double-click the file) to open the file in the designer.
3. Locate the StackPanel control that contains the controls (a TextBlock control and a ListBox control) for rendering the Product Category field from the Product Orders SharePoint
list. Add and configure a RadioButton control and another TextBox control to the StackPanel container, as shown in the following code.

<StackPanel Orientation="Vertical" Margin="0,5,0,5">


<TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource PhoneTextNormalStyle}">
Product Category</TextBlock>
<ListBox MaxHeight="400" Width="Auto" x:Name="lstBoxProduct_x0020_Category"
ItemsSource="{Binding [Product_x0020_Category]}">
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton FontSize="{StaticResource PhoneFontSizeNormal}" HorizontalAlignment="Left"
GroupName="Product_x0020_Category" Content="{Binding Name}"
IsChecked="{Binding IsChecked, Mode=TwoWay}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- The following two controls added to support UI Customization for Choice field. -->
<RadioButton x:Name="rbOtherCategory" FontSize="{StaticResource PhoneFontSizeNormal}" HorizontalAlignment="Left" GroupName="Product_x0020_Category" Content="Other:" IsChecked ="True" /><TextB
</StackPanel>

1. With the EditForm.xaml file selected in Solution Explorer, press F7 to open its associated code-behind file, EditForm.xaml.cs, for editing.
2. Modify the constructor in the file to add a handler, EditForm_Loaded, for the Loaded event. The modified constructor should match the constructor in the following code.

public EditForm()
{
InitializeComponent();

viewModel = App.MainViewModel.SelectedItemEditViewModelInstance;
if (!viewModel.IsInitialized)
{
viewModel.InitializationCompleted += new
EventHandler<InitializationCompletedEventArgs>(OnViewModelInitialization);
viewModel.Initialize();
}
else
{
this.DataContext = viewModel;
}

// Adding handler for Loaded event.


this.Loaded += new RoutedEventHandler(EditForm_Loaded);
}

1. Add the following implementation for the EditForm_Loaded event handler to the file, within the code block (demarcated by opening and closing braces) that implements the EditForm
partial class.
private void EditForm_Loaded(object sender, RoutedEventArgs e)
{
// Register EditFieldValueConverter SET function on Choice fields.
Converter.RegisterEditFieldValueConverter(FieldType.Choice,
(string fieldName, object fieldValue, ListItem item,
ConversionContext context) =>
{
string otherCategoryValue = string.Empty;
if (this.rbOtherCategory.IsChecked == true)
{
otherCategoryValue = this.txtOtherCategory.Text.Trim();
if (string.IsNullOrWhiteSpace(OtherCategoryValue))
{
otherCategoryValue = "(Unspecified)";
}
}

ContosoConverter.SetConvertedChoiceEditFieldValue(fieldName,
fieldValue, item, context, otherCategoryValue);
});

// Adding RadioButton event handlers here because the


// txtOtherCategory TextBox will be loaded and available at this point.
this.rbOtherCategory.Checked += new RoutedEventHandler(rbOtherCategory_Checked);
this.rbOtherCategory.Unchecked += new RoutedEventHandler(rbOtherCategory_Unchecked);
}

In this code, the lambda statement used in the call to the **RegisterEditFieldValueConverter** method of the **Converter** class determines whether the **rbOtherCategory** **RadioButton** control

1. Finally, add handlers for the Checked and Unchecked events of the rbOtherCategory RadioButton to show or hide the TextBox control used to provide custom Product Category
values. Include the following implementations for these handlers in the EditForm.xaml.cs file, again within the code block that implements the EditForm partial class.

private void rbOtherCategory_Checked(object sender, RoutedEventArgs e)


{
this.txtOtherCategory.Visibility = System.Windows.Visibility.Visible;
this.txtOtherCategory.Focus();
}

private void rbOtherCategory_Unchecked(object sender, RoutedEventArgs e)


{
this.txtOtherCategory.Visibility = System.Windows.Visibility.Collapsed;
}

1. Save the file.


If you build the project and deploy it to a Windows Phone Emulator (by pressing F5), you can see that in the Edit form, a RadioButton control is added for each choice value designated in
the Product Category field definition, based on the default UI rendering logic for Choice fields. In addition, another RadioButton control (labeled as "Other:" in the UI) is included for users
to be able to specify custom choice values. If the additional RadioButton control is checked, a TextBox control is displayed for entering the intended value.
For items in the Product Orders list that are already associated with a custom Product Category value and then edited in the app, the Edit form is rendered with the additional RadioButton
control already checked and the TextBox control displaying the custom value already visible.

See also
Build Windows Phone apps that access SharePoint
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Use multiple SharePoint lists in a Windows Phone app
3/26/2018 • 21 minutes to read Edit Online

Create Windows Phone apps that use data from multiple SharePoint lists. You can use multiple SharePoint lists in your app in several ways. When you create a Windows Phone app based
on the Windows Phone SharePoint List Application template, you specify a single target SharePoint list, but the architecture of the resulting project is extensible enough to accommodate the
integration of multiple lists.

Important: If you are developing an app for Windows Phone 8, you must use Visual Studio Express 2012 instead of Visual Studio 2010 Express. Except for the development
environment, all information in this article applies to creating apps for both Windows Phone 8 and Windows Phone 7. > For more information, see How to: Set up an environment for
developing mobile apps for SharePoint.

Create a solution involving SharePoint lists based on the same schema


If you have two SharePoint lists based on the same schema, you can take advantage of the classes implemented by the Windows Phone SharePoint List Application template and create
objects of those classes specific to each list.
Suppose you have two SharePoint lists based on the Contacts list template. One list, named, for instance, Marketing Team, contains members of a marketing team at your organization, and
the other list, Engineering Team, contains members of an engineering team. If you create a project using the Windows Phone SharePoint List Application template and specify the Marketing
Team list as the target list on which to base the project, an instance of the ListDataProvider class is created (named DataProvider by default) in the implementation of the App class in the
App.xaml.cs file in the project. This object represents the list (that is, the Marketing Team) list as a data source for the app, providing operations to access and manipulate items in the list. An
instance of the ListViewModel class is also created for the list on which the app is based. This object has a property member (which also happens to be named DataProvider) that can be
set to a given instance of the ListDataProvider class, establishing the data source for the ListViewModel class instance.
You can create an additional instance of the ListDataProvider class in the project to serve as the data source for the second list (Engineering Team) in the App.xaml.cs file. The object is
called SecondaryDataProvider in the following code.

private static ListDataProvider m_SecondaryDataProvider;

public static ListDataProvider SecondaryDataProvider


{
get
{
if (m_SecondaryDataProvider != null)
return m_SecondaryDataProvider;

m_SecondaryDataProvider = new ListDataProvider();


m_SecondaryDataProvider.ListTitle = "Engineering Team";
m_SecondaryDataProvider.SiteUrl = new Uri("http://contoso:2012/sites/samplesite/");

return m_SecondaryDataProvider;
}
}

Then you can instantiate another object of the ListViewModel class (named, for instance, SecondaryViewModel) and assign the SecondaryDataProvider object to its DataProvider
property, as in the following code.

private static ListViewModel m_SecondaryViewModel;

public static ListViewModel SecondaryViewModel


{
get
{
if (m_SecondaryViewModel == null)
m_SecondaryViewModel = new ListViewModel { DataProvider = App.SecondaryDataProvider };

return m_SecondaryViewModel;
}
set
{
m_SecondaryViewModel = value;
}
}

If the same fields and views for the two lists are suitable for your purposes (and, again, if the two lists have the same columns and fields), you don't need to make any changes in the
implementation of the ListDataProvider class (in the ListDataProvider.cs file).
To display or modify the data from the second list in your project, however, you need to add view forms to your project that are bound to and configured for this SecondaryViewModel. For
example, you could add a folder to your project named "SecondaryViews" and add a SecondaryList.xaml file to that folder with markup similar to that of the default List.xaml file generated
by the template for the primary list in the project. Note that you should distinguish your secondary List form from the primary List form in the app by specifying a distinguishing value for
the x:Class attribute of the PhoneApplicationPage element in the SecondaryList.xaml file.
<phone:PhoneApplicationPage
x:Class="MultipleSPListApp.SecondaryViews.ListForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
shell:SystemTray.IsVisible="True" x:Name = "ListViewPage">
...
</phone:PhoneApplicationPage>

In the associated code-behind file, SecondaryList.xaml.cs, replace all references to "App.MainViewModel" with references to "App.SecondaryViewModel". For example, the constructor in the
file should be as follows.

public ListForm()
{
InitializeComponent();
this.DataContext = App.SecondaryViewModel;
}

Also replace all references in the code-behind file to "App.DataProvider" with references to "App.SecondaryDataProvider" and update any navigation paths to point to the appropriate
secondary XAML pages. If you also add a secondary New form to your project (named, for example, SecondaryNewForm.xaml in the SecondaryViews folder of your project), the handler in
the SecondaryList.xaml.cs file for the OnNewButtonClick event would resemble the following code.

private void OnNewButtonClick(object sender, EventArgs e)


{
// Instantiate a new instance of NewItemViewModel and go to NewForm.
App.SecondaryViewModel.CreateItemViewModelInstance = new NewItemViewModel { DataProvider = App.SecondaryDataProvider };
NavigationService.Navigate(new Uri("/SecondaryViews/SecondaryNewForm.xaml", UriKind.Relative));
}

Finally, you can add a button to the ApplicationBar in the List.xaml file to display the SecondaryList.xaml page.

...
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="btnNew" IconUri="/Images/appbar.new.rest.png" Text="New" Click="OnNewButtonClick"/>
<shell:ApplicationBarIconButton x:Name="btnRefresh" IconUri="/Images/appbar.refresh.rest.png" Text="Refresh" IsEnabled="True" Click="OnRefreshButtonClick"/>
<!--Add the following button to navigate to the secondary list (Engineering Team).-->
<shell:ApplicationBarIconButton x:Name="btnSecondaryList" IconUri="/Images/appbar.upload.rest.png" Text="Engineering" IsEnabled="True" Click="OnSecondaryListButtonClick"/>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
...

In the associated code-behind file, List.xaml.cs, add a handler for the OnSecondaryListButtonClick event declared in the List.xaml file.

private void OnSecondaryListButtonClick(object sender, EventArgs e)


{
NavigationService.Navigate(new Uri("/SecondaryViews/SecondaryList.xaml", UriKind.Relative));
}

Users of your app can then navigate between the Marketing Team list and the Engineering Team list. Because the underlying list schemas are the same, the default DataProvider and
MainViewModel objects generated by the template and the added SecondaryDataProvider and SecondaryViewModel objects handle all the data transactions without requiring any
modifications to the ListDataProvider.cs file.

Create a solution involving SharePoint lists based on different schemas


The approach in the preceding section works as far as it goes (that is, for SharePoint lists based on the same schema) but the ListDataProvider class in the Windows Phone SharePoint List
Application template is available to developers for customization to handle multiple SharePoint lists that may not be based on the same schema or may not include the same columns and
fields.
Suppose, as in the preceding section, that you have a SharePoint list, Marketing Team (based on the Contacts list template), containing members of a marketing team. Suppose also that you
have a second list, named Orders (based on the Custom list template), containing the columns and field types shown in Table 1.
Table 1. Columns and fields for Orders list

CO LU MN FIELD T YPE R EQ U IR ED

Product (i.e., Title) Single line of text (Text) Yes

Unit Price Currency Yes

Quantity Number No (defaults to zero)

Order Value Calculated (Unit Price * Quantity) No


CO LU MN FIELD T YPE R EQ U IR ED

Order Date Date and Time (Datetime) No

Order Status Choice No

Customer Single line of text (Text) No

As in the example in the preceding section, you can instantiate a separate ListDataProvider object and another ListViewModel object to manage the Orders list. Assume that the
instantiated ListDataProvider object is named OrdersListDataProvider, as in the following code.

private static ListDataProvider m_OrdersListDataProvider;

public static ListDataProvider OrdersListDataProvider


{
get
{
if (m_OrdersListDataProvider != null)
return m_OrdersListDataProvider;

m_OrdersListDataProvider = new ListDataProvider();


m_OrdersListDataProvider.ListTitle = "Orders";
m_OrdersListDataProvider.SiteUrl = new Uri("http://contoso:2012/sites/samplesite/"); // Specify a URL here for your server.

return m_OrdersListDataProvider;
}
}

And assume that the instantiated ListViewModel object for the Orders list is named OrdersListViewModel, as in the following code.

private static ListViewModel m_OrdersListViewModel;

public static ListViewModel OrdersListViewModel


{
get
{
if (m_OrdersListViewModel == null)
m_OrdersListViewModel = new ListViewModel { DataProvider = App.OrdersListDataProvider };

return m_OrdersListViewModel;
}
set
{
m_OrdersListViewModel = value;
}
}

The schema for the Orders list differs from that of the Marketing Team list. You can accommodate the differences by adding code to the ListDataProvider.cs file, specifically to the
CamlQueryBuilder class.

public static class CamlQueryBuilder


{
static Dictionary<string, string> ViewXmls = new Dictionary<string, string>()
{
{"View1", @"<View><Query><OrderBy><FieldRef Name='Title' />
<FieldRef Name='FirstName' /></OrderBy></Query><RowLimit>30</RowLimit><ViewFields>{0}</ViewFields></View>"},
{"View2", @"<View><Query><OrderBy><FieldRef Name='ID' /></OrderBy></Query><RowLimit>30</RowLimit>
<ViewFields>{0}</ViewFields></View>"}
};

static string View1Fields = @"<FieldRef Name='Title'/><FieldRef Name='FirstName'/>


<FieldRef Name='JobTitle'/><FieldRef Name='Email'/><FieldRef Name='Comments'/>";
static string View2Fields = @"<FieldRef Name='Title'/><FieldRef Name='Unit_x0020_Price'/><FieldRef Name='Quantity'/>
<FieldRef Name='Order_x0020_Value'/><FieldRef Name='Order_x0020_Date'/>
<FieldRef Name='Status'/><FieldRef Name='Customer'/>";

public static CamlQuery GetCamlQuery(string viewName)


{
string viewXml = ViewXmls[viewName];
// Add ViewFields to the ViewXml depending on the view.
switch (viewName)
{
case "View2":
viewXml = string.Format(viewXml, View2Fields);
break;
case "View1":
default:
viewXml = string.Format(viewXml, View1Fields);
break;
}
return new CamlQuery { ViewXml = viewXml };
}
}

Here, a second entry with a key value of "View2" is added to the ViewXmls Dictionary object for the Orders list. (Keep in mind that the key values for entries added to the ViewXmls
Dictionary in the CamlQueryBuilder class must be unique (in the solution) for the caching logic in the template to operate properly.) String variables ( View1Fields and View2Fields) are
used to store the list of fields for each view. Then, depending on the value of the viewName parameter passed to the GetCamlQuery method, the appropriate CAML query XML string is
created.
Then, as in the preceding section, you can create view forms for the list, bound this time to the OrdersListViewModel and OrdersListDataProvider objects. As an example, the XAML for a
List form specific to the Orders list, named OrdersList.xaml, would be similar to the markup in the List.xaml file generated by the template for the primary list in the app, except that you
would name the PivotItem control that renders the list "View2" (rather than the default, "View1") and set the Binding declaration for the ItemsSource attribute of the ListBox control in
which list items are rendered to "View2" as in the following markup (which shows only the markup for the root grid of the page).

...
<Grid x:Name="LayoutRoot" Background="Transparent" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Contr
<!--Pivot Control-->
<ProgressBar x:Name="progressBar" Opacity="1" HorizontalAlignment="Center" VerticalAlignment="Top"
Height="30" Width="470" IsIndeterminate="{Binding IsBusy}" Visibility="{Binding ShowIfBusy}" />
<Grid x:Name="ContentPanel" Grid.Row="0" Width="470">
<controls:Pivot Name="Views" Title="Orders" LoadedPivotItem="OnPivotItemLoaded">
<!--Pivot item-->
<controls:PivotItem Name="View2" Header="All Orders">
<!--Double line list with text wrapping-->
<ListBox x:Name="lstBox1" Margin="0,0,-12,0" SelectionChanged="OnSelectionChanged" ItemsSource="{Binding [View2]}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="10">
<TextBlock Name="txtTitle" Text="{Binding [Title]}" TextWrapping="NoWrap"
Style="{StaticResource PhoneTextTitle2Style}" />
<TextBlock Name="txtUnitPrice" Text="{Binding [Unit_x0020_Price]}"
TextWrapping="NoWrap" Style="{StaticResource PhoneTextNormalStyle}" />
<TextBlock Name="txtQuantity" Text="{Binding [Quantity]}"
TextWrapping="NoWrap" Style="{StaticResource PhoneTextNormalStyle}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PivotItem>
</controls:Pivot>
</Grid>
</Grid>
...

A convenient way to create suitable XAML markup is to use the Windows Phone SharePoint List Application template to generate a separate project based on the Orders list and then copy
the generated XAML from that project to the project with multiple lists, taking care to change the name of the PivotItem control (which defaults to "View1") to "View2" and to change the
Binding declaration of the ListBox control as shown here. You would also need to change all references in the associated code-behind file for the form to specify the appropriate
ListViewModel and DataProvider objects (as, for example, OrdersListViewModel and OrdersListDataProvider).
This approach works because in the associated code-behind file (named, in this case, OrdersList.xaml.cs), the various event handlers that call methods of the ListDataProvider object (here,
OrdersListDataProvider) to access list data use the name of the PivotItem control as a way to specify the appropriate view to use. For example, the OnPivotItemLoaded event handler
calls the LoadData method of the OrdersListViewModel object instantiated from the ListViewModel class (and this method in turn calls the LoadData method of the
OrdersListDataProvider object), passing the name of the PivotItem control (here, "View2") as the value of the ViewName parameter to the method. This same value is ultimately passed
(as the value of the viewName parameter) to the GetCamlQuery method shown above in the modified implementation of the CamlQueryBuilder class.

An alternative approach for a solution involving SharePoint lists based on different schemas
As an alternative to the approach in the preceding section, you can use the Windows Phone SharePoint List Application template to create a Windows Phone app project in a Microsoft
Visual Studio 2010 solution based on a given SharePoint list and then add projects built based on other lists to that same solution. This approach allows you to take advantage of the
template for generating forms specific to each SharePoint list. You can then customize the solution according to your needs to control how users interact with the lists. The procedures in this
section demonstrate that approach.
Assume for the following procedures that you have a SharePoint list named Orders (based on the Custom list template), with the columns and field types as shown in Table 1 in the
preceding section. In addition, assume you have another SharePoint list (again, based on the Custom list template), named Customers, with the columns and field types shown in Table 2.
Table 2. Columns and fields for Customers list

CO LU MN FIELD T YPE R EQ U IR ED

Customer Name (i.e., Title) Single line of text (Text) Yes

Contact Number Single line of text (Text) No

E-mail Address Single line of text (Text) No

Company Single line of text (Text) No

In the following procedures, you create a Windows Phone app that uses both of these lists. The primary list in the app is the Customers list. When you display the details for a given
customer in the Display form, a button is included on the form that allows users to display all the orders (from the Orders list) associated with that customer.

To create the component projects for the solution


1. Create a Windows Phone app by using the Windows Phone SharePoint List Application template, specifying a SharePoint list defined based on the columns and field types shown in
Table 2. In the procedures in this section, it is assumed that the name of the list in the project is "Customers" and the name of the project is "CustomersSPListApp". (See How to:
Create a Windows Phone SharePoint list app for information about creating an app based on the Windows Phone SharePoint List Application template..md)
2. In Visual Studio, choose File, Add, New Project.
The Add New Project dialog box appears.
3. In the Add New Project dialog box, under the Visual C# node, choose the Silverlight for Windows Phone node.
4. In the Templates pane, choose the Windows Phone SharePoint List Application template.
5. Name the app, for example, OrdersSPListApp, and then choose OK.
6. Follow the procedure described in How to: Create a Windows Phone SharePoint list app to create another Windows Phone app project, specifying a SharePoint list defined based on
the columns and field types show in Table 1 as the target list for the project. You should now have two projects in your solution, named "CustomersSPListApp" and "OrdersSPListApp"
(if you are following the naming conventions in this procedure).
7. In Solution Explorer, choose the CustomerSPListApp project node.
8. On the Project menu, choose Add Reference.
The Add Reference dialog box appears.
9. On the Projects tab, choose the OrdersSPListApp project in the solution, and then choose the OK button. The project is added under the References node of the
CustomersSPListApp project.
Next, configure the two projects in the solution. You essentially configure the OrdersSPListApp project (based on the Orders list) to operate as a "look-up" project for the
CustomerSPListApp project (based on the Customers List).

To configure the OrdersSPListApp project


1. Change the navigation paths in the view forms of the OrdersSPListApp project to include the primary namespace of the project ("OrdersSPListApp") and the "component"
designation. For example, in the handler for the OnNewButtonClick event in the List.xaml.cs file of the OrdersSPListApp project, change the call to the Navigate method of the
NavigationService object from this:
NavigationService.Navigate(new Uri("/Views/NewForm.xaml", UriKind.Relative));

To this:
NavigationService.Navigate(new Uri("/OrdersSPListApp;component/Views/NewForm.xaml", UriKind.Relative));

The easiest way to make these changes is to use the Quick Replace command in the OrdersSPListApp project.
2. In Solution Explorer, choose the OrdersSPListApp project node.
3. Press Ctrl+H to display the Quick Replace dialog box.
4. In the Find what text box, specify the following text exactly as it is appears here:
Uri("/Views/
5. In the Replace with text box, specify the following text exactly as it appears here:
Uri("/OrdersSPListApp;component/Views/
6. Ensure that Current Project is selected in the Look in drop-down list.
7. Choose Replace All.
8. Save all changed files in the project.
9. Add a member property to the App.xaml.cs file of the OrdersSPListApp project. In Solution Explorer, under the OrdersSPListApp project node, choose the App.xaml file.
10. Press F7 to open its associated code-behind file, App.xaml.cs, for editing.
11. Within the code block (demarcated by opening and closing braces) that implements the App partial class, add the following code.

public static string CustomerName { get; set; }

1. In Solution Explorer, under the OrdersSPListApp project node, choose the List.xaml file.
2. Press F7 to open its associated code-behind file, List.xaml.cs, for editing.
3. Modify the OnNavigatedTo event handler in the file to parse the QueryString property of the NavigationContext object to set the value of the CustomerName variable declared
in step 4. You can also set the Header property of the PivotItem control on the List form to match the customer name, for the convenience of your users. The modified handler
should be as follows.

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)


{
base.OnNavigatedTo(e);

if (this.NavigationContext.QueryString.ContainsKey("CustomerName"))
{
App.CustomerName = NavigationContext.QueryString["CustomerName"];
}

// Also set the value of the Header property for the PivotItem to match the customer name.
if (!string.IsNullOrWhiteSpace(App.CustomerName))
{
this.View1.Header = App.CustomerName;
}

App.MainViewModel.ViewDataLoaded += new EventHandler<ViewDataLoadedEventArgs>(OnViewDataLoaded);


App.MainViewModel.InitializationCompleted += new EventHandler<InitializationCompletedEventArgs>(OnViewModelInitialization);
}

1. Add the CustomerName variable as an argument in the call to the LoadData method in the OnPivotItemLoaded event handler in the List.xaml.cs file. The implementation of the
OnPivotItemLoaded event handler should be as follows.

private void OnPivotItemLoaded(object sender, PivotItemEventArgs e)


{
if (!App.MainViewModel.IsInitialized)
{
//Initialize ViewModel and Load Data for PivotItem upon initialization.
App.MainViewModel.Initialize();
}
else
{
//Load Data for the currently loaded PivotItem.
App.MainViewModel.LoadData(e.Item.Name, App.CustomerName);
}
}
The **LoadData** method of the **ListViewModel** class in the template is defined such as to be able to accept optional parameters.

1. Also add the CustomerName variable as an argument in the call to the LoadData method in the OnViewModelInitialization event handler. The implementation of the
OnViewModelInitialization event handler should be as follows.

private void OnViewModelInitialization(object sender, InitializationCompletedEventArgs e)


{
this.Dispatcher.BeginInvoke(() =>
{
//If initialization has failed, show error message and return.
if (e.Error != null)
{
MessageBox.Show(e.Error.Message, e.Error.GetType().Name, MessageBoxButton.OK);
return;
}
App.MainViewModel.LoadData(((PivotItem)Views.SelectedItem).Name, App.CustomerName);
this.DataContext = (sender as ListViewModel);
});
}

1. Add the CustomerName variable as an argument in the call to the RefreshData method in the OnRefreshButtonClick event handler in the List.xaml.cs file. The implementation of the
OnRefreshButtonClick event handler should be as follows.

private void OnRefreshButtonClick(object sender, EventArgs e)


{
if (Views.SelectedItem == null)
return;

if (!App.MainViewModel.IsInitialized)
{
//Initialize ViewModel and Load Data for PivotItem upon completion.
App.MainViewModel.Initialize();
}
else
{ //Refresh Data for the currently loaded PivotItem.
App.MainViewModel.RefreshData(((PivotItem)Views.SelectedItem).Name, App.CustomerName);
}
}

As for the **LoadData** method, the **RefreshData** method is also defined to be able to accept optional parameters. Notice that in the preceding three steps, the only change to the event handler

1. When users choose the New button on the List form for the Orders list in your app, the Customer field in the New form should already contain the name of the customer, because the list
of orders displayed to the user has been filtered based on the customer name. New orders added from that filtered list should be associated with the customer name on which the list is
filtered. To pass the value of the CustomerName variable to the New form, modify the OnNewButtonClick event to include the value as a query string in the navigation path to the
New form, as shown in the following code.

private void OnNewButtonClick(object sender, EventArgs e)


{
//Instantiate a new instance of NewItemViewModel and go to NewForm.
App.MainViewModel.CreateItemViewModelInstance = new NewItemViewModel { DataProvider = App.DataProvider };

if (!string.IsNullOrWhiteSpace(App.CustomerName))
{
NavigationService.Navigate(new Uri("/OrdersSPListApp;component/Views/NewForm.xaml?CustomerName=" +
App.CustomerName, UriKind.Relative));
}
else
{
NavigationService.Navigate(new Uri("/OrdersSPListApp;component/Views/NewForm.xaml", UriKind.Relative));
}
}

1. In the OnNavigatedTo event handler for the New form, check the query string for a customer name and, if it's available, assign it to the Customer field of the ViewModel for the
form. In Solution Explorer, under the OrdersSPListApp project, choose the NewForm.xaml file and press F7 to open its associated code-behind file, NewForm.xaml.cs, for editing.
2. Modify the OnNavigatedTo event handler in the file to match the following code.

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)


{
base.OnNavigatedTo(e);

if (this.NavigationContext.QueryString.ContainsKey("CustomerName"))
{
this.viewModel["Customer"] = NavigationContext.QueryString["CustomerName"];
}

viewModel.ItemCreated += new EventHandler<ItemCreatedEventArgs>(OnItemCreated);


}

1. In the CamlQueryBuilder class in the ListDataProvider.cs file in the OrdersSPListApp project, add a WHERE clause to the Customer field in the CAML query used to get items from the
Orders list to filter the list based on a given customer name (from the CustomerName variable). Add a parameter to the GetCamlQuery method in the class for passing the customer
name. The modified CamlQueryBuilder class should be as follows.
public static class CamlQueryBuilder
{
static Dictionary<string, string> ViewXmls = new Dictionary<string, string>()
{
{"View1", @"<View><Query>{0}</Query><RowLimit>30</RowLimit><ViewFields>{1}</ViewFields></View>"}
};

static string ViewFields = @"<FieldRef Name='Title'/><FieldRef Name='Unit_x0020_Price'/><FieldRef Name='Quantity'/><FieldRef Name='Order_x0020_Value'/><FieldRef Name='Order_x0020_Date'/><Fiel

public static CamlQuery GetCamlQuery(string viewName, string customerName)


{
string queryClause = string.Empty;

// Create appropriate Query Clause, depending on customerName parameter.


if (string.IsNullOrWhiteSpace(customerName))
{
queryClause = "<OrderBy><FieldRef Name='ID' /></OrderBy>";
}
else
{
queryClause = string.Format("<Where><Eq><FieldRef Name='Customer' /><Value Type='Text'>{0}</Value></Eq></Where>", customerName);
}

// Add Query Clause and ViewFields to ViewXml.


string viewXml = ViewXmls[viewName];
viewXml = string.Format(viewXml, queryClause, ViewFields);

return new CamlQuery { ViewXml = viewXml };


}
}

1. Modify the LoadDataFromServer method in the ListDataProvider.cs file to check for the CustomerName argument and pass the argument to the GetCamlQuery method. The
modified method should be as follows.

private void LoadDataFromServer(string ViewName, Action<LoadViewCompletedEventArgs>


loadItemCompletedCallback, params object[] filterParameters)
{
string customerName = string.Empty;
string cacheKey = ViewName;

// Parse the optional parameters:


if (filterParameters.Length > 0)
{
customerName = filterParameters[0].ToString();
cacheKey += "-" + customerName;
}

CamlQuery query = CamlQueryBuilder.GetCamlQuery(ViewName, customerName);


ListItemCollection items = Context.Web.Lists.GetByTitle(ListTitle).GetItems(query);
Context.Load(items);
Context.Load(items, listItems => listItems.Include(item => item.FieldValuesAsText));

Context.ExecuteQueryAsync(
delegate(object sender, ClientRequestSucceededEventArgs args)
{
base.CacheView(cacheKey, items);
loadItemCompletedCallback(new LoadViewCompletedEventArgs { ViewName = ViewName, Items = base.GetCachedView(cacheKey) });
},
delegate(object sender, ClientRequestFailedEventArgs args)
{
loadItemCompletedCallback(new LoadViewCompletedEventArgs { Error = args.Exception });
});
}

1. Likewise, modify the LoadData method in the ListDataProvider.cs file to process the CustomerName parameter.

public override void LoadData(string ViewName, Action<LoadViewCompletedEventArgs>


loadViewCompletedCallback, params object[] filterParameters)
{
string customerName = string.Empty;
string cacheKey = ViewName;

// Parse the optional parameters:


if (filterParameters.Length > 0)
{
customerName = filterParameters[0].ToString();
cacheKey += "-" + customerName;
}

List<ListItem> CachedItems = GetCachedView(cacheKey);


if (CachedItems != null)
{
loadViewCompletedCallback(new LoadViewCompletedEventArgs { ViewName = ViewName, Items = CachedItems });
return;
}

LoadDataFromServer(ViewName, loadViewCompletedCallback, filterParameters);


}

1. Add a Cancel button to the ApplicationBar element in the List.xaml file in the OrdersSPListApp project. In Solution Explorer, under the OrdersSPListApp node, choose the
List.xaml file, and then press SHIFT+F7 to open the file for editing in the designer.
2. Add XAML to declare a Cancel button within the <phone:PhoneApplicationPage.ApplicationBar> tag, as shown in the following markup.
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="btnNew"
IconUri="/Images/appbar.new.rest.png" Text="New" Click="OnNewButtonClick"/>
<shell:ApplicationBarIconButton x:Name="btnRefresh" IconUri="/Images/appbar.refresh.rest.png"
Text="Refresh" IsEnabled="True" Click="OnRefreshButtonClick"/>
<shell:ApplicationBarIconButton x:Name="btnCancel" IconUri="/Images/appbar.cancel.rest.png" Text="Cancel" IsEnabled="True" Click="OnCancelButtonClick" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

1. With the List.xaml file selected in Solution Explorer, press F7 to open the associated code-behind file, List.xaml.cs, for editing.
2. Within the code block (demarcated by opening and closing braces) that implements the ListForm partial class, add the following handler for the OnCancelButtonClick event.

private void OnCancelButtonClick(object sender, EventArgs e)


{
NavigationService.Navigate(new Uri("/CustomersSPListApp;component/Views/DisplayForm.xaml", UriKind.Relative));
}

1. Save the files in the project.


Now, it remains to add a button to the Display form in the CustomersSPListApp project to show the orders associated with a given customer.

To configure the CustomersSPListApp project


1. In Solution Explorer, under the node for the CustomersSPListApp project, choose the DisplayForm.xaml file.
2. Press Shift + F7 (or double-click the file) to open the file for editing in the designer.
3. Add XAML declarations for a Button control within a containing StackPanel control after the final StackPanel control container for the last field of the list item, as in the following
markup.

...
<Grid x:Name="LayoutRoot" Background="Transparent" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Contr
<StackPanel>
<ProgressBar Background="Red" x:Name="progressBar" Opacity="1" HorizontalAlignment="Center"
VerticalAlignment="Top" Height="15" Width="470" IsIndeterminate="{Binding IsBusy}"
Visibility="{Binding ShowIfBusy}" />
<ScrollViewer HorizontalScrollBarVisibility="Auto" Height="700">
<Grid x:Name="ContentPanel" Width="470">
<StackPanel Margin="0,5,0,5">
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Title :</TextBlock>
<TextBlock Width="310" HorizontalAlignment="Left" Name="txtTitle"
Text="{Binding [Title]}" TextWrapping="Wrap" Style="{StaticResource PhoneTextSubtleStyle}" />
</StackPanel>
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Contact Number :</TextBlock>
<TextBlock Width="310" HorizontalAlignment="Left" Name="txtContact_x0020_Number"
Text="{Binding [Contact_x0020_Number]}" TextWrapping="Wrap"
Style="{StaticResource PhoneTextSubtleStyle}" />
</StackPanel>
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">E-mail Address :</TextBlock>
<TextBlock Width="310" HorizontalAlignment="Left" Name="txtE_x002d_mail_x0020_Address"
Text="{Binding [E_x002d_mail_x0020_Address]}" TextWrapping="Wrap"
Style="{StaticResource PhoneTextSubtleStyle}" />
</StackPanel>
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">Company :</TextBlock>
<TextBlock Width="310" HorizontalAlignment="Left" Name="txtCompany"
Text="{Binding [Company]}" TextWrapping="Wrap" Style="{StaticResource PhoneTextSubtleStyle}" />
</StackPanel>
<StackPanel Margin="0,60,0,5"><Button Content="Get Orders" Height="70" Name="OrdersButton" Width="400" Click="OnButtonOrdersClick" /></StackPanel>
</StackPanel>
</Grid>
</ScrollViewer>
</StackPanel>
</Grid>
...

1. With the DisplayForm.xaml file selected in Solution Explorer, press F7 to open the associated code-behind file, DisplayForm.xaml.cs, for editing.
2. Within the code block (demarcated by opening and closing braces) that implements the DisplayForm partial class, add the following handler for the OnButtonOrdersClick event.

private void OnOrdersButtonClick(object sender, RoutedEventArgs e)


{
this.NavigationService.Navigate(new Uri("/OrdersSPListApp;component/Views/List.xaml?CustomerName=" +
viewModel["Title"], UriKind.Relative));
}

1. Save the file.


If you build the solution and deploy it to the Windows Phone Emulator, the List form for the Customers list appears. If you choose an item in the list to show the Display form for a given
customer, you see a button to retrieve the orders associated with that customer (Figure 1).
Figure 1. Customers Display form
When you choose the Get Orders button on this Display form, the orders for the customer are displayed in the List form from the OrdersSPListApp project in the solution (Figure 2).
Figure 2. Orders List form

From this form (the List form for the Orders list) you can add, edit, or delete orders for a customer. If you choose the Cancel button, you navigate back to the List form for the Customers list.
In a single phone app, you can manage the list items from two SharePoint lists.

See also
How to: Configure and use push notifications in SharePoint apps for Windows Phone
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Configure and use push notifications in SharePoint apps for Windows Phone
4/20/2018 • 32 minutes to read Edit Online

Create a solution in SharePoint Server for sending push notifications and develop a Windows Phone app for receiving the notifications. Using the Microsoft Push Notification Service
(MPNS), Windows Phone apps can receive notifications through the Internet of events triggered on Microsoft SharePoint Server. The phone app doesn't have to poll the server for changes
to, for example, the items in a list on which the phone app is based. The app can be registered to receive notifications from the server, and an event receiver can initiate a notification and send
it to the receiving app for handling. The push notification is relayed to Windows Phone devices by MPNS.
Windows Phone 7 doesn't support running multiple apps simultaneously. Other than the components of the Windows Phone operating system (OS) itself, only one app can be running on
the phone at a time. An event relevant to a given phone app might occur (such as, for example, a list item being added to a list) when the app isn't running in the foreground on the phone
(that is, when the app is tombstoned or closed). You could develop a background service on the phone with a periodic task that might check for changes to the list on the server, but this
approach would consume resources (such as network bandwidth and battery power) on the phone. With MPNS and the components that support notifications built into the Windows Phone
7 OS, the phone itself can receive a notification relevant to the context of a given app—even when that app isn't running—and the user can be given the opportunity to start the relevant app
in response to the notification. (For more information about push notifications, see Push Notifications Overview for Windows Phone in the MSDN Library.) In this topic, you create a server-
side solution for sending push notifications to a phone app based on a change in the list on which the app is based. You will then create the phone app for receiving these notifications.

Create a server-side solution to send push notifications based on a list item event
The server-side solution can be either a SharePoint app deployed in an isolated SPWeb object, or a SharePoint farm solution packaged as a SharePoint solution package (that is, a .wsp file)
that contains a Web-scoped Feature. In the procedures in this section, you will develop a simple SharePoint solution that creates a target list to be used by a Windows Phone app and that
activates the push notification mechanism on the server. In the subsequent section, you will develop the Windows Phone app for receiving notifications from the server-side solution.

To create the server-side project


1. Start Visual Studio 2012 by using the Run as Administrator option.
2. Choose File, New, Project.
The New Project dialog box appears.
3. In the New Project dialog box, expand the SharePoint node under Visual C#, and then choose the 15 node.
4. In the Templates pane, select SharePoint Project and specify a name for the project, such asPushNotificationsList.
5. Choose the OK button. The SharePoint Customization Wizard appears. This wizard enables you to select the target site for developing and debugging the project and the trust level of
the solution.
6. Specify the URL of a SharePoint Server site. Select a site that you will be able to use later in the development of the SharePoint list app for Windows Phone.
7. Select Deploy as a farm solution, and then click Finish to create the project.
Next, add a class file to the project and create a couple of classes to encapsulate and manage push notifications.

To create the classes for managing push notifications


1. In Solution Explorer, choose the node representing the project (named PushNotificationsList if you follow the naming convention used in these procedures).
2. On the Project menu, choose Add Class. The Add New Item dialog box appears with the C# Class template already selected.
3. Specify PushNotification.cs as the name of the file and click Add. The class file is added to the solution and opened for editing.
4. Replace the contents of the file with the following code.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using Microsoft.SharePoint;

namespace PushNotificationsList
{
internal static class WP7Constants
{
internal static readonly string[] WP_RESPONSE_HEADERS =
{
"X-MessageID",
"X-DeviceConnectionStatus",
"X-SubscriptionStatus",
"X-NotificationStatus"
};
}

public enum TileIntervalValuesEnum


{
ImmediateTile = 1,
Delay450SecondsTile = 11,
Delay900SecondsTile = 21,
}

public enum ToastIntervalValuesEnum


{
ImmediateToast = 2,
Delay450SecondsToast = 12,
Delay900SecondsToast = 22,
}

public enum RawIntervalValuesEnum


{
ImmediateRaw = 3,
Delay450SecondsRaw = 13,
Delay900SecondsRaw = 23
}
public enum NotificationTypeEnum
{
Tile = 1,
Toast = 2,
Raw = 3
}

class PushNotification
{
public PushNotificationResponse PushToast(SPPushNotificationSubscriber subscriber, string toastTitle, string toastMessage, string toastParam, ToastIntervalValuesEnum intervalValue)
{
// Construct toast notification message from parameter values.
string toastNotification = "<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>" +
"<wp:Notification xmlns:wp=\\"WPNotification\\">" +
"<wp:Toast>" +
"<wp:Text1>" + toastTitle + "</wp:Text1>" +
"<wp:Text2>" + toastMessage + "</wp:Text2>" +
"<wp:Param>" + toastParam + "</wp:Param>" +
"</wp:Toast> " +
"</wp:Notification>";

return SendPushNotification(NotificationTypeEnum.Toast, subscriber, toastNotification, (int)intervalValue);


}

public PushNotificationResponse PushRaw(SPPushNotificationSubscriber subscriber, string rawMessage, RawIntervalValuesEnum intervalValue)


{
return SendPushNotification(NotificationTypeEnum.Raw, subscriber, rawMessage, (int)intervalValue);
}

private PushNotificationResponse SendPushNotification(NotificationTypeEnum notificationType, SPPushNotificationSubscriber subscriber, string message, int intervalValue)
{
// Create HTTP Web Request object.
string subscriptionUri = subscriber.ServiceToken;
HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(subscriptionUri);

// MPNS expects a byte array, so convert message accordingly.


byte[] notificationMessage = Encoding.Default.GetBytes(message);

// Set the notification request properties.


sendNotificationRequest.Method = WebRequestMethods.Http.Post;
sendNotificationRequest.ContentLength = notificationMessage.Length;
sendNotificationRequest.ContentType = "text/xml";
sendNotificationRequest.Headers.Add("X-MessageID", Guid.NewGuid().ToString());

switch (notificationType)
{
case NotificationTypeEnum.Tile:
sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "token");
break;
case NotificationTypeEnum.Toast:
sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "toast");
break;
case NotificationTypeEnum.Raw:
// A value for the X-WindowsPhone-Target header is not specified for raw notifications.
break;
}

sendNotificationRequest.Headers.Add("X-NotificationClass", intervalValue.ToString());

// Merge byte array payload with headers.


using (Stream requestStream = sendNotificationRequest.GetRequestStream())
{
requestStream.Write(notificationMessage, 0, notificationMessage.Length);
}

string statCode = string.Empty;


PushNotificationResponse notificationResponse;

try
{
// Send the notification and get the response.
HttpWebResponse response = (HttpWebResponse)sendNotificationRequest.GetResponse();
statCode = Enum.GetName(typeof(HttpStatusCode), response.StatusCode);

// Create PushNotificationResponse object.


notificationResponse = new PushNotificationResponse((int)intervalValue, subscriber.ServiceToken);
notificationResponse.StatusCode = statCode;
foreach (string header in WP7Constants.WP_RESPONSE_HEADERS)
{
notificationResponse.Properties[header] = response.Headers[header];
}
}
catch (Exception ex)
{
statCode = ex.Message;
notificationResponse = new PushNotificationResponse((int)intervalValue, subscriber.ServiceToken);
notificationResponse.StatusCode = statCode;
}

return notificationResponse;
}
}

/// <summary>
/// Object used for returning notification request results.
/// </summary>
class PushNotificationResponse
{
private DateTime timestamp;
private int notificationIntervalValue;
private string statusCode = string.Empty;
private string serviceToken;
private Dictionary<string, string> properties;

public PushNotificationResponse(int numericalIntervalValue, string srvcToken)


public PushNotificationResponse(int numericalIntervalValue, string srvcToken)
{
timestamp = DateTime.UtcNow;
notificationIntervalValue = numericalIntervalValue;
serviceToken = srvcToken;
properties = new Dictionary<string, string>();
}

public DateTime TimeStamp


{
get { return timestamp; }
}

public int NotificationIntervalValue


{
get { return notificationIntervalValue; }
}

public string StatusCode


{
get { return statusCode; }
set { statusCode = value; }
}

public string ServiceToken


{
get { return serviceToken; }
}

public Dictionary<string, string> Properties


{
get { return properties; }
}
}
}

1. Save the file.


In this code, the PushToast and PushRaw methods take parameter arguments appropriate for the given type of notification to send, process those arguments, and then call the
SendPushNotification method, which does the work of sending the notification using the Microsoft Push Notification Service. (In this sample code, a method for sending tile notifications
has not been implemented.) The PushNotificationResponse class is simply a mechanism for encapsulating the result received from the notification request. Here, the class adds some
information to the object (cast as an HttpWebResponse object) returned by the GetResponse method of the HttpWebRequest object. The event receiver you create in the following
procedure uses this PushNotificationResponse class to update a notifications results list on the server.
Now create an event receiver class that will send push notifications to devices that have been registered to receive them. (You will bind this event receiver to the Jobs list that is created in a
later procedure.)

To create the event receiver class for a list


1. In Solution Explorer, choose the node representing the project.
2. On the Project menu, click Add Class. The Add New Item dialog box appears with the C# Class template already selected.
3. Specify ListItemEventReceiver.cs as the name of the file and click Add. The class file is added to the solution and opened for editing.
4. Replace the contents of the file with the following code.
using System;
using System.Security.Permissions;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;

namespace PushNotificationsList
{
/// <summary>
/// List Item Events
/// </summary>
public class ListItemEventReceiver : SPItemEventReceiver
{
internal static string ResultsList = "Push Notification Results";

/// <summary>
/// An item was added.
/// </summary>
public override void ItemAdded(SPItemEventProperties properties)
{
SPWeb spWeb = properties.Web;
SPPushNotificationSubscriberCollection pushSubscribers = spWeb.PushNotificationSubscribers;
PushNotification pushNotification = new PushNotification();

SPListItem listItem = properties.ListItem;

string jobAssignment = "[Unassigned]";

// This event receiver is intended to be associated with a specific list,


// but the list may not have an "AssignedTo" field, so using try/catch here.
try
{
jobAssignment = listItem["AssignedTo"].ToString();
}
catch { }

PushNotificationResponse pushResponse = null;

foreach (SPPushNotificationSubscriber ps in pushSubscribers)


{
// Send a toast notification to be displayed on subscribed phones on which the app is not running.
pushResponse = pushNotification.PushToast(ps, "New job for:", jobAssignment, string.Empty, ToastIntervalValuesEnum.ImmediateToast);
UpdateNotificationResultsList(spWeb, ps.User.Name, pushResponse);

// Also send a raw notification to be displayed on subscribed phones on which the app is running when the item is added.
pushResponse = pushNotification.PushRaw(ps, string.Format("New job for: {0}", jobAssignment), RawIntervalValuesEnum.ImmediateRaw);
UpdateNotificationResultsList(spWeb, ps.User.Name, pushResponse);
}

base.ItemAdded(properties);
}

private void UpdateNotificationResultsList(SPWeb spWeb, string subscriberName, PushNotificationResponse pushResponse)


{
SPList resultsList = spWeb.Lists.TryGetList(ResultsList);

if (resultsList == null)
return;

try
{
SPListItem resultItem = resultsList.Items.Add();
resultItem["Title"] = subscriberName;
resultItem["Notification Time"] = pushResponse.TimeStamp;
resultItem["Status Code"] = pushResponse.StatusCode;
resultItem["Service Token"] = pushResponse.ServiceToken;

StringBuilder builder = new StringBuilder();


foreach (string key in pushResponse.Properties.Keys)
{
builder.AppendFormat("{0}: {1}; ", key, pushResponse.Properties[key]);
}
resultItem["Headers"] = builder.ToString();

resultItem["Interval Value"] = pushResponse.NotificationIntervalValue;


resultItem.Update();
}
catch
{
// Could log to ULS here if adding list item fails.
}
}
}
}

1. Save the file.


In this code, after an item is added to the list to which the event receiver is bound, push notifications are sent to subscribers that have registered to receive notifications. The value of the
AssignedTo field from the added list item is included in the notification message sent to subscribers. For the toast notification, the values of the toastTitle parameter (for the PushToast
method defined in the preceding procedure) and the toastMessage parameter are set. These values correspond to the Text1 and Text2 properties in the XML schema that defines toast
notifications.
An empty string is simply being passed as the value of the toastParam parameter, which corresponds to the Param property in the XML schema for toast notifications. You could use this
parameter to specify, for example, a page of the phone app to open when the user clicks the notification in the phone. In the sample phone app developed later in this topic for receiving these
notifications from the server, the Param property is not used. The List form (List.xaml) in the app is simply opened when the user clicks the notification.
NOTE

The Param property for toast notifications is supported only in Windows Phone OS version 7.1 or greater.
For the raw notification in this sample, a string is passed that contains the value of the AssignedTo field from the added list item.
Note that the toast notification will be displayed on subscribed phones (if the phone app for which the notification is intended is not running), and the message displayed will be truncated if it
is longer than approximately 41 characters. Raw notifications in MPNS are limited to 1024 bytes (1 kilobyte). (The exact number of characters that can be sent depends on the kind of
encoding used, such as UTF-8). Tile notifications are also subject to size limitations. Large amounts of data can't be sent using any of the notifications types. The best use of these notifications
is not as a mechanism for transferring data, but as a way to send short messages to subscribed phones so that certain actions can be taken on the phone. Those actions, such as refreshing a
list on the phone with data from the server, may involve larger amounts of data, depending on the design of the Windows Phone app.
The PushNotificationResponse object that is returned from a notification request is passed to the UpdateNotificationResultsList method. This method adds information about the
request to a SharePoint list named Push Notification Results (if the list exists). This is simply a demonstration of one way to use the returned object. You can put the returned object to more
sophisticated uses in a production solution. You might, for example, examine the returned object for particular status codes when a notification is sent to a given user (such as the user
designated for the assignment in the AssignedTo field) and take the appropriate action. In a production application, you probably wouldn't store all of this information in a list on the server.
The information is being stored here to help you understand the properties associated with MPNS notifications.
Next, you create a simple SharePoint list, named Jobs, that contains a job category, a description of a job, and the person to whom the job is assigned. Also, you create an auxiliary list, named
Push Notification Results, for storing information related to notification requests sent to subscribing phones.
In the following procedure, you create a class, ListCreator, that includes a CreateJobsList method for creating and configuring the Jobs list when the solution is activated on the server. The
class also adds the ItemAdded event receiver (created earlier in the ListItemEventReceiver class) to the EventReceivers collection associated with the list. The ListCreator class also
includes a method for creating the Push Notification Results SharePoint list.

To create a class for adding and configuring the lists


1. In Solution Explorer, choose the node representing the project (again, named PushNotificationsList if you follow the naming convention used in these procedures).
2. On the Project menu, click Add Class. The Add New Item dialog box appears with the C# Class template already selected.
3. Specify ListCreator.cs as the name of the file and click Add. The class file is added to the solution and opened for editing.
4. Replace the contents of the file with the following code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Microsoft.SharePoint;

namespace PushNotificationsList
{
class ListCreator
{
internal void CreateJobsList(SPWeb spWeb)
{
string listTitle = "Jobs";
string listDescription = "List of jobs and assignments.";
Dictionary<string, SPFieldType> columns = new Dictionary<string, SPFieldType>();

// The "Title" column will be added based on the GenericList template. That field
// will be used as the category name for the job (e.g., Shopping), so only need to add
// the remaining fields.
columns.Add("Description", SPFieldType.Text);
columns.Add("AssignedTo", SPFieldType.Text);

// Creating list (or retrieving GUID for list if it already exists).


Guid listId = CreateCustomList(spWeb, listTitle, listDescription, columns, false);
if (listId.Equals(Guid.Empty))
return;

SPList list = spWeb.Lists[listId];

// Add event receiver (if the current Jobs list is not already associated with the receiver).
bool ReceiverExists = false;
string receiverClassName = "PushNotificationsList.ListItemEventReceiver";

for (int i = 0; i < list.EventReceivers.Count; i++)


{
SPEventReceiverDefinition rd = list.EventReceivers[i];
if (rd.Class == receiverClassName &amp;&amp; rd.Type == SPEventReceiverType.ItemAdded)
{
ReceiverExists = true;
break;
}
}

if (ReceiverExists == false)
{
SPEventReceiverDefinition eventReceiver = list.EventReceivers.Add();
// Must specify information here for this specific assembly.
eventReceiver.Assembly = "PushNotificationsList,
Version=1.0.0.0, Culture=Neutral,
PublicKeyToken=[YOUR TOKEN VALUE HERE]";
eventReceiver.Class = receiverClassName;
eventReceiver.Name = "ItemAdded Event";
eventReceiver.Type = SPEventReceiverType.ItemAdded;
eventReceiver.SequenceNumber = 10000;
eventReceiver.Synchronization = SPEventReceiverSynchronization.Synchronous;
eventReceiver.Update();
}
}

internal void CreateNotificationResultsList(SPWeb spWeb)


{
string listTitle = "Push Notification Results";
string listDescription = "List for results from push notification operations.";

Dictionary<string, SPFieldType> columns = new Dictionary<string, SPFieldType>();


columns.Add("Notification Time", SPFieldType.Text);
columns.Add("Status Code", SPFieldType.Text);
columns.Add("Service Token", SPFieldType.Text);
columns.Add("Service Token", SPFieldType.Text);
columns.Add("Headers", SPFieldType.Text);
columns.Add("Interval Value", SPFieldType.Integer);

// Creating the list for storing notification results.


CreateCustomList(spWeb, listTitle, listDescription, columns, true);
}

/// <summary>
/// Creates a SharePoint list (based on the Generic List template).
/// </summary>
/// <param name="spWeb">The target website for the list.</param>
/// <param name="listTitle">The title of the list.</param>
/// <param name="listDescription">A description for the list.</param>
/// <param name="columns">A Dictionary object containing field names and types.</param>
/// <param name="replaceExistingList">Indicates whether to overwrite an existing list of the same name on the site.</param>
/// <returns>A GUID for the created (or existing) list.</returns>
internal Guid CreateCustomList(SPWeb spWeb, string listTitle, string listDescription, Dictionary<string, SPFieldType> columns, bool replaceExistingList)
{
SPList list = spWeb.Lists.TryGetList(listTitle);

if (list != null)
{
if (replaceExistingList == true)
{
try
{
list.Delete();
}
catch
{
return Guid.Empty;
}
}
else
{
return list.ID;
}
}

try
{
Guid listId = spWeb.Lists.Add(listTitle, listDescription, SPListTemplateType.GenericList);
list = spWeb.Lists[listId];
SPView view = list.DefaultView;

foreach (string key in columns.Keys)


{
list.Fields.Add(key, columns[key], false);
view.ViewFields.Add(key);
}

list.Update();
view.Update();

return listId;
}
catch
{
return Guid.Empty;
}
}
}
}

Be sure to specify the appropriate Public Key Token value for particular your assembly. To add a tool to Visual Studio for getting the Public Key Token value for your assembly, see [How to: Crea

1. Save the file.


In this code, the CreateJobsList method of the ListCreator class creates the list (or gets the list if it exists on the server) and binds the event receiver created in an earlier procedure to the
list by adding it to the EventReceivers class associated with the list. The CreateNotificationResultsList method creates the Push Notification Results list.
Next you add a Feature to your project in order to perform initialization operations on the server when your solution is deployed and activated. You add an event receiver class to the Feature
to handle the FeatureActivated and FeatureDeactivating events.

To add a Feature to your project


1. In Visual Studio 2012, on the View menu, point to Other Windows and then click Packaging Explorer.
2. In the Packaging Explorer, right-click the node representing your project and click Add Feature. A new Feature (named "Feature1" by default) is added to your project, under a
Features node (in Solution Explorer).
3. Now, in Solution Explorer, under the Features node, right-click the newly added Feature (that is, Feature1), and click Add Event Receiver. An event receiver class file
(Feature1.EventReceiver.cs) is added to the Feature and opened for editing.
4. Within the implementation (demarcated by opening and closing braces) of the Feature1EventReceiver class, add the following code.

internal const string PushNotificationFeatureId = "41E1D4BF-B1A2-47F7-AB80-D5D6CBBA3092";

This string variable stores the identifier for the Push Notification Feature on the server.

> **Tip:**
> You can obtain a list of unique identifiers for the Features on a SharePoint Server by executing the following Windows PowerShell cmdlet: > `Get-SPFeature | Sort -Property DisplayName`> The
1. The event receiver class file is created with some default method declarations for handling Feature events. The method declarations in the file are initially commented out. Replace the
FeatureActivated method in the file with the following code.

public override void FeatureActivated(SPFeatureReceiverProperties properties)


{
base.FeatureActivated(properties);
SPWeb spWeb = (SPWeb)properties.Feature.Parent;

ListCreator listCreator = new ListCreator();


listCreator.CreateJobsList(spWeb);
listCreator.CreateNotificationResultsList(spWeb);

// Then activate the Push Notification Feature on the server.


// The Push Notification Feature is not activated by default in a SharePoint Server installation.
spWeb.Features.Add(new Guid(PushNotificationFeatureId), false);
}

1. Replace the FeatureDeactivating method in the file with the following code.

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)


{
base.FeatureDeactivating(properties);
SPWeb spWeb = (SPWeb)properties.Feature.Parent;

// Deactivate the Push Notification Feature on the server


// when the PushNotificationsList Feature is deactivated.
spWeb.Features.Remove(new Guid(PushNotificationFeatureId), false);
}

1. Save the file.


In the implementation of the FeatureActivated event handler here, an instance of the ListCreator class is instantiated and its CreateJobsList and CreateNotificationResultsList
methods are called, using the SPWeb where the Feature is deployed and activated as the location in which the lists will be created. In addition, because push notification functionality is not
enabled by default in a standard installation of SharePoint Server, the event handler activates the Push Notification Feature on the server. In the FeatureDeactivating event handler, push
notification functionality is deactivated when the application has been deactivated. It isn't necessary to handle this event. You may or may not want to deactivate push notifications on the
server when the application is deactivated, depending on the circumstances of your installation and whether other applications on the target site make use of push notifications.

Create a Windows Phone SharePoint list app to receive push notifications


In this section, you create a Windows Phone app from the Windows Phone SharePoint List Application template, specifying the SharePoint list created in the preceding section as the target
list for the app. You then develop a Notifications class for subscribing to push notifications, implementing handlers for notification events, and storing information related to notifications on
the phone. You also add a XAML page to your app with controls to allow users to register or unregister for push notifications.
To follow the procedures in this section, first perform the steps in the procedure described in How to: Create a Windows Phone SharePoint list app to create a Visual Studio project from the
Windows Phone SharePoint List Application template, using the Jobs list created in the preceding section as the target SharePoint list for the project. For the purposes of the procedures in
this section, it is assumed that the name specified for the project isSPListAppForNotifications.

To create the class for managing subscriptions and received notifications


1. In Solution Explorer, choose the node representing the project (named SPListAppForNotifications).
2. On the Project menu, click Add Class. The Add New Item dialog box appears with the C# Class template already selected.
3. Specify "Notifications.cs" as the name of the file and click Add. The class file is added to the solution and opened for editing.
4. Replace the contents of the file with the following code.

using System;
using System.Linq;
using System.Net;
using System.Windows;
using Microsoft.Phone.Notification;
using Microsoft.SharePoint.Client;
using System.Diagnostics;
using System.Collections.Generic;
using Microsoft.Phone.Shell;
using System.IO;
using System.IO.IsolatedStorage;

namespace SPListAppForNotifications
{
public class Notifications
{
static HttpNotificationChannel httpChannel;
private const string RegStatusKey = "RegistrationStatus";
public static string DeviceAppIdKey = "DeviceAppInstanceId";
public static string ChannelName = "JobsListNotificationChannel";
public static ClientContext Context { get; set; }

public static void OpenNotificationChannel(bool isInitialRegistration)


{
try
{
// Get channel if it was created in a previous session of the app.
httpChannel = HttpNotificationChannel.Find(ChannelName);

// If channel is not found, create one.


if (httpChannel == null)
{
httpChannel = new HttpNotificationChannel(ChannelName);

// Add event handlers. When the Open method is called, the ChannelUriUpdated event will fire.
// A call is made to the SubscribeToService method in the ChannelUriUpdated event handler.
AddChannelEventHandlers();
httpChannel.Open();
httpChannel.Open();
}
else
{
// The channel exists and is already open. Add handlers for channel events.
// The ChannelUriUpdated event won't fire in this case.
AddChannelEventHandlers();

// If app instance is registering for first time


// (instead of just starting up again), then call SubscribeToService.
if (isInitialRegistration)
{
SubscribeToService();
}
}
}
catch (Exception ex)
{
ShowMessage(ex.Message, "Error Opening Channel");
CloseChannel();
}
}

private static void AddChannelEventHandlers()


{
httpChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(httpChannel_ChannelUriUpdated);
httpChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(httpChannel_ExceptionOccurred);
httpChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(httpChannel_ShellToastNotificationReceived);
httpChannel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(httpChannel_HttpNotificationReceived);
}

private static void httpChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)


{
UpdateChannelUriOnServer();
SubscribeToService();
}

private static void httpChannel_ExceptionOccurred(object sender, NotificationChannelErrorEventArgs e)


{
// Simply showing the exception error.
ShowMessage(e.Message, "Channel Event Error");
}

static void httpChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)


{
if (e.Collection != null)
{
Dictionary<string, string> collection = (Dictionary<string, string>)e.Collection;
ShellToast toast = new ShellToast();
toast.Title = collection["wp:Text1"];
toast.Content = collection["wp:Text2"];

// Note that the Show method for a toast notification won't


// display the notification in the UI of the phone when the app
// that calls the method is running (as the foreground app on the phone).
// toast.Show();
//Toast and Raw notification will be displayed if user is running the app. Be default only Toast notification
// will be displayed when the app is tombstoned

// Showing the toast notification with the ShowMessage method.


ShowMessage(string.Format("Title: {0}\\r\\nContent: {1}", toast.Title, toast.Content), "Toast Notification");
}
}

static void httpChannel_HttpNotificationReceived(object sender, HttpNotificationEventArgs e)


{
Stream messageStream = e.Notification.Body;
string message = string.Empty;

// Replacing NULL characters in stream.


using (var reader = new StreamReader(messageStream))
{
message = reader.ReadToEnd().Replace('\\0', ' ');
}

// Simply displaying the raw notification.


ShowMessage(message, "Raw Notification");
}

private static void SubscribeToService()


{
Guid deviceAppInstanceId = GetSettingValue<Guid>(DeviceAppIdKey, false);

Context.Load(Context.Web, w => w.Title, w => w.Description);

PushNotificationSubscriber pushSubscriber = Context.Web.RegisterPushNotificationSubscriber(deviceAppInstanceId, httpChannel.ChannelUri.AbsoluteUri);

Context.Load(pushSubscriber);

Context.ExecuteQueryAsync
(
(object sender, ClientRequestSucceededEventArgs args) =>
{
SetRegistrationStatus(true);

// Indicate that tile and toast notifications can be


// received by phone shell when phone app is not running.
if (!httpChannel.IsShellTileBound)
httpChannel.BindToShellTile();

if (!httpChannel.IsShellToastBound)
httpChannel.BindToShellToast();

ShowMessage(
string.Format("Subscriber successfully registered: {0}", pushSubscriber.User.LoginName),
"Success");
},
(object sender, ClientRequestFailedEventArgs args) =>
{
ShowMessage(args.Exception.Message, "Error Subscribing");
});
}

private static void UpdateChannelUriOnServer()


{
Guid deviceAppInstanceId = GetSettingValue<Guid>(DeviceAppIdKey, false);

Context.Load(Context.Web, w => w.Title, w => w.Description);

PushNotificationSubscriber subscriber = Context.Web.GetPushNotificationSubscriber(deviceAppInstanceId);

Context.Load(subscriber);

Context.ExecuteQueryAsync(
(object sender1, ClientRequestSucceededEventArgs args1) =>
{
subscriber.ServiceToken = httpChannel.ChannelUri.AbsolutePath;
subscriber.Update();
Context.ExecuteQueryAsync(
(object sender2, ClientRequestSucceededEventArgs args2) =>
{
ShowMessage("Channel URI updated on server.", "Success");
},
(object sender2, ClientRequestFailedEventArgs args2) =>
{
ShowMessage(args2.Exception.Message, "Error Upating Channel URI");
});
},
(object sender1, ClientRequestFailedEventArgs args1) =>
{
// This condition can be ignored. Getting to this point means the subscriber
// doesn't yet exist on the server, so updating the Channel URI is unnecessary.
//ShowMessage("Subscriber doesn't exist on server.", "DEBUG");
});
}

public static void UnSubscribe()


{
Context.Load(Context.Web, w => w.Title, w => w.Description);
Guid deviceAppInstanceId = GetSettingValue<Guid>(DeviceAppIdKey, false);

Context.Web.UnregisterPushNotificationSubscriber(deviceAppInstanceId);

Context.ExecuteQueryAsync
(
(object sender, ClientRequestSucceededEventArgs args) =>
{
CloseChannel();
SetRegistrationStatus(false);
//SetInitializationStatus(false);
ShowMessage("Subscriber successfully unregistered.", "Success");
},
(object sender, ClientRequestFailedEventArgs args) =>
{
ShowMessage(args.Exception.Message, "Error Unsubscribing");
});
}

public static void ClearSubscriptionStore()


{
Context.Load(Context.Web, w => w.Title, w => w.Description);
List subscriptionStore = Context.Web.Lists.GetByTitle("Push Notification Subscription Store");
Context.Load(subscriptionStore);
ListItemCollection listItems = subscriptionStore.GetItems(new CamlQuery());
Context.Load(listItems);

Context.ExecuteQueryAsync
(
(object sender1, ClientRequestSucceededEventArgs args1) =>
{
foreach (ListItem listItem in listItems.ToList())
{
listItem.DeleteObject();
}
Context.ExecuteQueryAsync(
(object sender2, ClientRequestSucceededEventArgs args2) =>
{
// Close channel if open and set registration status for current app instance.
CloseChannel();
SetRegistrationStatus(false);

ShowMessage("Subscriber store cleared.", "Success");


},
(object sender2, ClientRequestFailedEventArgs args2) =>
{
ShowMessage(args2.Exception.Message, "Error Deleting Subscribers");
});
},
(object sender1, ClientRequestFailedEventArgs args1) =>
{
ShowMessage(args1.Exception.Message, "Error Loading Subscribers List");
});
}

private static void CloseChannel()


{
if (httpChannel == null) return;
try
{
httpChannel.UnbindToShellTile();
httpChannel.UnbindToShellToast();
httpChannel.Close();
httpChannel.Close();
}
catch (Exception ex)
{
ShowMessage(ex.Message, "Error Closing Channel");
}
}

public static void SaveDeviceAppIdToStorage()


{
if (!IsolatedStorageSettings.ApplicationSettings.Contains(DeviceAppIdKey))
{
Guid DeviceAppId = Guid.NewGuid();
SetSettingValue<Guid>(DeviceAppIdKey, DeviceAppId, false);
}
}

public static bool GetRegistrationStatus()


{
bool status = GetSettingValue<bool>(RegStatusKey, false);
return status;
}

private static void SetRegistrationStatus(bool isRegistered)


{
SetSettingValue<bool>(RegStatusKey, isRegistered, false);
}

private static T GetSettingValue<T>(string key, bool fromTransientStorage)


{
if (fromTransientStorage == false)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(key))
return (T)IsolatedStorageSettings.ApplicationSettings[key];
return default(T);
}

if (PhoneApplicationService.Current.State.ContainsKey(key))
return (T)PhoneApplicationService.Current.State[key];
return default(T);
}

private static void SetSettingValue<T>(string key, T value, bool toTransientStorage)


{
if (toTransientStorage == false)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(key))
IsolatedStorageSettings.ApplicationSettings[key] = value;
else
IsolatedStorageSettings.ApplicationSettings.Add(key, value);

IsolatedStorageSettings.ApplicationSettings.Save();
}
else
{
if (PhoneApplicationService.Current.State.ContainsKey(key))
PhoneApplicationService.Current.State[key] = value;
else
PhoneApplicationService.Current.State.Add(key, value);
}
}

// Method for showing messages on UI thread coming from a different originating thread.
private static void ShowMessage(string message, string caption)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(message, caption, MessageBoxButton.OK);
});
}
}
}

1. Save the file.


In this code, the OpenNotificationChannel creates a notification channel for receiving notifications from MPNS. Event handlers are attached to the channel object for dealing with
notification events, and then the channel is opened. In this sample, the HttpNotificationReceived event (for receiving raw notifications) is implemented. Raw notifications can be received
only when the phone app is running. The handler for the ShellToastNotificationReceived event (for receiving toast notifications) is also implemented here to demonstrate its use. Tile
notifications can be received only when the subscribing phone app is not running, so there's no need to implement an event handler in the app for receiving tile notifications.
The SubscribeToService method executes the RegisterPushNotificationSubscriber method of the SPWeb object asynchronously (passing a value to identify the phone app and a URI
value associated with the notification channel) to register with the SharePoint Server to receive push notifications. If the registration is successful, the Windows Phone shell is set to receive
(and display) toast and tile notifications on the particular notification channel registered with the SharePoint Server when the phone app itself is not running.
The UnSubscribe method in this code calls the UnregisterPushNotificationSubscriber method of the SPWeb object. The development guidelines for Windows Phone apps recommend
that users be allowed to choose whether to subscribe to push notifications or not. In a later procedure, you will add a mechanism for the user to register or unregister for notifications and
that registration state is preserved between sessions of the app, making it unnecessary to ask to register every time the app is started. The GetRegistrationStatus method is made available
so that the phone app can determine whether the user has registered (in an earlier session) to receive push notifications and the notification channel is subsequently opened. The
SaveDeviceAppIdToStorage saves the identifier (represented as a GUID) for the app instance on a given Windows Phone to isolated storage.
The ClearSubscriptionStore method is included here as a demonstration of one way of clearing the subscribers from the subscription store on the SharePoint Server. Subscribers to push
notifications are stored in a SharePoint list named "Push Notification Subscription Store". A button for calling this method of the Notifications class is added to the notifications settings
page added to the app in a later procedure.
Note that the operations that involve accessing the SharePoint Server to configure settings or prepare for notifications (such as the RegisterPushNotificationSubscriber method) can take
time to complete, depending on the conditions of the network and the accessibility of the server. These operations are therefore executed asynchronously (specifically, by using the
ExecuteQueryAsync method of a ClientContext object) to allow the app to continue other processes and to keep the UI responsive to the user.
Next, add a page to the app with controls that allow a user to register for or unregister from push notifications from the server.
To add a notification settings page to the app
1. In Solution Explorer, choose the node representing the project (named SPListAppForNotifications if you follow the naming convention in these procedures).
2. On the Project menu, click Add New Item. The Add New Item dialog box appears.
3. In the Templates pane, choose Windows Phone Portrait Page template. SpecifySettings.xaml as the name of the file for the page and click Add. The page is added to the project
and opened for editing.
4. In the XAML view for the page, replace the content between the closing bracket of the XML tag that defines the PhoneApplicationPage element and the closing tag of the element (
</phone:PhoneApplicationPage> ), with the following markup.

<Grid x:Name="LayoutRoot" Background="Transparent">


<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<!--TitlePanel contains the name of the application and page title-->


<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="JOBS LIST" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Settings" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>

<!--ContentPanel - place additional content here-->


<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel Margin="0,5,0,5">
<StackPanel Orientation="Vertical" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Center" Style="{StaticResource PhoneTextTitle2Style}">Notification Registration</TextBlock>
<StackPanel Orientation="Vertical" Margin="0,5,0,5">
<TextBlock x:Name="txtRegistrationStatus" TextWrapping="Wrap" HorizontalAlignment="Center" Text="Registered: No" Style="{StaticResource PhoneTextAccentStyle}" Foreground="{Sta
<Button x:Name="btnRegister" Content="Register" Height="71" Width="260" Click="OnRegisterButtonClick" />
<Button x:Name="btnUnregister" Content="Unregister" Height="71" Width="260" Click="OnUnregisterButtonClick" />
</StackPanel>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0,5,0,5">
<TextBlock TextWrapping="Wrap" HorizontalAlignment="Center" Style="{StaticResource PhoneTextTitle2Style}">Subscriber Management</TextBlock>
<Button x:Name="btnDeleteSubscribers" Content="Delete Subscribers" Height="71" Width="260" Click="OnDeleteSubscribersButtonClick" />
</StackPanel>
</StackPanel>
</Grid>
</Grid>

<!--Sample code showing usage of ApplicationBar-->


<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="False">
<shell:ApplicationBarIconButton x:Name="btnOK" IconUri="/Images/appbar.check.rest.png" Text="OK" Click="OnOKButtonClick" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

1. With the Settings.xaml file selected in Solution Explorer, press F7 to open its associated code-behind file, Settings.xaml.cs, for editing.
2. Replace the contents of the code-behind file with the following code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.SharePoint.Client;

namespace SPListAppForNotifications
{
public partial class Settings : PhoneApplicationPage
{
private const string RegisteredYesText = "Registered: Yes";
private const string RegisteredNoText = "Registered: No";

public Settings()
{
InitializeComponent();
}

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)


{
this.txtRegistrationStatus.Text = (Notifications.GetRegistrationStatus()) ? RegisteredYesText : RegisteredNoText;
}

private void OnOKButtonClick(object sender, EventArgs e)


{
NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative));
}

private void OnRegisterButtonClick(object sender, RoutedEventArgs e)


{
Notifications.OpenNotificationChannel(true);
// Navigating back to List form. User will be notified when process is complete.
NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative));
}

private void OnUnregisterButtonClick(object sender, RoutedEventArgs e)


{
Notifications.UnSubscribe();
// Navigating back to List form. User will be notified when process is complete.
NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative));
}

private void OnDeleteSubscribersButtonClick(object sender, RoutedEventArgs e)


{
Notifications.ClearSubscriptionStore();
// Navigating back to List form. User will be notified when process is complete.
NavigationService.Navigate(new Uri("/Views/List.xaml", UriKind.Relative));
}
}
}

1. Save the file.


2. To add to your project the image file (appbar.check.rest.png) for the ApplicationBar button (btnOK) declared in the Settings.xaml file, choose the Images folder node in Solution
Explorer.
3. On the Project menu, click Add Existing Item. A File Browser window opens.
4. Navigate to the folder in which the standard Windows Phone icon images were installed by the Windows Phone SDK 7.1.
NOTE

The images with a light foreground and a dark background are in %PROGRAMFILES%(x86)\Microsoft SDKs\Windows Phone\v7.1\Icons\dark in a standard installation of the SDK.
5. Choose the image file named appbar.check.rest.png and click Add. The image is added is added to the project under the Images node.
6. In Solution Explorer, choose the image file just added and in the Properties Window for the file, set the Build Action property for the image file to "Content" and set the Copy to
Output Directory property to "Copy if newer".
Next, add a button to the List form (List.xaml) in the project and implement the Click event handler of the button to navigate to the Settings page created in the preceding steps. Also modify
the OnViewModelInitialization event handler to open a notification channel (if the user has chosen to subscribe to push notifications).

To modify the List form


1. In Solution Explorer, under the Views node, double-click the List.xaml file. The file is opened for editing.
2. Add markup to declare an additional button in the ApplicationBar element of the file, as in the following example.

...
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="btnNew"
IconUri="/Images/appbar.new.rest.png" Text="New"
Click="OnNewButtonClick" />
<shell:ApplicationBarIconButton x:Name="btnRefresh"
IconUri="/Images/appbar.refresh.rest.png" Text="Refresh" IsEnabled="True"
Click="OnRefreshButtonClick" />
<shell:ApplicationBarIconButton x:Name="btnSettings" IconUri="/Images/appbar.feature.settings.rest.png" Text="Settings" IsEnabled="True" Click="OnSettingsButtonClick" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
...

1. With the List.xaml file selected in Solution Explorer, press F7 to open its associated code-behind file, List.xaml.cs, for editing.
2. Within the code block (demarcated by opening and closing braces) that implements the ListForm partial class, add the following event handler to the file.
private void OnSettingsButtonClick(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/Settings.xaml", UriKind.Relative));
}

1. Locate the OnViewModelInitialization in the List.xaml.cs file and add a call to the OpenNotificationChannel method of the Notifications class created earlier. The modified
implementation of the handler should resemble the following code.

private void OnViewModelInitialization(object sender, InitializationCompletedEventArgs e)


{
this.Dispatcher.BeginInvoke(() =>
{
//If initialization has failed, show error message and return
if (e.Error != null)
{
MessageBox.Show(e.Error.Message, e.Error.GetType().Name, MessageBoxButton.OK);
return;
}

App.MainViewModel.LoadData(((PivotItem)Views.SelectedItem).Name);
this.DataContext = (sender as ListViewModel);
});

// Open notification channel here if user has chosen to subscribe to notifications.


if (Notifications.GetRegistrationStatus() == true)
Notifications.OpenNotificationChannel(false);
}

1. Save the file.


2. To add to your project the image file (appbar.feature.settings.rest.png) for the ApplicationBar button (btnSettings) declared in the List.xaml file, choose the Images folder node in
Solution Explorer.
3. On the Project menu, click Add Existing Item. A File Browser window opens.
4. Navigate to the folder in which the standard Windows Phone icon images were installed by the Windows Phone SDK 7.1. (See the note in the previous procedure for the location of
the image files in a standard installation of the SDK.)
5. Choose the image file named appbar.feature.settings.rest.png and click Add. The image is added is added to the project under the Images node.
6. In Solution Explorer, choose the image file just added and in the Properties Window for the file, set the Build Action property for the image file to "Content" and set the Copy to
Output Directory property to "Copy if newer".
Finally, add code to the Application_Launching event hander in the App.xaml.cs file to prepare the app for receiving push notifications, using properties and methods of the Notifications
class created earlier.

To add code to the App.xaml.cs file


1. In Solution Explorer, under the node representing the project, choose the App.xaml file.
2. Press F7 to open its associated code-behind file, App.xaml.cs, for editing.
3. Locate the Application_Launching event handler in the file. (For new projects created from the Windows Phone SharePoint List Application template, the signature for the method
that handles the Application_Launching event is included but no logic is implemented in the method.)
4. Replace the Application_Launching event handler with the following code.

private void Application_Launching(object sender, LaunchingEventArgs e)


{
// Get set up for notifications.
Notifications.Context = App.DataProvider.Context;
Notifications.SaveDeviceAppIdToStorage();
}

1. Save the file.


If you compile the project and deploy the app to the Windows Phone Emulator to run it, you can click the Settings button on the Application Bar to display a page from which you can
register for push notifications (Figure 1).
Figure 1. Settings page for notification registration
If you have deployed and activated the PushNotificationsList solution (developed in the section Create a server-side solution to send push notifications based on a list item event earlier in
this topic) to your target SharePoint Server, and if registration from the phone for notifications is successful, you can add an item to the Jobs list on the server and you should receive both a
toast notification (Figure 2) and, if the app is running on the phone when the item is added to the list, a raw notification (Figure 3).
Figure 2. Toast notification (app running)

The message displayed when your app received a toast notification while it's running depends on how you've implemented the ShellToastNotificationReceived event handler in your app.
In the Notifications class for this sample, the title and content of the message are simply displayed to the user.
Figure 3. Raw notification

If the app is not running when the item is added to the list, the phone should still display a toast notification (Figure 4).
Figure 4. Toast notification (app not running)

When you add an item to the Jobs SharePoint list, the code in the event receiver associated with the list attempts to send notifications using MPNS to subscribed phones, but, depending on
network conditions and other factors, a given notification may not be received by a phone. You can look at the Push Notification Results list on the server, especially the values in the Status
Code and Headers columns, to determine the status and results related to individual notifications.

See also
Build Windows Phone apps that access SharePoint
Push Notifications Overview for Windows Phone
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Create a mobile app in SharePoint that contains data from an external data source
3/26/2018 • 7 minutes to read Edit Online

Learn how to create a simple mobile app in SharePoint that contains data from external data source by using Business Connectivity Services and connecting to an external list. SharePoint
enables you to build mobile applications that can access external data from databases, enterprise applications, and Web 2.0 services using Business Connectivity Services. You can also
provide complete interaction with the external data including write-back capabilities from your mobile device. You do this by creating apps that connect to external lists, which are a special
type of lists in SharePoint that are based on external content types and contain data from an external system. The new Windows Phone SharePoint List template in Visual Studio 2010
Express enables you to quickly and easily create apps for the Windows Phone that connects to external lists. For example, you can build a Windows phone app that brings the product catalog
for an inventory list in SharePoint to the phone for the sales people. This topic shows how to create a Windows Phone app that displays external data from the Northwind sample database
by connecting to an external list in SharePoint. Notice that in this example, the external list connects to the Northwind database using a custom OData service; however, it's possible to
connect to databases directly as well as any external system that is supported by Business Connectivity Services, using external lists. With the new SharePoint List template in Visual Studio,
you can create a mobile app that can access an external list on a SharePoint site. This article provides a step-by-step procedure that begins with uploading an external Business Data
Connectivity (BDC) service model and ends with testing your new mobile app.

Important: If you are developing an app for Windows Phone 8, you must use Visual Studio Express 2012 instead of Visual Studio 2010 Express. Except for the development
environment, all information in this article applies to creating apps for both Windows Phone 8 and Windows Phone 7. > For more information, see How to: Set up an environment for
developing mobile apps for SharePoint.

Prerequisites for creating a mobile app that contains external data


A SharePoint installation with administrative privileges to upload the BDC model for the Northwind database and a SharePoint site where you create the external list
Microsoft Visual Studio Express with the new SharePoint phone templates from Microsoft SharePoint SDK for Windows Phone 7.1
The BDC model for our exampleNorthwind_oData.bdmc (download from SharePoint: Create a simple external list-based phone app)
A SharePoint installation with administrative privileges to upload the BDC model for the Northwind database and a SharePoint site where you create the external list

Step 1: Upload a BDC metadata model


A BDC model is the core of Business Connectivity Services. It's an XML file that uses data structures such as Entity (external content type) and Method to abstract out complex details about
the external system. It's auto-generated when you create an external content type using SharePoint Designer and for some data source types such .NET and OData sources, you need to
create the BDC model manually or by using Visual Studio. When you upload a BDC model to the BDC metadata store using SharePoint Central Administration, the external content types
defined in the model can be used to create external lists in SharePoint which are lists that display data from the underlying external system. In this step, you'll upload the Northwind sample
BDC model to the Metadata Store using SharePoint Central Administration.
1. Navigate to Central Administration.
2. Choose Application Management, and then choose Manage Service Applications.
3. On the Service Application page, choose Business Data Connectivity Service.
4. On the ribbon in the BDC Service application, choose Import.
5. On the Import BDC Model page, choose Business Data Connectivity Service.
6. On the ribbon in the BDC Service application, choose Import.
7. On the Import BDC Model page, choose Browse.
8. In the Choose a File to upload dialog box, browse to the Northwind_oData.bdcm file, and then choose Open.
9. After the file is imported, choose the OK button.

Step 2: Grant permissions


Next you need to set permissions on the BDC model to specify who can execute the methods described in the model. This is a required step. We recommend that you give specific
permissions to each user or group that needs them, in such a way that the credentials provide the least privilege necessary to perform the needed tasks. For more information about setting
permissions, see Business Connectivity Service permissions overview in Business Connectivity Services security overview (SharePoint Server 2010). In this step, you give permission to
yourself to execute the methods described in the Northwind sample BDC model.
1. Navigate to Central Administration.
2. Choose Application Management, and then choose Manage Service Applications.
3. On the Service Application page, choose Business Data Connectivity Service.
4. In the ribbon, choose BDC Models from the drop-down list in the View group.
5. In the list of BDC models, hover over Northwind_oData.bdcm and choose Set Permissions, as shown in Figure 1.
Figure 1. Choosing permissions for BDC model

1. In the Set Object Permissions dialog box, choose the Browse button.
2. In the Select People and Groups dialog box, search for your account and choose the OK button.
3. Select the permissions for Edit, Execute, Selectable In Clients, and Set Permissions, as shown in Figure 2.
Figure 2. Setting object permissions
1. Choose the OK button.
2. In the ribbon, select External Content Types from the drop-down list in the View group.
3. In the list of external content types, hover over Customer, and then choose Set Permissions.
4. In the Set Object Permissions dialog box, choose the Browse button and search for your account.
5. In the Set Object Permissions dialog box, choose Add and select the permissions for Edit, Execute, Selectable In Clients, and Set Permissions.
6. Ensure that the Propagate Permissions box is selected.
7. Choose the OK button.

Step 3: Create an external list


Now that you've uploaded the BDC model and set permissions, you can create an external list based on the external content type defined in the BDC model. In this step, you will create an
external list based on the Customer external content type defined in the Northwind BDC model you uploaded in Step 1: Upload a BDC metadata model.
1. Navigate to the SharePoint site where you want the new list.
2. On the home page of the site, choose More.
3. On the Apps page, choose Add an App.
4. On the Add an App page, hover over External List and choose Add it.
5. In the Adding an External List dialog box, enter a name such asCustomers in the Name field.
6. In the External Content Type box, specify the external data source that you uploaded in step 1.
7. Choose the OK button.
8. On the Apps page, choose Customers List to view the list.

Step 4: Create a mobile app using the Windows Phone SharePoint List Application template
Your external list is ready and you can now create a Windows Phone 7 app that connects to the external list you created in Step 3: Create an external list and display Customer data from the
Northwind database.
1. Start Visual Studio 2010 Express.
2. On the menu bar, choose File, New Project. The New Project dialog box opens.
3. In the New Project dialog box, choose Visual C#, choose Silverlight for Windows Phone, and then choose Windows Phone SharePoint List Application.
4. Specify a name for the project. We use CustomerApp in this example, as shown in Figure 3.
Figure 3. Selecting the Windows Phone SharePoint List Application template in Visual Studio

1. Choose the OK button.


2. In the SharePoint Phone Application Wizard, enter the URL of the SharePoint site in which you created the external list.
3. Choose the Customers list, and choose Next.
4. On the Choose Views screen, select Customer Read List and choose Next.
5. On the Choose Operations screen, choose Display, and then choose Next.
6. On the Choose Fields screen, select the fields you want to use or display in your mobile app, and then choose Next.
7. On the Order Fields screen, reorder the fields if needed, and then choose Finish.
8. You've now successfully created the app that connects to the external list.
Run and test your app
Now that the app is ready to run, you can test it using phone emulator.
1. In Visual Studio, choose Debug, and then choose Start Debugging, or press F5.
2. When prompted, log in by using the same username and password that you used to log in to the SharePoint site. Ensure that you have admin rights.
3. Scroll through the resulting Customers list, as shown in Figure 4.
Figure 4. Mobile app displaying SharePoint external list

NOTE

When you use the SharePoint List Template wizard to create a mobile app for an external list that has read-only fields, the code that is generated by the wizard does not allow users to create
or edit items.

See also
Build Windows Phone apps that access SharePoint
Overview of Windows Phone SharePoint application templates in Visual Studio
How to: Create External Lists in SharePoint
How to: Create a Windows Phone SharePoint list app
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Integrate maps with Windows Phone apps and SharePoint lists
3/26/2018 • 6 minutes to read Edit Online

Learn how to integrate location information and maps in SharePoint lists and location-based web and mobile SharePoint Add-ins, by using the new Geolocation field, and by creating your
own geolocation-based field types. SharePoint introduces a new field type named Geolocation that enables you to annotate SharePoint lists with location information. In columns of type
Geolocation, you can enter location information as a pair of latitude and longitude coordinates in decimal degrees or retrieve the coordinates of the user's current location from the browser,
if the browser implements the W3C Geolocation API. In the list, SharePoint displays the location on a map powered by Bing Maps. Together, the Geolocation field and the Map View enable
you to give a spatial context to any information by integrating data from SharePoint into a mapping experience, and let your users engage in new ways in your web and mobile apps and
solutions. We'll help you create a simple Windows 7 mobile app which uses the SharePoint Geolocation field type feature to use mapping capabilities so you can display maps on mobile
SharePoint Add-in list items.

Important: If you are developing an app for Windows Phone 8, you must use Visual Studio Express 2012 instead of Visual Studio 2010 Express. Except for the development
environment, all information in this article applies to creating apps for both Windows Phone 8 and Windows Phone 7. > For more information, see How to: Set up an environment for
developing mobile apps for SharePoint.

Prerequisites for creating a map-based Windows phone app


Ensure that you have the following installed:
SharePoint
Visual Studio 2012
Visual Studio Express 2010 with new the SharePoint phone templates from Microsoft SharePoint SDK for Windows Phone 7.1
Access to a SharePoint list, with sufficient privileges to add a column
The Bing Maps key deployed to your server; see How to: Set the Bing Maps key at the web and farm level in SharePoint

Step 1: Create a SharePoint field by using the Geolocation feature


The Geolocation column is not available by default in SharePoint lists. You have to write code to add the column to a SharePoint list. We'll show you how to add the Geolocation field to a list
programmatically by using the SharePoint client object model. After you add the field to the list, you can add Geolocation field as a feature to the list.

To create the Visual Studio project


1. Log on as an administrator to the server running SharePoint.
2. Start Visual Studio and choose File, New Project. The New Project dialog box opens.
3. In the New Project dialog box, choose Visual C#, choose SharePoint, and then choose the SharePoint Project type.
4. Name the project. In this example, we use GeoList. Choose the OK button.
5. In the SharePoint Customization Wizard, enter the URL for the site collection that uses the same SharePoint list that you want to access for phone development.
6. In Solution Explorer, open the shortcut menu for the GeoList project, and then choose Add, New Item.
7. In the Add New Item dialog box, choose List. Name the list. In this example, we use ServiceCalls.
8. In the Choose List Settings dialog box, add a display name. In this example, we use Service Calls. For Choose to customize the list based on, choose Default (Blank), as shown
in Figure 1.
Then, choose Finish.
Figure 1. Adding the SharePoint list by using the SharePoint List wizard

To add a Feature to the SharePoint list


1. In Solution Explorer, and then expand the Features node.
2. Open the shortcut menu for the Feature1 node, and then choose Add, Add Event Receiver.
3. Uncomment the FeatureActivated method and FeatureDeactivating method, and then add the following code.
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb site = properties.Feature.Parent as SPWeb;
SPList list = site.Lists.TryGetList("Service Calls");
if (list != null)
{
list.Fields.AddFieldAsXml(
"<Field Type='Geolocation' DisplayName='Location'/>",
true,
SPAddFieldOptions.Default);
list.Update();
}
}
public override void FeatureDeactivating(
SPFeatureReceiverProperties properties)
{
SPWeb site = properties.Feature.Parent as SPWeb;
SPList list = site.Lists.TryGetList("Service Calls");
if (list != null)
{
list.Delete();
}
}

1. Build the solution by choosing the F6 key.

Step 2: Deploy the list and enter data into the location-based SharePoint list
In this step, you deploy the newly created list from Visual Studio and use the new Location field in SharePoint.

To deploy the SharePoint list


In Solution Explorer, open the shortcut menu for the GeoList project, and then choose Deploy.

To enter data in the new SharePoint list with the Geolocation field
1. After the list successfully deploys, open the site you are using for phone development.
2. Choose More, and then choose the Service Calls list.
3. Choose Add New Item.
4. Provide a title for the Title field. For this example, use New Geolocation Item.
5. Choose Use Current Location in the Location field, or you can choose Specify Location, and then enter values for Longitude and Latitude.
6. Choose Save.

Step 3: Build a phone app for the location-based List


In this step, you create a phone app that uses the SharePoint list you created previously in step 1 and step 2.
1. Log on to the Phone Development environment on the client side.
2. Start Visual Studio 2010 Express with the new SharePoint templates.
3. On the menu bar, choose File, New Project.
The New Project dialog box opens.
4. In the New Project dialog box, choose Visual C#, Silverlight for Windows Phone, Windows Phone SharePoint List Application.
5. Name the project. In this example, we use GeoApp. Choose the OK button.
6. In the SharePoint Phone Application Wizard, enter the URL of the SharePoint site where you have deployed the list in Step 2. Deploy the list and enter data into the
location-based SharePoint list, and then choose Find Lists.
7. Choose the Service Calls list, and then choose Next.
8. On the Choose Views page, choose All Items, and then choose Next.
9. On the Choose Operations page, choose Display, and then choose Next.
10. On the Choose Fields page, choose the field you want to see on your phone app, and then choose Next.
11. On the Order Fields page, reorder the fields as you need, and then choose Finish.

Step 4: Test and validate your app


In this step, you can run your app and validate it.
1. In Visual Studio, choose Debug, Start Debugging.
2. When prompted, log on, using credentials that have admin rights on the server running SharePoint.
3. For this example, choose the first entry, Brian Cox.
4. Choose the Map It link found in the Location field.
5. On the Allow maps to access and use your location privacy policy screen, choose Allow, as shown in Figure 2.
Figure 2. Mobile app request to have access to your current location
The map view is displayed, as shown in Figure 3.

Figure 3.Mobile App display location in Bing map

NOTE

The user's experience of the Geolocation field can be different on mobile devices than in browsers. The Use Specific Location option, available in the browser, is not available for mobile
devices. For mobile devices, only one option is available: Use my location.

See also
Build Windows Phone apps that access SharePoint
Integrating location and map functionality in SharePoint
How to: Extend the Geolocation field type using client-side rendering
How to: Add a Geolocation column to a list programmatically in SharePoint
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Build search-driven mobile apps with the Navigation and Event Logging REST interfaces
3/26/2018 • 6 minutes to read Edit Online

SharePoint introduces the Navigation and Event Logging REST interfaces, enabling you to create a search-driven mobile app for mobile devices such as phones and tablets that run on
operating systems other than Windows—for example, Android and iOS.

How apps work with the product catalog


A product catalog can be displayed on a mobile device in different ways. Traditionally, you can configure a mobile channel for the product catalog within SharePoint. Creating a mobile
channel enables you to tailor a look and feel that matches any screen size on a mobile device. The resulting page is viewed in .ASPX format using the web browser on the mobile device. The
structure of the pages and its corresponding logic is handled by the server running SharePoint. In contrast, an app created with the Navigation and Event Logging REST interfaces is search-
driven and acts as a front-end to navigate the product catalog structures.
An app is not a stand-alone program, but works with a product catalog set up in an existing SharePoint installation. The app can update the navigation structure dynamically if the product
catalog has changed in that particular SharePoint installation. In addition, click events made by the user are sent back to the server running SharePoint to improve the overall quality of
recommendations made by the product catalog.
The app constructs the pages needed by the user to view the product catalog without using a web browser. Master pages, page layouts, and logic to construct the pages to view the product
catalog are downloaded onto devices as an app; these pages are reused whenever the user runs the app. While the user navigates the product catalog, the app simultaneously constructs a
navigation structure and sets up the pages. To fill in relevant pages with item content, search queries are sent to the product catalog in SharePoint. The corresponding search results are then
used to fill the pages.

Example: Create a search-driven mobile app with home, category, and item detail pages
Suppose you have a mobile app with three types of pages: a home page, category pages, and item detail pages. The following sections describe how the Navigation, Event Logging, and
Search REST interfaces are used to create the pages.

Home page for a search-driven mobile app


Typically the Home page is displayed when the app starts up. The Home page contains the product catalog menu, some text, and a static image, as shown in Figure 1.
Figure 1. Home page for a search-driven mobile app

To construct this page, the app sends a Navigation REST call to the server running SharePoint requesting the navigation structure of the product catalog. Next, the app uses the response
data to set up the correct taxonomy or menu structure and displays the correct term names for the product catalog. Additional content such as page layout, title text, and static images are
stored in the app itself. If the taxonomy is modified at a later time, the app can be updated with the Navigation REST call when it is run.
The following is an example of a typical Navigation REST call.

GET http://server/_api/navigation/menustate?mapprovidername='GlobalNavigationSwitchableProvider'

A matching response is shown in Example response for a Navigation REST call for a mobile app.

Category page for a search-driven mobile app


The Category page displays many items in a selected category. Each item listed in a category can typically be represented by some relevant item data, such as title, an image, and price. This
data is collected from the product catalog by using a search query through the SharePoint Search REST service as shown in Figure 2.
Figure 2. Category page for a search-driven mobile app

If you choose one of the categories in the previous diagram, for example, TV, a Category page appears.
The following is an example of a typical Search REST query to obtain content for a particular category.

GET http://server/_api/search/query?querytext='owstaxidProductCatalogItemCategory:#0<TermGuid>'

A matching response is shown in Example response for a Search REST query for a mobile app.
The query processing component in SharePoint returns search results that contain data for a particular category, and the app presents the data in the Category page. If there is a Best Bet
associated with the selected category, the query processing component detects this association and extracts the Best Bet data from the Best Bet database, labeled BB in the diagram. The
search results are then mixed with results from the Best Bet database and sent back to the app in a result table. The app is responsible for extracting the different parts of the results from the
table and displaying the Best Bet in a dedicated location.

Item detail pages for a search-driven mobile app


If you select an item in a category, the Item details page appears. On this page, an item is described in detail with data such as title, product images, technical description, price, and delivery
information. More recommendations or ratings, if available, are also displayed. To construct the Item details page, the app sends two queries: one query to retrieve item data and another
query to receive recommendations related to that item, as shown in Figure 3.
Figure 3. Item detail page for a search-driven mobile app

The following is an example of a typical Search REST query to obtain content for a particular item.

GET http://server/_api/search/query?querytext='ProductCatalogItemNumberOWSTEXT:1234567'

Recommendations are calculated in SharePoint, not in the app itself. To create recommendations based on user events—not only in this particular app but all user events that are collected by
the product catalog—the app constantly sends user events, as they occur, back to the product catalog in SharePoint via an Event call. These user events are stored in the event log and
processed only like other user events associated with that particular item. No callback is sent to the app from the product catalog. The recommendations calculated are available for the app
through the SharePoint Search REST service.
The following example shows a typical POST call for event logging.

POST http://server/_api/events/logevent
{
"usageEntry": {
"__metadata": {
"type": "Microsoft.SharePoint.Administration.UsageEntry"
},
"EventTypeId": 1,
"ItemId": "an item fb7c-4196-8123-e54eee5f4787",
"ScopeId": "61141c0e-fb7c ",
"Site": "61141c0e-
-4196-8123-e54eee5f4787",
"User": "johndoe"
}
}

The service follows standard HTTP return codes: an HTTP 200 response indicates a successful request. There are no responses from the product catalog for the Event Logging REST
interface.

Example response for a Navigation REST call for a mobile app


<?xml version="1.0" encoding="utf-8"?>
<d:MenuState xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" x

<d:FriendlyUrlPrefix>/sites/contoso/</d:FriendlyUrlPrefix>
<d:Nodes>
<d:element m:type="SP.MenuNode">
<d:CustomProperties m:null="true" />
<d:FriendlyUrlSegment>electronics</d:FriendlyUrlSegment>
<d:Hidden m:type="Edm.Boolean">false</d:Hidden>
<d:Key>16c4c3c8-0309-47f7-9d9b-17e699febce8</d:Key>
<d:Nodes>
<d:element m:type="SP.MenuNode">
<d:CustomProperties m:null="true" />
<d:FriendlyUrlSegment>audio</d:FriendlyUrlSegment>
<d:Hidden m:type="Edm.Boolean">false</d:Hidden>
<d:Key>3e2d5c67-3fad-4cfa-8e1c-8c74fdf3a34b</d:Key>
<d:Nodes>
<d:element m:type="SP.MenuNode">
<d:CustomProperties m:null="true" />
<d:FriendlyUrlSegment>car-audio</d:FriendlyUrlSegment>
<d:Hidden m:type="Edm.Boolean">false</d:Hidden>
<d:Key>e3d271a4-dcbf-464d-a557-23848ccaa54f</d:Key>
<d:Nodes />
<d:NodeType m:type="Edm.Int32">1</d:NodeType>
<d:SimpleUrl></d:SimpleUrl>
<d:Title>Car audio</d:Title>
</d:element>
<d:element m:type="SP.MenuNode">
<d:CustomProperties m:null="true" />
<d:FriendlyUrlSegment>headphones</d:FriendlyUrlSegment>
<d:Hidden m:type="Edm.Boolean">false</d:Hidden>
<d:Key>7ad146d0-61b5-4b55-9da0-db7eaaa20f4a</d:Key>
<d:Nodes />
<d:NodeType m:type="Edm.Int32">1</d:NodeType>
<d:SimpleUrl></d:SimpleUrl>
<d:Title>Headphones</d:Title>
</d:element>
<d:element m:type="SP.MenuNode">
<d:CustomProperties m:null="true" />
<d:FriendlyUrlSegment>mp3</d:FriendlyUrlSegment>
<d:Hidden m:type="Edm.Boolean">false</d:Hidden>
<d:Key>7387fe97-52fa-464b-878a-b05d04e7032e</d:Key>
<d:Nodes />
<d:NodeType m:type="Edm.Int32">1</d:NodeType>
<d:SimpleUrl></d:SimpleUrl>
<d:Title>MP3</d:Title>
</d:element>
<d:element m:type="SP.MenuNode">
<d:CustomProperties m:null="true" />
<d:FriendlyUrlSegment>speakers</d:FriendlyUrlSegment>
<d:Hidden m:type="Edm.Boolean">false</d:Hidden>
<d:Key>65da907c-9565-45f6-a278-cbce7f74ab3d</d:Key>
<d:Nodes />
<d:NodeType m:type="Edm.Int32">1</d:NodeType>
<d:SimpleUrl></d:SimpleUrl>
<d:Title>Speakers</d:Title>
</d:element>
</d:Nodes>
<d:NodeType m:type="Edm.Int32">1</d:NodeType>
<d:SimpleUrl></d:SimpleUrl>
<d:Title>Audio</d:Title>
</d:element>
</d:Nodes>
<d:NodeType m:type="Edm.Int32">1</d:NodeType>
<d:SimpleUrl></d:SimpleUrl>
<d:Title>Electronics</d:Title>
</d:element>
</d:Nodes>
<d:SimpleUrl m:null="true" />
<d:SPSitePrefix>/sites/contoso/</d:SPSitePrefix>
<d:SPWebPrefix>/sites/contoso/</d:SPWebPrefix>
<d:StartingNodeKey>2168423f-3fea-4324-a5cb-90be8f079750</d:StartingNodeKey>
<d:StartingNodeTitle>contoso</d:StartingNodeTitle>
<d:Version>2012-05-29T12:00:04.4747484Z</d:Version>
</d:MenuState>

Example response for a Search REST query for a mobile app


<d:query xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns
<d:ElapsedTime m:type="Edm.Int32">4640</d:ElapsedTime>
<d:PrimaryQueryResult m:type="Microsoft.Office.Server.Search.REST.QueryResult">
<d:CustomResults m:null="true"/>
<d:QueryId>7fea4ced-5789-4067-beab-8f807410b29e</d:QueryId>
<d:QueryRuleId m:type="Edm.Guid">00000000-0000-0000-0000-000000000000</d:QueryRuleId>
<d:RefinementResults m:null="true"/>
<d:RelevantResults m:type="Microsoft.Office.Server.Search.REST.RelevantResults">
<d:GroupTemplateId m:null="true"/>
<d:ItemTemplateId m:null="true"/>
<d:Properties>
...
</d:Properties>
<d:ResultTitle m:null="true"/>
<d:ResultTitleUrl m:null="true"/>
<d:RowCount m:type="Edm.Int32">10</d:RowCount>
<d:Table m:type="SP.SimpleDataTable">
<d:Rows>
...
</d:Rows>
</d:Table>
<d:TotalRows m:type="Edm.Int32">2048964</d:TotalRows>
<d:TotalRowsIncludingDuplicates m:type="Edm.Int32">2048964</d:TotalRowsIncludingDuplicates>
</d:RelevantResults>
<d:SpecialTermResults m:null="true"/>
</d:PrimaryQueryResult>
<d:Properties>
...
</d:Properties>
<d:SecondaryQueryResults m:null="true"/>
<d:SpellingSuggestion/>
<d:TriggeredRules>
</d:TriggeredRules>
</d:query>

See also
Build Windows Phone apps that access SharePoint
Use OData query operations in SharePoint REST requests
Overview of the SharePoint mobile object model
3/26/2018 • 20 minutes to read Edit Online

Learn about the new public classes in the SharePoint server object model and Silverlight client object model that are used to develop integrated solutions for SharePoint and Windows
Phone 7.5.

Client object model for mobile Silverlight


All classes in this section are in the Microsoft.SharePoint.Client namespace. In addition to the APIs in this section, most of the classes and members in the section Server Object Model for
SharePoint Mobility are also callable in the client object model. For classes that begin with "SP", the client object model name has the "SP" removed. In other cases, the client object model
name is specified. Member names are the same in the client object model except where specified otherwise.

AlternateUrl class
Represents an alternative URL for a web application and the zone to which it applies.

public class AlternateUrl

Properties
Uri (read-only)
Gets the URI of the alternate URL.

public String Uri

UrlZone (read-only)
Gets the zone of the alternate URL.

public UrlZone UrlZone

The UrlZone class is the client object model version of the SPUrlZone class in the server object model. For more information about it, see the SharePoint 2010 Software Development Kit
(SDK).

AuthenticationCompletedEventArgs class
Provides data about an AuthenticationCompleted event.

public sealed class AuthenticationCompletedEventArgs : AsyncCompletedEventArgs

Constructors
Initializes a new instance of the AuthenticationCompletedEventArgs class.

public AuthenticationCompletedEventArgs(Exception error, bool canceled, HttpStatusCode userState)

Parameters
error is the Exception object if there was an exception thrown in the authentication attempt.
canceled is true if the authentication attempt was canceled before it could succeed or fail.
userState is the HttpStatusCode returned by the server.
Properties
HttpStatusCode (read-only)
Gets the status returned by the server after an authentication attempt.

public HttpStatusCode HttpStatusCode

AuthenticationStatus enum
Specifies the current state of an authentication attempt.
NotStarted
InProgress
CompletedSuccess
CompletedException

Authenticator class
Provides methods for authenticating a user on a SharePoint website.

public class Authenticator : ICredentials

Constructors
Initializes a new instance of the class.
public Authenticator()

public Authenticator(Uri uagServerUrl)

Parameters
uagServerUrl is the absolute URL of a United Access Gateway (UAG) server.

public Authenticator(string userName, string password)

Parameters
userName is the name for the credentials.
password is the password for the credentials.

public Authenticator(string userName, string password, string domain)

Parameters
userName is the name for the credentials.
password is the password for the credentials.
domain is the name of the domain or computer where the credentials are verified, typically the domain of the current user.

public Authenticator(string userName, string password, Uri uagServerUrl)

Parameters
userName is the name for the credentials.
password is the password for the credentials.
uagServerUrl is the absolute URL of a United Access Gateway (UAG) server.

public Authenticator(string userName, string password, string domain, Uri uagServerUrl)

Parameters
userName is the name for the credentials.
password is the password for the credentials.
domain is the name of the domain or computer where the credentials are verified, typically the domain of the current user.
uagServerUrl is the absolute URL of a United Access Gateway (UAG) server.
Methods
ClearAllApplicationSettings
Clears all cookies, credentials, and UAG settings from the cache.

public static void ClearAllApplicationSettings

ClearAllCookies
Clears all stored cookies and sets the Status property of all Authenticator objects to NotStarted.

public static void ClearAllCookies()

ClearAllCredentials
Clears all credentials from the cache and sets the Status property of all Authenticator objects to NotStarted.

public static void ClearAllCredentials()

GetCredential
Gets a credential object for the specified uri and authentication type.

public NetworkCredential GetCredential(Uri uri, string authType)

Parameters
uri is the URI, including port, for which the client is providing authentication.
authType is the type of authentication requested.
This method is only used for anonymous authentication. If authType is not "Basic", an empty object is returned. For more information about the NetworkCredential class, see
NetworkCredential Class.
IsRequestUnauthorized
Returns true if the authorization request failed because of an invalid cookie or credentials.
public static bool IsRequestUnauthorized(ClientRequestFailedEventArgs failedEventArgs)

Properties
AllowSmartRouting
Gets or sets an indicator of whether smart routing is enabled.

public bool AllowSmartRouting

When smart routing is enabled, the Authenticator object tries to connect to the server that is running SharePoint and the UAG server and uses whichever responds first as its
communication channel. If there is no UAG server, this property is ignored. The default is true. If set to false, the UAG server is always used.
AuthenticatorMode
Gets or sets the authentication mode.

public ClientAuthenticationMode AuthenticationMode

For more information about the ClientAuthenticationMode enum, see later in this document.
CookieCachingEnabled
Gets or sets an indicator of whether cookies are cached.

public bool CookieCachingEnabled

If you enable caching of cookies, consider that the cookies expire at some point. If they are expired when ExecuteQueryAsync is called, then it fails and the callback for failure runs.
Accordingly, if you set this property to true, you must add code to the callback for failure that clears the cache if this happens. Here is an example, where execQueryArgs is of the type
ClientRequestFailedEventArgs passed in the failure callback of ExecuteQueryAsync.

if (Authenticator.IsRequestUnauthorized(execQueryArgs))
{
(sender as Authenticator).ClearCookies();
}

CredentialCachingEnabled
Gets or sets an indicator of whether credentials are cached.

public bool CredentialCachingEnabled

Domain
Gets or sets the domain or computer for the credential, usually this is the domain of the current user.

public string Domain

When this property is set to a new value, the Status property is set to NotStarted.
NavigateBackAfterAuthentication
Gets or sets a indicator of whether the user should be navigated back to the previous page from the login page.

public bool NavigateBackAfterAuthentication

Password
Gets or sets the password for the credential.

public string Password

When this property is set to a new value, the Status property is set to NotStarted.
PromptOnFailure
Gets or sets an indicator of whether the user should be prompted to enter a name and password if initial authentication fails.

public bool PromptOnFailure

Status (read-only)
Gets the status of the attempt to authenticate.

public AuthenticationStatus Status

See earlier in this document for information about the AuthenticationStatus class.
UagServerUrl
Gets or sets the URL of the UAG server.

public Uri UagServerUrl


UserName
Gets or sets the user name for the credential.

public string UserName

When this property is set to a new value, the Status property is set to NotStarted.
Events
AuthenticationCompleted
Raised when the authentication attempt is completed, regardless of whether it succeeded.

public event EventHandler<AuthenticationCompletedEventArgs> AuthenticationCompleted;

ClientAuthenticationMode enum
Specifies an authentication mode for an Authenticator object. This is an existing enum to which a new value, BrowserBasedAuthentication has been added.

D EFAU LT

FormsAuthentication Represents forms-based authentication mode

Anonymous Represents anonymous access mode

BrowserBasedAuthentication Represents Microsoft Office Forms Based Authentication (MSOFBA) mode

ODataAuthenticator class
Provides methods for authenticating a user on a SharePoint website.

public class ODataAuthenticator : Authenticator

Constructors
The constructors are identical to the parent class constructors. For more information, see Authenticator Class earlier in this document.
Methods
Authenticate
Authenticates a user to the specified website.

public new void Authenticate(Uri serverUrl)

The new keyword is used because the parent class has an internal method of the same name.
Properties
CookieContainer (read-only)
Gets a container with the cookies for requests to the website.

public new CookieContainer CookieContainer

The new keyword is used because the parent class has an internal method of the same name.
ResolvedUrl (read-only)
Gets the URL that is used for communication to the server that is running SharePoint when an ODataAuthenticator is being used. This may be the URL published on the UAG server or, if
the AllowSmartRouting property is true, this may be the SharePoint intranet URL if it is reached first when the Authenticate method is called.

public Uri ResolvedUrl

ServerSettings class
Provides a method for getting the Alternate URLs of the web application that contains a website.

public static class ServerSettings

Methods
GetAlternateUrls
Gets the alternate URLs of the specified website.

public static ClientObjectList<AlternateUrl> GetAlternateUrls(ClientRuntimeContext context)

Parameters
context is the an object that represents the current client context.
See earlier in this document for information about the AlternateUrl class.

Server object model for SharePoint mobility


All classes in this section are in the Microsoft.SharePoint namespace. Except where specified, these are all available also in the client object model. For classes that begin with "SP", the
client object model name has the "SP" removed. In other cases, the client object model name is specified. Member names are the same in the client object model except where specified
otherwise.
GeolocationFieldControl class
(Not available in client object model.)
Governs the rendering of SPFieldGeolocation fields. An object of this type is used as the value of the FieldRenderingControl property of a SPFieldGeolocation object.

public class GeolocationFieldControl : BaseFieldControl

In connection with this class, note also that there are two rendering templates, one for Display mode and one for New and Edit mode. They are defined in the file
%SHAREPOINTROOT%\TEMPL ATE\ControlTemplates\DefaultTemplates.ascx.
Fields
The following are used to render the field in the New and Edit modes.

protected TextBox m_latitudeBox;


protected TextBox m_longitudeBox;
protected Label m_longitudeLabel;
protected Label m_latitudeLabel;

Methods
No non-derived public properties are introduced with this class. There are standard overrides of some derived methods as indicated in the following table.

ME THO D THIS O V ER R ID E???

CreateChildControls Creates the child controls including a JavaScript map control for Display mode.

Focus Gives focus to the longitude textbox child control.

OnPreRender Calls the base method.

Validate Validates the latitude and longitude values that appear in the user interface (UI). This does not validate
the Longitude and Latitude properties of the underlying SPFieldGeolocatonValue object, which will
differ if the user has changed one or more of these values in the UI and not yet saved the changes.

Properties
No non-derived public properties are introduced with this class. There are standard overrides of some derived properties as indicated in the following table.

PR O PER T Y THIS O V ER R ID E...

CssClass Behaves just like the parent implementation.

DefaultTemplateName Returns "GeolocationField"

DisplayTemplateName Returns "GeolocationDisplayField"

Value Gets or sets the value that is rendered by using a SPFieldGeolocationValue object.

SPFieldGeolocation class
Represents a field (column) that holds a location on the globe defined by longitude, latitude, and possibly altitude.

public class SPFieldGeolocation : SPField

In connection with this class, the Geolocation field type is defined in % SHAREPOINTROOT%\TEMPL ATE\XML\fldtypes.xml.
Constructors (overloaded)
Initializes a new instance of the SPFieldGeolocation class.

public SPFieldGeolocation(SPFieldCollection fields, string fieldName)


public SPFieldGeolocation(SPFieldCollection fields, string fieldName, string displayName)

Parameters
fields is the collection of field types to which the new field type object is added.
fieldName is an internal name of the new field type.
displayName is a friendly name of the new field type.
Methods
GetFieldValueForClientRender
Gets the value of the field so that it can be rendered on the client.

public override object GetFieldValueForClientRender(SPItem item, SPControlMode mode)

Parameters
item is the current list item.
mode is the current rendering mode such as New, Edit, or Display.
GetJsonClientFormFieldSchema
Gets the field schema as JavaScript Object Notation (JSON).
public override Dictionary<string, object> GetJsonClientFormFieldSchema(SPControlMode mode)

Parameters
mode is the current rendering mode such as New, Edit, or Display.
ValidateAndParseValue
Verifies that the specified list item is not null and then verifies that the string is structured in compliance with Open Geospatial Consortium (OGC) standards and returns it as an object that is
castable to the SPFieldGeolocationValue type.

public override object ValidateAndParseValue(SPListItem item, string value)

Parameters
item is a list item that is to be updated with the value.
value is a string representation of a geolocation value.
The following methods are standard overrides of inherited methods that were in SharePoint 2010. The specific information for this class is in the following table.

ME THO D THIS O V ER R ID E...

GetFieldValue(String s) Returns the specified value as an Object that is castable to SPFieldGeolocationValue.

GetFieldValueAsText(Object o) Wraps GetValidatedString.

GetValidatedString(Object o) Verifies that the specified value is structured in compliance with Open Geospatial Consortium (OGC)
standards and returns it as a string.

Properties
JSLink
Gets or sets the name of the JavaScript file that renders the fields of the SPFieldGeolocation type.
NOTE

The JSLink property is not supported on Survey or Events lists. A SharePoint calendar is an Events list.

public override string JSLink

The default value is "clienttemplates.js|Geolocationfieldtemplate.js|sp.map.js".


FieldRenderingMobileWebControl
Gets the SPMobileGeolocationField object that renders the field.

public override SPMobileBaseFieldControl FieldRenderingMobileControl

This property replaces the obsolete FieldRenderingMobileControl.


The other properties are standard overrides of inherited properties that were in SharePoint 2010. The specific information for this class is in the following table.

PR O PER T Y THE O V ER R ID E...

FieldValueType Returns typeof(SPFieldGeolocationValue).

FieldRenderingControl Returns a GeolocationFieldControl object.

Filterable Returns false.

Sortable Returns false.

[Obsolete] Returns a SPMobileGeolocationField object.


FieldRenderingMobileControl

SPFieldGeolocationValue class
Represents a location on the globe defined by longitude, latitude, and possibly altitude too.

public class SPFieldGeolocationValue : SPFieldGeographyValue

Constructors (overloaded)
Initializes a new instance of the SPFieldGeolocationValue class.

public SPFieldGeolocationValue()
public SPFieldGeolocationValue(string fieldValue)
public SPFieldGeolocationValue(double latitude, double longitude)
public SPFieldGeolocationValue(double latitude, double longitude, double altitude, double measure)

Parameters
fieldValue is a string in one of the following Well-Known Text (WKT) formats:
"Point( longitude latitude)", where longitude and latitude are strings of one or more numerals, optionally including one period (which is interpreted as a decimal point) and
optionally beginning with a hyphen (which is interpreted as a negative sign).
"Point( longitude latitude altitude measure)", where longitude, latitude, altitude, and measure are strings of one or more numerals, optionally including one period (which is
interpreted as a decimal point) and optionally beginning with a hyphen (which is interpreted as a negative sign).
latitude is the latitude and must be between -90.0 and 90.0.
longitude is the longitude and must be between -180.0 and 180.0.
altitude is the altitude.
measure is an alternate designation of the point. See the Measure property later in this section for more information.
Methods
ToString
This override returns one of the following, depending on whether the Altitude or Measure properties have been assigned a non-null value.
If neither Altitude nor Measure have been assigned a non-null value:
"Point( longitude latitude)", where longitude and latitude are strings of one or more numerals, optionally including one period (which is interpreted as a decimal point) and optionally
beginning with a hyphen (which is interpreted as a negative sign).
Otherwise (at least one of Altitude or Measure have been assigned a non-null value):
"Point(longitude latitude altitude measure)", where longitude, latitude, altitude, and measure are strings of one or more numerals, optionally including one period (which is interpreted
as a decimal point) and optionally beginning with a hyphen (which is interpreted as a negative sign). If either Altitude or Measure has not been assigned a non-null value, it is
reported as "0" in the value of the WellKnownText property. The converse does not hold: if either Altitude or Measure is reported as 0, that might be because it was never assigned
a non-null value, but it might be because it was assigned 0.

public override string ToString()

ToWellKnownText
Wraps ToString.

public string ToWellKnownText()

Properties
Altitude
Gets or sets the altitude of the location. Use of this property is optional and the assumed unit-of-measure (for example, meters) and zero-point (for example, sea level or center-of-the-earth)
is user-defined.

public double Altitude

Latitude
Gets or sets the latitude of the location.

public double Latitude

The value must be between -90.0 and 90.0.


Longitude
Gets or sets the longitude of the location.

public double Longitude

The value must be between -180.0 and 180.0..


Measure
Gets or sets a user-defined alternate designation of the location point. For example, if the point is along a highway with milestone markers, this property could be used to hold the number of
the milestone that is nearest to the point. If the point is in a public camping area with numbered campsites, this property could be used to hold the number of the nearest campsite. The
semantics of the property are entirely user-determined and its use is optional.

public double Measure

SPFieldType enum
A new value has been added to this enum:

Geolocation

SPPhoneNotificationContent class
A base class for classes that represent the content of a phone notification. Derived classes must declare one or more fields or properties to hold the content and must implement the
PreparePayload method to transform the content into a byte array.

public abstract class SPPhoneNotificationContent

Methods
PreparePayload
When implemented in a derived class, transforms the content into a Byte array that is sent over the wire to the notification service. There is no default implementation so a derived class must
implement this method.
protected internal abstract byte[] PreparePayload();

Properties
NotificationType (read-only)
Gets the type of notification (for example, tile or toast) for which the content is intended.

public SPPhoneNotificationType NotificationType

For information about the SPPhoneNotificationType, see later in this document.


SubscriberType (read-only)
Gets the type of the subscriber's device, for example, a Windows Phone.

public SPPhoneNotificationSubscriberType SubscriberType

For information about the SPPhoneNotificationSubscriberType, see later in this document.

SPPhoneNotificationResponse class
Represents the outcome of an attempt to send a notification.

public class SPPhoneNotificationResponse

Methods
Create
Creates an SPPhoneNotificationResponse object.

public static SPPhoneNotificationResponse


Create(SPPhoneNotificationSubscriberType subscriberType,
SPPhoneNotificationType notificationType, HttpWebResponse response)

Parameters
subscriberType is the device, such as Windows Phone 7.5.
notificationType is the type of notification, such as toast or tile.
response is the HTTP response object that was generated by the server.
For more information about SPPhoneNotificationSubscriberType and SPPhoneNotificationType, see later in this document.
Properties
NotificationType (read-only)
Gets the type of notification (for example, toast or tile).

public SPPhoneNotificationType NotificationType

For information about the SPPhoneNotificationType, see later in this document.


ServiceToken (read-only)
Gets the token of the notification service that was used in the notification.

public string ServiceToken

StatusCode (read-only)
Gets the HTTP status code. A string version of a HttpStatusCode value.

public string StatusCode

SubscriberType
Gets or sets the type of device to which the notification was sent.

public SPPhoneNotificationSubscriberType SubscriberType

For information about the SPPhoneNotificationSubscriberType, see later in this document.


TimeStamp (read-only)
The UTC time of the notification.

public DateTime Timestamp

SPPhoneNotificationSubscriber class
A base class for classes that represent a subscriber to notifications issued by a server-side SharePoint application.

public abstract class SPPhoneNotificationSubscriber


Methods
Notify
Sends the specified notification content to the subscriber with error checking.

public SPPhoneNotificationResponse Notify(SPPhoneNotificationContent notificationContent)

Parameters
notificationContent is information about the event that triggered the notification.
This method cannot be overridden. It wraps the abstract NotifyInternal method and ensures that certain error checking is done when NotifyInternal is called.
For more information about the SPPhoneNotificationContent and SPPhoneNotificationResponse classes, see earlier in this document.
NotifyInternal
When overridden in a derived class, sends the specified notification content to the subscriber.

protected abstract SPPhoneNotificationResponse NotifyInternal(SPPhoneNotificationContent notificationContent);

Parameters
notificationContent is information about the event that triggered the notification.
For more information about the SPPhoneNotificationContent and SPPhoneNotificationResponse classes, see earlier in this document.
ToString
Returns selected properties of the object as a string.

public override string ToString()

The default implementation includes the ParentWeb, ApplicationTag, and DeviceAppInstanceId properties.
Update
Saves a (possibly changed) SPPhoneNotificationSubscriber object to the website's Subscriber Store.

public void Update()

ValidateSubscriberProperties
When implemented in a derived class, validates selected properties of the object.

protected abstract void ValidateSubscriberProperties();

Properties
CustomArgs
Gets or sets a custom arguments string which represents the state of the notifications subscription. This string could be used by the application logic to differentiate between its notification
subscribers for different kinds of notifications.

public string CustomArgs

DeviceAppInstanceId (read-only)
Gets an ID for the specific instance of the application on the phone or other mobile device.

public Guid DeviceAppInstanceId

LastModifiedTimeStamp (read-only)
Gets the date and time when the subscriber was last modified.

public DateTime LastModifiedTimeStamp

RegistrationTimeStamp (read-only)
Gets the date and time when the subscriber registered for notifications.

public DateTime RegistrationTimeStamp

ServiceToken
Gets or sets delivery channel information that is needed by a notification service, such as channel URI.

public string ServiceToken

SubscriberType (read-only)
Gets the type of the device, such as Windows Phone 7.

public SPPhoneNotificationSubscriberType SubscriberType

For information about the SPPhoneNotificationSubscriberType class, see later in this document.
User (read-only)
Gets the user who registered for notifications.

public SPUser User

SPPhoneNotificationSubscriberCollection class
A collection of notification subscribers. The collection object takes Int32 indexers.

public sealed class SPPhoneNotificationSubscriberCollection : SPBaseCollection

Properties
Count
Gets the number of items in the collection.

public override int Count

SPPhoneNotificationSubscriberType enum
Specifies a type of device that can receive notifications.

NO TIFICATIO N D EV ICE

WP7 Windows Phone 7.5

Custom Any device other than Windows Phone 7.5

SPPhoneNotificationType enum
Specifies the type of notification.

None

Tile

Toast

Raw

SPWeb class
The following members have been added to this class.
Methods
DoesPhoneNotificationSubscriberExist
Gets a value that indicates whether the current user is a subscriber for the specified instance of the specified app.

public bool DoesPhoneNotificationSubscriberExist(Guid deviceAppInstanceId)

GetPhoneNotificationSubscriber
Gets a notification subscriber with the specified application and phone IDs from the website's notification Subscription Store list.

public SPPhoneNotificationSubscriber GetPhoneNotificationSubscriber(Guid deviceAppInstanceId)

Parameters
deviceAppInstanceId is an ID for the instance of the application on a specific phone or device.
For information about the SPPhoneNotificationSubscriber class see earlier in this document.
GetPhoneNotificationSubscribers (overloaded)
Gets a collection of notification subscribers from the website's notification Subscription Store list, optionally filtering on the ID of the phone applications and possibly also on one of the
following: the user or some custom arguments.

public SPPhoneNotificationSubscriberCollection GetPhoneNotificationSubscribers(string customArgs)

NOTE

Client object model name is GetPhoneNotificationSubscribersByArgs.

public SPPhoneNotificationSubscriberCollection GetPhoneNotificationSubscribers(string user)

NOTE

Client object model name is GetPhoneNotificationSubscribersByUser.


Parameters
customArgs are additional custom information that some notification-enabled applications may use.
user is the user who registered for the notifications.
For information about the SPPhoneNotificationSubscriberCollection class see earlier in this document.
RegisterPhoneNotificationSubscriber
Registers a phone app on a phone to receive notifications.

public SPPhoneNotificationSubscriber RegisterPhoneNotificationSubscriber(SPPhoneNotificationSubscriberType subscriberType, Guid deviceAppInstanceId, string serviceToken)

Parameters
subscriberType is the device type, such as Windows Phone 7.
deviceAppInstanceId is an ID for the instance of the app on a specific phone or device.
serviceToken is the token that is used by the notification service that sends notifications to the subscriber.
For information about SPPhoneNotificationSubscriberType, see earlier in this document.
UnregisterPhoneNotificationSubscriber
Unregisters a phone app on a phone from receiving notifications.

public void UnregisterPhoneNotificationSubscriber(Guid deviceAppInstanceId)

Parameters
deviceAppInstanceId is an ID for the instance of the app on a specific phone or device.
Properties
PhoneNotificationSubscribers (read-only)
Gets a collection of all the phone notification subscribers in the website's Subscriber Store.

public SPPhoneNotificationSubscriberCollection PhoneNotificationSubscribers

For information about the SPPhoneNotificationSubscriberCollection class, see earlier in this document.

WP7NotificationTileContent class
Represents the content of a tile notification.

public sealed class WP7NotificationTileContent : SPPhoneNotificationContent

Constructors
Initializes a new instance of the WP7NotificationTileContent class.

public WP7NotificationTileContent()

Methods
PreparePayload
Transforms the content into a Byte array that is sent over the wire to the notification service.

protected internal override byte[] PreparePayload();

Properties
Count
Gets or sets the count of the notification. Must be from -1 to 99 inclusive.

public int Count

Setting the property to -1 will not change the count over the tile.
Title
Gets or sets the title of the tile notification.

public string Title

BackgroundImagePath
Gets or sets the path to the tile's background image.

public string BackgroundImagePath

BackBackgroundImagePath
Gets or sets the background image of the back side of a flipping tile.

public string BackBackgroundImagePath


BackContent
Gets or sets the content of the back side of a flipping tile.

public string BackContent

BackTitle
Gets or sets of the title that appears on the back side of a flipping tile.

public string BackTitle

TileId
Gets or sets the ID of the tile.

public string TileId

WP7NotificationToastContent class
Represents the content of a toast notification.

public sealed class WP7NotificationToastContent : SPPhoneNotificationContent

Constructors
Initializes a new instance of the WP7NotificationToastContent class.

public WP7NotificationToastContent()

Methods
PreparePayload
Transforms the content into a Byte array that is sent over the wire to the notification service.

protected internal override byte[] PreparePayload();

Properties
Message
Gets or sets the message of the toast notification.

public string Message

Title
Gets or sets the title of the toast notification.

public string Title

Param
Gets or sets custom settings data that is passed to the receiving application if the user responds to the toast notification.

public string Param

This property can be used to pass information to the receiving application such as a URL or a set of name-value pairs.

WP7NotificationRawContent class
Represents the content of a raw notification.

public sealed class WP7NotificationRawContent : SPPhoneNotificationContent

Constructors
Initializes a new instance of the WP7NotificationRawContent class.

public WP7NotificationRawContent()

Methods
PreparePayload
Transforms the content into a Byte array that is sent over the wire to the notification service.

protected internal override byte[] PreparePayload();

Properties
Message
Gets or sets the message of the raw notification.

public string Message


WP7PhoneNotificationResponse class
Represents the outcome of an attempt to send a notification to a Windows Phone 7 subscriber.

public WP7PhoneNotificationResponse(SPPhoneNotificationType notificationType, HttpWebResponse response)

Parameters
notificationType is the type of notification, such as toast or tile.
response is the HTTP response object that was generated by the server.
For more information about SPPhoneNotificationType, see earlier in this document.
Properties
NotificationStatus (read-only)
Gets the notification status, for example, success or failure.

public string NotificationStatus

DeviceConnectionStatus (read-only)
Gets the status of the device at the time of the notification.

public string DeviceConnectionStatus

SubscriptionStatus (read-only)
The subscription status of the device at the time of the notification.

public string SubscriptionStatus

MessageId (read-only)
Gets the ID of the message that was sent in the notification.

public string MessageId

See also
Build Windows Phone apps that access SharePoint
How to: Configure and use push notifications in SharePoint apps for Windows Phone
Integrating location and map functionality in SharePoint
Overview of the SharePoint mobile client authentication object model
Overview of the SharePoint mobile client authentication object model
5/11/2018 • 6 minutes to read Edit Online

Get an overview of development with the authentication APIs of the SharePoint client object model for Silverlight.

Authentication and client context on a Windows Phone


The process of authenticating a SharePoint user on a Windows Phone 7.5 is a little different from the same process on a client computer. Client code on a Windows Phone 7.5 first creates an
object of the Authenticator class or ODataAuthenticator class, which were added to the SharePointclient object model for Microsoft Silverlight for Windows Phone. It then uses this
object as the user's credentials.
NOTE

For more information about the APIs that are discussed in this section, see Overview of the SharePoint mobile object model. For more information about the SharePoint client object model
for Silverlight, see Managed Client Object Model and Using the Silverlight Object Model.

Authenticating the user in the SharePoint client object model for Silverlight
The following are the required steps to get an authenticated client context object:
1. Obtain a ClientContext object.
2. Construct a new Authenticator object and initialize its properties.
NOTE

One Authenticator object can be used with one ClientContext object only. You can't share an Authenticator object across multiple ClientContext objects with different URLs.
3. The Authenticator class implements the ICredentials interface, so you assign the object to the Credentials property of the ClientContext object.
You can then add the rest of your client object model code and call ExecuteQueryAsync.
The following code shows these steps.

ClientContext context = new ClientContext(ListUrl);

// Create an instance of Authenticator object.


Authenticator at = new Authenticator();

// Replace <username> and <password> with valid values.


at.UserName = "<username>";
at.Password = "<password>";
at.AuthenticationMode = ClientAuthenticationMode.FormsAuthentication;

at.CookieCachingEnabled = true;

// Assign the instance of Authenticator object to the ClientContext.Credential property.


// ClientContext is the object that is central to the client object model for making calls to the server running SharePoint
// for fetching and updating data.
context.Credentials = at;

ListItemCollection items = context.Web.Lists.GetByTitle(ListName).GetItems(CamlQuery.CreateAllItemsQuery());

// Load the query and execute the request to fetch data.


context.Load(items);
context.ExecuteQueryAsync(
(object obj, ClientRequestSucceededEventArgs args) =>
{
// Success logic
},

(object obj, ClientRequestFailedEventArgs args) =>


{
// Failure logic
});

Optionally, you can specify a Unified Access Gateway (UAG) server by setting the Authenticator.UagServerUrl property.
If the SharePoint URL has basic or forms-based authentication support, the ExecuteQueryAsync calls prompt the user for logon information, as shown in Figure 1. Otherwise, the call will
fail. Enable basic or forms-based authentication authorization on the SharePoint site to avoid an authentication error.
Figure 1. SharePoint client authentication
The user enters the user name and password and chooses Log On, as shown in Figure 1. The user has the option to choose Remember me to remember their user name and has the option
to choose Remember my password to remember their password, as shown in Figure 1. After the user name or password is remembered, the user doesn't have to enter credentials the next
time the app is started. The ExecuteQueryAsync then uses the logged on credentials to make web requests to the server running SharePoint to fetch data.

Authenticating the user in the SharePoint OData object model


The following are the required steps to get an authenticated OData context object.
1. Construct a new ODataAuthenticator object and initialize its properties.
2. Register a handler for the AuthenticationCompleted event.
3. Call the ODataAuthenticator.Authenticate method, which will raise the AuthenticationCompleted event.
4. Obtain an OData context object inside the OnAuthenticationCompleted handler.
You can then add the rest of your OData calls in the OnAuthenticationCompleted handler.
The following code shows these steps.

ODataAuthenticator oat = new ODataAuthenticator();

// Replace <username> and <password> with valid values.


oat.UserName = "<username>";
oat.Password = "<password>";

oat.AuthenticationMode = ClientAuthenticationMode.FormsAuthentication;

oat.AuthenticationCompleted +=
new EventHandler<SendingRequestEventArgs>(OnAuthenticationCompleted);

// The Authenticate method will raise the AuthenticationCompleted event.


oat.Authenticate("My_service_URL");

Your code must also implement two event handlers, as described in the following section.

Implementing the OnAuthenticationCompleted and OnSendingRequest handlers and getting the ClientContext object
An implementation of the OnAuthenticationCompleted handler should first check for any errors in the authentication. If there are any, it should handle them appropriately, such as
displaying an error message to the user, and then exit.
If there are no errors, the handler should create an instance of a new DataServiceContext object and then register a handler for the SendingRequest event. From that point, your OData
calling code is programmed against the DataServiceContext object just as it is on a computer.
The following is an example of an implementation of an OnAuthenticationCompleted handler.

void OnAuthenticationCompleted(object sender, AuthenticationCompletedEventArgs e)


{
if (e.Error != null)
{
MessageBox.Show(error);
return;
}
ODataAuthenticator oat = sender as ODataAuthenticator;

// Construct an OData context object.


contextObj = new DataServiceContext(oat.ResolvedUrl);

// Register the SendingRequest event handler.


contextObj.SendingRequest +=
new EventHandler<SendingRequestEventArgs>(OnSendingRequest);

// Your data retrieval logic goes here.


// For example, if there is a GetData method:
// contextObj.GetData();
}

All that the OnSendingRequest handler needs to do is set the cookie container of the Request object to the cookie container of the ODataAuthenticator object. The following is an
example.

void OnSendingRequest(object sender, SendingRequestEventArgs e)


{
ODataAuthenticator oat = sender as ODataAuthenticator;
((HttpWebRequest)e.Request).CookieContainer = oat.CookieContainer;
}

Advanced usage
1. You can choose to construct an Authenticator object with a hard-coded user name/password option. The user of the app will not be prompted for a user name and password, and
hard-coded credentials will be used for authenticating the user.
public Authenticator(string userName, string password)

public Authenticator(string userName, string password, string domain)

The same constructor can be used to create a custom logon page. You can write a custom logon page by passing the credentials from code-behind files.
Authenticator at = new Authenticator();
at.AuthenticationMode = ClientAuthenticationMode.MicrosoftOnline;

1. Authentication type can be set accordingly. By default, basic authentication is used.

Authenticating against SharePoint Online


To authenticate against a SharePoint Online URL, set the AuthenticationMode property of the Authenticator object to MicrosoftOnline mode. The remaining steps in the procedure are
the same as those for an on-premises SharePoint URL.
NOTE

The user name and password cannot be hard-coded for SharePoint Online.The user will be prompted for logon credentials.
Federation Authentication
FederationAuthURI property is used to pass ADFS authentication scheme preference where, ADFS is configured to use multiple authentication handlers. FederationAuthURI specifies
the type of authentication required by Authentication request when, SharePoint Online authentication is used with Federation. This parameter can override the priority established by the
order in which authentication handlers are configured. To know more about Authentication handler, see Authentication Handler Overview.

Authenticator auth = new Authenticator("domain\\\\name", "xyz");


auth.FederationPassiveAuthUri = "urn:oasis:names:tc:SAML:2.0:ac:classes:Password";
//Replace <SiteUrl> with valid value
ClientContext ctx = new ClientContext("SiteUrl");
ctx.Credentials = auth;
ctx.ExecuteQueryAsync(
(object sender, ClientRequestSucceededEventArgs args) =>
{
/* successful callback code */
},
(object sender, ClientRequestFailedEventArgs args) =>
{
/* failure callback code */
});

ADFS is an optional property which will be effective only when it is used with Microsoft SharePoint Online. Using ADFS authentication with any other authentication scheme will not have
any effect. With Microsoft SharePoint Online, if ADFS is not set then default scheme will be used, i.e. server preference.

Cookie caching
The Authenticator class also includes members that you can use to enable and manage caching of cookies or credentials or both. For information about these members of the
Authenticator class and their uses, see Overview of the SharePoint mobile object model.

See also
Build Windows Phone apps that access SharePoint
Overview of the SharePoint mobile object model
Export the Name field in a Document Library list to a mobile app
3/26/2018 • 2 minutes to read Edit Online

Export the Name field of a Document Library list to a mobile app by using the Visual Studio SharePoint List wizard. The Name field does not appear automatically when a user creates a
mobile app for a document library in SharePoint. In a Document Library list, a user can upload various documents. A list item for a document typically has Title, Name, and a link to the
document as properties. If a developer creates a Windows Phone 7 app against the document library, the Name field is not exported in the IDE wizard. Thus the developer has no easy way
of knowing the document name. (This is because SharePoint does not support fields of type "FILE" by default.)
NOTE

The Title property does not include the file name extension.
So if you want to fetch a document, build the full URL of the document, and open the document in the default application (such as Word), you must write code to get the actual file name.

Important: If you are developing an app for Windows Phone 8, you must use Visual Studio Express 2012 instead of Visual Studio 2010 Express. Except for the development
environment, all information in this article applies to creating apps for both Windows Phone 8 and Windows Phone 7. > For more information, see How to: Set up an environment for
developing mobile apps for SharePoint.

Prerequisites for exporting the Name field of a document library


SharePoint
Visual Studio Express 2010 with the new SharePoint templates

Customize the generated classes


To export the Name field and access attachments from a document library, you must make a few changes in the ListDataProvider class, in DisplayItemViewModel.cs, and in the
DisplayForm class. When a developer uses the new SPList wizard from Visual Studio, the wizard creates several classes that follow the Model-View-ViewModel design pattern. (For more
information, see Using the Model-View-ViewModel Pattern.) Two folders are created: One is named Views and contains all files needed to modify various list views (such as DisplayForm,
EditForm, List, and NewForm). The other is named ViewModels and contains DisplayItemViewModel, EditItemViewModel, ListViewModel, and NewItemViewModel. You will be modifying
some of these classes generated by the wizard.

Step 1: Modify ListDataProvider to fetch SPListItem.File property


1. In the ListDataProvider class, add the following line of code in the LoadItem method.
Context.Load(spListItem, Item => Item.File);

2. Also in the ListDataProvider class, add the following code in the LoadData method.
Context.Load(items, listItems => listItems.Include(item => item.File));

Step 2: Add the FileUrl and FileName properties


In DisplayItemViewModel.cs, add the following code to DisplayVM.

public string m_fileUrl;


public string FileUrl
{
get
{
if (string.IsNullOrEmpty(m_fileUrl))
{
IListDataProvider p = this.DataProvider;
p.LoadItem(this.ID, (LoadItemCompletedEventArgs args) =>
{
FileUrl = this.DataProvider.SiteUrl +
args.Item.File.ServerRelativeUrl;
});
}
return m_fileUrl;
}
set
{
m_fileUrl = value;
RaisePropertyChanged("FileUrl");
}
}
public string m_fileName;
public string FileName
{
get
{
if (string.IsNullOrEmpty(m_fileName))
{
IListDataProvider p = this.DataProvider;
p.LoadItem(this.ID, (LoadItemCompletedEventArgs args) =>
{
FileName = args.Item.File.Name;
});
}

return m_fileName;
}
set
{
m_fileName = value;
RaisePropertyChanged("FileName");
}
}

Step 3: Add a hyperlink to the DisplayForm that binds to FileUrl and FileName
Add the following changes to the Display form.

<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,5,0,5">


<TextBlock TextWrapping="Wrap" Width="150" HorizontalAlignment="Left"
Style="{StaticResource PhoneTextNormalStyle}">
FileUrl :
</TextBlock>
<HyperlinkButton Content="{Binding FileName}" NavigateUri="{Binding FileUrl}"
x:Name="hypFile" TargetName="_blank" />
</StackPanel>

See also
Build Windows Phone apps that access SharePoint
How to: Create a Windows Phone SharePoint list app
How to: Set up an environment for developing mobile apps for SharePoint
Windows Phone SDK 7.1
Microsoft SharePoint SDK for Windows Phone 7.1
Build localized applications for Windows Phone based on the SharePoint templates
3/26/2018 • 2 minutes to read Edit Online

Learn how building a localizable Windows Phone app using the new SharePoint templates is different from building one using other Windows Phone templates. The SharePoint SDK for
Windows Phone 7.1 installs Windows Phone project templates, which you can use to build Windows Phone 7.1 applications against SharePoint or SharePoint 2010. For more information,
see Overview of Windows Phone SharePoint application templates in Visual Studio.
Visual Studio uses language-specific resource files to create assemblies that allow your mobile application to support many languages. For more information about this process, see
Packaging and Deploying Resources in Desktop Apps.

Important: If you plan to localize your application for East Asian languages, be sure to read the "Fonts and Your Application" section of Font Support for Windows Phone

Differences when building localized applications for Windows Phone using the SharePoint templates
Building a localizable Windows Phone app using the new SharePoint templates is slightly different from building one using other Windows Phone templates. When you use the SharePoint
templates, the SupportedCultures element requires a slightly different format. For example, in a standard Windows Phone app that uses English (United States) for its default culture but
also supports German (Germany) and Spanish (Spain), the SupportedCultures element appears as follows:
<SupportedCultures>de-DE;es-ES;</SupportedCultures>

This format does not work when you build a localized Windows Phone app that is based on the SharePoint templates. Instead, locate the SupportedCultures element in the .csproj file and
add the names of each culture (language) that your application needs to support (other than the default culture). Separate the names using semicolons. You should have an entry for each
.resx file that is in the project.
For the previous example, the SupportedCultures element should appear as follows:
<SupportedCultures>de;es;</SupportedCultures>

To see a step-by-step process of how to build a localized application for Windows Phone, see How to: Build a Localized Application for Windows Phone.

See also
Build Windows Phone apps that access SharePoint
How to: Build a Localized Application for Windows Phone.
Globalization and Localization for Windows Phone
Language support for Windows Phone in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn about language support for the Visual Studio templates that are installed by the SharePoint Software Development Kit (SDK) for Windows Phone for mobile app development. To
develop your mobile application for more than one language, you need to globalize and localize the application. Most of the globalization and localization functionality that you need to
implement is already built into the .NET Framework. By using this functionality, you can reach customers in many other countries and regions.
The Windows Phone SDK includes Visual Studio 2010 Express for Windows Phone, Windows Phone Emulator, XNA Game Studio, and Expression Blend. To get started, install the Windows
Phone SDK 7.1 for Windows Phone development. Then install the Microsoft SharePoint SDK for Windows Phone 7.1 to install the SharePoint templates for Windows Phone. After you set
up your development environment and install the SharePoint SDK for Windows Phone, see How to: Set up an environment for developing mobile apps for SharePoint.
For more information about the SharePoint templates for Windows Phone, see Overview of Windows Phone SharePoint application templates in Visual Studio.

Templates and libraries installed by the SharePoint SDK for Windows Phone
The SharePoint SDK for Windows Phone 7.1 installs the client object model (CSOM) libraries for Windows Phone, the SharePoint Auth library for Windows Phone, and the Windows Phone
project templates, which you can use to build Windows Phone 7.1 applications against SharePoint or SharePoint 2010.
When you install the SharePoint SDK for Windows Phone, two additional Silverlight for Windows Phone templates are available for projects:
Windows Phone Empty SharePoint Application
Windows Phone SharePoint List Application

Localized versions of the SharePoint SDK for Windows Phone


Nine languages are supported by the SharePoint SDK for Windows Phone Developer Toolkit 7.1. Most of the work of creating an application is done at design time, including creating
projects, designing forms, developing controls, and adding code. You can write Windows Phone applications by using any of the following localized versions of the SharePoint SDK for
Windows Phone:
English (en-US)
French (fr-FR)
German (de-DE)
Italian (it-IT)
Japanese ( ja-JP)
Korean (Ko-KR)
Russian (ru-RU)
Spanish (es-ES)
Traditional Chinese (zh-TW)

Supported localized languages for SharePoint Windows Phone applications


When an application takes control, you interact with the application in the same way a user does. You can view code, run the application, and debug it, but you cannot change the code.
Although you have programmatic access to nine languages, you can run your SharePoint mobile applications in the twenty languages shown in Table 1.
Table 1. Supported display/run-time languages in the SharePoint SDK for Windows Phone

CU LTU R E NAME CU LTU R E CO D E

Chinese Simplified (PRC) zh-CN

Chinese Traditional (Taiwan) zh-TW

Czech (Czech Republic) cs

Danish (Denmark) da

Dutch (Netherlands) nl

Finnish (Finland) fi

French (France) fr

German (Germany) de

Greek (Greece) el

Hungarian (Hungary) hu

Italian (Italy) it

Japanese (Japan) ja

Korean (Korea) ko

Norwegian (Norway) nb
CU LTU R E NAME CU LTU R E CO D E

Polish (Poland) pl

Portuguese (Brazil) pt-BR

Portuguese (Portugal) pt-PT

Russian (Russia) ru

Spanish (Spain) es

Swedish (Sweden) sv

See also
Overview of Windows Phone SharePoint application templates in Visual Studio
Build Windows Phone apps that access SharePoint
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Build mobile apps for other platforms using SharePoint
3/26/2018 • 7 minutes to read Edit Online

Learn how to use Representational State Transfer (REST) to create a SharePoint mobile app for any platform. Mobile devices have become more powerful and easy to use nowadays.
Laptops, netbooks, tablet PCs, and mobile phones provide workers access to the information and applications that they need to do their jobs. And developing applications for mobile devices
is now easier than ever. As a result, more and more business scenarios demand integrating client applications together with their business processes. This article describes how to integrate
mobile client apps together with SharePoint. You can create a mobile app to browse SharePoint content from any location and connect with SharePoint lists and libraries to access data.
To develop a mobile app that interacts with SharePoint, you can use common services that can be accessed using open protocols. SharePoint Foundation 2010 introduced the client object
models, which enabled developers to perform remote communication with SharePoint by using the web programming technology of their choice: .NET Framework, Microsoft Silverlight, or
JavaScript. SharePoint introduces a Representational State Transfer (REST) service that is fully comparable to the client object models. In SharePoint, nearly every API in the client object
models will have a corresponding REST endpoint. Now, developers can interact remotely with the SharePoint object model by using any technology that supports REST web requests. REST
can be consumed by any programming language that you want to use for your mobile application development. You can perform basic create, read, update, and delete (CRUD) operations by
using the REST interface provided by SharePoint. REST exposes all of the SharePoint entities and operations that are available in the other SharePoint client APIs. One advantage of using
REST is that you don't have to add references to any SharePoint libraries or client assemblies. Instead, you make HTTP requests to the appropriate endpoints to retrieve or update
SharePoint entities, such as webs, lists, and list items. For a thorough introduction to the SharePoint REST interface and its architecture, see Use OData query operations in SharePoint REST
requests.

REST endpoints in SharePoint


To use the REST capabilities that are built into SharePoint, you can construct a RESTful HTTP request using the Open Data Protocol (OData) standard that corresponds to the desired client
object model API. The client.svc web service handles the HTTP request and serves the appropriate response, in either Atom or JavaScript Object Notation (JSON) format. The client
application must then parse that response. Figure 1 shows a high-level view of the SharePoint REST architecture.
Figure 1. SharePoint REST architecture

The endpoints in the SharePoint REST service correspond to the types and members in the SharePoint client object models. By using HTTP requests, you can use these REST endpoints to
perform typical CRUD operations against SharePoint artifacts, such as lists and sites.
In general:
Endpoints that represent read operations map to HTTP GET commands.
Endpoints that represent update operations map to HTTP POST commands.
Endpoints that represent update or insert operations map to HTTP PUT commands.
In choosing an HTTP request to use, you should also consider the following:
Use POST to create artifacts such as lists and sites. The SharePoint REST service supports sending POST commands that include object definitions to endpoints that represent
collections.
For POST operations, any properties that are not required are set to their default values. If you try to set a read-only property as part of a POST operation, the service returns an
exception.
Use PUT, PATCH, and MERGE operations to update existing SharePoint objects. Any service endpoint that represents an object property set operation supports both PUT requests
and MERGE requests. For MERGE requests, setting properties is optional; any properties that you do not explicitly set retain their current property. But for PUT commands, any
properties you do not explicitly set are set to their default properties. In addition, if you do not specify all settable properties in object updates when you use HTTP PUT commands,
the REST service returns an exception.
Use the HTTP DELETE command against the specific endpoint URL to delete the SharePoint object represented by that endpoint. For recyclable objects, such as lists, files, and list
items, this results in a Recycle operation. For more information, see Get to know the SharePoint REST service.

Authenticate users to SharePoint


To authenticate your mobile app with SharePoint, you can use the MS-OFBA protocol. For more information, see [MS-OFBA]: Office Forms Based Authentication Protocol Specification. The
protocol client is configured to store and transmit cookies. The protocol client relies on the remote protocol server to set the user's identity as one or more HTTP cookies. After the user's
identity is established, the client then sends each cookie with each subsequent HHT request.
When a user signs in to SharePoint, the user's token is validated and then used to sign in to SharePoint. The user's token is a security token that is issued by an identity provider. SharePoint
supports several kinds of authentication. For more information, see Authentication, authorization, and security in SharePoint. To authenticate a user, you can use the REST interface. The
authorization process verifies that an authenticated subject (an app or a user the app is acting on behalf of.md) has permission to perform certain operations or to access specific resources
(for example, a list or a SharePoint document folder.md).
OData lets you access a data source, such as a database, by browsing to a specially constructed URL. This allows for a simplified approach for connecting to, and working with, data sources
that are hosted within an organization. OData is a protocol that uses HTTP, Atom, and JavaScript Object Notation (JSON) to enable developers to write applications that communicate with
an ever-growing number of data sources. Microsoft supports the creation of this standard as a way to enable the exchange of data between applications and data stores that can be accessed
from the web. The new OData connector enables SharePoint to communicate with OData providers. For more information, see Open Data Protocol.
The following code demonstrates how to authenticate your app to SharePoint using REST endpoints for basic or forms-based authentication. The following code example is written in C#,
but any other programming language can be used to create the Http request, as per the requirement of the platform.
string SharePointUrl = "https://Target SharePoint site";

private void AuthenticateToSharePoint(object sender, RoutedEventArgs e)


{
ODataAuthenticator odataAt = new ODataAuthenticator("<Username>", "<password>");
odataAt.CookieCachingEnabled = true;
odataAt.AuthenticationCompleted += new EventHandler<AuthenticationCompletedEventArgs>(odataAt_AuthenticationCompleted);
odataAt.Authenticate(new Uri(SharePointUrl, UriKind.Absolute));
}

void odataAt_AuthenticationCompleted(object sender, AuthenticationCompletedEventArgs e)


{
HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(SharePointUrl.ToString() + "/_api/web/lists");
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";
endpointRequest.CookieContainer = (sender as ODataAuthenticator).CookieContainer;

endpointRequest.BeginGetResponse(new AsyncCallback((IAsyncResult res) =>


{
HttpWebRequest webReq = res.AsyncState as HttpWebRequest;
WebResponse response = webReq.EndGetResponse(res);

HttpWebResponse httpResponse = response as HttpWebResponse;


HttpStatusCode code = httpResponse.StatusCode;
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(code.ToString());
});
}), endpointRequest);
}

To authenticate an HttpWebrequest to the endpoint, you should first authenticate to SharePoint with the ODataAuthenticator class. Before calling the Authenticate method, register the
ODataAuthenticator object to the AuthenticationCompleted event.
After authentication is done inside the OnAuthenticationCompleted event, you can use the CookieContainer property on the ODataAuthenticator object, which can be attached to the
HttpWebRequest object to authenticate the REST calls to SharePoint.

Work with SharePoint list items using REST


The following example shows how to retrieve all of a list's items.

url: http://site url/_api/web/lists/GetByTitle('Test')/items


method: GET
headers:
// MS-OFBA protocol returns a cookie.
Cookie: cookie

accept: "application/json;odata=verbose" or "application/atom+xml"

The following example shows how to retrieve a specific list item.

url: http://site url/_api/web/lists/GetByTitle('Test')/items(item id)


method: GET
headers:

// MS-OFBA protocol return a cookie.


Cookie: cookie
accept: "application/json;odata=verbose" or "application/atom+xml"

The following XML shows an example of the list item properties that are returned when you request the XML content type.

<content type="application/xml">
<m:properties>
<d:FileSystemObjectType m:type="Edm.Int32">0</d:FileSystemObjectType>
<d:Id m:type="Edm.Int32">1</d:Id>
<d:ID m:type="Edm.Int32">1</d:ID>
<d:ContentTypeId>0x010049564F321A0F0543BA8C6303316C8C0F</d:ContentTypeId>
<d:Title>an item</d:Title>
<d:Modified m:type="Edm.DateTime">2012-07-24T22:47:26Z</d:Modified>
<d:Created m:type="Edm.DateTime">2012-07-24T22:47:26Z</d:Created>
<d:AuthorId m:type="Edm.Int32">11</d:AuthorId>
<d:EditorId m:type="Edm.Int32">11</d:EditorId>
<d:OData__UIVersionString>1.0</d:OData__UIVersionString>
<d:Attachments m:type="Edm.Boolean">false</d:Attachments>
<d:GUID m:type="Edm.Guid">eb6850c5-9a30-4636-b282-234eda8b1057</d:GUID>
</m:properties>
</content>

The following example shows how to create a list item.


NOTE

To do this operation, you must know the ListItemEntityTypeFullName property of the list and pass that as the value of type in the HTTP request body.
url: http://site url/_api/web/lists/GetByTitle('Test')/items
method: POST
body: { '__metadata': { 'type': 'SP.Data.TestListItem' }, 'Title': 'Test'}
headers:

// MS-OFBA protocol returns a cookie.


Cookie: cookie
X-RequestDigest = form digest value
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
content-length:length of post body

The following example shows how to update a list item.


NOTE

To do this operation, you must know the ListItemEntityTypeFullName property of the list and pass that as the value of type in the HTTP request body.

url: http://site url/_api/web/lists/GetByTitle('Test')/items(item id)


method: POST
body: { '__metadata': { 'type': 'SP.Data.TestListItem' }, 'Title': 'TestUpdated'}
headers:
// MS-OFBA protocol returns a cookie.
Cookie: cookie
X-RequestDigest = form digest value
"IF-MATCH": etag or "*"
"X-HTTP-Method":"MERGE",
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
content-length:length of post body

The following example shows how to delete a list item.

url: http://site url/_api/web/lists/GetByTitle('Test')/items(item id)


method: POST
headers:
// MS-OFBA protocol returns a cookie.
Cookie: cookie
X-RequestDigest = form digest value
"IF-MATCH": etag or "*"
"X-HTTP-Method":"DELETE"

For more information, see Complete basic operations using SharePoint REST endpoints.

See also
Build Windows Phone apps that access SharePoint
Using the SharePoint REST service
Build Windows Phone apps that access SharePoint
Choose the right API set in SharePoint
Use OData query operations in SharePoint REST requests
Get to know the SharePoint REST service
Making REST calls with C# and JavaScript for SharePoint
Making REST calls with C# and JavaScript for SharePoint demo
Open Data Protocol
Authorization and authentication of SharePoint Add-ins
Windows Phone SDK 8.0
Microsoft SharePoint SDK for Windows Phone 8
Build reusable components for SharePoint
5/3/2018 • 2 minutes to read Edit Online

Learn about some of the most important reusable components you can build in SharePoint, including web parts, workflows, custom lists, and more.

Reusable components in SharePoint


Using SharePoint, you can build a variety of components, such as lists, web parts, and content types, which you can reuse in various apps, sites, and solutions. This section summarizes some
of the most common reusable components that you can build in SharePoint. Future updates to this documentation will contain information about additional components you can build.
NOTE

There are some restrictions on which components you can use in SharePoint Add-ins. For more information, see Host webs, add-in webs, and SharePoint components in SharePoint.
Web Parts are the most common way to extend SharePoint. Learning to build web parts is a great way to start SharePoint development. For more information, see SharePoint
Developer Building Blocks: Technologies for Creating SharePoint Applications.
Custom lists in SharePoint sites provide locations to store data. Data manipulation in SharePoint lists is a widely used practice. You can use lists to contain data that you access
programmatically. For more information, see Building Block: Lists and Document Libraries.
Workflows enable you to codify and standardize business processes, and are one of the essential tools for implementing certain scenarios. For more information, see Workflows in
SharePoint.
External content types make data from outside the SharePoint deployment available to the SharePoint application. For more information, see External content types in SharePoint.
You can define a content type that is a prototype of a list item. If you are using content types for a list, you can define the list so that it contains only items of one content type, or you
can specify that it can contain items of one of several content types. For more information, see Introduction to Content Types.
Column types and field types enable you to define rich metadata for standardized fields and columns in SharePoint lists. You can define a site column (in a site column gallery) of a
specific data type that you can use throughout your site. This resembles defining domains in database schema design. It lets you ensure that columns in several lists use the same
value space. For more information, see Custom Field Types.
Event receivers enable you to write event handlers that are called when, for example, users add, delete, or modify items in SharePoint document libraries or lists. For more
information, see Building Block: Event Handling.
Remote event receivers provide a way to notify external systems of SharePoint events. You can specify the endpoint and event properties to call when an event happens. For more
information, see Create a remote event receiver in SharePoint Add-ins.

See also
Programming models in SharePoint
Set up a general development environment for SharePoint
SharePoint development overview
Host webs, add-in webs, and SharePoint components in SharePoint
SharePoint Foundation 2010 Building Blocks
SharePoint Developer Building Blocks: Technologies for Creating SharePoint Applications (Part 1 of 2)
SharePoint Developer Building Blocks: Technologies for Creating SharePoint Applications (Part 2 of 2)
Build sites for SharePoint
5/3/2018 • 6 minutes to read Edit Online

Learn about the new site authoring and publishing model for websites in SharePoint.

Introduction to site publishing for designers and developers in SharePoint


SharePoint introduces a site authoring and publishing model to create publishing sites. You can use publishing sites to publish content on intranet or Internet sites. Publishing sites differ
from other types of SharePoint sites, such as team sites, mainly due to their purpose—many users read publishing site content, but only a few contribute by adding, updating, and deleting
content from one or more site collections. Contrast these sites with team sites, where many people may collaborate and contribute to the content.
You can use the SharePoint site publishing capabilities to build, customize, and maintain publishing sites that meet specific business needs. Whether you are a professional designer with
HTML, CSS, and JavaScript skills or a developer who writes SharePoint apps and uses custom .NET code to build sites and farm solutions, you can use site features in SharePoint to manage
all phases of the content life cycle, including:
Authoring and reusing site content.
Branding and designing your site's look, feel, and behavior.
Managing metadata—you can build a taxonomy-driven site navigation system.
Publishing content smoothly to the current site collection, or publishing content across site collections—even spanning the intranet and Internet site boundary.
Accessibility—you can use to improve the accessibility of your published sites.
If you want to see a summary of what's new for designers and developers of publishing websites in SharePoint, see What's new with SharePoint site development.

Authoring, design, and branding in SharePoint


SharePoint provides a new approach for designing websites. The content-creation workflow is revised so that you can create content using any —and author great content. To brand your site
without having to write custom .NET code, use the Design Manager to import design elements. With Design Manager, you can also create an HTML-based master page to define the chrome
shared by all of your site's pages and create page layouts to design templates for pages. If you choose to write custom code, you can use .NET server, .NET client (CSOM.md), Silverlight, and
JavaScript libraries.
SharePoint also provides a new approach to content and authoring. The content-creation workflow is revised so that you can create content using any authoring and branding tool and
author great content. To brand your site without having to write custom ASP.NET code, use the Design Manager. You can import design elements and create an HTML-based master page to
define the shared framing elements—the chrome—that all of your site's pages and page layouts share. If you choose to write custom code when branding your site, you can use the
publishing and taxonomy libraries.

Publishing sites, client object model programming, and the new SharePoint app model
You can use the new .NET client object model (CSOM) to develop SharePoint apps with the model for SharePoint Add-ins. You can use many of the APIs that are also available for .NET
server programming in the .NET client object models, which support .NET client, Silverlight, JavaScript—and in some cases Windows Phone—development. Some ideas for developing apps
for websites include surveys, account management apps, eCommerce support, integrating social features and external data into publishing websites, outsourced content additions, and
mobile companion apps.

Page model for publishing websites


SharePoint includes a page model for publishing websites. The page model includes master pages, page layouts, and other components that render your site structure, content, look and feel,
and behavior. To learn more, see Overview of the SharePoint page model.

Master pages and page layouts


A master page is the main template that defines the shared structural elements of your site—the chrome. All of the pages on the site share these elements, which define the regions of the
page that display page layout content.
Page layouts are used by individual pages of a certain type. They are populated with arrangements of page fields. These pages define individual elements on the page. Individual pages are
based on page layouts and are created in your web browser either by custom code or by how the site's users fill out the page's fields. To learn more about the page model in SharePoint, see
Overview of the SharePoint page model.

Client-side rendering controls


All new controls in SharePoint are rendered. Data is written to the controls in a client-side JSON array, and you can display content using JavaScript, CSS, and templates. As a designer or
developer, you have control over how content is rendered on the page, and you can use various design techniques to get the look and behaviors you want on your published pages by using
features like the Content Search web part in SharePoint and display templates.

Sites and mobile devices


Publishing websites in SharePoint are optimized for mobile development. You can define channels for one or more devices (device channels) and assign an alternate master page for each
channel, giving it unique structural elements, or chrome. You can choose to include or exclude portions of any page layout in a channel, and preview how mobile channel design is
progressing while it's being developed.

Metadata and navigation in SharePoint


Managed metadata capabilities introduced in Microsoft SharePoint Server 2010 are improved and extended in SharePoint for better performance, easier access through the user interface,
and taxonomy-driven navigation—called managed navigation. You can use managed navigation or navigation based on the SharePoint website structure—called structured navigation—to
build your site navigation. To learn more about managed navigation, see Managed metadata and navigation in SharePoint and Managed navigation in SharePoint.

Publishing content in SharePoint


SharePoint offers the following new content publishing features that enable you to develop publishing sites that support more flexible, more accessible, and more complex topologies and
scenarios.
Catalogs
SharePoint introduces catalogs, which you can use to publish content across site collections. Cross-site publishing features depend on catalogs. You can use them to reuse content across
your sites and across the boundary between your intranet sites and Internet sites. For predefined search queries, catalogs are flagged in search. You can surface content stored in catalogs
across site collections by using the Content Search web part in SharePoint.

Cross-site publishing
SharePoint introduces a cross-site publishing feature to reuse content across multiple site collections. It uses built-in search capabilities to enable publishing scenarios and architectures. For
the first time, you can design sites that cross SharePoint farms—enabling your sites to span the boundary between intranets and the Internet. You can use the CSWP to display search data
published from across sites and site collections.

Variations and multilingual sites


You can use the variations feature in SharePoint to create multilingual sites or other sites where you want to vary the presentation of your content. The variations feature is constrained to
one site collection. That is, you can create target language/locale "variants" of a source language/locale as current websites within the same SharePoint site collection. Variations supports
friendly URLs and the ability to export or import content for translation by a third party in XLIFF file format. You can include labels, a page for translation and replication, a variety of list
items (for example, document libraries.md), and navigation in your export packages.

Accessible sites
You can use the variations feature in SharePoint to create accessible sites or other sites where you want to adapt the presentation of your content for users who have a variety of accessability
needs. SharePointprovides a "More Accessible Mode", which can be activated by opening a SharePoint webpage, and pressing the TAB key until you find the "Turn on More Accessible Mode"
link. This feature recreates the webpage in standard HTML, making it friendlier for screen-readers. By ensuring that users are able to press the TAB key to focus on this link, you are able to
create a more accessible version of your SharePoint webpage. This includes JavaScript-based drop-down menus being converted to hyperlink lists and objects are converted to simpler
HTML to allow screen-readers to understand the content.

See also
Optimize SharePoint site accessibility
Set up a general development environment for SharePoint
What's new with SharePoint site development
Minimal Download Strategy overview
Modify SharePoint components for MDS
SharePoint Sites and Content server class library
Sites and Content client class library
What's new with SharePoint site development
5/3/2018 • 14 minutes to read Edit Online

Learn about the new site authoring and publishing model in SharePoint that enables you to create publishing sites.

Introduction to site publishing for designers and developers in SharePoint


The following features are new in SharePoint and support the enterprise content management (ECM) site creation workflow for publishing sites.

Client programming models for publishing site development


In SharePoint, you can use the .NET client object model (CSOM), Silverlight, and JavaScript programming models to develop custom sites, site components, branding elements, and
behavior. Most APIs available for .NET server programming are available in corresponding .NET client (CSOM), Silverlight, and JavaScript assemblies. In some cases, corresponding APIs
are also available in Windows Phone libraries.
To learn more, see the reference home pages for sites and content for .NET server, .NET client, and JavaScript. Or, start with the reference home page if you want to start at the top and then
explore the contents of each programming model.

Using publishing and taxonomy APIs with the new SharePoint app model
You can write custom client and server code in SharePoint Add-ins that extend the SharePoint publishing and taxonomy functionality that's available to users through the user interface (UI).
Some ideas for developing apps that enhance site publishing include surveys, account management apps, eCommerce support, apps that integrate social features and external data into
publishing sites, outsourced content additions to your sites, and mobile companion apps.

Authoring, design, and branding features


SharePoint includes features and APIs that you can use to author, design, brand, and extend your site, site design and branding elements, and behaviors.

Design Manager
In previous versions of SharePoint, branding a site required specific technical expertise about things like what content placeholders are required on a master page, or how a master page
implements certain classes of styles. SharePoint introduces Design Manager—a new interface and central hub for managing all aspects of branding your SharePoint site. You can find the
Design Manager in the top-level site for your site collection. It is a part of the Publishing Portal site collection template in SharePoint.
Design Manager enables a step-by-step approach for creating design assets that you can use to brand sites. Upload design assets—images, HTML, CSS, and so on—and then create your
master pages and page layouts. You can preview how your design looks either in a client-side code editor or on the server as you are designing it. You can add custom SharePoint
components and ribbon elements by using the Design Manager UI. The Design Manager generates HTML snippets that can be used by any web design tool—it renders HTML and ignores
ASP.NET and SharePoint markup (while SharePoint renders only ASP.NET and SharePoint markup and ignores HTML.md).
You can use your expertise in HTML, CSS, and JavaScript to design master pages in HTML, and design HTML page layouts in the HTML editor of your choice. To connect your favorite
authoring and design tool to your SharePoint site, map a network drive and then edit the SharePoint file as if it were a local file. When your site design is ready, upload the HTML and
supporting files and use Design Manager to convert the HTML file into an ASP.NET master page (.master.md) file. Now, apply the master page to your SharePoint site. Use Design Manager
to create a new page layout, and the HTML version of it is automatically associated with the corresponding ASP.NET page (.aspx file.md) that SharePoint interprets.
After you convert your HTML files, you can use your HTML editor to continue to refine your design, preview your files, and save them. Every time you save the HTML versions of the master
page or page layout files, SharePoint automatically updates the associated SharePoint master page and page layouts to reflect your changes.
With Design Manager, you only have to edit the HTML files—while you can continue to write custom master pages and page layouts using your ASP.NET and SharePoint development skills,
Design Manager enables you to design great sites without SharePoint developer expertise.
If you prefer, SharePoint also includes HTML versions of several master pages and page layouts that you can use as starter templates. If you want to start from these files, create a copy of
the HTML file (the associated ASP.NET file will be taken care of for you), and then edit the HTML file as you normally would. You can also start from just a basic template by using the
master page from minimal template option, which automatically creates the associated .master file.

Snippet Gallery
SharePoint contains many ready-to-use components—like web parts and controls—that you can add to your site's pages. For example, by inserting a SharePoint component such as a search
box or navigation control into your HTML master page, you can quickly and easily build a lot of functionality into your pages.
On the ribbon, in the Snippet Gallery group, you can select a component, configure its properties and update the snippet, copy the HTML snippet that's generated, and paste that HTML
snippet into your HTML file. The HTML snippet gives you a high-fidelity preview of that component, both in the server-side preview and in your HTML editor of choice. After you add
SharePoint components to your HTML files, you can use CSS to fully brand them. And just like any update to the HTML file, after you add SharePoint components and brand them, the
changes are automatically synchronized to the associated master page or page layout. The HTML snippets are automatically converted into SharePoint components.
Whether your HTML file is a master page or a page layout, the Snippet Gallery shows you the components that you need. If you don't see the snippet you want, you can create an HTML
snippet of ASP.NET markup and add that to your HTML master page or page layout.
Design Manager generates HTML snippets that can be used by any web design tool—it just renders HTML and ignores ASP.NET and SharePoint markup. SharePoint renders only ASP.NET
and SharePoint markup and ignores HTML.

Device channels
In Design Manager, you create device channels, and then you map them to mobile devices or browsers by using substrings of each incoming device's user agent string. A device can belong
to multiple channels, so channels can be ranked. For example, if you create device channels for "smart phones" and "Windows Phone 8", you can rank the channels so that devices running
Windows Phone 8 get the channel specifically assigned to them, while all other smart phones get content associated with the "smart phones" channel.
After you define channels, map a master page to each one. This master page can reference a different CSS file than the master page for the default channel. All page layouts that you create
will work with all of the channels that you create; to differentiate page layout designs between channels, use the Device Channel Panel control.
Publishing sites in SharePoint are optimized for mobile development. You can use the device channels feature to define channels for one or more devices—giving you finely-tuned control
over how mobile users experience your site. You can assign an alternate master page to each channel, giving it a unique chrome. You can choose to include or exclude portions of any page
layout in a channel and preview how mobile channel design is progressing while it is being developed. Device channels are designed with search engine optimization (SEO) in mind. You can
use them to transform the look and feel of existing pages to support mobile scenarios.
You can use channels to force specific renderings to appear on specific devices—this is called forcing channels. This is useful in mobile scenarios where you have defined a rendering that is
optimal for a specific mobile device.
Device Channel Panel control
The Device Channel Panel is a new control that you can include in a page layout to control what content is rendered in which channel. The Device Channel Panel is a container that is mapped
to one or more channels: If one or more of those channels are active when the page is rendered, all of the contents of the Device Channel Panel are rendered. The Device Channel Panel helps
you determine when to include specific content for specific channels.

Display templates
You may want to control the format and presentation of search results on your website. You can do that using display templates, which extend the options available for customizing search
results through the user interface beyond mapping the predefined fields that you want to display.
There are three contexts when you may want to use display templates with search results—when you want to map how the overall structure of search results are presented, when you want
to show groups of results, and when you want to show how each result, or item, in the result set is displayed. These are called Control, Group, and Item templates, respectively.
To learn more about display templates, see SharePoint Design Manager display templates.

Image renditions
You can use image renditions to display uploaded images in predefined sizes, widths, and crops. You can create more than one rendition of a source image file, which means that you can set
the display characteristics once and apply them to any number of images. For example, a rendition named Article_image displays a full-sized image in an article, while the rendition named
Thumbnail_small displays a smaller version of the image in a context that you define.
Before you can use image renditions, ensure that the BLOB cache is enabled on the server, which you can do in the Administration tools in Internet Information Services (IIS). Find your
web.config file there and enable the BLOB cache. Refresh the page, and image renditions will be available.

Managed metadata and navigation in SharePoint


Enterprise managed metadata (EMM) capabilities introduced in are improved and extended in SharePoint for better performance, easier access through the UI, and taxonomy-driven
navigation—called managed navigation.

Managed navigation
Managed navigation is the taxonomy-based alternative to the traditional SharePoint navigation feature—called structured navigation—that is based on the structure of SharePoint. The
managed navigation feature enables you to design a site navigation that is driven by managed metadata. Managed navigation creates SEO-friendly URLs that are derived from the managed
navigation structure. Because managed navigation is driven by taxonomy, you can use it to design site navigation around important business concepts without changing the structure of your
sites or site components.

Content Search web part


You can use the Content Search web part (CSWP) to display search data on your pages. It serves a function similar to that of the Content Query web part, but it serves different site design
goals. CSWP styles are easier to customize than Content Query web part styles. CSWP returns client-side results in JSON format. On the server, you can customize results by using display
templates.

Other managed metadata improvements for sites


SharePoint introduces several improvements to the managed metadata UI and functionality. To learn more, see Managed metadata and navigation in SharePoint.

Publishing content in SharePoint


SharePoint offers new content publishing features that enable you to develop publishing sites that support new, more flexible, and more complex topologies and scenarios.

Design packages
If you're a professional web designer, you may want to create and test a design in your own environment or site collection before handing it off to install in other site collections. If you're
using cross-site publishing to share content across site collections, you may want to package and install the same design on each site.
In previous versions of SharePoint, if you wanted to reuse a design, you had to use Visual Studio to create a SharePoint Solution Package (.wsp file). Then, in the destination site, you would
upload the package to the Solutions Gallery and execute it. Now, in SharePoint, after you finish designing your site, you can choose Export Package in Design Manager to export a single
.wsp file called a design package. When you export a design package, SharePoint automatically packages all of the contents that you have added or changed in the Master Page Gallery, Style
Library, Theme Gallery, the Device Channels list, and Page content types into a design package.
NOTE

A design package does not include pages, navigation settings, or the term store.
For Office 365 public websites, design packages do not overwrite existing files. Installing a design package creates a new folder in the Master Page Gallery, Style Gallery, and Theme Gallery
where design assets are isolated.
When you import a design package, the design assets in the package overwrite any existing files and are applied as the current design of the site. The site's default and system master page,
theme, and alternate CSS are all set from the files in the design package. With design packages, a design built in one environment can easily be applied to another, separate environment.

Catalogs
SharePoint site publishing introduces catalogs, which enable you to incorporate lists into your publishing sites. Catalogs enable content to be published across site collections—the cross-site
publishing features depend on catalogs. You can use catalogs to truly reuse content across your sites and across the boundary between your intranet sites, Internet sites, and extranet sites.
For predefined search queries, catalogs are flagged in search. You can surface content stored in catalogs across site collections by using the Content Search web part (CSWP). You can write
custom code to populate catalogs, connect a product catalog to a site, and curate individual pages with custom page layouts, web parts, and HTML content that appears only in the defined
context.

Client-side rendering controls


All new controls in SharePoint are rendered client-side. As a designer or a developer, you have control over how content is rendered on the page, and you can use various design techniques
to get the look and behaviors you want on your published pages by using features including the Content Search web part and display templates. Data is written to the controls in a client-side
JSON array, and you can display content using JavaScript, CSS, and templates.

Cross-site publishing
Microsoft SharePoint introduces a cross-site publishing feature that enables you to reuse content across multiple site collections. It uses built-in search capabilities to enable publishing
scenarios and architectures. For the first time, you can design sites that cross SharePoint farms—enabling your sites to span the boundary between intranets and the Internet.
Use the topic pages feature to customize the landing page experience for content that is published across sites. Use SEO-friendly URLs to manage and more easily persist and maintain site
structure across a broad range of scenarios—including complex multilingual site topologies.
To learn more about cross-site publishing, see Scenario: Create SharePoint sites by using cross-site publishing in SharePoint. To learn more about development options for cross-site
publishing, see Cross-site publishing in SharePoint.

SEO enhancements
Many business site users are referred to Internet business sites from large search engines like Bing and its global competitors. SharePoint includes features like friendly URLs, home page
redirects, XML sitemaps, custom SEO properties that enable you to flexibly define the browser title and tag descriptions and keywords, and easier-to-understand URLs for multilingual site
variations.
In Office 365, the site infrastructure generates an updated XML sitemap for you within 24 hours of a site change. With an on-premises installation, you can tune the freshness of your
sitemaps and specify which search engines you want Microsoft to ping when we update the sitemap.
What your friends like on Facebook affects what you see in the search results returned by Bing and other large search engines. You can use APIs in SharePoint programming models to
customize how search is optimized for your site.

Analytics and recommendations


You can track how people use publishing sites and their components using the SharePoint analytics feature, which is deeply integrated with the search engine. Analytics drives
recommendations capabilities on content, and injects calculations into the search index as managed properties. The recommendations provided by search analytics, which include page views
and unique items per day, can influence the relevance of search results.
Analytics makes data anonymous and rolls it up every 15 days. Analytics purges events every 15 days and then monthly after 3 years. Lifetime views are always retained. The least-visited
content is trimmed before analytics pushes aggregate data to a reporting database. You can use custom code to export data to Excel from the reporting database, customize the weight of the
View event, and create custom events—including those submitted by JavaScript.

Variations and multilingual sites


You can use the variations feature in SharePoint to create multilingual sites or other sites where you want to vary the presentation of your content. The variations feature is constrained to
one site collection. That is, you can create target language/locale "variants" of a source language/locale as current websites within the same SharePoint site collection. Variations supports
friendly URLs and the ability to export or import content for translation by a third party in XLIFF file format. You can include labels, a page for translation and replication, a variety of list
items (for example, document libraries.md), and navigation in your export packages.

See also
Complete basic operations using SharePoint client library code
Complete basic operations using JavaScript library code in SharePoint
How to: Customize page layouts for a catalog-based site in SharePoint
How to: Change the preview page in SharePoint Design Manager
How to: Resolve errors and warnings when previewing a page in SharePoint
Themes overview for SharePoint
Managed metadata and navigation in SharePoint
What's new in SharePoint search for developers
Develop the site design in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Find links to information about using Design Manager and implementing a design for your SharePoint site. If you want your SharePoint site to represent your organization's brand and not
"look like SharePoint," you can create a custom design and use Design Manager to achieve that goal. Design Manager is a feature in SharePoint that makes it easier to create a fully
customized, pixel-perfect design while using the web-design tools that you're already familiar with. Design Manager is a publishing feature that is available in publishing sites in both
SharePoint and Office 365. You can also use Design Manager to brand the public-facing website in Office 365.
For more information about using Design Manager to customize your sites, see the following articles and their subtopics:
Overview of Design Manager in SharePoint : Get an overview of using Design Manager to brand your SharePoint site. Design Manager is a publishing feature that is available in
publishing sites in both SharePoint and Office 365.
Overview of the SharePoint page model : Learn about the revised page model—including master pages and page layouts—redesigned for SharePoint.
Master pages, the Master Page Gallery, and page layouts in SharePoint : Find links to information about using Design Manager to work with master pages, page layouts, and display
templates in publishing sites in SharePoint.
SharePoint Design Manager branding and design capabilities : Find links to information about using Design Manager branding and design capabilities in SharePoint.

See also
Build sites for SharePoint
What's new with SharePoint site development
Overview of Design Manager in SharePoint
5/3/2018 • 15 minutes to read Edit Online

Get an overview of using Design Manager to brand your SharePoint site. Design Manager is a publishing feature that is available in publishing sites in both SharePoint and Office 365.

Introduction to Design Manager


If you want your SharePoint site to represent your organization's brand and not "look like SharePoint," you can create a custom design and use Design Manager to achieve that goal. Design
Manager is a feature in SharePoint that makes it easier to create a fully customized, pixel-perfect design while using the web-design tools that you're already familiar with. Design Manager is
a publishing feature that is available in publishing sites in both SharePoint and Office 365.
With Design Manager, you can create a visual design for your website by using whatever web design tool or HTML editor you prefer, using only HTML and CSS, and then upload that design
into SharePoint. Design Manager is the central hub and interface where you manage all aspects of a custom design.
Creating the visual design of a site often fits into a larger process, in which multiple people or organizations are involved. For a roadmap of the tasks from a larger perspective, see Design
and branding in SharePoint
At a high level, the designer will perform the following tasks:
Understand core SharePoint design concepts. For more information, see Overview of the SharePoint page model.
Create a mock-up of the design in HTML and CSS. Creating the design is a core skill of a web designer, and is not covered in this article.
Implement the design by using Design Manager. Sections of this article provide an introduction to Design Manager and the process of using Design Manager to implement a visual
design.

Use Design Manager to implement a design


When you look at Design Manager, you see a series of links on the left side that represent the high-level tasks that you have to perform. Depending on your design and your site's
requirements, you may not have to perform all of these tasks, and you don't necessarily have to perform them in this order. Still, this sequence is a useful starting point.

Before you begin


Before you can use Design Manager, you need a design. You can create your own, or use a ready-made website template. A "design" is simply a group of files that implement the visual
design of your site, most commonly:
At least one HTML file that will be converted into a SharePoint master page
One or more CSS files
JavaScript files
Images
Other supporting files
As you mock up your site in HTML and CSS, you will likely have several HTML files that implement designs for how you want different pages or types of pages to appear. Remember that
only one of these HTML files will be converted into the master page (unless you have multiple device channels, where each channel has its own master page—see the following section).
After you use Design Manager to create other site elements, such as page layouts or display templates, you can transfer markup from your HTML mock-ups to the HTML and CSS files
associated with the page layout or display template.
Before you begin, you also need the required SharePoint permissions. To use Design Manager, you must have at least the Designer permission level.

Manage device channels


Even before you design your site, you want to consider what devices your site should target and what will be the user experience on each device. For example, you may want to optimize your
site's design for a certain class of smart phones or tablets.
Depending on what channels you define, you may want several designs, and so several HTML files, where each file gets converted into a separate master page. Also, each HTML file (and so
each master page) can reference its own CSS file. Before you design your site, device channels are one of the first things to consider.
With device channels, you can render a single publishing site in multiple ways by mapping different designs to different devices. Each channel can have its own master page that links to a
style sheet that is optimized for a specific device. Each channel specifies the user agent substrings for one or more devices, such as "Windows Phone OS". These are rules that determine
what devices are included in each channel. Then, when visitors browse your site, each channel captures the traffic for its specified device or class of devices, such as Windows phones, and
visitors see your site in a design optimized for their specific device.
Device channels are created and stored in a SharePoint list in which order matters, because device channels also have rankings. Device channels in the list are ordered from top to bottom,
and the inclusion rules are processed in that order. This means that you want device channels with the most specific rules at the top. For example, a channel targeting "Windows Phone OS
7.0" should precede a channel targeting "Windows Phone OS".

Upload design files


When you create a design, you can use whatever HTML editor you prefer and work with files locally on your computer. But, eventually, you will have to upload those files to the Master Page
Gallery of your SharePoint site, so that you can use Design Manager to convert, preview, and polish your design.
The easiest way to upload and continue to work on design files is to map a drive on your computer to the Master Page Gallery of your SharePoint site. This connects a folder on your
computer to the Master Page Gallery, so that you can work on files that reside on the server in SharePoint as if they were local files.
After you map a network drive, you can upload your design to SharePoint simply by copying the design files to a folder on the mapped drive of your computer that is connected to
SharePoint. After you convert your HTML file to a SharePoint master page, and after you create page layouts and display templates that each have their own associated HTML file, you can
continue to edit those associated HTML files in your HTML editor on your computer. Each time you save a file in the mapped drive, SharePoint automatically synchronizes the files on your
computer with the Master Page Gallery. You can create your own folder structure on the mapped drive, and that structure is maintained by SharePoint and appears in the Master Page
Gallery. You should keep all files related to one design in a single folder, and then copy that folder to the mapped drive when you are ready to upload your design.
For more information, see How to: Map a network drive to the SharePoint Master Page Gallery.

Edit master pages


Creating a fully branded master page that contains all of the SharePoint functionality that you want, such as navigation and search, is basically a three-step process:
1. Convert an HTML file into a SharePoint master page.
2. Preview the master page and fix any issues.
3. Add SharePoint snippets to the master page.
Each of these three steps is performed on a different page in Design Manager.
Convert an HTML file
The core feature of Design Manager is that it converts your HTML design into a SharePoint master page. To render successfully, a SharePoint master page must contain many ASP.NET
elements and elements that are specific to SharePoint. When you convert an HTML file to a master page, Design Manager creates a .master file that contains all of these required elements,
so that you don't have to know about them. During conversion, some HTML markup (such as comments) also gets added to your original HTML file.
After the conversion, your HTML file and the SharePoint master page are associated, so that when you edit and save the HTML file in your mapped drive, the master page is updated
automatically. In Design Manager, the HTML master page has a property named Associated File that determines whether changes to the HTML file are synced to the .master file.
NOTE

Design Manager also provides an option to begin your design by using a minimal master page. In this scenario, you don't have to begin with an HTML design; instead, you can create an
HTML master page that contains the minimum page elements necessary to render the master page correctly in SharePoint, and then build out your design by editing the HTML master page.
Preview the master page
In addition to converting your master page, Design Manager provides a server-side preview (vs. the design-time preview in your HTML editor), so that you can get a live preview of your
master page and fix any issues that might prevent the page from rendering. For example, your HTML file must be XML-compliant, so you may have to fix minor markup issues such as
providing closing tags for all elements. To fix any issues, you should edit the HTML file, save it, and then refresh the server-side preview.
When you preview a master page, you can use the Change Preview Page option in the top-left corner to preview the master page along with any existing page, or create a new page to
preview with. Unlike the design-time preview of your HTML master page in an HTML editor, this server-side preview is a fully functional live preview, so you may prefer to edit the HTML
file, save it so that the latest changes are synced to the associated .master file, and refresh the live preview and view your latest design changes in the browser.
Add snippets
After you convert your master page and successfully preview it, you are ready to add snippets to the master page. A snippet is an HTML representation of a SharePoint component—such as
a navigation control or search box or web part—that you can add to your master page. Adding snippets to your master page is how you quickly build the full range of SharePoint
functionality into your master page. Adding snippets is basically a three-step process:
1. Find and configure snippets in the Snippet Gallery.
2. Copy snippets to your HTML master page.
3. Preview and style snippets by using CSS.
For more information, see SharePoint Design Manager snippets.
Find and configure snippets in the Snippet Gallery
The Snippet Gallery is where you can quickly see which components are available for the type of file you're editing, either master page or page layout. On the ribbon, you select a snippet. In
the property grid on the right, you can configure the properties for this instance of a snippet, and then choose Update to refresh the HTML snippet on the left.
Copy snippets to your HTML master page
After you configure a snippet, you copy it to the Clipboard and then paste it at the right spot in your HTML file. Your HTML design may already contain mockup or static controls, in which
case you'll want to delete them or comment them out as you replace them with dynamic snippets from the Snippet Gallery.
Preview and style snippets by using CSS
After you copy snippets into your HTML file and then save the changes, you can refresh the server-side preview of the master page to see how the control is rendered. Snippets contain
markup that provides a design-time preview in an HTML editor, but the server-side preview shows a full-fidelity preview with live data—for example, a navigation control will show the site's
current navigation structure with live data from your data source.
By default, most snippets inherit styles from the main SharePoint style sheet, corev15.css. To style a snippet, you have to identify what styles are applied to the snippet and then override
them with custom CSS. To identify these default styles, you can use a browser tool such as the developer tools in Internet Explorer. While viewing your master page in the server-side preview
in Internet Explorer, press F12, choose Find, and then choose Select element by click. This lets you click the snippet and see exactly what styles to override by adding CSS to whatever
custom style sheet your master page links to.

Edit display templates


If you are using an on-premises installation of SharePoint Server, you can use the Content Search web part and other search-driven web parts to display the results of search queries as
content on your pages. Search-driven web parts use display templates for two main purposes:
To map the managed properties that are returned in search-result items to properties that will be available for JavaScript, including whatever custom JavaScript you choose to
implement.
To use HTML and CSS to present and style how those properties are displayed.
With master pages and page layouts, you edit an associated HTML file but not the .master file or .aspx file. Similarly, display templates are made of an HTML file and an associated .js file,
where you edit only the HTML file. Each time you save that HTML file, SharePoint automatically updates the associated .js file.
When you want to create a custom display template, you should begin by copying and then modifying one of the existing display templates. This is helpful because the default display
templates contain information in comments in the HTML files, and you'll have the proper basic page structure and a framework in place for basic tasks like mapping input fields.

Edit page layouts


The process for creating a page layout is a bit different from that for creating a master page. For a master page, you start with an HTML design, convert that into a SharePoint master page,
and then continue to edit the associated HTML file. But for a page layout, you first create the page layout in Design Manager, which creates an .aspx file and an HTML file, and then you edit
the associated HTML file from the mapped drive in your HTML editor. The reason you have to use Design Manager to create a page layout is so that the correct set of page fields can get
added to the page layout.
When you create a page layout, you select a master page with which to preview your page layout, and you select a Page Layout Content Type. A content type is a schema of fields and data
types, and the fields available in the page layout content type determine what page field controls are available on the page layout that you design. You create a page layout in the browser first
so that the page fields can be added.
After you create a page layout with its associated HTML file, the remaining steps are the same as for a master page:
Preview the page layout and fix any issues by editing and saving the HTML version.
Add snippets to the page layout (configure, copy, preview, style).
In the Snippet Gallery, different snippets are available for page layouts and master pages, and the ribbon displays only the snippets that are relevant for that type of file. For example,
navigation and search box snippets are available only for a master page, while page fields are available only on a page layout.
When you design a page layout, your basic task is to position and style the page field controls that will display content created by content authors. The styles for a page layout can reside in
whatever style sheet the master page links to, or each page layout can link to its own specific style sheet. If your HTML design includes content more suitable for a page layout than a master
page, you want to transfer that content out of your HTML master page, and then apply those styles to the correct controls and elements of the relevant page layout.
For more information, see How to: Create a page layout in SharePoint.

Create themes and composed looks


In the Office 365, but not in on-premises SharePoint installations, Design Manager has the option of creating themes and composed looks. A theme is a set of fonts and colors that can be
applied to a custom design (meaning a master page). Themes are defined in .xml files that you upload to the Themes gallery. If you want a custom master page to be theme-able, you need to
add special markup to the master page that SharePoint recognizes and uses to insert theme elements such as fonts and colors.
A composed look is just an association between a background image, a theme (meaning fonts and colors), and a design (meaning a master page). A composed look takes predefined design
elements—themes, background images, and master pages—and enables them to be used in many different combinations.

Publish and apply design


Most assets used by your design, such as images, HTML, CSS, and JavaScript files, will reside in the Master Page Gallery. The Master Page Gallery is a SharePoint document library that by
default has versioning turned on, which creates major and minor (draft) versions each time you edit a file.
Before you can apply your design to a site, you first have to publish a major version of each file or asset used by your design. If you are designing your site in a test environment, you should
turn off versioning for the Master Page Gallery, so that you don't have to remember to publish every file before you preview the site. But this is not a best practice if you are designing on a
live site.
After you publish all the design files, you are ready to apply the design by assigning your finished master pages to your site. Each site can have a different master page assigned to each
device channel, and this page of Design Manager is where you apply a master page to a channel.

Create a design package


A design package is an easy way to collect all the files and assets used by your design, export them from one site, import them into another site, and apply the design to the new site. If you
implement and polish your design in a test site collection and want to deploy it in a live site collection, you can use a design package to transfer your design.
A design package is a .wsp file, a SharePoint solution file, which is basically a special type of .cab file. When you create or import a design package, the .wsp file is stored in the Solutions
gallery. After you import a design package, the package is automatically activated. If the master pages and page layouts were published before they were packaged, and if the master pages
were assigned to device channels before they were packaged, the design will be automatically applied to the site when the design package is deployed. Otherwise, to apply the design to the
new site, you just have to publish the design files and apply the master pages per device channel.

See also
Overview of the SharePoint page model
How to: Convert an HTML file into a master page in SharePoint
How to: Create a page layout in SharePoint
Overview of the SharePoint page model
5/3/2018 • 10 minutes to read Edit Online

Learn about the revised page model—including master pages and page layouts—redesigned for SharePoint.

Introduction to the page model


Before you design or brand a SharePoint site, you need a basic understanding of the parts of a SharePoint site and how a SharePoint page is put together. This article gives you a visual
overview of the pieces to think about as you plan how to brand your site. This article applies specifically to publishing sites in SharePoint.

Master pages, page layouts, and pages


SharePoint uses templates to define and render the pages that a site displays. The structure of a SharePoint page includes three main elements:
Master pages define the shared framing elements—the chrome—for all pages in your site.
Page layouts define the layout for a specific class of pages.
Pages are created from a page layout by authors who add content to page fields.
Figure 1. Master page, page layout, and page

Master pages
A master page defines the chrome (the shared framing elements) of your site. These elements may include the header and footer, top navigation, breadcrumbs, search box, site logo, and
other branding elements. The master page remains consistent as visitors navigate through your site.
Figure 2. Master page

A master page also defines regions called content placeholders that are filled in by content from matching regions on page layouts. Most commonly, the body of a master page contains just
a single content placeholder (named PlaceHolderMain, which is created automatically), and all of the content from a page layout appears inside this one content placeholder (the
PlaceHolderMain content placeholder is outlined in red in Figure 3).
Figure 3. Master page with page layout outlined
When you preview a master page in Design Manager, you see the following message. This
resides inside the main content placeholder. Put simply, the master page defines the chrome of a page, and the page layout defines the body contained in the main content placeholder.
Figure 4. Master page preview message

Page layouts
A page layout is a template for a specific type of page in your site, such as an article page or a product details page. Just like its name implies, you can think of a page layout as defining the
layout or structure for the body of a page.
Figure 5. Page layout

Page layouts define regions or content areas that map to content placeholders on the master page (outlined in red in Figure 6). Again, the most common scenario is that a page layout
defines a single content region that maps to the single content placeholder that is created automatically on a master page.
Figure 6. Content region and content placeholder

Page field controls


The primary purpose of a page layout is to arrange page fields. When you design a page layout, you insert, position, and style elements called page field controls. These controls will
eventually contain content when an author creates a page based on that page layout. In addition to page fields, page layouts can also contain web part zones, to which content authors can
add web parts. (Master pages can't contain web part zones.)
With a page field control, you can define the styles used by the content. Authors can add content to a page, but the designer has ultimate control over how that content is rendered through
CSS applied to those controls.
Figure 7. Page layout with page field controls
Every page layout is associated with a content type in the Pages library of a site. A content type is a schema of columns and data types. For any page layout, the page fields that are available
for that layout correspond directly to the columns defined for that page layout's content type.

Relationship of master pages and page layouts


Together, a master page and a page layout create a content page.
Figure 8. Master page with page layout

The master page defines the chrome for all pages in the site so, often many page layouts (and therefore many pages created from those page layouts) are associated with one master page.
Figure 9. One master page tied to three page layouts

But, your site will likely use multiple master pages. For example, in addition to the default master page, you may have one or more master pages that target specific devices such as smart
phones or tablets. In this case, one page layout is used by many master pages (see the section about device channels).
You can use one master page per channel per SharePoint site.

Pages
Authors can create pages and add content to the page fields, and they can add web parts to any web part zones or Rich Text Editors. Pages are structured so that content authors cannot
make changes outside of page fields.
Figure 10. Page with authored content
The rendered page is what site visitors see. When a page is requested by the browser, the master page is merged with a page layout to create a content page, and the content for that page is
merged into the page fields from that page in the Pages library.
Figure 11. Rendered page in browser

Figure 12. Master page, page layout, and page

Search-driven web parts and display templates


The previous section explains the SharePoint page model in terms of master pages, page layouts (with page fields), and pages. These elements are the most common in a publishing site in
which authors regularly create and publish new content. When it comes to surfacing that content on your site, though, a couple more elements come into play. Whether you have connected
to an external catalog or simply want to show a particular set of search results, search-driven web parts can help you achieve your goal.
In the search-driven pages scenario, a SharePoint page contains these main elements:
Master pages
Page layouts:
Regular page layouts that you created for specific content types, as described previously in this article
Category and item details page layouts that are created through cross-site publishing of a catalog
Pages
Search-driven web parts, such as the Content Search web part
Display templates to control which managed properties appear in the search results of a search-driven web part, and control the styling and behavior of those search results:
Control display templates, which control the layout of search results and any elements common to all results such as paging, sorting, and other links
Item display templates, which control how each search result is displayed and repeated for each result
Figure 13. Master page, page layout, and page with web part

Search-driven web parts


With search-driven web parts, you can dynamically present information stored in the search index. The presentation of data in the Content Search web part is controlled by display
templates, which reside in the Master Page Gallery alongside master pages and page layouts.
SharePoint includes several ready-to-use display templates such as lists and slideshows for your Content Search web parts. When you configure a Content Search web part in the browser,
you choose which display templates to use.
Figure 14. Tool pane of Content Search web part

Content Search web parts use two types of display templates, control and item. As part of the design or branding of your site, you can create custom display templates that use layouts,
styles, and behaviors that you define.
Figure 15. Two diagrams of Content Search web parts
Control display template
The control template determines the overall structure and layout of how you want to present the search results, such as a list with paging or a slideshow. Each Content Search web part uses
one control template.
The control template also includes functionality common to all the search results, including paging, sorting, view options, and separators.
Figure 16. Control template outlined on web part and webpage

Item display template


The item template determines how each result in the set is displayed, and the template is repeated for each result. An item template can display an image, an image with text, a video, and
other content.
The item display template also determines which managed properties and values are displayed by the Content Search web part. In this example, the item template displays three managed
properties: a small-sized image, a product name as a hyperlink, and a brief text description.
Figure 17. Item templates outlined on web part and webpage

Device channels and device channel panels


In SharePoint, you can use device channels to render a single publishing site in multiple ways by using different designs that target different devices. You create a single site and author the
content in it a single time. Then, that site and content can be mapped to use different master pages and style sheets to target a specific device or group of devices.
When you design for more than one device, consider these elements:
Device channels:
By using different master pages and CSS per channel, identical page content can be presented in different ways for specific devices (for example, Windows Phone) or groups of
devices (all smart phones).
Page layouts:
If the content does not change, you use the same page layouts for all device channels, though they can be styled differently based on the CSS of the different master page for
each channel.
If you want to include content only for specific devices, use device channel panels.
Pages

Device channels
When you create a device channel, you specify the user agent substrings for the devices that you want the channel to target. This gives you fine-tuned control over what devices (or browsers)
are captured by each channel. Then you assign a master page to that channel; in turn, each master page links to its own style sheet where the layout and styles are optimized for that type of
device.
Figure 18. Two device channels with separate master pages

You can accomplish a great deal using only CSS. It is possible for the master pages for two different channels (for example, desktop and phone) to be identical except that they link to
different style sheets. The CSS files simply use different styles for the same page elements.

Relationship of master pages and page layouts


Unlike master pages, you do not specify different page layouts for different device channels. All page layouts work with all channels that you create. Thus, one page layout applies to many
device channels and master pages.
This is one of the primary benefits of device channels: the design changes (the master page and CSS), but the content stays the same (page layouts and pages). But, you can vary what
content from a page layout is displayed across different channels by using device channel panels (see the next section).
Figure 19. One page layout working with two master pages

Device channel panels


A device channel panel is a control that you can add to a master page, page layout, or display template to control what content is rendered in each channel. A channel panel is basically a
container that specifies one or more channels; if one or more of those channels are active when the page is rendered, all of the contents of the channel panel are also rendered. A channel
panel can include any type of content, including a link to a CSS file or a .js file, and is an easy way to include specific content for specific channels.
Perhaps the most common scenario for using channel panels is to selectively include parts of a page layout for specific channels. For example, you may have a page layout with separate text
fields for a long greeting and a short greeting. By placing the page fields inside channel panels, you can display the short greeting only to phones and the long greeting only to desktops. The
content of a device channel panel is not displayed to channels that it doesn't include—and the content inside that device channel panel is not rendered at all, which prevents bytes from going
across the wire.
Figure 20. Page layout with channel panels
You can also use channel panels on master pages. For example, if you have a master page that can accommodate two different devices (or two different browsers) with only minimal changes,
you can use channel panels to hold the content on the master page that is specific to each of those devices.
Or, you can use a channel panel inside the item display template of a Content Search web part, to display additional managed properties for that item from the catalog only for desktops and
not for phones.
Figure 21. Page layout and item templates with channel panels

See also
Overview of Design Manager in SharePoint
Build sites for SharePoint
SharePoint Design Manager display templates
SharePoint Design Manager device channels
Master pages, the Master Page Gallery, and page layouts in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Find links to information about using Design Manager to work with master pages, page layouts, and display templates in publishing sites in SharePoint. Design Manager is a feature in
SharePoint that makes it easier to create a fully customized, pixel-perfect design while using the web-design tools that you're already familiar with. Design Manager is a publishing feature
that is available in publishing sites in both SharePoint and Office 365. You can also use Design Manager to brand the public-facing website in Office 365.
For more information about using Design Manager to work with master pages, page layouts, and display templates, see the following articles:
How to: Map a network drive to the SharePoint Master Page Gallery : Learn how to map a network drive so that you can work with design files in your SharePoint site as if they were
local files.
How to: Apply a master page to a site in SharePoint : Learn how to map a master page to a SharePoint site.
How to: Create a page layout in SharePoint : Learn how to create a page layout.
How to: Customize page layouts for a catalog-based site in SharePoint : Learn how to create and customize category page and catalog-item page layouts for a SharePoint cross-site
publishing site.
How to: Apply styles to page fields in SharePoint : In a page layout, you can apply styles to a page field, and those styles are applied to any content added by content authors when
they create a page from that page layout. Also, you have further options to control how content in a RichHtmlField page field is styled.
How to: Resolve errors and warnings when previewing a page in SharePoint : When you use Design Manager to see a live preview of a master page or page layout, you may need to
resolve some common preview errors.
How to: Convert an HTML file into a master page in SharePoint : Learn how to create a master page by converting a typical HTML file into the .master file required by SharePoint.
How to: Create a minimal master page in SharePoint : A minimal master page contains only those page elements that are required by SharePointto render the page correctly in the
browser. With Design Manager, you can quickly create a minimal master page without first having to design and convert an HTML file.
How to: Change the preview page in SharePoint Design Manager : Learn how to set, create, and change the preview page in Design Manager in SharePoint.

See also
SharePoint Design Manager display templates
Build sites for SharePoint
SharePoint Design Manager branding and design capabilities
Overview of the SharePoint page model
Map a network drive to the SharePoint Master Page Gallery
3/26/2018 • 2 minutes to read Edit Online

Learn how to map a network drive to the Master Page Gallery so that you can use Design Manager to upload design files in SharePoint. You can create a visual design for your website by
using any web design tool or HTML editor, and then use Design Manager to import the design into SharePoint. To do this, you have to make sure that the design tool stores its files in your
site's Master Page Gallery, which is where SharePoint expects to find the files. We recommend that you map a network drive to the Master Page Gallery to make it easier to save files in the
correct location.
First, find the location of the Master Page Gallery.

To find the location of the Master Page Gallery


1. On the site for which you are creating a design, start Design Manager. (For example, on the Settings menu, choose Design Manager.)

Important: If your site is hosted in SharePoint Online, when you sign in to the site by using your Office 365 credentials, make sure that you select the Keep me signed in check
box. For more information, see How to configure and to troubleshoot mapped network drives that connect to SharePoint Online sites in Office 365 for enterprises.

2. In the numbered list, select Upload Design Files.


3. The Design Manager: Upload Design Files page contains the location of the Master Page Gallery. The location probably ends in /_catalogs/masterpage/ . This is the location to which
you will map a network drive.
4. Make a note of the location of the Master Page Gallery, or copy it to the Clipboard.
On the computer that runs your design tool or HTML editor, map a network drive to the location that you just copied. The procedure for mapping a network drive differs depending on the
computer's operating system:
If the computer is running Windows 8, follow the steps that are described in the Windows 8 version of the article Create a shortcut to (map) a network drive.
If the computer is running Windows 7, follow the steps that are described in the Windows 7 version of the article Create a shortcut to (map) a network drive.
If the computer is running Windows Vista, follow the steps that are described in the version of the article Create a shortcut to (map) a network drive.
If the computer is running Windows XP, follow the steps that are described in the article How to connect and disconnect a network drive in Windows XP.
If the computer is running another operating system, follow the instructions for creating a shortcut to a new location for that operating system. You might have to provide
different credentials for connecting to the SharePoint site, and you might have to specify that the connection be re-established every time that you log on to the computer.

See also
How to: Apply a master page to a site in SharePoint
Develop the site design in SharePoint
SharePoint Design Manager device channels
How to: Change the preview page in SharePoint Design Manager
SharePoint Design Manager image renditions
Apply a master page to a site in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn how to map a master page to a SharePoint site.

Mapping a master page to a site


In SharePoint, a master page defines the shared framing elements such as the chrome for all pages in your site. After a master page is created, it can be mapped to a site. This could be for all
publishing pages designated for all users, or for the administrative pages used for site maintenance. Alternatively, if you are configuring a child site of a parent site, you can inherit the master
page from the parent. This article provides the steps to map a created master page to a site, inherit the master page from a parent site, or map a master page to a specific device channel.
NOTE

For more information about Design Manager and master pages, see Overview of Design Manager in SharePoint. For more information about how to create device channels, see SharePoint
Design Manager device channels.

To map a master page to a SharePoint site


1. In Site Settings for the designated site, under the Look and Feel section, choose Master Page.
NOTE

If the Master Page link is not there, you need to enable the publishing feature with these steps. Navigate to Site Settings | Site Collection Administration | Site Collection
Features. Scroll down to the SharePoint Server Publishing Infrastructure feature and press Activate.
2. On Site Master Page Settings, select one of the two options for the Site Master Page or System Master Page sections:
Inherit site master page from parent site Choose this option if you are configuring a child SharePoint site and want to use the parent master page.
NOTE

If you are working on the top-level parent site this option is unavailable.
Specify a master page to be used by this site and all sites that inherit from it Choose this option if you want to map a specific master page to the site, or if you want to
map a specific master page for administrative pages. A drop-down box named Default or All Channels is available for you, depending on your site or system configuration, so
you can select a specific master page stored in the master page gallery. Select the desired master page from the drop-down box.
NOTE

If you have any device channels configured, there are additional drop-down boxes available for additional master page mapping options.
3. Choose OK.

See also
Develop the site design in SharePoint
Overview of Design Manager in SharePoint
What's new with SharePoint site development
Create a page layout in SharePoint
5/3/2018 • 12 minutes to read Edit Online

When you use Design Manager to create a page layout, two files are created: an .aspx file that SharePoint uses, and an HTML version of that page layout that you can edit in your HTML
editor. The HTML file and page layout are associated, so that whenever you edit and save the HTML file, your changes are synced to the associated page layout.

Introduction to page layouts


When you use Design Manager to create a page layout, two files are created: an .aspx file that SharePoint uses, and an HTML version of that page layout that you can edit in your HTML
editor. The HTML file and page layout are associated, so that whenever you edit and save the HTML file, your changes are synced to the associated page layout.
When you create a master page, you upload and convert an HTML file directly into a master page. But, unlike a master page, you do not directly convert an HTML file into a page layout. This
is because the primary purpose of a page layout is to contain page fields, and these page fields must get added when the page layout is created in Design Manager.
When you create a page layout:
An .aspx file and an HTML file with the same name are created in the Master Page Gallery.
All markup required by SharePoint is added to the .aspx file so that the page layout renders correctly.
Other markup such as comments,
tags, snippets, and content placeholders are added to the HTML file.
Page fields unique to the content type are added automatically to the page layout. Other page fields are available to be added from the ribbon in the Snippet Gallery.
The HTML file and the .aspx file are associated, so that any later edits to the HTML file are synced to the .aspx file whenever the HTML file is saved. Other markup such as comments,
tags, snippets, and content placeholders are added to the HTML file.
NOTE

The syncing goes in one direction only. Changes to the HTML page layout are synced to the associated .aspx file, but if you choose to edit the .aspx file directly, those changes are not synced
to the HTML file. Every HTML page layout (and every HTML master page) has a property named Associated File that is set to True by default, which creates the association and syncing
between files.
For example, if you have a pair of associated files (HTML and .aspx) and you edit the .aspx file without breaking the association,the .aspx file changesare saved, but you can't check in or
publish the .aspx file, so those changes are not saved in a meaningful way. Any changes to the HTML file override the .aspx file. If you check in or publish the HTML file, the HTML file
changes override any changes that were made to the .aspx file. The .aspx file changes are lost.
If you're a developer comfortable working with ASP.NET, you can choose to work only with the .aspx file by breaking the association between the files. To break the association between the
HTML file and .aspx file, in Design Manager, choose Edit Properties for the HTML file, and then clear the Associated File check box. You can later re-associate the files by editing the
properties and selecting this check box, in which case changes saved in the HTML file will again overwrite the .aspx file.

Understanding the relationship between page fields and a content type


Every page layout is associated with a content type, typically one of the content types in the Page Layout group. For example, the Article Page content type that is associated with the Article
Page page layout, both of which are included in a publishing site.
A content type is made of site columns, which together define a schema of allowed data types. You can tell that site columns are unique to the current content type because the Source
column is blank—this means that these site columns are defined by the current content type, and are not inherited from a parent content type.
For any given page layout, the site columns that make up the content type correspond directly to the page fields that are available for that page layout. The first group of page fields on the
ribbon is page fields that get automatically added to the page layout when you create it. SharePoint adds these fields automatically because they're unique to this content type, and so it's
likely that these fields were created specifically to be used by the page layout, as opposed to being general SharePoint metadata.
Before you create a page layout in Design Manager, you may first have to create a content type that defines the page fields that you want for that page layout

Understanding the relationship between content placeholders on a page layout and master page
A page layout and a master page must have the identical set of content placeholders for the page layout to render correctly. This is not a problem if you use Design Manager to create master
pages and page layouts, because the correct set of content placeholders is added to every file when you create it. This ensures that every page layout works across every channel that uses a
different master page. You don't have to know about or work with most of these content placeholders. They exist because they're required by SharePoint to render the page correctly.
But, if you edit an HTML page layout and manually add a content placeholder, you should add that same content placeholder to every master page that needs to work with that page layout.
This is not a common scenario.
If you're using Design Manager to create page layouts and master pages, the most common scenario is that you're working with only the following content placeholders:
PlaceHolderMain The master page contains a content placeholder with ID="PlaceholderMain" , which contains the DefaultContentBlock
tag with the yellow box that shows This area will be filled in by content you create in your page layouts. You should not put any content inside this placeholder on the master page.
The page layout contains a content placeholder with the same ID. You should put markup only inside this placeholder, and put no markup outside this placeholder, on a page layout. The
IDs for the two placeholders ( PlaceholderMain) should match.
PlaceHolderAdditionalPageHead When you work with a page layout, you typically don't insert elements into the tag of the page layout. Instead, you add elements to the content
placeholder with id="PlaceHolderAdditionalPageHead" . When a content page is rendered in the browser, this additional page head gets merged into the end of the head of the master
page.

Create a page layout


Before you begin, you need to know which content type and master page the page layout will be associated with.

To create a page layout


1. Browse to your publishing site.
2. In the upper-right corner of the page, choose the gear icon, and then choose Design Manager.
Gear icon menu
1. In Design Manager, in the left navigation pane, choose Edit Page Layouts.
2. Choose Create a page layout.
3. In the Create a Page Layout dialog box, enter a name for your page layout.
4. Select a master page.
The master page that you choose here will be shown in the preview for this page layout. This master page also determines what content placeholders get added to the page layout.
NOTE

After you choose this master page, you cannot preview the page layout with a different master page, even after you apply a different master page to the live site.
5. Select a content type. The content type for this page layout determines what page fields will be available for this page layout in the Snippet Gallery.
6. Choose OK.
At this point, SharePoint creates an HTML file and an .aspx file with the same name.
In Design Manager, your HTML file now appears with a Status column that shows one of two possible statuses:
Warnings and Errors
Conversion successful
1. Click the link in the Status column to preview the file and to view any errors or warnings about the master page.
The preview page is a live server-side preview of your page layout. The top of the preview displays any warnings or errors that you may have to resolve by editing the HTML file in an
HTML editor. Errors must be fixed before the preview will display the page layout correctly.
For more information about resolving errors and warnings, see How to: Resolve errors and warnings when previewing a page in SharePoint.
For more information about previewing the page layout, see How to: Change the preview page in SharePoint Design Manager.
The preview page also contains a Snippets link in the upper-right corner. This link opens the Snippet Gallery, where you can begin replacing mockup controls in your design with
dynamic SharePoint controls. For more information, see SharePoint Design Manager snippets.
2. To fix any errors, edit the HTML file that resides directly on the server by using an HTML editor to open and edit the HTML file in the mapped drive. Each time you save the HTML file,
any changes are synced to the associated .aspx file.
3. The preview of the page layout shows the page fields that were added automatically to the page layout. These page fields are site columns that are unique to the current content type.
Now you are ready to style the page layout according to your original HTML mockups.

Determine where the styles for a page layout should go


When you create HTML mockups for your site, you may have HTML files that represent different classes of pages, such as an article page or an item details page that contains a web part to
display the details of a single item from a catalog. After you create the page layout that represents that class of pages, you're ready to transfer the styles from your HTML mockup to the
HTML version of your page layout.
You can simply put the styles for one or more page layouts into the same style sheet that the master page links to. But, if you want to minimize the weight of the CSS that is loaded per page,
you can also use different style sheets for different page layouts. When you do this, it's important to know that a link to a style sheet cannot go in the tag of a page layout. Instead, the link
must go in the content placeholder named PlaceHolderAdditionalPageHead.
NOTE

In this markup, the attribute ms-design-css-conversion="no" excludes the style sheet from theming. Also, the link to the style sheet should appear after the lines commented <!--SPM.

<!--MS:<asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead" runat="server">-->


<!--SPM:<%@Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e94
<!--SPM:<%@Register Tagprefix="Publishing" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, Public
<link href="MyPageLayout.css" rel="stylesheet" type="text/css" ms-design-css-conversion="no" />
<!--ME:</asp:ContentPlaceHolder>-->

When a site visitor browses a page that uses this page layout, this additional page head gets merged into the end of the head of the master page—so, styles for the page layout are applied
after styles for the master page.
In this way, each page layout can have its own style sheet. For example, you can have a
with id="xyz" in one page layout that appears on the left, and in another page layout appears on the right.
Each page layout can also have one or more device channel-specific style sheets. For example, you might want a page layout to have a layout for phones that is different from the desktop
layout. To do this, you can include one or more device channel panels inside PlaceHolderAdditionalPageHead, where each channel panel includes a link to a style sheet with channel-
specific styles. This way, for example, a
with id="abc" can display large text in one channel and small text in a different channel.
The following are some common scenarios for where to put the style sheet links for page layouts.

Link to styles from a master page


The simplest scenario is to include styles for one or more page layouts in the same style sheet that the master page links to. In the master page, place the link to the .css file just before the
closing tag, so that it overrides the default SharePoint style sheets such as corev15.css.

<head>

<link rel="stylesheet" type="text/css" href="MyStyleSheet.css" />
</head>

Link to styles from a page layout


If you want to minimize the weight of CSS that gets loaded with each page, you can have separate CSS files for each page layout. In this scenario, the styles for a page layout go in the
content placeholder named PlaceHolderAdditionalPageHead.

<!--MS:<asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead" runat="server">-->


<!--SPM:<%@Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e94
<!--SPM:<%@Register Tagprefix="Publishing" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, Public
<link href="MyPageLayout.css" rel="stylesheet" type="text/css" ms-design-css-conversion="no" />
<!--ME:</asp:ContentPlaceHolder>-->

Link to styles in the page layout per device channel


If you have different device channels, you likely want your page layouts to render differently for different channels. In this scenario, you include one or more device channel panels inside
PlaceHolderAdditionalPageHead, and then include a link to channel-specific CSS files inside each channel panel.

<!--MS:<asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead" runat="server">-->


<div data-name="DeviceChannelPanel">
<!--CS: Start Device Channel Panel Snippet-->
<!--SPM:<%@Register Tagprefix="Publishing" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken
<!--MS:<Publishing:DeviceChannelPanel runat="server" IncludedChannels="Channel1">-->
…..
<link rel="stylesheet" type="text/css" href="MyStyleSheet.css" ms-design-css-conversion="no" />
<!--ME:</Publishing:DeviceChannelPanel>-->
<!--CE: End Device Channel Panel Snippet-->
</div><div data-name="DeviceChannelPanel">
<!--CS: Start Device Channel Panel Snippet-->
<!--SPM:<%@Register Tagprefix="Publishing" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken
<!--MS:<Publishing:DeviceChannelPanel runat="server" IncludedChannels="Channel2">-->
…..
<link rel="stylesheet" type="text/css" href="CSS5.css" />
<!--ME:</Publishing:DeviceChannelPanel>-->
<!--CE: End Device Channel Panel Snippet-->
</div>

Understanding the markup in the HTML page layout


When you create a page layout, an .aspx file gets created that SharePoint uses, and some HTML markup gets added to the HTML version of the page layout. When you edit the HTML page
layout in your HTML editor, it might be helpful to understand the purpose of some of this markup. Most of it is similar to the markup that gets added to an HTML master page. For more
information, see How to: Convert an HTML file into a master page in SharePoint.
The markup that is unique to page layouts is page fields that are added to the page layout based on the content type that the page layout is associated with. Page fields appear inside the
content placeholder with id="PlaceHolderMain" . For example, the following markup for PlaceHolderMain contains two page fields that represent the Title and Page Image fields from the
associated content type.

<!--MS:<asp:ContentPlaceHolder ID="PlaceHolderMain" runat="server">-->


<div>
<!--CS: Start Page Field: Title Snippet-->
<!--SPM:<%@Register Tagprefix="PageFieldTextField" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=7
<!--SPM:<%@Register Tagprefix="Publishing" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, Pu
<!--MS:<Publishing:EditModePanel runat="server" CssClass="edit-mode-panel">-->
<!--MS:<PageFieldTextField:TextField FieldName="fa564e0f-0c70-4ab9-b863-0177e6ddd247" runat="server">-->
<!--ME:</PageFieldTextField:TextField>-->
<!--ME:</Publishing:EditModePanel>-->
<!--CE: End Page Field: Title Snippet-->
</div>
<div>
<!--CS: Start Page Field: Page Image Snippet-->
<!--SPM:<%@Register Tagprefix="PageFieldRichImageField" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Cultur
<!--MS:<PageFieldRichImageField:RichImageField FieldName="3de94b06-4120-41a5-b907-88773e493458" runat="server">-->
<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><div id="ctl02_label" style="display:none">Page Image</div><div id="ctl02__ControlWrapper_RichImageField" class="ms-rtesta
<!--ME:</PageFieldRichImageField:RichImageField>-->
<!--CE: End Page Field: Page Image Snippet-->
</div>
<!--ME:</asp:ContentPlaceHolder>-->

See also
Overview of Design Manager in SharePoint
How to: Convert an HTML file into a master page in SharePoint
SharePoint Design Manager snippets
Customize page layouts for a catalog-based site in SharePoint
5/3/2018 • 19 minutes to read Edit Online

Learn how to create and customize category page and catalog-item page layouts for a SharePoint cross-site publishing site.

Prerequisites for creating and customizing page layouts for a catalog-based site
To follow the steps in this example, you must have the following:
An HTML editor
A SharePoint cross-site publishing environment
For information about how to set up a SharePoint cross-site publishing environment, see Configure cross-site publishing in SharePoint.

Core concepts to know for creating and customizing page layouts for a catalog-based site
Table 1 lists useful articles that can help you understand the concepts and steps that are involved in creating and customizing page layouts for a catalog-based site.
Table 1. Core concepts for creating and customizing page layouts for a catalog-based site

AR TICLE TITLE D ES CR IPTIO N

Overview of cross-site publishing in SharePoint Learn about how to use cross-site publishing and Search web parts to create adaptive SharePoint
Internet, intranet, and extranet sites.

How to: Create a page layout in SharePoint Learn about how to create page layouts in SharePoint.

How to: Resolve errors and warnings when previewing a page in SharePoint Learn about how to resolve any issues that prevent the server-side preview from rendering your page.

SharePoint Design Manager snippets Learn about how to use snippets to add SharePoint functionality to your HTML master page or page
layout.

Introduction to category page layouts and catalog item page layouts


Category pages and catalog item pages are page layouts that you can use to show structured catalog content consistently across a site. By default, SharePoint can automatically create one
category page layout and one catalog item page layout per catalog connection. Pages based on these layouts are created in the Pages library of a publishing site when you connect the site to
a catalog. For more information about page layouts, see How to: Create a page layout in SharePoint. For more information about features that are specific to category page layouts and
catalog item page layouts, see Overview of cross-site publishing in SharePoint.
By default, category page layouts and catalog item page layouts are created automatically when you connect a publishing site to a catalog. You can also use Design Manager to create
category page layouts and catalog item page layouts that you can select when you connect a publishing site to a catalog, or when you configure the navigation term set on a publishing site.

Create a category page layout


Before you can create or customize a category page layout, we recommend that you create a mapped network drive that points to the Master Page Gallery. For more information, see How
to: Map a network drive to the SharePoint Master Page Gallery.
The simplest way to create a category page layout is to let SharePoint create the page layout automatically when you connect the publishing site to a catalog, and then customize the existing
category page layout to change the markup as required by the page design. Alternatively, you can create a new category page layout from scratch by using Design Manager.

To customize an existing category page layout that was created automatically by SharePoint
1. Using Windows Explorer, open the mapped network drive to the Master Page Gallery.
2. To customize a category page layout, edit the HTML file that resides directly on the server by using an HTML editor to open and edit the HTML file in the mapped drive. Each time that
you save the HTML file, any changes are synched to the associated .aspx file.
3. Replace the markup inside the content placeholder that has id="PlaceHolderMain" with the markup that you want to use in the page layout.

Important: You must keep the Content Search Snippet markup so that the category page can display search results.

4. To configure and copy the HTML for any snippets you want to add to the page, follow step 1 through step 11 in the "Insert a snippet from the Snippet Gallery" section of SharePoint
Design Manager snippets.
5. Make any other required changes to the markup, and then save the file.
6. Follow step 9 through step 11 in the "Create a page layout" section of How to: Create a page layout in SharePoint to check the status of the file, preview the page layout, and fix any
errors.

To create a category page layout by using Design Manager


1. Follow step 1 through step 6 in the "Create a page layout" section of How to: Create a page layout in SharePoint.
2. In step 7, choose the Article Page content type.
3. Choose OK.
At this point, SharePoint creates an HTML file and an .aspx file that has the same name.
In Design Manager, your HTML file now appears with a Status column that shows one of two statuses:
Warnings and Errors
Conversion successful
1. Using Windows Explorer, open the mapped network drive to the Master Page Gallery.
2. To customize the category page layout, edit the HTML file that resides directly on the server by using an HTML editor to open and edit the HTML file in the mapped drive. Each time
that you save the HTML file, any changes are synched to the associated .aspx file.
3. In the <head> tag, replace the content placeholder that has id="PlaceHolderPageTitle" with:

<!--MS:<asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server">-->


<!--CS: Start Taxonomy TermProperty Snippet-->
<!--SPM:<%@Register Tagprefix="Taxonomy" Namespace="Microsoft.SharePoint.Taxonomy" Assembly="Microsoft.SharePoint.Taxonomy, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<!--MS:<Taxonomy:TermProperty Property="Name" runat="server">-->
<!--ME:</Taxonomy:TermProperty>-->
<!--ME:</asp:ContentPlaceHolder>-->

1. Find the content placeholder that has the id="PlaceHolderPageTitleInTitleArea" and replace it with:

<!--MS:<asp:ContentPlaceHolder id="PlaceHolderPageTitleInTitleArea" runat="server">-->


<!--SPM:<asp:SiteMapPath runat="server" ParentLevelsDisplayed="1" SiteMapProvider="CurrentNavigationSwitchableProvider"/>-->
<!--ME:</asp:ContentPlaceHolder>-->

1. Replace the markup inside the content placeholder that has id="PlaceHolderMain" with the markup that you want to use in the page layout.
2. To configure and copy the HTML for the Content Search Snippet and any other snippets you want to add to the page, follow step 1 through step 11 in the "Insert a snippet from the
Snippet Gallery" section of SharePoint Design Manager snippets.
NOTE

When you add the Content Search Snippet to the page layout, be sure to change the query to use the result source that was created when you connected the publishing site to a
catalog. For more information, see Configure result sources for web content management in SharePoint.
3. Make any other required changes to the markup, and then save the file.
4. Follow step 9 through step 11 in the "Create a page layout" section of How to: Create a page layout in SharePoint to check the status of the file, preview the page layout, and fix any
errors.

Understanding the markup in the HTML category page layout


When you create a page layout, an .aspx file is created that SharePoint uses, and some HTML markup is added to the HTML version of the page layout. Category page layouts have markup
components that are added to the page layout based on the Cross-Site Collection Publishing feature, and that are unique to category page layouts. When you edit the HTML category page
layout in your HTML editor, it might be helpful to understand some of this markup.

Browser window page title


The component that appears inside the content placeholder with id="PlaceHolderPageTitle" contains markup that tells SharePoint to use a term property as the page title in the browser
window, instead of using the standard page field value. The following code shows the markup for the browser window page title.

<!--CS: Start Taxonomy TermProperty Snippet-->


<!--SPM:<%@Register Tagprefix="Taxonomy" Namespace="Microsoft.SharePoint.Taxonomy" Assembly="Microsoft.SharePoint.Taxonomy, Version=15.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" %>-->
<!--MS:<Taxonomy:TermProperty Property="Name" runat="server">-->
<!--ME:</Taxonomy:TermProperty>-->

Page title
The component that appears inside the content placeholder with id="PlaceHolderPageTitleInTitleArea" contains markup that tells SharePoint to use a term property as the page title on
the page, instead of using the SPTitleBreadcrumb snippet and the standard page title field value. The following code shows the markup for the page title.

<!--SPM:<asp:SiteMapPath runat="server" ParentLevelsDisplayed="1" SiteMapProvider="CurrentNavigationSwitchableProvider"/>-->"

Content Search Snippet


The components that appear after the page content snippet, inside the content placeholder with id="PlaceHolderMain", contain markup for a web part Zone Snippet that contains four
web part zones. The first web part zone contains a Content Search Snippet that displays a Content Search web part on the page. This snippet also contains information that helps the
Content Search web part query a result source and show the results on the page. The last three web part zones are empty. If you choose to create your own category page layout, you must
include the markup for the Content Search Snippet in the HTML file for your page layout. The following code shows the markup for the Content Search snippet. Replace ResultSourceID with
the GUID of the result source, and replace CatalogURL with the URL of the catalog.
NOTE

The GUIDs for ID and __WebPartId are randomly generated by SharePoint when the snippets are added to the page layout.
<!--
CS: Start Content Search Snippet-->
<!--SPM:<%@Register Tagprefix="a781102493" Namespace="Microsoft.Office.Server.Search.WebControls" Assembly="Microsoft.Office.Server.Search, Version=15.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c"%>-->
<!--MS:<a781102493:ContentBySearchWebPart runat="server" DataProviderJSON="{&amp;#34;QueryTemplate&amp;#34;:&amp;#34;&amp;#34;,&amp;#34;SourceID&amp;#34;
:&amp;#34;ResultSourceID&amp;#34;,&amp;#34;PropertiesJson&amp;#34;:&amp;#34;
{'Tag':'{Term.IDWithChildren}','Scope':'CatalogURL'}&amp;#34;}" ResultsPerPage="3" RenderTemplateId="~sitecollection/_catalogs/masterpage/Display Templates/Content Web Parts/Control_ListWithPagin
ItemTemplateId="~sitecollection/_catalogs/masterpage/Display Templates/Content Web Parts/Item_PictureOnTop.js" SelectedPropertiesJson="[&amp;#34;WorkId&amp;#34;,&amp;#34;Rank&amp;#34;,&amp;#34;Ti
Size&amp;#34;,&amp;#34;Path&amp;#34;,&amp;#34;Description&amp;#34;,&amp;#34;Write&amp;#34;,&amp;#34;CollapsingStatus&amp;#34;,&amp;#34;
HitHighlightedSummary&amp;#34;,&amp;#34;HitHighlightedProperties&amp;#34;,&amp;#34;ContentClass&amp;#34;,&amp;#34;
PictureThumbnailURL&amp;#34;,&amp;#34;ServerRedirectedURL&amp;#34;,&amp;#34;ServerRedirectedEmbedURL&amp;#34;,&amp;#34;
ServerRedirectedPreviewURL&amp;#34;,&amp;#34;FileExtension&amp;#34;,&amp;#34;ContentTypeId&amp;#34;,&amp;#34;ParentLink&amp;#34;,&amp;#34;
ViewsLifeTime&amp;#34;,&amp;#34;ViewsRecent&amp;#34;,&amp;#34;SectionNames&amp;#34;,&amp;#34;SectionIndexes&amp;#34;,&amp;#34;
SiteLogo&amp;#34;,&amp;#34;SiteDescription&amp;#34;,&amp;#34;deeplinks&amp;#34;,&amp;#34;importance&amp;#34;]" ShouldHideControlWhenEmpty="True" FrameType="None" SuppressWebPartChrome="False" Des
ZoneID="" PartOrder="0" FrameState="Normal" AllowRemove="True" AllowZoneChange="True"
AllowMinimize="True" AllowConnect="True" AllowEdit="True" AllowHide="True" IsVisible="True"
DetailLink="" HelpLink="" HelpMode="Modeless" Dir="Default" PartImageSmall="" IsIncludedFilter="" ExportControlledProperties="True" ConnectionID="00000000-0000-0000-0000-000000000000" ID="g_54e35
WebPart="true" Height="" Width="" Title="$Resources:cms,WebPartZoneTitle_Dynamic;">-->
<!--ME:</a781102493:ContentBySearchWebPart>-->
<!--CE: End Content Search Snippet-->

Create a catalog item page layout


Before you can create or customize a catalog item page layout, we recommend that you create a mapped network drive that points to the Master Page Gallery. For more information, see
How to: Map a network drive to the SharePoint Master Page Gallery.
As with the category page layout, the simplest way to create a catalog item page layout is to let SharePoint create the page layout automatically when you connect the publishing site to a
catalog, and then customize the existing catalog item page layout to add any additional markup required by the page design. Alternatively, you can create a catalog item page layout from
scratch by using Design Manager.

To customize an existing catalog item page layout that was created automatically by SharePoint
1. Using Windows Explorer, open the mapped network drive to the Master Page Gallery.
2. To customize a catalog item page layout, edit the HTML file that resides directly on the server by using an HTML editor to open and edit the HTML file in the mapped drive. Each time
that you save the HTML file, any changes are synched to the associated .aspx file.
3. Inside the content placeholder that has id="PlaceHolderMain", add the markup that you want to use in the page layout.
4. Delete any snippets that you do not want to use in the page layout, and move the remaining snippets to places in the markup where you want the property values to appear.

Caution: By default, a web part Zone Snippet that contains a Catalog-Item Reuse Snippet is added to the page layout. This snippet contains the data provider that returns query
results that are used by all other snippets on the page. We recommend that you keep the Catalog-Item Reuse Snippet in this default web part Zone Snippet. (You can move the
Catalog-Item Reuse Snippet outside the web part Zone, and you can change the property that it displays. But, you must keep the Catalog-Item Reuse Snippet in the page layout.)
For more information, see Page fields, later in this article.

5. To configure and copy the HTML snippet for any snippets you want to use in the page, follow step 1 through step 11 in the "Insert a snippet from the Snippet Gallery" section of
SharePoint Design Manager snippets.
6. Make any other required changes to the markup, and then save the file.
7. Follow step 9 through step 11 in the "Create a page layout" section of How to: Create a page layout in SharePoint to check the status of the file, preview the page layout, and fix any
errors.

To create a catalog item page layout by using Design Manager


1. Follow step 1 through step 6 in the "Create a page layout" section of How to: Create a page layout in SharePoint.
2. In step 7, choose Remote Catalog, and then choose the catalog that contains the data to appear on the page.
3. Choose OK.
At this point, SharePoint creates an HTML file and an .aspx file that has the same name.
In Design Manager, your HTML file now appears with a Status column that shows one of two statuses:
Warnings and Errors
Conversion successful
1. Using Windows Explorer, open the mapped network drive to the Master Page Gallery.
2. To customize the catalog item page layout, edit the HTML file that resides directly on the server by using an HTML editor to open and edit the HTML file in the mapped drive. Each
time that you save the HTML file, any changes are synched to the associated .aspx file.
3. Inside the content placeholder that has id="PlaceHolderMain", add the markup that you want to use in the page layout.
4. Delete any snippets that you do not want to use in the page layout, and move the remaining snippets to places in the markup where you want the property values to appear.

Caution: By default, a web part Zone Snippet that contains a Catalog-Item Reuse Snippet is added to the page layout. This snippet contains the data provider that returns query
results that are used by all other snippets on the page. We recommend that you keep the Catalog-Item Reuse Snippet in this default web part Zone Snippet. (You can move the
Catalog-Item Reuse Snippet outside the web part Zone, and you can change the property that it displays. But, you must keep the Catalog-Item Reuse Snippet in the page layout.)
For more information, see Page fields, later in this article.

5. To configure and copy the HTML snippet for any snippets you want to use in the page, follow step 1 through step 11 in the "Insert a snippet from the Snippet Gallery" section of
SharePoint Design Manager snippets.
6. Make any other required changes to the markup, and then save the file.
7. Follow step 9 through step 11 in the "Create a page layout" section of How to: Create a page layout in SharePoint to check the status of the file, preview the page layout, and fix any
errors.
Understanding the markup in the HTML catalog item page layout
When you create a page layout, an .aspx file is created that SharePoint uses, and some HTML markup is added to the HTML version of the page layout. Catalog item page layouts have
markup components that are added to the page layout based on the Cross-Site Collection Publishing feature, and that are unique to catalog item page layouts. When you edit the HTML
catalog item page layout in your HTML editor, it might be helpful to understand some of this markup.

Browser window page title


The component that appears inside the content placeholder with id="PlaceHolderPageTitle" contains a Catalog-Item Reuse Snippet that tells SharePoint to use the name of the catalog
item as the page title in the browser window, instead of using the standard page title field value. The following code shows the markup for the browser window page title.
NOTE

The GUIDs for ID and __WebPartId are randomly generated by SharePoint when the snippets are added to the page layout.

<!--CS: [Title] Start Catalog-Item Reuse Snippet-->


<!--SPM:<cc1:CatalogItemReuseWebPart runat="server" UseServerSideRenderFormat="True" ResultType="" NumberOfItems="1" UseSharedDataProvider="True" OverwriteResultPath="False" ResultsPerPage="1" S
Title="$Resources:Microsoft.Office.Server.Search,CBSItem_Title;" Description="$Resources:Microsoft.Office.Server.Search,CBSItem_Description;"
MissingAssembly="Cannot import this web part." ID="g_863912c1_c849_46dc_8781_2920ee2bc83f" __WebPartId="{863912c1-c849-46dc-8781-2920ee2bc83f}">-->
<!--SPM:<RenderFormat>-->
<!--DC:Renders value from search without any additional formatting.-->
<!--SPM:</RenderFormat>-->
<!--SPM:</cc1:CatalogItemReuseWebPart>-->
<!--CE:End Catalog-Item Reuse Snippet-->

Page fields
The components that appear inside the content placeholder with id="PlaceHolderMain" contain snippets for the Title, Page Content, and Catalog-Item URL fields. You may delete any
of these snippets from the page layout. The following code shows the markup for these page fields.

<div>
<!--CS: Start Page Field: Title Snippet-->
<!--SPM:<%@Register Tagprefix="PageFieldTextField" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint,
Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>-->
<!--SPM:<%@Register Tagprefix="Publishing" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken
<!--MS:<Publishing:EditModePanel runat="server" CssClass="edit-mode-panel">-->
<!--MS:<PageFieldTextField:TextField FieldName="fa564e0f-0c70-4ab9-b863-0177e6ddd247"
runat="server">-->
<!--ME:</PageFieldTextField:TextField>-->
<!--ME:</Publishing:EditModePanel>-->
<!--CE: End Page Field: Title Snippet-->
</div>
<div>
<!--CS: Start Page Field: Page Content Snippet-->
<!--SPM:<%@Register Tagprefix="PageFieldRichHtmlField" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, Pu
<!--MS:<PageFieldRichHtmlField:RichHtmlField FieldName="f55c4d88-1f2e-4ad9-aaa8-819af4ee7ee8" runat="server">-->
<!--PS: Start of READ-ONLY PREVIEW (do not modify)-->
<div id="ctl02_label" style="display:none">Page Content</div>
<div id="ctl02__ControlWrapper_RichHtmlField" class="ms-rtestate-field" style="display:inline" aria-labelledby="ctl02_label">
<div align="left" class="ms-formfieldcontainer">
<div class="ms-formfieldlabelcontainer" nowrap="nowrap">
<span class="ms-formfieldlabel" nowrap="nowrap">Page Content</span>
</div>
<div class="ms-formfieldvaluecontainer">
<div class="ms-rtestate-field">Page Content field value. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore mag
</div>
</div>
</div>
<!--PE: End of READ-ONLY PREVIEW-->
<!--ME:</PageFieldRichHtmlField:RichHtmlField>-->
<!--CE: End Page Field: Page Content Snippet-->
</div>
<div>
<!--CS: Start Page Field: Catalog-Item URL Snippet-->
<!--SPM:<%@Register Tagprefix="PageFieldCatalogSourceFieldControl" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture
<!--MS:<PageFieldCatalogSourceFieldControl:CatalogSourceFieldControl FieldName="75772bbf-0c25-4710-b52c-7b78344ad136" runat="server">-->
<!--PS: Start of READ-ONLY PREVIEW (do not modify)-->
<div align="left" class="ms-formfieldcontainer">
<div class="ms-formfieldlabelcontainer" nowrap="nowrap">
<span class="ms-formfieldlabel" nowrap="nowrap">Catalog-Item URL</span>
</div>
<div class="ms-formfieldvaluecontainer">
<a href="http://www.example.com">Link to sample web site.</a>
</div>
</div>
<!--PE: End of READ-ONLY PREVIEW-->
<!--ME:</PageFieldCatalogSourceFieldControl:CatalogSourceFieldControl>-->
<!--CE: End Page Field: Catalog-Item URL Snippet-->
</div>

If the catalog item page layout was created automatically when the publishing site was connected to a catalog, or was created by selecting a remote catalog during page layout creation, the
page layout also contains a web part Zone Snippet that contains a Catalog-Item Reuse Snippet that registers a data provider for the page. The Catalog-Item Reuse Snippet contains a
UseSharedDataProvider property, which is set to False. The web part Zone Snippet can be deleted from the page layout. But, the Catalog-Item Reuse Snippet must be kept in the page
layout markup for the page to display catalog items. When you create a page that uses this page layout, you can configure the web part so that it is hidden when a user views the page.

Important: If you create a new catalog item page layout, and you choose a content type instead of a remote catalog, you must include a Catalog-Item Reuse Snippet in the page layout.
The following code shows the markup for the Catalog-Item Reuse Snippet as it appears inside the web part Zone Snippet. Replace ManagedPropertyName with the name of the
managed property to display, replace ResultSourceID with the GUID of the result source, and replace CatalogURL with the URL of the catalog.
<div>
<!--CS: Start web part Zone Snippet-->
<!--SPM:<%@Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint,
Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>-->
<!--SPM:<%@Register Tagprefix="cc1" Namespace="Microsoft.Office.Server.Search.WebControls" Assembly="Microsoft.Office.Server.Search, Version=15.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" %>-->
<!--MS:<WebPartPages:WebPartZone runat="server" Title="&amp;#60;%$Resources:cms,WebPartZoneTitle_Body%&amp;#62;" AllowPersonalization="False" FrameType="TitleBarOnly" ID="Body" Orientation="V
<!--MS:<ZoneTemplate>-->
<!--CS: [ManagedPropertyName] Start Catalog-Item Reuse Snippet-->
<!--DC:To render the search property using a rendering template, change the "UseServerSideRenderFormat" property to "False".-->
<!--SPM:<cc1:CatalogItemReuseWebPart runat="server" UseServerSideRenderFormat="True"
ResultType="" NumberOfItems="1" AddSEOPropertiesFromSearch="True" LogAnalyticsViewEvent="True" UseSharedDataProvider="False" OverwriteResultPath="False" DataProviderJSON="{&amp;#34;QueryTemplate&
<!--SPM:<RenderFormat>-->
<!--DC:Renders value from search without any additional formatting.-->
<!--SPM:</RenderFormat>-->
<!--SPM:</cc1:CatalogItemReuseWebPart>-->
<!--ME:</ZoneTemplate>-->
<!--ME:</WebPartPages:WebPartZone>-->
<!--CE:End Catalog-Item Reuse Snippet-->
</div>

If the catalog item page layout was created automatically when the publishing site was connected to a catalog, or was created by selecting a remote catalog during page layout creation, the
rest of the page contains Catalog-Item Reuse Snippets that correspond to managed properties from the catalog on the authoring site. These managed properties display the details for the
specific catalog item that is displayed by using the catalog item page layout. These Catalog-Item Reuse Snippets appear outside the web part zone, and are rendered directly on the page
when an item is chosen on a category page. Table 2 lists the managed properties that are automatically included in the catalog item page layout.
NOTE

Some managed properties are included only if the catalog is a Pages library. The Used by column in Table 2 indicates which managed properties are used by both a Pages library and a list,
and which from a Pages library only.
Table 2. Default managed properties Catalog-Item Reuse Snippets

MANAG ED PR O PER T Y D ES CR IPTIO N U S ED B Y

AuthorOWSUSER The name of the user who created the page. Pages library only

CreatedOWSDATE The date the page or list item was created. Pages library and list

EditorOWSUSER The name of the user who last changed the page or list item. Pages library and list

ListItemID The ID for the page or list item. Pages library and list

ModifiedOWSDATE The date the page or list item was last changed. Pages library and list

PublishingContactOWSUSER Contact is a site column created by the Publishing feature. It is used Pages library only
on the Page Content Type as the person or group who is the
contact person for the page.

PublishingIsFurlPageOWSBOOL A Boolean value that indicates whether the page is associated with a Pages library only
friendly URL.

PublishingPageContentOWSHTML The HTML content of the page. Pages library only

PublishingPageLayoutOWSURLH The URL to the page layout that was used to create the page. Pages library only

Title The title of the page or list item. Pages library and list

The managed properties for custom columns that you add to the Pages library or list are also included in Catalog-Item Reuse Snippets. The managed property name will vary, based on the
site column type that you use when you create the site column. For more information, see Automatically created managed properties in SharePoint, and Overview of the search schema in
SharePoint.

Important: The Page Image site column in a Pages library is mapped to the PublishingImage managed property. But, the PublishingImage managed property is not automatically
included in the category-item page layout. To include the image in your page layout, you must add a Catalog-Item Reuse Snippet for the PublishingImage managed property. Use the
following HTML to add a Catalog-Item Reuse Snippet to display the value of the PublishingImage managed property in your page layout. Replace UniqueID with a GUID that is
unique to each instance of the snippet.

<div>
<!--CS: [PublishingImage] Start Catalog-Item Reuse Snippet-->
<!--SPM:<cc1:CatalogItemReuseWebPart runat="server" UseServerSideRenderFormat="True"
ResultType="" NumberOfItems="1" UseSharedDataProvider="True" OverwriteResultPath="False"
ResultsPerPage="1" SelectedPropertiesJson="[&amp;#34;PublishingImage&amp;#34;]"
Title="$Resources:Microsoft.Office.Server.Search,CBSItem_Title;"
Description="$Resources:Microsoft.Office.Server.Search,CBSItem_Description;"
MissingAssembly="Cannot import this web part." ID="g_UniqueID" __WebPartId="{UniqueID}">-->
<!--SPM:<RenderFormat>-->
<!--SPM:<Format Type="HTML"> -->
<!--SPM:<Picture>-->True<!--SPM:</Picture>-->
<!--SPM:</Format> -->
<!--SPM:</RenderFormat>-->
<!--SPM:</cc1:CatalogItemReuseWebPart>-->
<!--CE:End Catalog-Item Reuse Snippet-->
</div>

If you create a new catalog item page layout by using Design Manager, and you choose a content type instead of a remote catalog, you can add Catalog-Item Reuse Snippets to the page by
using the Snippet Gallery. The following code shows the markup for the Catalog-Item Reuse Snippets for the Title, PublishingPageContentOWSHTML, CreatedOWSDATE, and
owstaxIdPageCategory managed properties.
NOTE
The GUIDs for ID and __WebPartId are randomly generated by SharePoint when the snippets are added to the page layout.

<div>
<!--CS: [Title] Start Catalog-Item Reuse Snippet-->
<!--SPM:<cc1:CatalogItemReuseWebPart runat="server" UseServerSideRenderFormat="True"
ResultType="" NumberOfItems="1" UseSharedDataProvider="True" OverwriteResultPath="False"
ResultsPerPage="1" SelectedPropertiesJson="[&amp;#34;Title&amp;#34;]"
Title="$Resources:Microsoft.Office.Server.Search,CBSItem_Title;"
Description="$Resources:Microsoft.Office.Server.Search,CBSItem_Description;"
MissingAssembly="Cannot import this web part." ID="g_0dc23bb8_8d34_4f9f_8085_5a6ac286cb9e"
__WebPartId="{0dc23bb8-8d34-4f9f-8085-5a6ac286cb9e}">-->
<!--SPM:<RenderFormat>-->
<!--DC:Renders value from search without any additional formatting.-->
<!--SPM:</RenderFormat>-->
<!--SPM:</cc1:CatalogItemReuseWebPart>-->
<!--CE:End Catalog-Item Reuse Snippet-->
</div>
<div>
<!--CS: [PublishingPageContentOWSHTML] Start Catalog-Item Reuse Snippet-->
<!--SPM:<cc1:CatalogItemReuseWebPart runat="server" UseServerSideRenderFormat="True"
ResultType="" NumberOfItems="1" UseSharedDataProvider="True" OverwriteResultPath="False"
ResultsPerPage="1" SelectedPropertiesJson="[&amp;#34;PublishingPageContentOWSHTML&amp;#34;]"
Title="$Resources:Microsoft.Office.Server.Search,CBSItem_Title;"
Description="$Resources:Microsoft.Office.Server.Search,CBSItem_Description;"
MissingAssembly="Cannot import this web part." ID="g_25253a49_a9a6_4277_bf9d_416961024cee"
__WebPartId="{25253a49-a9a6-4277-bf9d-416961024cee}">-->
<!--SPM:<RenderFormat>-->
<!--DC:Renders value from search without any additional formatting.-->
<!--SPM:</RenderFormat>-->
<!--SPM:</cc1:CatalogItemReuseWebPart>-->
<!--CE:End Catalog-Item Reuse Snippet-->
</div>
<div>
<!--CS: [CreatedOWSDATE] Start Catalog-Item Reuse Snippet-->
<!--SPM:<cc1:CatalogItemReuseWebPart runat="server" UseServerSideRenderFormat="True"
ResultType="" NumberOfItems="1" UseSharedDataProvider="True" OverwriteResultPath="False"
ResultsPerPage="1" SelectedPropertiesJson="[&amp;#34;CreatedOWSDATE&amp;#34;]"
Title="$Resources:Microsoft.Office.Server.Search,CBSItem_Title;"
Description="$Resources:Microsoft.Office.Server.Search,CBSItem_Description;"
MissingAssembly="Cannot import this web part."
ID="g_4e1f180b_12f8_4e50_84d7_c72b0ee3793f"
__WebPartId="{4e1f180b-12f8-4e50-84d7-c72b0ee3793f}">-->
<!--SPM:<RenderFormat>-->
<!--SPM:<Format Type="DateTime"> -->
<!--DC:To render Date and Time, change this value to False.-->
<!--SPM:<DateOnly>-->True<!--SPM:</DateOnly>-->
<!--SPM:</Format> -->
<!--SPM:</RenderFormat>-->
<!--SPM:</cc1:CatalogItemReuseWebPart>-->
<!--CE:End Catalog-Item Reuse Snippet-->
</div>
<div>
<!--CS: [owstaxIdPageCategory] Start Catalog-Item Reuse Snippet-->
<!--SPM:<cc1:CatalogItemReuseWebPart runat="server" UseServerSideRenderFormat="True"
ResultType="" NumberOfItems="1" UseSharedDataProvider="True" OverwriteResultPath="False"
ResultsPerPage="1" SelectedPropertiesJson="[&amp;#34;owstaxIdPageCategory&amp;#34;]"
Title="$Resources:Microsoft.Office.Server.Search,CBSItem_Title;"
Description="$Resources:Microsoft.Office.Server.Search,CBSItem_Description;"
MissingAssembly="Cannot import this web part." ID="g_22e39e9d_1b25_42c7_bf2a_7ebca37616d4"
__WebPartId="{22e39e9d-1b25-42c7-bf2a-7ebca37616d4}">-->
<!--SPM:<RenderFormat>-->
<!--DC:Renders value from search without any additional formatting.-->
<!--SPM:</RenderFormat>-->
<!--SPM:</cc1:CatalogItemReuseWebPart>-->
<!--CE:End Catalog-Item Reuse Snippet-->
</div>

See also
Develop the site design in SharePoint
Overview of Design Manager in SharePoint
Overview of the SharePoint page model
How to: Create a page layout in SharePoint
SharePoint Design Manager display templates
Apply styles to page fields in SharePoint
5/3/2018 • 10 minutes to read Edit Online

In a page layout, you can apply styles to a page field, and those styles are applied to any content added by content authors when they create a page from that page layout. Also, you have
further options to control how content in a RichHtmlField page field is styled.

Introduction to applying styles to page fields


As a designer, you have ultimate control over the positioning and styling of page fields on a page layout and on any pages created from that page layout. When content authors create pages
from a browser, they can't move page fields on the page or override the styles that you specify. This helps to ensure that your branding remains consistent through all pages in the site.
When you apply styles to page fields, there are two basic categories of field types to consider:
Field types other than RichHtmlField The page fields that make up a page layout conform to the content type for that page layout. A page field can be of many types, such as a
Single Line of Text (TextField) or Multiple Lines of Text (NoteField). As a designer, you can apply styles to all of these page fields in the same way, by applying styles to the page field
directly on the page layout.
RichHtmlField The rich HTML field control (also known as a Publishing HTML field) is one of the most powerful and frequently used controls in page layouts. By default, in a rich
HTML field, content authors use the ribbon to format and apply styles to content, and to insert tables, media such as images and video, and web parts. This field type is useful when
you want to give content authors the freedom to add and style content within parameters that you can control. You can control a RichHtmlField in two ways:
Create a custom style sheet By default, the styles available on the ribbon of a RichHtmlField come from a style sheet named HtmlEditorStyles.css. You can configure the
PrefixStyleSheet property for this snippet so that your own custom styles appear on the ribbon for content authors to use.
Configure the Allow properties A snippet for a RichHtmlField has 28 available properties that start with Allow, and you can use these properties to make specific
commands or groups of commands on the ribbon unavailable to content authors. For example, if you set the AllowFontsMenu property to False, authors cannot use the Font
menu on the ribbon to change what font is applied to text; instead, they can use only the CSS styles that you specify.
For all types of page fields, including the RichHtmlField, the designer determines how the content is styled. You can use the RichHtmlField to give content authors the freedom to insert rich
content and apply styles; you still have ultimate control over what content can be added and what styles can be applied.

Applying styles to page fields other than RichHtmlField


With a page field control, you can define the styles used by the content. Authors can add content to a page, but the designer controls how that content is rendered through CSS applied to
those controls.
In the HTML page layout, each page field is wrapped in a <div> tag. To apply a style to a page field, you can simply add a style to the <div>—for example, <div style="font-weight:bold" .
But the more common and useful scenario is that you add an id attribute to the <div> for each page field in the page layout, and then use the id as a selector for styles that reside in an
external style sheet. This way, if you have multiple device channels, and each channel has its own style sheet, you can apply different styles to each page field for each channel. For example,
the following page field of the type TextField (also called Multiple Lines of Text) might have only an id attribute on the <div> tag.

<div id="ShortSummaryPageField">
<!--CS: Start Page Field: ShortSummary Snippet-->
<!--SPM:<%@Register Tagprefix="PageFieldNoteField" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
<!--MS:<PageFieldNoteField:NoteField FieldName="a5249942-2dc5-4917-85e2-661d019ad548" runat="server">-->
<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><div align="left" class="ms-formfieldcontainer"><div class="ms-formfieldlabelcontainer" nowrap="nowrap"><span class="ms-formfieldlabel" nowrap
<!--ME:</PageFieldNoteField:NoteField>-->
<!--CE: End Page Field: ShortSummary Snippet-->
</div>

For more information about where styles and style references for a page layout should go, see How to: Create a page layout in SharePoint.

Disabling options on the ribbon of a RichHtmlField


When content authors create or edit a page and then add content to a RichHtmlField using a browser, they can use commands on the ribbon for that field to format, style, or insert rich
content and media.
In the Snippet Gallery, you can configure the properties of a page field of the type RichHtmlField, so that specific commands or groups of commands on the ribbon are made unavailable to
authors. For example, by setting the AllowFontSizesMenu property to False, you can disable the Font Size menu on the ribbon. By setting the AllowFonts property to False, you can
disable the entire Font group on the ribbon.
After you configure these properties in the Snippet Gallery and then update the snippet, the properties appear in the snippet markup inside the <!--MS:> comment.

<div data-name="Page Field: ArticleBody">


<!--CS: Start Page Field: ArticleBody Snippet-->
<!--SPM:<%@Register Tagprefix="PageFieldRichHtmlField" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, Public
<!--MS:<PageFieldRichHtmlField:RichHtmlField runat="server" AllowFonts="False" FieldName="db3168db-8778-4fb6-a48f-57f598497388">-->
<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><div id="ctl02_label" style="display:none">ArticleBody</div><div id="ctl02__ControlWrapper_RichHtmlField" class="ms-rtestate-field" style="dis
<!--PE: End of READ-ONLY PREVIEW-->
<!--ME:</PageFieldRichHtmlField:RichHtmlField>-->
<!--CE: End Page Field: ArticleBody Snippet-->
</div>

NOTE

If you set AllowFonts to False, content authors can still use keyboard shortcuts such as CTRL+B (strong) to format text. To prevent authors from adding any styles to text, you can set
AllowTextMarkup to False. With this setting, when content authors attempt to save content that contains styles applied to text, the HTML editor in the browser returns an error and
prompts the author to remove the markup that is not valid.
A RichHtmlField page field contains 28 different Allow properties. For more information about what specific properties control, see RichHtmlField properties For more information about
adding and configuring snippets, see SharePoint Design Manager snippets.

Controlling the styles available in a RichHtmlField


In a RichHtmlField, content authors can use options on the ribbon to format content. These formatting options are implemented by using CSS, and these styles are defined in a SharePoint
style sheet named HtmlEditorStyles.css that resides on the server at one of the following locations:
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPL ATE\L AYOUTS\1033\STYLES
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPL ATE\FEATURES\PublishingLayouts\en-us
Because the RichHtmlField in the browser uses CSS to implement its styles, you can create your own styles that are consistent with the branding of your site, and then you can make those
styles available on the ribbon for content authors to use. To make minor changes to the default styles, you can copy an existing style from HtmlEditorStyles.css to your style sheet that is
referenced by the page layout, and then modify that style by changing the CSS properties and values (but not the selector). You can also hide default styles from the ribbon by copying them
to your style sheet and then setting display:none .
To implement custom styles, you can also build a style sheet from scratch by changing the PrefixStyleSheet property for the RichHtmlField snippet. By default, this property is set to ms-
rte, and the styles in the default style sheet HtmlEditorStyles.css each begin with this prefix—for example:

H1. ms-rteElement-H1
{
-ms-name:"Heading 1";
-ms-element:"true";
}

When you change the value of the PrefixStyleSheet property, none of the existing ms-rte styles are available in the rich HTML editor, and only styles that you create that use the new prefix
are available to content authors. This means if you want to use some of the default styles, they must be copied to your style sheet and modified so that they use the new prefix.
NOTE

The PrefixStyleSheet property is defined per each RichHtmlField page field, but multiple page fields can use the same value for this property. So, if multiple page layouts reference the
same style sheet, it's possible for multiple RichHtmlFields on those page layouts to have the same style prefix and reference the same styles.

To define a new list of styles for a RichHtmlField


1. Browse to your publishing site.
2. In the upper-right corner of the page, choose Settings, and then choose Design Manager.
3. In Design Manager, in the left navigation pane, choose Edit Page Layouts.
4. Choose the page layout on which the RichHtmlField page field will reside.
5. In the upper-right corner of the server-side preview, choose Snippet Gallery.
6. On the ribbon, choose Page Fields, and then choose a page field of the type RichHtmlField.
7. In the property grid, expand the Misc section, and then change the PrefixStyleSheet property to a value other than ms-rte—for example, change the value to be customstyle.

Important: This property value must be all lowercase.

8. Choose Update.
9. On the left side of the Snippet Gallery, choose Copy to Clipboard.
10. In the mapped network drive on your computer, open the HTML page layout in your HTML editor.
NOTE

For more information, see How to: Map a network drive to the SharePoint Master Page Gallery.
11. In the HTML page layout, paste the HTML snippet inside PlaceHolderMain.
12. Save the HTML page layout. The changes to the HTML file are synced to the associated .aspx page layout.
At this point, if a content author creates or edits a page based on this page layout, no styles are available on the ribbon of the HTML editor because this specific page field uses only
styles that begin with the new prefix customstyle, but those styles have not yet been defined.
13. On the server, browse to the following location and open HtmlEditorStyles.css:
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPL ATE\L AYOUTS\1033\STYLES
It's useful to view the default styles, understand how they're written, and possibly reuse some of them by copying them to your style sheet and then modifying them. If you do this,
replace the default ms-rte prefix with your own prefix.
IM P O R T A N T

Do not modify the default style sheet, HtmlEditorStyles.css. This style sheet provides styles for every RichHtmlField in the farm. Also, service updates or an upgrade may overwrite
this file, causing you to lose any changes.
14. In your style sheet, create a list of new styles that start with the new prefix.
For example, if customstyle is the new prefix, your style sheet might contain the following style.

H2.customstyleElement-H2
{
-ms-name:"Heading 2";
-ms-element:"true";
}
customstyleElement-H2
{
font-weight: bold;
font-family: Cambria;
font-size: 16pt;
}
For clarity, the class name and the name of the style as it appears on the ribbon are defined separately from the style properties. In this example, **H2** is the element selector for the style,

SharePoint maps a style to a menu or command on the ribbon by parsing the class name immediately after the prefix and looking for one of these strings:

Element: The Page Elements section of the Styles gallery


Style: The Text Styles section of the Styles gallery
FontSize: The Font Size menu
ThemeFontFace: The Font menu
ForeColor: The Font Color menu
BackColor: The Highlight Color menu
Image: The Image menu
Table: The Table menu
Position: The Align buttons in the Paragraph group

For more information about where styles for a page layout should reside, see [How to: Create a page layout in SharePoint](how-to-create-a-page-layout-in-sharepoint.md).

See also
Overview of Design Manager in SharePoint
How to: Create a page layout in SharePoint
SharePoint Design Manager snippets
Resolve errors and warnings when previewing a page in SharePoint
5/3/2018 • 5 minutes to read Edit Online

After you convert an HTML file into a SharePoint master page, or after you create a page layout, you can preview that page in the browser. But before you can preview a master page or page
layout, you may have to resolve any issues that prevent the server-side preview from rendering your page.

Introduction to resolving preview errors


After you convert an HTML file into a SharePoint master page, or after you create a page layout, you can preview that page in the browser. As you edit and save your HTML master page or
page layout, you can refresh the preview to see exactly how SharePoint renders your page.
The preview in Design Manager is a live server-side preview, so any snippets or controls on your page, such as a navigation control or a search-driven web part, use live data. Also, when you
preview a master page or page layout, you can choose a generic preview of just that file, or you can choose to preview how a specific page in your site renders with that master page or page
layout. The server-side preview is a highly useful tool that complements the design-time preview in an HTML editor. For more information, see How to: Change the preview page in
SharePoint Design Manager.
But before you can preview a master page or page layout, you may have to resolve any issues that prevent the server-side preview from rendering your page. If the server-side preview isn't
working, this means that the master page or page layout also won't work after they're applied to your site. In Design Manager, after you convert a master page or create a page layout, you
can click the file name or conversion status to preview that file. On the preview page, the notification area at the top of the page displays any errors or warnings.
Here are the preview errors and warnings that you might encounter, and help for how to resolve them.

HTML file cannot contain <form> tags


Message
Your Master Page has one or more HTML <FORM> tags. For your master page to work, remove the tags (but you can leave the content in them).

Resolution
SharePoint pages are already wrapped in a <form> tag so that ASP.NET can do post-backs (specifically, a SharePoint.master page contains the <SharePoint:SharePointForm> tag that
creates an actual <form> tag when an associated content page is rendered). So, including a <form> tag on your master page or page layout means that there would be nested <form> tags
on the final rendering of the page, which is not valid in HTML. In your HTML editor, delete any <form> tags, save the page, and then refresh the preview.
If you want an HTML <form> tag in the page layout, you should put the form within a content placeholder with the ID PlaceHolderUtilityContent by adding this code to your HTML page
layout:

<!--CS: Start Create Snippets From Custom ASP.NET Markup Snippet-->


<!--SPM:<SharePoint:AjaxDelta id="DeltaPlaceHolderUtilityContent" runat="server">-->
<!--SPM:<asp:ContentPlaceHolder id="PlaceHolderUtilityContent" runat="server" />-->
<!--SPM:</SharePoint:AjaxDelta>-->
<!--CE: End Create Snippets From Custom ASP.NET Markup Snippet-->

You can also add the HTML Form web part or the InfoPath Form web part to your page from the Snippet Gallery. For more information, see SharePoint Design Manager snippets.

HTML file must be XML-compliant


Message
SharePoint requires HTML files to be XML-compliant. Your file isn't XML-compliant, likely because of tag properties without quotes, missing closing tags, or invalid
properties in tags. {Type of error, location of error}. Occurred at: {Time}.

Resolution
For an HTML file to be converted into the corresponding ASP.NET file, the HTML file must be XML-compliant. This error identifies specific markup in your HTML file that is not XML-
compliant. Run the HTML file through an XML validator, fix any issues in your HTML editor, save the file, and then refresh the preview.
NOTE

This requirement overrides some HTML 5 standards. For example, in HTML 5 you can specify the doctype in lowercase, but in XML the doctype must be uppercase.

HTML file contains problematic markup


Message
SharePoint can't parse this file, most likely because of an incorrectly formatted SharePoint snippet. The markup at the following location is causing problems. Edit the
markup manually to fix it, or replace it with a new snippet from the Snippet Gallery. {Type of error, location of error}. Occurred at: {Time}.

Resolution
You see this error when there is a problem with a SharePoint snippet in your HTML file. To fix this error, undo whatever change caused the error, or replace the problematic snippet with a
new one, either from the Snippet Gallery or from a different master page or page layout file that has a working version of the snippet. In your HTML editor, after you fix or replace the
snippet, save the page, and then refresh the preview.

Master page for a page layout has changed


Message
This page layout's master page has changed, which will cause inconsistencies across your site. Click here to update the sections of your page layout that represent master
page regions.

Resolution
For a page layout to work with a given master page, the two must have the same set of content placeholders. If you create a page layout based on a particular master page, and then edit that
HTML master page, you'll see this message. Even if you know that changes to the master page didn't add or remove content placeholders, you should update the content regions of your
page layout anyway, so that you can preview any changes from the master page that might affect your page layout.
Reset the preview
Message
Your master page (page layout) doesn't have any warnings or errors. Reset the preview to its original state.

Explanation
This message simply confirms that the conversion process worked with no errors or issues. However, when you preview a page, you may navigate away from that specific page or change the
preview in some other way. If this happens, you can always choose Reset the preview in the message area. Doing so refreshes the preview so that it uses the specific master page or page
layout that you're working on, and whatever page you've selected in the Change Preview Page option in the upper-left corner.

Change the preview page


Message
You're currently previewing your master page (page layout) without any content. You can change the page you're previewing from the menu above.

Explanation
You see this message when you aren't using a live SharePoint page with which to preview your master page or page layout. For example, if you're previewing a page layout, you can choose
Change Preview Page in the upper-left corner, and then select a specific content page to preview with your page layout. This way, you can preview the page layout with actual page content
in the page fields. If you want the preview to show just the positions of ContentPlaceHolderMain or page fields, you can always use Change Preview Page to switch back to a generic
preview.

See also
Develop the site design in SharePoint
How to: Change the preview page in SharePoint Design Manager
SharePoint Design Manager snippets
Convert an HTML file into a master page in SharePoint
5/3/2018 • 15 minutes to read Edit Online

With Design Manager, you can convert an .html file into a SharePoint master page, a .master file. After the conversion, the HTML file and master page are associated, so that when you edit
and save the HTML file, the changes are synced to the associated master page.

Introduction to converting a master page


With Design Manager, you can convert an .html file into a SharePoint master page, a .master file. After the conversion, the HTML file and master page are associated, so that when you edit
and save the HTML file, the changes are synced to the associated master page.
Why do you want to convert an HTML file, instead of creating a .master file from scratch? In SharePoint, master pages work exactly as they do in ASP.NET, but SharePoint also requires that
certain elements, such as controls and content placeholders that are specific to SharePoint, must be present on the page for SharePoint to correctly render that master page. By using Design
Manager to convert an HTML file into a fully functioning SharePoint master page, you don't have to know about ASP.NET or the SharePoint-specific markup; instead, you can focus on
designing your site in HTML, CSS, and JavaScript.
When you convert an HTML file into a master page:
A .master file with the same name as your HTML file is created in the Master Page Gallery.
All markup required by SharePoint is added to the .master file so that the master page renders correctly.
Markup such as comments, <div> tags, snippets, and content placeholders are added to your original HTML file.
The HTML file and master page are associated, so that any later edits to the HTML file are synced to the .master file when the HTML file is saved.
NOTE

The syncing goes in one direction only. Changes to the HTML master page are synced to the associated .master file, but if you choose to edit the .master file directly the changes are not
synced to the HTML file. Every HTML master page (and every HTML page layout) has a property named Associated File that is set to True by default, which creates the association and
syncing between files.
If you have a pair of associated files (HTML and .master) and you edit the .master file without breaking the association, the changes to the .master file will be saved, but you can't check in or
publish the .master file, so those changes are not saved in a meaningful way. Any changes to the HTML file override the .master file. If you check in or publish the HTML file, the HTML file
changes override any changes that were made to the .master file. The changes to the .master file are lost.
If you're a developer comfortable working with ASP.NET, you can choose to work only with the .master file by breaking the association between the files. To break the association between the
HTML file and the .master file, in Design Manager, choose Edit Properties for the HTML file, and then clear the Associated File check box. You can later re-associate the files by editing the
properties and selecting this check box, in which case the HTML file will again overwrite the .master file, and changes made to the .master file will be lost.

Prepare the HTML file for conversion


Before you convert your HTML file, here are some best practices and guidance to consider:
Consider the SharePoint page model. For more information, see Overview of the SharePoint page model. As you design the HTML mockups of your site, you'll probably have several
HTML files for different types of pages, such as an article page or a category page that contains web parts that display a category of items from a catalog. But, only one HTML file will
be converted into the master page. An HTML file can be converted into a master page, but an HTML file can't be converted directly into a page layout because a page layout requires
page fields.
Make sure your HTML file is XML-compliant. For the conversion to work, the HTML file must be XML-compliant. Unfortunately, this requirement overrides some HTML 5 standards
—for example, in HTML 5 you can specify the doctype in lowercase, but in XML the doctype must be uppercase. Also, you should remove any <form> tags from your HTML file.
Consider running your HTML file through an external XML validator to identify XML errors before conversion.
Consider these important guidelines for your CSS references:
Don't put <style> blocks in the <head> tag. These styles are removed during conversion. Instead, link from your HTML file to an external CSS file.
Add ms-design-css-conversion="no" to the <CSS link> tag if you're using a web font.
Be cautious about applying styles to general HTML tags like <body>, <div>, and <img>. Everything within your SharePoint design, including the ribbon, is within the
<body> tag. For styles that you would usually apply to the <body> tag, consider applying them instead to <div id="s4-bodyContainer">, which is a tag that SharePoint
uses for the main body of the page. Also, SharePoint uses many images that are affected by whatever styles you apply to the <img> tag.
Many designers style the navigation by applying classes to <ul> and <li> elements. But, SharePoint uses a dynamic navigation control, which you can add to your master page
from the Snippet Gallery. SharePoint navigation controls have styles applied by default that you have to override.
Consider these potential issues about file naming:
If you have Index.html and Index.htm, those files will have the same .master file.
If you have Design/Index.html and Design/SubDesign/Index.html, both of those files are available for conversion into their own, separate .master files, but they'll both show up
as Index.html in the master page list in Design Manager. To disambiguate them, click or select the ellipsis button for each file to see the full path.
If you're adding a JavaScript widget, make sure the <script> start tag is on its own line.

<script>
(function( …

Do not put them on the same line, like this.

<Script> (function( …

A reference to the JQuery library (an external reference) should go before the </head> tag.

Convert the HTML file into a master page


Before you convert an HTML file, you first have to upload all of your design files, including your HTML file. For more information, see How to: Map a network drive to the SharePoint Master
Page Gallery.

To convert the HTML file into a .master file


1. Browse to your publishing site.
2. In the upper-right corner of the page, choose Settings, and then choose Design Manager.
3. In Design Manager, in the left navigation pane, choose Edit Master Pages.
4. Choose Convert an HTML file to a SharePoint master page.
5. In the Select an Asset dialog box, browse to and select the HTML file that you want to convert.
NOTE

When you upload your design files, you should keep all files that are related to a single design in their own folder in the Master Page Gallery. When you copy your design folder into
the mapped network drive, the Master Page Gallery retains whatever folder structure you created.
6. Choose Insert.
At this point, SharePoint converts your HTML file into a .master file with the same name.
In Design Manager, your HTML file now appears with a Status column that shows one of two possible statuses:
Warnings and Errors
Conversion successful
1. Follow the link in the Status column to preview the file and to view any errors or warnings about the master page.
The preview page is a live server-side preview of your master page. The top of the preview displays any warnings or errors that you may have to resolve by editing the HTML file in an
HTML editor. Errors must be fixed before the preview will display the master page correctly.
For more information about resolving errors and warnings, see How to: Resolve errors and warnings when previewing a page in SharePoint.
For more information about previewing the master page with different pages, see How to: Change the preview page in SharePoint Design Manager.
The preview page also contains a Snippets link in the upper-right corner. This link opens the Snippet Gallery, where you can begin replacing static or mockup controls in your design
with dynamic SharePoint controls. For more information, see SharePoint Design Manager snippets.
2. To fix any errors, edit the HTML file that resides directly on the server by using an HTML editor to open and edit the HTML file in the mapped drive. Each time you save the HTML file,
any changes are synced to the associated .master file.
3. After your master page previews successfully, you will see a <div> tag that gets added to your HTML file. You may have to scroll to the bottom of the page to see the <div> tag.
This <div> is the main content block. It resides inside a content placeholder named ContentPlaceHolderMain. At run time, when a visitor browses your site and requests a page,
this content placeholder gets filled with content from a page layout that contains content in a matching content region. You should position this <div> where you want your page
layouts to appear on the master page.
If your HTML file contains static or mockup content in the body of the page, now you begin the process of removing that static content from the HTML master page and applying
those styles to other elements of the SharePoint page model, such as page layouts, page field controls, snippets, and display templates. For an example, see How to: Create a page
layout in SharePoint.

Understanding the HTML file after conversion


When you convert an HTML file into a master page, many lines of markup get added to your HTML file. You can safely ignore most of this markup, and most of it will not appear in the final
markup of your site when you view source in the browser, but this markup is critical for converting your HTML file into the .master file that SharePoint actually uses. Each time you save a
change to your HTML file, this SharePoint markup makes it possible for that same change to be made to the associated .master file in the background.
The markup that gets added includes tags before and in the <head> tag, snippets, and content placeholders. Most of the markup is enclosed within comment tags: Whenever you save a
change to the HTML file, the conversion process strips out the comments to use the ASP.NET markup within.

Types of markup
The following is a breakdown of the types of markup that are added to the HTML file:
Document properties The <mso> tag contains SharePoint metadata, including information about the file itself and some properties needed for the successful conversion to the .master
file.

<mso:CustomDocumentProperties>
<mso:HtmlDesignFromMaster msdt:dt="string"></mso:HtmlDesignFromMaster>
<mso:HtmlDesignStatusAndPreview msdt:dt="string">http://[server_name]/sites/PubSite/_catalogs/masterpage/[site_name]/index.html, Conversion successful.</mso:HtmlDesignStatusAndPreview>
<mso:ContentTypeId msdt:dt="string">0x0101000F1C8B9E0EB4BE489F09807B2C53288F0054AD6EF48B9F7B45A142F8173F171BD10003D357F861E29844953D5CAA1D4D8A3A0084F0F9C7FCB65541A59990D173DA60FA</mso:ContentType
<mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
<mso:HtmlDesignConversionSucceeded msdt:dt="string">True</mso:HtmlDesignConversionSucceeded>
</mso:CustomDocumentProperties>

SharePoint namespace registration The <SPM> tag ("SharePoint markup") provides a line registering a SharePoint namespace.

<!--SPM:<%@Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>-->


<!--SPM:<%@Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e942

Comments The <CS> and <CE> ("Comment start" and "comment end") tags are ignored during the conversion process. These tags are to help you parse the lines of markup.
<!--CS: Start Page Head Contents Snippet-->

<!--CE: End Page Head Contents Snippet-->

<!--CS: Start Ribbon Snippet-->



<!--CE: End Ribbon Snippet-->

<!--CS: Start PlaceHolderMain Snippet-->



<!--CE: End PlaceHolderMain Snippet-->

Snippets The <MS> and <ME> ("markup start" and "markup end") tags denote the beginning and end of a SharePoint control or a snippet. A snippet is a SharePoint control that adds
SharePoint functionality to your page. You can add snippets yourself by using the Snippet Gallery. For more information, see SharePoint Design Manager snippets.

<!--MS:<SharePoint:RobotsMetaTag runat="server">-->
<!--ME:</SharePoint:RobotsMetaTag>-->
<!--MS:<SharePoint:PageTitle runat="server">-->
<!--MS:<asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server">-->
<!--MS:<SharePoint:ProjectProperty Property="Title" runat="server">-->
<!--ME:</SharePoint:ProjectProperty>-->
<!--ME:</asp:ContentPlaceHolder>-->
<!--ME:</SharePoint:PageTitle>-->
<!--MS:<SharePoint:StartScript runat="server">-->
<!--ME:</SharePoint:StartScript>-->
<!--MS:<SharePoint:CssLink runat="server" Version="15">-->
<!--ME:</SharePoint:CssLink>-->
<!--MS:<SharePoint:CacheManifestLink runat="server">-->
<!--ME:</SharePoint:CacheManifestLink>-->
<!--MS:<SharePoint:PageRenderMode runat="server" RenderModeType="Standard">-->
<!--ME:</SharePoint:PageRenderMode>-->
<!--MS:<SharePoint:ScriptLink language="javascript" name="core.js" OnDemand="true" runat="server" Localizable="false">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink language="javascript" name="menu.js" OnDemand="true" runat="server" Localizable="false">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink language="javascript" name="callout.js" OnDemand="true" runat="server" Localizable="false">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink language="javascript" name="sharing.js" OnDemand="true" runat="server" Localizable="false">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink language="javascript" name="suitelinks.js" OnDemand="true" runat="server" Localizable="false">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:CustomJSUrl runat="server">-->
<!--ME:</SharePoint:CustomJSUrl>-->
<!--MS:<SharePoint:SoapDiscoveryLink runat="server">-->
<!--ME:</SharePoint:SoapDiscoveryLink>-->
<!--MS:<SharePoint:AjaxDelta id="DeltaPlaceHolderAdditionalPageHead" Container="false" runat="server">-->
<!--MS:<asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead" runat="server">-->
<!--ME:</asp:ContentPlaceHolder>-->
<!--MS:<SharePoint:DelegateControl runat="server" ControlId="AdditionalPageHead" AllowMultipleControls="true">-->
<!--ME:</SharePoint:DelegateControl>-->
<!--MS:<asp:ContentPlaceHolder id="PlaceHolderBodyAreaClass" runat="server">-->
<!--ME:</asp:ContentPlaceHolder>-->
<!--ME:</SharePoint:AjaxDelta>-->
<!--MS:<SharePoint:CssRegistration Name="Themable/corev15.css" runat="server">-->
<!--ME:</SharePoint:CssRegistration>-->
<!--MS:<SharePoint:AjaxDelta id="DeltaSPWebPartManager" runat="server">-->
<!--MS:<WebPartPages:SPWebPartManager runat="server">-->
<!--ME:</WebPartPages:SPWebPartManager>-->
<!--ME:</SharePoint:AjaxDelta>-->

Preview blocks The <PS> and <PE> ("Preview start" and "preview end") tags surround a section of HTML code that you shouldn't edit because this section affects only the design-time
preview. These preview sections are a snapshot in time of the SharePoint control that snippet is inserting. A preview makes it possible for you to work more meaningfully on the HTML
file in a client-side HTML editor. But, changing the content or styling within that preview has no lasting effect on the .master file, which is what SharePoint is ultimately using. To style a
snippet, you have to identify and override the SharePoint styles with your own custom CSS.

<!--PS: Start of READ-ONLY PREVIEW (do not modify) -->


<div class="DefaultContentBlock" style="background:rgb(0, 114, 198); color:white; width:100%; padding:8px; height:64px; overflow:hidden;">The SharePoint ribbon will be here when your file is eith
<!--PE: End of READ-ONLY PREVIEW -->

SharePoint IDs Two of the snippets added to your HTML file during the conversion (the Page Head Contents snippet and the SharePoint Ribbon) have an associated SharePoint ID, or
SID (00 and 02, respectively). These IDs make it possible to shorten the snippets and make the HTML in the page easier to read.

<!--SID:00 -->

<!--SID:02 {Ribbon}-->

Added snippets
It's important to know about two of the snippets that are added to your HTML file. These snippets are added automatically during the conversion, but they're not available for you to add
from the Snippet Gallery.
The Ribbon For content authors to be able to create pages and author content on your SharePoint site, your master page needs the ribbon and the "suite navigation" that is new to
SharePoint. The ribbon is contained in a security-trimming snippet, so that when a visitor browses your site, the ribbon is displayed only to authenticated users, not anonymous users. You
can move the ribbon to a different position on the page or style it by overriding the default CSS classes, but we do not recommend moving or reordering the components (such as the
Site Actions menu) that are contained inside the ribbon.
<!--MS:<SharePoint:SPSecurityTrimmedControl runat="server" AuthenticationRestrictions="AnonymousUsersOnly">-->
<!--MS:<wssucw:Welcome runat="server" EnableViewState="false">-->
<!--ME:</wssucw:Welcome>-->
<!--ME:</SharePoint:SPSecurityTrimmedControl>-->

ContentPlaceHolderMain At the bottom of the <div id="s4-bodyContainer"> tag, before the closing </body> tag, the conversion process inserts a content placeholder named
PlaceHolderMain. Inside this snippet is the black-bordered, yellow <div> that appears in the design view of your HTML editor, or in the server-side preview in Design Manager.
This <div> represents the area where the content specified by your page layouts and pages will go. You should move the PlaceHolderMain snippet to the place within your master
page that will be filled by your page layouts—the area of your site design that isn't the same across all pages of your site.

<!--CS: Start PlaceHolderMain Snippet-->


<!--SPM:<%@Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9b
<!--MS:<SharePoint:AjaxDelta ID="DeltaPlaceHolderMain" IsMainContent="true" runat="server">-->
<!--MS:<asp:ContentPlaceHolder ID="PlaceHolderMain" runat="server">-->
<div class="DefaultContentBlock" style="border:medium black solid; background:yellow; color:black; margin:20px; padding:10px;">
This div, which you should delete, represents the content area that your Page Layouts and pages will fill. Design your Master Page around this content placeholder.

</div>
<!--ME:</asp:ContentPlaceHolder>-->
<!--ME:</SharePoint:AjaxDelta>-->
<!--CE: End PlaceHolderMain Snippet-->

Reference: Examples of SharePoint markup added to the HTML file


The following is an example of markup added to an HTML file after it is converted to a master page.

Markup added to the <head> tag


<head>
<meta http-equiv="X-UA-Compatible" content="IE=10" />
<!--CS: Start Page Head Contents Snippet-->
<!--SPM:<%@Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
<!--SPM:<%@Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e942
<!--SID:00 -->
<meta name="GENERATOR" content="Microsoft SharePoint" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta http-equiv="Expires" content="0" />
<!--MS:<SharePoint:RobotsMetaTag runat="server">-->
<!--ME:</SharePoint:RobotsMetaTag>-->
<!--MS:<SharePoint:PageTitle runat="server">-->
<!--MS:<asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server">-->
<!--MS:<SharePoint:ProjectProperty Property="Title" runat="server">-->
<!--ME:</SharePoint:ProjectProperty>-->
<!--ME:</asp:ContentPlaceHolder>-->
<!--ME:</SharePoint:PageTitle>-->
<!--MS:<SharePoint:StartScript runat="server">-->
<!--ME:</SharePoint:StartScript>-->
<!--MS:<SharePoint:CssLink runat="server" Version="15">-->
<!--ME:</SharePoint:CssLink>-->
<!--MS:<SharePoint:CacheManifestLink runat="server">-->
<!--ME:</SharePoint:CacheManifestLink>-->
<!--MS:<SharePoint:PageRenderMode runat="server" RenderModeType="Standard">-->
<!--ME:</SharePoint:PageRenderMode>-->
<!--MS:<SharePoint:ScriptLink language="javascript" name="core.js" OnDemand="true" runat="server" Localizable="false">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink language="javascript" name="menu.js" OnDemand="true" runat="server" Localizable="false">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink language="javascript" name="callout.js" OnDemand="true" runat="server" Localizable="false">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink language="javascript" name="sharing.js" OnDemand="true" runat="server" Localizable="false">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:ScriptLink language="javascript" name="suitelinks.js" OnDemand="true" runat="server" Localizable="false">-->
<!--ME:</SharePoint:ScriptLink>-->
<!--MS:<SharePoint:CustomJSUrl runat="server">-->
<!--ME:</SharePoint:CustomJSUrl>-->
<!--MS:<SharePoint:SoapDiscoveryLink runat="server">-->
<!--ME:</SharePoint:SoapDiscoveryLink>-->
<!--MS:<SharePoint:AjaxDelta id="DeltaPlaceHolderAdditionalPageHead" Container="false" runat="server">-->
<!--MS:<asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead" runat="server">-->
<!--ME:</asp:ContentPlaceHolder>-->
<!--MS:<SharePoint:DelegateControl runat="server" ControlId="AdditionalPageHead" AllowMultipleControls="true">-->
<!--ME:</SharePoint:DelegateControl>-->
<!--MS:<asp:ContentPlaceHolder id="PlaceHolderBodyAreaClass" runat="server">-->
<!--ME:</asp:ContentPlaceHolder>-->
<!--ME:</SharePoint:AjaxDelta>-->
<!--MS:<SharePoint:CssRegistration Name="Themable/corev15.css" runat="server">-->
<!--ME:</SharePoint:CssRegistration>-->
<!--MS:<SharePoint:AjaxDelta id="DeltaSPWebPartManager" runat="server">-->
<!--MS:<WebPartPages:SPWebPartManager runat="server">-->
<!--ME:</WebPartPages:SPWebPartManager>-->
<!--ME:</SharePoint:AjaxDelta>-->
<!--CE: End Page Head Contents Snippet-->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!--DC:Business Solutions-->
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
<!--[if lte IE 7]>
<link rel="stylesheet" href="css/ie.css" type="text/css" charset="utf-8"/>
<![endif]-->
<!--[if gte mso 9]><xml>
<mso:CustomDocumentProperties>
<mso:HtmlDesignFromMaster msdt:dt="string"></mso:HtmlDesignFromMaster>
<mso:HtmlDesignStatusAndPreview msdt:dt="string">http://[server_name]/sites/PubSite/_catalogs/masterpage/[site_name]/index.html, Conversion successful.</mso:HtmlDesignStatusAndPreview>
<mso:ContentTypeId msdt:dt="string">0x0101000F1C8B9E0EB4BE489F09807B2C53288F0054AD6EF48B9F7B45A142F8173F171BD10003D357F861E29844953D5CAA1D4D8A3A0084F0F9C7FCB65541A59990D173DA60FA</mso:ContentType
<mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
<mso:HtmlDesignConversionSucceeded msdt:dt="string">True</mso:HtmlDesignConversionSucceeded>
</mso:CustomDocumentProperties>
</xml><![endif]-->
</head>

Markup added after the start <body> tag


Ribbon snippet
<!--CS: Start Ribbon Snippet-->
<!--SPM:<%@Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
<!--SPM:<%@Register Tagprefix="wssucw" TagName="Welcome" Src="~/_controltemplates/15/Welcome.ascx"%>-->
<!--MS:<SharePoint:SPSecurityTrimmedControl runat="server" HideFromSearchCrawler="true" EmitDiv="true">-->
<div id="TurnOnAccessibility" style="display:none" class="s4-notdlg noindex">
<a id="linkTurnOnAcc" href="#" class="ms-accessible ms-acc-button" onclick="SetIsAccessibilityFeatureEnabled(true);UpdateAccessibilityUI();document.getElementById('linkTurnOffAcc'
<!--MS:<SharePoint:EncodedLiteral runat="server" text="&amp;lt;%$Resources:wss,master_turnonaccessibility%&amp;gt;" EncodeMethod="HtmlEncode">-->
<!--ME:</SharePoint:EncodedLiteral>-->
</a>
</div>
<div id="TurnOffAccessibility" style="display:none" class="s4-notdlg noindex">
<a id="linkTurnOffAcc" href="#" class="ms-accessible ms-acc-button" onclick="SetIsAccessibilityFeatureEnabled(false);UpdateAccessibilityUI();document.getElementById('linkTurnOnAcc
<!--MS:<SharePoint:EncodedLiteral runat="server" text="&amp;lt;%$Resources:wss,master_turnoffaccessibility%&amp;gt;" EncodeMethod="HtmlEncode">-->
<!--ME:</SharePoint:EncodedLiteral>-->
</a>
</div>
<!--ME:</SharePoint:SPSecurityTrimmedControl>-->
<div id="ms-designer-ribbon">
<!--SID:02 {Ribbon}-->
<!--PS: Start of READ-ONLY PREVIEW (do not modify) --><div class="DefaultContentBlock" style="background:rgb(0, 114, 198); color:white; width:100%; padding:8px; height:64px; overflow:
</div>
<!--MS:<SharePoint:SPSecurityTrimmedControl runat="server" AuthenticationRestrictions="AnonymousUsersOnly">-->
<!--MS:<wssucw:Welcome runat="server" EnableViewState="false">-->
<!--ME:</wssucw:Welcome>-->
<!--ME:</SharePoint:SPSecurityTrimmedControl>-->
<!--CE: End Ribbon Snippet-->

Two SharePoint <div> tags

<div id="s4-workspace">
<div id="s4-bodyContainer">

Markup added before the closing </body> tag and two closing </div> tags

<div data-name="ContentPlaceHolderMain">
<!--CS: Start PlaceHolderMain Snippet-->
<!--SPM:<%@Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9b
<!--MS:<SharePoint:AjaxDelta ID="DeltaPlaceHolderMain" IsMainContent="true" runat="server">-->
<!--MS:<asp:ContentPlaceHolder ID="PlaceHolderMain" runat="server">-->
<div class="DefaultContentBlock" style="border:medium black solid; background:yellow; color:black; margin:20px; padding:10px;">
This div, which you should delete, represents the content area that your Page Layouts and pages will fill. Design your Master Page around this content placeholder.

</div>
<!--ME:</asp:ContentPlaceHolder>-->
<!--ME:</SharePoint:AjaxDelta>-->
<!--CE: End PlaceHolderMain Snippet-->
</div>

See also
Overview of Design Manager in SharePoint
How to: Create a page layout in SharePoint
SharePoint Design Manager snippets
Create a minimal master page in SharePoint
3/26/2018 • 5 minutes to read Edit Online

A minimal master page contains only those page elements that are required by SharePoint to render the page correctly in the browser. With Design Manager, you can quickly create a
minimal master page without first having to design and convert an HTML file.

Introduction to the minimal master page


With Design Manager, you can convert a typical HTML file into a SharePoint master page. But, if you don't have a prebuilt mock-up, you can still quickly start from scratch by creating a
minimal master page. The minimal master page contains only those page elements required by SharePoint to render the page in the browser.
When you create a minimal master page, Design Manager creates both the .master file and an associated HTML file, so that you can still work with only the HTML file if you prefer. Working
with a minimal master page is exactly the same as working with a master page that you convert from an HTML file. The HTML file and master page are associated, so that whenever you edit
and save the HTML file, those changes are synced to the associated master page. And the HTML file contains special types of markup that make syncing with the .master file possible. For
more information about this association and these types of markup, see How to: Convert an HTML file into a master page in SharePoint.
Starting with a minimal master page is useful when:
You want to start quickly from scratch, and then build out your design in the HTML file that's associated with the minimal master page, instead of starting with a mock-up HTML file.
You want to rapidly test or prototype a design element that requires a working SharePoint master page. For example, creating a minimal master page does not require preparing an
HTML file for conversion or resolving any preview errors that result from markup that is not valid in the HTML file. This means you can immediately work with the server-side
preview or the Snippet Gallery.
You want to work directly with the .master file. If you're an ASP.NET developer or a SharePoint developer, you can create a minimal master page, remove the association between the
HTML file and the .master file by clearing the Associated File check box in the properties of the HTML file, and then work directly with the .master file.

Create a minimal master page


To create a minimal master page
1. Browse to your publishing site.
2. In the upper-right corner of the page, choose Settings, and then choose Design Manager.
3. In Design Manager, in the left navigation pane, choose Edit Master Pages.
4. Choose Create a minimal master page.
5. In the Create a Master Page dialog box, enter a name for the master page, and then choose OK.
At this point, SharePoint creates both a .master file and an associated HTML file with the same name in the Master Page Gallery.
In Design Manager, your HTML file now appears with Conversion successful displayed in the Status column.
6. Follow the link in the Status column to preview the file.
The preview page is a live server-side preview of your master page.
For more information about previewing the master page with different pages, see How to: Change the preview page in SharePoint Design Manager.
The preview page also contains a Snippets link in the upper-right corner. This link opens the Snippet Gallery, where you can begin replacing static or mock-up controls in your design
with dynamic SharePoint controls. For more information, see SharePoint Design Manager snippets.
After your master page previews successfully, you will see a <div> tag that gets added to your HTML file. You may have to scroll to the bottom of the page to see the <div> tag.
This <div> is the main content block. It resides inside a content placeholder named ContentPlaceHolderMain. At run time, when a visitor browses your site and requests a page,
this content placeholder gets filled with content from a page layout that contains content in a matching content region. You should position this <div> where you want your page
layouts to appear on the master page.
7. You can edit the HTML file that resides directly on the server by using an HTML editor to open and edit the HTML file in a mapped drive. Each time you save the HTML file, any
changes are synced to the associated .master file. For more information, see How to: Map a network drive to the SharePoint Master Page Gallery.
8. To work only with the .master file and not the HTML file, you must break the association between the two files. In Design Manager, on the Edit Master Pages page, select the HTML
file, open the Properties menu, and then choose Edit Properties. On the Edit tab, clear the Associated File check box, and then choose Save.
Breaking the association enables you to work directly with the .master file and save changes without having them overwritten by any changes made to the HTML file. You can restore
this association at any time. If you restore the association, the associated HTML file will sync to the .master file and overwrite it.

Understand the associated HTML file


When you create a minimal master page, an HTML file is created that's associated with the .master file, and this HTML file contains many lines of markup that are specific to how SharePoint
works. You can safely ignore most of this markup, and most of it does not appear in the final markup of your site when you view source in the browser, but this markup is critical for syncing
changes from the HTML file to the .master file that SharePoint actually uses. Each time you save a change to your HTML file, this SharePoint markup makes it possible for that same change
to be made to the associated .master file in the background. For more information, see the markup samples in How to: Convert an HTML file into a master page in SharePoint.

See also
Overview of Design Manager in SharePoint
How to: Create a page layout in SharePoint
How to: Convert an HTML file into a master page in SharePoint
SharePoint Design Manager snippets
Change the preview page in SharePoint Design Manager
3/26/2018 • 2 minutes to read Edit Online

Learn how to set, create, and change the preview page in Design Manager in SharePoint. The preview page is the page of your site that you use to see how your design looks. You can set the
preview page to be either a specific page within your site or a generic preview. If you choose the generic preview, you'll see your master page with only a placeholder for content. You'll also
see a message in the banner that you're currently previewing the master page without any content. If you choose a specific page, you'll see the page content rendered with the master page
and the appropriate page layout.
As you interact with the page, you might do something that causes SharePoint to move away from the preview. For example, if you select Save on the ribbon, SharePoint saves the page and
then displays the live version of the page. (The live version of the page uses the live master page, not the master page that you are designing.) You can return to the preview page by choosing
Reset the preview.

Set the preview page in Design Manager


Use this procedure to set the preview page.

To set the preview page


1. In the banner at the top of the web browser, choose Change Preview Page.
2. Choose Select Existing.
3. To use a generic preview page, select Generic Preview.
4. To use a specific page as the preview page, select URL and enter the URL of the page.
5. Choose OK.

Create a new preview page in Design Manager


Use this procedure to create a page and set it as the preview page.

To create a new preview page


1. In the banner at the top of the web browser, choose Change Preview Page.
2. Choose Create New.
3. Type a name for the page and then choose Create.
The page is created, and you are taken to a view from which you can add content to the new page.

Return to the preview page in Design Manager


Use this procedure to return to the preview page.

To return to the preview page


In the information message at the top of the web browser, select Reset the preview.

See also
Master pages, the Master Page Gallery, and page layouts in SharePoint
Develop the site design in SharePoint
How to: Map a network drive to the SharePoint Master Page Gallery
SharePoint Design Manager device channels
SharePoint Design Manager image renditions
SharePoint Online Suite Navigation control
5/3/2018 • 3 minutes to read Edit Online

Learn about master page markup for the Suite Navigation control in SharePoint Online. {insert introductory content}

SharePoint Online Suite Navigation control


The Suite Navigation control renders a consistent top navigation bar in SharePoint Online. This control is now a part of all uncustomized out-of-the-box master pages.
If a master page was customized, it will not pick up the new Suite Navigation control. To add this control to your custom master page, replace the suiteBar <div> with the markup that
corresponds to the type of site you're using.
The new Suite Navigation control supports any theme applied to the site. If you want to change the color of the top navigation bar, apply a theme.

Important: When customizing a site, the best practice is to apply a theme. While you can apply custom CSS to the site, custom CSS may break in the future if the Suite Navigation
control is updated again in the service.
Caution: If you do not want to use the new control, remove the Suite Navigation markup from your master page and add custom markup. However, be aware that customized master
pages run the risk of not picking up updates to default master page controls or new functionality that is added to uncustomized master pages. Using a customized master page
introduces the risk that service updates will break the functionality or style of your site.

Suite Navigation control for intranet sites


For intranet sites, use the following master page markup for the Suite Navigation control. Table 1 lists web controls used in the Suite Navigation code.
Table 1. Suite Navigation web controls for intranet sites

W EB CO NTR O L D ES CR IPTIO N

SharePoint:Menu Displays a menu in an ASP.NET webpage.

SharePoint:MenuItemTemplate Represents a control that creates an item in a drop-down menu.

<SharePoint:AjaxDelta runat="server" id="suiteBarDelta" BlockElement="true" CssClass="ms-dialogHidden ms-fullWidth noindex">


<div id="suiteMenuData" class="ms-hide">
<wssuc:Welcome id="IdWelcomeData" runat="server" EnableViewState="false" RenderDataOnly="true"/>
<span class="ms-siteactions-root" id="siteactiontd">
<SharePoint:SiteActions runat="server" accesskey="<%$Resources:wss,tb_SiteActions_AK%>"
id="SiteActionsMenuMainData"
PrefixHtml=""
SuffixHtml=""
ImageUrl="/_layouts/15/images/spcommon.png?rev=32"
ThemeKey="spcommon"
MenuAlignment="Right"
LargeIconMode="false"
>
<CustomTemplate>
<SharePoint:Menu runat="server" Visible="false"/>
<SharePoint:FeatureMenuTemplate runat="server"
FeatureScope="Site"
Location="Microsoft.SharePoint.StandardMenu"
GroupId="SiteActions"
UseShortId="true"
>
<SharePoint:MenuItemTemplate runat="server"
id="MenuItem_ShareThisSite"
Text="<%$Resources:wss,siteactions_sharethissite%>"
Description="<%$Resources:wss,siteactions_sharethissitedescription%>"
MenuGroupId="100"
Sequence="110"
UseShortId="true"
PermissionsString="ViewPages"
PermissionMode="Any" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_EditPage"
Text="<%$Resources:wss,siteactions_editpage15%>"
Description="<%$Resources:wss,siteactions_editpagedescriptionv4%>"
ImageUrl="/_layouts/15/images/ActionsEditPage.png?rev=32"
MenuGroupId="200"
Sequence="210"
PermissionsString="EditListItems"
ClientOnClickNavigateUrl="javascript:ChangeLayoutMode(false);" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_CreatePage"
Text="<%$Resources:wss,siteactions_addpage15%>"
Description="<%$Resources:wss,siteactions_createpagedesc%>"
ImageUrl="/_layouts/15/images/NewContentPageHH.png?rev=32"
MenuGroupId="200"
Sequence="220"
UseShortId="true"
ClientOnClickScriptContainingPrefixedUrl="OpenCreateWebPageDialog('~siteLayouts/createwebpage.aspx')"
PermissionsString="AddListItems, EditListItems"
PermissionMode="All" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_Create"
Text="<%$Resources:wss,siteactions_addapp15%>"
Description="<%$Resources:wss,siteactions_createdesc%>"
MenuGroupId="200"
Sequence="230"
UseShortId="true"
ClientOnClickScriptContainingPrefixedUrl="GoToPage('~siteLayouts/addanapp.aspx')"
PermissionsString="ManageLists, ManageSubwebs"
PermissionMode="Any" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_ViewAllSiteContents"
Text="<%$Resources:wss,quiklnch_allcontent_15%>"
Description="<%$Resources:wss,siteactions_allcontentdescription%>"
ImageUrl="/_layouts/15/images/allcontent32.png?rev=32"
MenuGroupId="200"
MenuGroupId="200"
Sequence="240"
UseShortId="true"
ClientOnClickNavigateUrl="~siteLayouts/viewlsts.aspx"
PermissionsString="ViewFormPages"
PermissionMode="Any" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_ChangeTheLook"
Text="<%$Resources:wss,siteactions_changethelook15%>"
Description="<%$Resources:wss,siteactions_changethelookdesc15%>"
MenuGroupId="300"
Sequence="310"
UseShortId="true"
ClientOnClickNavigateUrl="~siteLayouts/designgallery.aspx"
PermissionsString="ApplyThemeAndBorder,ApplyStyleSheets,Open,ViewPages,OpenItems,ViewListItems"
PermissionMode="All" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_Settings"
Text="<%$Resources:wss,siteactions_settings15%>"
Description="<%$Resources:wss,siteactions_sitesettingsdescriptionv4%>"
ImageUrl="/_layouts/15/images/settingsIcon.png?rev=32"
MenuGroupId="300"
Sequence="320"
UseShortId="true"
ClientOnClickScriptContainingPrefixedUrl="GoToPage('~siteLayouts/settings.aspx')"
PermissionsString="EnumeratePermissions,ManageWeb,ManageSubwebs,AddAndCustomizePages,ApplyThemeAndBorder,ManageAlerts,ManageLists,ViewUsageData"
PermissionMode="Any" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_SwitchToMobileView"
Visible="false"
Text="<%$Resources:wss,siteactions_switchtomobileview%>"
Description="<%$Resources:wss,siteactions_switchtomobileviewdesc%>"
MenuGroupId="300"
Sequence="330"
UseShortId="true"
ClientOnClickScript="STSNavigate(StURLSetVar2(ajaxNavigate.get_href(), 'mobile', '1'));" />
</SharePoint:FeatureMenuTemplate>
</CustomTemplate>
</SharePoint:SiteActions></span>
</div>
<SharePoint:ScriptBlock runat="server">
var g_navBarHelpDefaultKey = "HelpHome";
</SharePoint:ScriptBlock>
<SharePoint:DelegateControl id="ID_SuiteBarDelegate" ControlId="SuiteBarDelegate" runat="server" />
</SharePoint:AjaxDelta>

Learning about Suite Navigation web controls for public-facing sites


For public-facing sites, use the following master page markup for the Suite Navigation control. Table 2 lists web controls used in the Suite Navigation code.
Table 2. Suite Navigation web controls for public-facing sites

W EB CO NTR O L D ES CR IPTIO N

SharePoint:DelegateControl Renders an ASP.NET web control. Delegate controls make their candidate controls pluggable and
traceable.

SharePoint:FeatureMenuTemplate Represents a control that creates a template for a drop-down menu.

SharePoint:Menu Displays a menu in an ASP.NET webpage.

SharePoint:MenuItemTemplate Represents a control that creates an item in a drop-down menu.

SharePoint:ScriptBlock Represents a script block control on a page.

SharePoint:SiteActions Represents a template control for the Site Action menu.

SharePoint:SPSecurityTrimmedControl Renders conditionally the contents of the control to the current user only if the current user has
permissions defined in the PermissionString.

Suite Navigation control for public-facing sites

<SharePoint:AjaxDelta runat="server" id="suiteBarDelta" BlockElement="true" CssClass="ms-dialogHidden ms-fullWidth noindex">


<SharePoint:SPSecurityTrimmedControl runat="server" AuthenticationRestrictions="AuthenticatedUsersOnly" EmitDiv="true">
<div id="suiteMenuData" class="ms-hide">
<wssuc:Welcome id="IdWelcomeData" runat="server" EnableViewState="false" RenderDataOnly="true"/>
<span class="ms-siteactions-root" id="siteactiontd">
<SharePoint:SiteActions runat="server" accesskey="<%$Resources:wss,tb_SiteActions_AK%>"
id="SiteActionsMenuMainData"
PrefixHtml=""
SuffixHtml=""
ImageUrl="/_layouts/15/images/spcommon.png?rev=32"
ThemeKey="spcommon"
MenuAlignment="Right"
LargeIconMode="false"
>
<CustomTemplate>
<SharePoint:Menu runat="server" Visible="false"/>
<SharePoint:FeatureMenuTemplate runat="server"
FeatureScope="Site"
Location="Microsoft.SharePoint.StandardMenu"
GroupId="SiteActions"
UseShortId="true"
>
<SharePoint:MenuItemTemplate runat="server"
id="MenuItem_ShareThisSite"
Text="<%$Resources:wss,siteactions_sharethissite%>"
Description="<%$Resources:wss,siteactions_sharethissitedescription%>"
MenuGroupId="100"
Sequence="110"
UseShortId="true"
UseShortId="true"
PermissionsString="ViewPages"
PermissionMode="Any" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_EditPage"
Text="<%$Resources:wss,siteactions_editpage15%>"
Description="<%$Resources:wss,siteactions_editpagedescriptionv4%>"
ImageUrl="/_layouts/15/images/ActionsEditPage.png?rev=32"
MenuGroupId="200"
Sequence="210"
PermissionsString="EditListItems"
ClientOnClickNavigateUrl="javascript:ChangeLayoutMode(false);" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_CreatePage"
Text="<%$Resources:wss,siteactions_addpage15%>"
Description="<%$Resources:wss,siteactions_createpagedesc%>"
ImageUrl="/_layouts/15/images/NewContentPageHH.png?rev=32"
MenuGroupId="200"
Sequence="220"
UseShortId="true"
ClientOnClickScriptContainingPrefixedUrl="OpenCreateWebPageDialog('~siteLayouts/createwebpage.aspx')"
PermissionsString="AddListItems, EditListItems"
PermissionMode="All" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_Create"
Text="<%$Resources:wss,siteactions_addapp15%>"
Description="<%$Resources:wss,siteactions_createdesc%>"
MenuGroupId="200"
Sequence="230"
UseShortId="true"
ClientOnClickScriptContainingPrefixedUrl="GoToPage('~siteLayouts/addanapp.aspx')"
PermissionsString="ManageLists, ManageSubwebs"
PermissionMode="Any" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_ViewAllSiteContents"
Text="<%$Resources:wss,quiklnch_allcontent_15%>"
Description="<%$Resources:wss,siteactions_allcontentdescription%>"
ImageUrl="/_layouts/15/images/allcontent32.png?rev=32"
MenuGroupId="200"
Sequence="240"
UseShortId="true"
ClientOnClickNavigateUrl="~siteLayouts/viewlsts.aspx"
PermissionsString="ViewFormPages"
PermissionMode="Any" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_ChangeTheLook"
Text="<%$Resources:wss,siteactions_changethelook15%>"
Description="<%$Resources:wss,siteactions_changethelookdesc15%>"
MenuGroupId="300"
Sequence="310"
UseShortId="true"
ClientOnClickNavigateUrl="~siteLayouts/designgallery.aspx"
PermissionsString="ApplyThemeAndBorder,ApplyStyleSheets,Open,ViewPages,OpenItems,ViewListItems"
PermissionMode="All" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_Settings"
Text="<%$Resources:wss,siteactions_settings15%>"
Description="<%$Resources:wss,siteactions_sitesettingsdescriptionv4%>"
ImageUrl="/_layouts/15/images/settingsIcon.png?rev=32"
MenuGroupId="300"
Sequence="320"
UseShortId="true"
ClientOnClickScriptContainingPrefixedUrl="GoToPage('~siteLayouts/settings.aspx')"
PermissionsString="EnumeratePermissions,ManageWeb,ManageSubwebs,AddAndCustomizePages,ApplyThemeAndBorder,ManageAlerts,ManageLists,ViewUsageData"
PermissionMode="Any" />
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_SwitchToMobileView"
Visible="false"
Text="<%$Resources:wss,siteactions_switchtomobileview%>"
Description="<%$Resources:wss,siteactions_switchtomobileviewdesc%>"
MenuGroupId="300"
Sequence="330"
UseShortId="true"
ClientOnClickScript="STSNavigate(StURLSetVar2(ajaxNavigate.get_href(), 'mobile', '1'));" />
</SharePoint:FeatureMenuTemplate>
</CustomTemplate>
</SharePoint:SiteActions></span>
</div>
<SharePoint:ScriptBlock runat="server">
var g_navBarHelpDefaultKey = "HelpHome";
</SharePoint:ScriptBlock>
<SharePoint:DelegateControl id="ID_SuiteBarDelegate" ControlId="SuiteBarDelegate" runat="server" />
</SharePoint:SPSecurityTrimmedControl>

See also
Build sites for SharePoint
What's new with SharePoint site development
Menu control overview (ASP.NET)
Retrieve the URL of a Pages library
3/26/2018 • 2 minutes to read Edit Online

Learn how to retrieve the URL for the pages list for a publishing web in a site collection that differs from the current context.

Core concepts to know for retrieving the URL of a Pages list


When developing custom applications for publishing sites, you may notice that the PublishingWeb object model does not expose a way to retrieve the URL for the Pages list of a publishing
web in a site collection that differs from the current context. Although the PublishingWeb class wraps the SPWeb class for instances that have the publishing feature activated, the class is
not intended to be used to instantiate SPWeb objects outside of the current context.
If you need to retrieve the URL for the Pages list for a different web application, you can query the Properties property. Since the PublishingWeb object is the SPWeb object of a publishing
site, you can query the Properties property and write its contents to a console application. If the entry Key = vti_pageslistname, Value = {the URL to the Pages library} is returned in the
console, {the URL to the Pages library} is the Pages list URL.
Table 1. Core concepts for retrieving the URL of a Pages library

AR TICLE TITLE D ES CR IPTIO N

Pages Library A document library that contains all the content pages for a publishing site.

SPWeb Represents a SharePoint Foundation website.

Properties Gets a SPPropertyBag object with metadata for the current website.

SPPropertyBag Stores arbitrary key and value pairs that contain custom property settings.

PublishingWeb Provides publishing behavior for an instance of SPWeb that supports publishing.

Retrieve the URL of a Pages list for a publishing web in a site collection that differs from the current context
This example console application accesses the Properties property, iterates through the collection, and writes each key/value pair to the console.

To query the SPWeb.Properties property for the URL to the Pages list
1. Write the console application.
2. View the output in the console.

Example: Query SPWeb.Properties property for the URL to the Pages list
The application queries the SPPropertyBag object, iterates through its dictionary entries, and writes those entries to the console.

using System;
using System.Collections;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;

namespace Test
{
class Program
{
static void Main(string[] args)
{
using (SPSite site = new SPSite("http://localhost"))
{
using (SPWeb web = site.OpenWeb())
{
SPPropertyBag props = web.Properties;
foreach (DictionaryEntry de in props)
{
Console.WriteLine("Key = {0}, Value = {1}", de.Key, de.Value);
}
}
}
Console.ReadLine();
}
}
}

The output that this application prints to the console varies from website to website, but it might look like the following:

Key = vti_associatemembergroup, Value = 5


Key = vti_extenderversion, Value = 14.0.0.4016
Key = vti_associatevisitorgroup, Value = 4
Key = vti_associategroups, Value = 5;4;3
Key = vti_createdassociategroups, Value = 3;4;5
Key = vti_siteusagetotalbandwidth, Value = 547
Key = vti_siteusagetotalvisits, Value = 9
Key = vti_associateownergroup, Value = 3
Key = vti_defaultlanguage, Value = en-us
Key = vti_pageslistname, Value = {the URL to the Pages list}

See also
Build sites for SharePoint
SharePoint Design Manager branding and design capabilities
5/3/2018 • 2 minutes to read Edit Online

Find links to information about using Design Manager branding and design capabilities in SharePoint. Design Manager in SharePoint provides a new approach for designing websites.
Several new branding and design-based capabilities available in Design Manager enable you to create a compelling look, feel, and behavior for your SharePoint site. Design Manager also
supports importing and exporting a visual design, and can help you ensure a consistent visual experience across all device platforms in your organization.
See these articles for more information about the design and support capabilities included in Design Manager:
Design packages: Learn how to build and export the visual design of a SharePoint site collection as a package.
Device channels: With device channels in SharePoint, you can render a single publishing site in multiple ways by using different designs that target different devices. Learn how to
create a device channel, change a device channel, delete a device channel, and reorder device channels in SharePoint.
Display templates: Learn about display templates, including how they relate to Search web parts, how the templates are structured, how to map properties and use variables and
jQuery, and how to create a custom display template in SharePoint.
Image renditions: Learn how to create, edit, or delete image renditions. An image rendition defines the dimensions that are used to display images in SharePoint publishing sites.
Snippets: A snippet is an HTML representation of a SharePoint component or control such as a navigation bar or a web part. By using the Snippet Gallery in Design Manager, you can
quickly add SharePoint functionality to your HTML master page or page layout.
Themes: Learn about the theming experience in SharePoint and how you can use themes to customize the look and feel of sites.

See also
Build sites for SharePoint
Overview of Design Manager in SharePoint
Overview of the SharePoint page model
SharePoint Design Manager design packages
3/26/2018 • 6 minutes to read Edit Online

Learn how to build and export the visual design of a SharePoint site collection as a package.

Overview of Design Packages


In SharePoint, Design Manager can help web developers and designers build and export the visual design of a SharePoint site collection as a package. This package can easily be distributed
to customers, or other designated groups, for installation on their site collections. This new feature reduces the complexity of transporting designs, and makes it easier for customers to
outsource the visual design of their sites. For example, some usage scenarios can include the following:
New Design —A company with limited web design capabilities might contract a vendor agency to refresh their current SharePoint site with a more modern interpretation. The
agency can create the site and easily package the contents for importing back into the company SharePoint farm.
Cross-Site Publishing —An enterprise IT department using cross-site publishing in SharePoint might have to share a visual design across multiple site collections. They create the
site in-house and want a simple way to transport the design across several SharePoint websites. The design package functionality through Device Manager enables them to export
and import with reduced administrative support and complexity.
This article can help you understand design packaging in SharePoint by providing an overview of package creation, and offers workflow guidance for package exporting and importing. It
also discusses required permissions for specific operations, and design package architecture.

Creating a design package


A user creates a design package, called a SharePoint solution package (.wsp file) on their SharePoint site, through Design Manager in Site Settings. The step for creating the package follows
other Design Manager steps for branding and publishing a SharePoint site, including uploading design files, creating a master page, and editing page layouts. After the site is published, it is a
relatively simple process to create the .wsp file for export.
Figure 1 shows the option in Design Manager for naming and creating the design package.
Figure 1. Exporting a design package

Alternatively, you can import a design package from another SharePoint site collection through Design Manager on the Welcome page, or by choosing Import design package in Site
Settings.
NOTE

For more information about Design Manager and the publishing process, see Overview of Design Manager in SharePoint.
There is a check box for including the search configuration in the design package. You would choose this option if you are designing a site and creating conditional search results, or
controlling the search experience. This configuration contains assets like query rules, result sources, result types, and any schema and ranking models. To ensure that the import of the search
configuration does not fail, there must not be duplicate names for any elements of the search configuration. For example, if you have a query rule in a site collection named
SampleQueryRule, and you import it into another site collection with an existing rule named SampleQueryRule, importing the search configuration fails. To prevent this, you can rename
or delete the query rule on the source or on the target. Result sources, and the schema, also have to be uniquely named. If you want to include a search configuration in your design package,
you must activate the following features at the site level under Manage Site Features before you export the design package:
Search Config Data Content Types
Search Config Data Site Columns
Search Config List Instance Feature
Search Config Template Feature
If you want your design to be published on the target of import, you should publish all design assets or disable major versioning in design-related libraries on the source of export. Design
Manager exports only the most recent version of each asset from the source. For example, if you have version 1.1 of a master page on the source it will be copied to the target as a draft. But,
version 1.0 is not copied. Also, files that are checked out are not exported.

Exporting and importing a design package


You can approach an end-to-end packaging workflow several ways, with much of the approach depending on your objectives and available design resources. You may decide to outsource to
a vendor agency, or do the work in-house if you have internal resourcing. Table 1 provides a sample workflow and exchange between a client and a vendor agency over the design, exporting,
and importing of the design package. It also provides the required permissions for design-related operations, and packaging operations.
Table 1. Sample design package workflow

S TEP ACTIO N D ES CR IPTIO N


S TEP ACTIO N D ES CR IPTIO N

1 Customer contracts vendor agency to create visual design. The vendor designer creates site, based on company requirements.
Note: The vendor designer must have the Designers permission
level to use Design Manager and create and export packages. More
specifically, the Design permission that allows viewing, adding,
updating, deleting, approving, and customizing visual designs.

2 Vendor designer exports visual design into a design package. The vendor designer exports the SharePoint solution package (.wsp
file) after completing the other required branding and publishing
steps.
The design package is delivered to the customer via a secure
channel.

3 Customer imports visual design into their specified SharePoint site The customer receives the design package via a secure channel.
collection. Through the Welcome page in Design Manager or by choosing
Import design package in Site Settings, the customer imports
the .wsp file and applies the design package to the specified site
collection.
Note: The customer must have the Designers permission level to
use Design Manager and import design packages.

Understanding design package contents


Several files are included in the design package .wsp file when it is created through Design Manager. The process exports files from various lists and libraries to form the overall package.
While importing to a site collection, these files are distributed to different locations based on file type. Table 2 details the location and type of files exported during the assembly process.
Table 2. Summary of design package contents and file exportation locations

E X PO R T LO CATIO N E X PO R TED AS S E TS

Document libraries Master Pages Gallery


Themes Gallery
Style Library
Site Assets Library

Content types, fields Content types that inherit from the Page content type

Lists Design Gallery


Composed looks
Device channels
NOTE

In SharePoint, only customized files are included in design packages. The packaging process will not export most of the default non-customized system files.
In SharePoint you cannot uninstall an imported design package, and you should never attempt to deactivate a design package through the solution gallery. If you do, page layout content
types are removed and users may not be able to create subsites. To recover from this state, you should perform the following steps where site A= the original site collection, site B = the site
collection with the deactivated design package (bad state), and site C = a new, blank site collection that you have created:
1. Export a design package from site A
2. Import the design package to site C
3. Export a design package from site B
4. Import the design package to site C
5. Export the design package from site C
6. Import the design package to site B
Any created device channels, and their configurations, are also imported when the design package is unloaded. But, you have to re-associate master pages to specified device channels
because these mappings will not be configured.
When importing a design package, an alternate CSS URL is not set, even if one was configured on the source of export. CSS classes should be stored in an external file in the Master Page
Gallery and not in the master page file itself.

See also
Develop the site design in SharePoint
Overview of Design Manager in SharePoint
What's new with SharePoint site development
SharePoint Design Manager device channels
3/26/2018 • 17 minutes to read Edit Online

Learn about, plan and configure a device channels experience on a SharePoint site.

Introduction to device channels


Browsing the web on a mobile device is now so common that a SharePoint site must be optimized for readability and ease of use on smartphones and other mobile devices such as tablets.
With device channels in SharePoint, you can render a single publishing site in multiple ways by using different designs that target different devices. This article can help you plan for using
the device channels feature in SharePoint. It provides a detailed overview of the feature itself, and provides the necessary information for creating a device channel. Also, after reading this
article, you'll know what device channels you need to implement, and how to implement those channels.
Device channels are available only for SharePoint publishing sites. Before you implement device channels, you should already have a general understanding of the parts of a SharePoint site,
how a SharePoint page is put together, and a general understanding of design manager. For more information about the SharePoint page model, including master page and page layouts, see
Overview of the SharePoint page model. For more information about design manager, see Overview of Design Manager in SharePoint.

What is a device channel?


A device channel is part of the SharePoint publishing infrastructure that enables you to render certain site content, style your content, and even change images—while maintaining the same
URL across a pool of different devices. Compared to the desktop version of the SharePoint site, a mobile rendering can be formatted with a smaller width, have better navigation with wider
touch targets, and show a reduced amount of information for better usability. You can create a single site, and author and edit the content a single time for all your different mobile devices.
When a user browses a SharePoint site from a mobile device such as a smartphone or tablet, the mobile browser submits to the site an HTTP GET request that includes a user agent string.
This string contains information about the type of device that is trying to access the site. Based on that device substring, the device browser can be redirected to a specific master page view.
For example, if you have a collection of Windows Phone and iPad devices, you can provide each pool with a unique rendering of the SharePoint publishing site by using device channels.
These device channels can each be given a different master page and thus CSS file to give users a more optimal viewing experience. Figure 1 shows the use of two device channels to provide
two unique site renderings for a phone and tablet device.
Figure 1. Using device channels across different device platforms

You can create and configure a device channel from the Site Settings menu under the Look and Feel section, or alternatively through the Design Manager option in the same section.
When you create a device channel item, there are five required and optional fields to supply for the process. Table 1 lists these fields and describes what type of information must be
provided.
Table 1. Required and optional fields for creating a device channel

FIELD R EQ U IR ED V ALU E V ALU E

Name Yes This is the name of your design channel. It can be a friendly name to
identify the channel.

Alias Yes The alias name enables you to identify your device channel in code,
device channel panels (discussed later in this article), previews, and
other contexts.
Important: If you later change the channel alias, you'll have to
manually update master page mappings, device channel panels, and
any custom code or markup.

Description No A field for supplying a general description for the device channel.

Device Inclusion Rules Yes A field for supplying the user agent substring such as Windows
Phone OS. Device redirection to a specific master page depends on
what is entered for this value. For more information about what
values to supply in this field, see the section User agent substrings
and device channel rankings in this article.
FIELD R EQ U IR ED V ALU E V ALU E

Active No Selecting this check box activates your device channel. If you are
working on a live site, you should not activate the channel before
you have finished designing it. For testing, you can use the query
string ?DeviceChannel=alias within a browser to preview your
site for a specific channel.
NOTE

For more information and steps for creating a device channel, see the Create a device channel section of this article.
After a device channel is created and activated, device redirection to a specific master page, for example a mobile version, is possible. The next step is to specify what master page should be
displayed for mobile devices at the site level, through either the Site Master Page Settings or by using the Publish and Apply option in Design Manager.
Figure 2. Setting master pages for mobile device viewing and default desktop viewing

As seen in Figure 2, you can assign a specific master page for regular desktop viewing of the site, and a mobile master page for device redirection. Whether the mobile or default master
pages are rendered depends on the configured, active device channel. Specifically, it depends on the device inclusion rule substring that is supplied in the device channel creation process.

User agent substrings and device channel rankings


When creating a device channel, you are asked to supply a user agent substring that is responsible for device redirection to a specified master page. If you do not provide this value in the
Device Inclusion Rules field, device redirection is not possible and the channel cannot be created. Table 2 provides some sample user agent substring values that can be used when you are
creating a device channel.
Table 2. Sample user agent substring values

D EV ICE U S ER AG ENT S U B S TR ING (S )

Windows Phone Windows Phone OS 7.5 (Specific to Windows Phone 7.5 phone.)
Windows Phone OS (Generic substring for all Windows Phone versions.)

iPhone iPhone

iPad iPad

Android Android

In the Device Inclusion Rules field, you add just the substring value or values for the devices that you want to include.
IM P O R T A N T

User agent substring values differ from device manufacturer to device manufacturer, and possibly throughout a set of similarly branded devices, as seen above with Windows Phone. To
achieve successful traffic redirection to a specific pool, you must provide a unique identifier for the user agent substring. For more information about how to isolate a substring across
different devices, see the Planning your device channels experience section of this article.
After they are created, device channels are ordered and stored in a list. It is possible to support up to 10 device channels per site in SharePoint, so it may be necessary to rank your channels
for proper traffic routing. You should order the most specific rules at the top for higher priority. For example, you may have multiple OS versions for Windows Phone devices in your
organization, and want a unique master page rendering for Windows Phone 7.5 devices. All other Windows Phone devices would receive another mobile master page view. Table 3 shows
two ordering schemes that could be applied, and the effects on the routing decision.
NOTE

For more information about how to reorder device channels see the Create a device channel section of this article.
Table 3. Sample ordering of device channels

O R D ER 1 (D EV ICE CHANNELS ) O R D ER 2 (D EV ICE CHANNELS )

device channel 1—Windows Phone OS 7.5 device channel 1—Windows Phone OS

device channel 2—Windows Phone OS device channel 2—Windows Phone OS 7.5

device channel 3—Default device channel 3—Default

If you choose Order 1, where the device inclusion rule substring is set to Windows Phone OS 7.5, a user browsing to your site with a Windows Phone 7.5 device is directed to device
channel 1. A user with any other Windows Phone version is directed to device channel 2, and any non-Windows Phone user receives channel 3. But, if you choose Order 2, which prioritizes
the generic Windows Phone OS substring, all Windows Phone traffic is directed to device channel 1. Device channel 2 isn't invoked for Windows Phone 7.5 devices because of the
prioritization and generic nature of device channel 1. If you create multiple device channels, it is important to understand how order and ranking affect traffic redirection for your device
pools.
NOTE

For more information and steps for ordering device channels, see the Change the order of device channels section of this article.

Device channel panels


A device channel panel is a container that can be used on a master page or page layout when you want specific content to render based on the alias of a given device channel, or set of
channels. For example, you may have a web part or control that you want revealed only on the desktop view of the site, and not on any mobile device. The device channel panel can enable
you to encapsulate this web part in code, and enable you to render it only through a designated device channel. A major benefit of device channel panels over using Display:None in a CSS
class is that the content inside a device channel panel is not rendered at all on the non-specified channels. Also, device channel panels can be used to reduce the rendered size of a page for
devices by eliminating bulky content. This provides a way to increase site responsiveness on bandwidth-constrained devices.
A device channel panel snippet can be produced from the snippet gallery when you are previewing a master page or page layout. The following HTML example shows how to create a device
channel panel. In this scenario, there is a paragraph of inserted text that is rendered only for a specific device channel. The attribute IncludedChannels is where you specify the alias of your
configured device channel. Again, an alias is a name that is assigned during the device channel creation process and can be referenced in your code.

<div data-name="DeviceChannelPanel">
<!--CS: Start device channel panel snippet.-->
<!--SPM:<%@Register Tagprefix="Publishing" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=62T
<!--MS:<Publishing:MobilePanel runat="server" IncludedChannels="DEFAULT">-->
<p>
This paragraph of content shows up only in the default channel, which means that you can use the same page layout for all your different devices. You can put HTML content, page fields, web parts,
</p>
<!--ME:</Publishing:MobilePanel>-->
<!--CE: End Device Channel Panel Snippet-->
</div>

If you want the content to be displayed on more than one channel, the aliases should be separated by commas within the quotation marks: IncludedChannels="alias1, alias2" For more
information about the device channel panel container, see Overview of the SharePoint page model. For more information about using Design Manager snippets, see SharePoint Design
Manager snippets.

Planning your device channels experience


There are several questions and pieces of information that have to be answered and collected before you implement device channels in your organization. This section helps you plan for
using device channels by asking relevant questions about your device and usability needs, and offering guidance on your approach for the feature. The questions in this section are intended
to be read in order and not individually.

What site experience am I trying to achieve across the desktop and my devices?
Like most organizations, there will be unique usability requirements based on your organization's needs. The ideal goal is to make sure that this experience is translated optimally to any type
of form factor, whether a desktop or device. But, despite that broad generalization, it is still a complex process, especially when you deal with varying resolutions and less screen area for
touch interaction. Also, perhaps some phones in your inventory require unique UI customization that others cannot or should not have. Web development can be difficult in these scenarios,
and more so if you do not have the luxury of assigning a single master page across several device brands.
One first task should be to write down what has to be achieved functionally to create a successful user experience across devices. What does the user base expect to be able to do with your
SharePoint publishing site on their desktop, phone, tablet? You may discover various issues including possible limitations, and individual device considerations that have to be considered.
Record all of this information in any format; it will help you understand your specific objectives with the device channel feature, and help you answer successive questions listed below, like
what devices you are willing to support and how many device channels you should implement.
Also, it is important to remember some key functions the device channels feature provides that can solve various planning issues. Examples include the support of several device channels for
unique master page mappings to multiple devices. Also, the use of device channel panels to selectively display various content elements across different device pools.

How many device channels do you need?


You can have a maximum of 10 device channels including the default configured on a specific site for an on-premises installation, and a total of two device channels when using SharePoint
Online. For your organization, it might be as simple as creating a single device channel, applying several device inclusion rules representing all the devices, and redirecting to a specific
master page. Ideally, it is optimal to have as few device channels as possible. However, based on device differentiation or unique HTML/CSS customization, having only one channel might
not an option, and you might require additional device channels.
To determine the number of device channels, you should reference the information collected about your site goals across devices, devices that you plan to support, and the level of required
customization from the previous questions. Using this information, create a list of the channels you want to implement. Can one mobile master page attached to one device channel address
all requirements? Or do you need a separate master page association for tablets, and so multiple channels? This is also an appropriate time to name your channels, and think of a suitable
alias name for each channel so that it can be referenced in code. If you change the channel alias later, you will have to update all references to it.

Where is a list of all of the device substrings I can use?


There are some generic manufacturer user agent substrings that you can use for device redirection such as Windows Phone OS or iPhone, as shown in Table 2. The substring needed in the
Device Inclusion Rules field is usually a subset of the much larger user agent string provided when the device connects to the site. It is recommended that you find a device-specific string
by locating it on the manufacturer or software provider website, or through a general web-based search. Sometimes a specific, versioned substring might be difficult to isolate given
similarities in user agent string construction. Table 4 provides two sample user agent strings, for Windows 8 desktop and for a tablet device.
NOTE

The below strings are examples, and not genuine strings for the covered Windows devices. They are provided to illustrate the point of isolating a substring if needed.
Table 4. Differentiating between user agent strings

D EV ICE U S ER AG ENT S TR ING

Windows 8 desktop (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)

Windows 8 tablet (example) (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; touch)

These strings are very similar in format; the only difference is the inclusion of touch for the Windows 8 tablet example. For this particular scenario, if you wanted a specific master page
rendering for the tablet device, you would supply touch as your substring when you are creating a device inclusion rule. The key, when you deal with situations such as this, is to find a point
of differentiation between similar strings. If you were to create a device channel with a device inclusion rule using a common value such as MSIE 10.0, there would be no way to differentiate
between the desktop and the tablet.

Do I need to use device channel panels?


No. Device channel panels are helpful when you want to allow, adjust, or prevent the rendering of some UI-based element across different device experiences. For example, you may have
text or a control that you want to appear on iPhone that you wouldn't want to appear on an Android device. A reason could be that the form factor has a smaller screen size and usability
would be affected. Regardless of the condition, device channel panels can be assigned to an alias of a created device channel and provide the flexibility needed for this level of differentiation.
A good question to ask is would there be a reason for not applying a single master page to a group of different devices in my organization? If so, a device channel panel may be the best
option to get a more granular development experience that caters to specific device needs. Also, you can use device channel panels to add channel-specific CSS to page layouts.

Can I use cookies to select a device channel?


Yes, you can force or override device channel selection through the use of cookies. To do so, you have to create a browser cookie named deviceChannel, and provide it with the alias of your
specified device channel. Also, device channels can set a JavaScript variable called effectiveDeviceChannel that contains the current channel alias. This variable can be used to show which
channel is currently being used. To make your site emit the JavaScript variable, add this property to the root web property bag:

key = PublishingInformationControlIncludeEffectiveDeviceChannel, value = true

This variable can also be used to affect the rendering of content, and web parts, on a page.

Create a device channel


Use this procedure to create a new device channel.

To create a device channel


1. Start Design Manager. (For example, on the Settings menu, choose Design Manager.)
2. In the numbered list, select Manage Device Channels.
3. On the Design Manager: Manage Device Channels page, choose Create a channel.
4. On the Device Channels - New Item page, in the Name text box, enter a name for the device channel.
5. In the Alias text box, enter an alias for the device channel. The alias must be alphanumeric characters and may not contain spaces. You will use the alias to refer to the device channel
in code and in other contexts.
6. In the Description text box, enter a brief description of the devices or browsers that the channel will capture.
7. In the Device Inclusion Rules text box, enter the user agent substrings for the channel. A request for a webpage will use this channel if any of the strings that you provide match the
user agent string of the request.
8. If you are ready to make the channel available to render pages, select the Active check box.
9. Choose Save.

Change a device channel


Use this procedure to change an existing device channel.
NOTE

You cannot modify the Default channel.

To change a device channel


1. Start Design Manager. (For example, on the Settings menu, choose Design Manager.)
2. In the numbered list, select Manage Device Channels.
3. On the Design Manager: Manage Device Channels page, choose Edit or reorder existing channels.
4. In the Device Channels list, select the device channel that you want to change, and then, on the ITEMS tab, choose Edit Item.
5. To change the name of the device channel, enter a new name in the Name text box.
6. To change the alias of the device channel, enter a new alias in the Alias text box.
NOTE

If you change a device channel's alias, you must manually change the alias in other places where you use it. For example, you must manually change the alias in custom code or
markup, and you must manually change the mappings between the device channel and master pages.
7. To change the description of the device channel, enter a new description in the Description text box.
8. To change the device inclusion rules, edit the strings in the Device Inclusion Rules text box.
9. To make the device channel active, select the Active check box. To make the channel inactive, clear the Active check box.
10. Choose Save.

Delete a device channel


Use this procedure to delete an existing device channel.
NOTE

You cannot delete the Default channel.

To delete a device channel


1. Start Design Manager. (For example, on the Settings menu, choose Design Manager.)
2. In the numbered list, select Manage Device Channels.
3. On the Design Manager: Manage Device Channels page, choose Edit or reorder existing channels.
4. In the Device Channels list, select the device channel that you want to delete.
5. On the ITEMS tab, choose Delete Item.
6. Choose OK.

Change the order of device channels


Use this procedure to change the order of device channels.

To reorder device channels


1. Start Design Manager. (For example, on the Settings menu, choose Design Manager.)
2. In the numbered list, select Manage Device Channels.
3. On the Design Manager: Manage Device Channels page, choose Edit or reorder existing channels.
4. On the ITEMS tab, choose Reorder Channels.
5. On the Device Channel Reordering page, choose the channel whose order you want to change, and then select Move Up or Move Down.
6. After the channels are ordered the way that you want them, choose OK.

See also
Develop the site design in SharePoint
Overview of the SharePoint page model
Overview of Design Manager in SharePoint
SharePoint Design Manager display templates
5/3/2018 • 12 minutes to read Edit Online

Learn about display templates, including: how they relate to Search web parts, how the templates are structured, how to map properties and use variables and jQuery, and how to create a
custom display template in SharePoint.

Introduction to display templates


Display templates in SharePoint are templates used in web parts that use search technology (referred to in this article as Search web parts) to show the results of a query made to the search
index. Display templates control which managed properties are shown in the search results, and how they appear in the web part. Each display template is made of two files: an HTML
version of the display template that you can edit in your HTML editor, and a .js file that SharePoint uses.
NOTE

Only Search web parts can use display templates. The Content Query web part is not search-driven, and so does not use display templates.
You can view existing display templates in Design Manager, but you don't create them in Design Manager the way that you create master pages and page layouts. Instead, you:
Open your mapped network drive to the Master Page Gallery.
Open one of the four folders in the Display Templates folder.
NOTE

The folder you choose depends on the type of display template you want to use. For example, if your site uses cross-site publishing, copy a display template from the Content Web
Parts folder. For more information, see Display template reference in SharePoint.
Copy the HTML file for an existing display template that's similar to what you want. The exact location that you copy the file to does not matter, as long as it is in the Master Page
Gallery.
Open and modify your copy in an HTML editor.
By using an existing display template as a starting point for a new display template, you can benefit from helpful information about the customization process in the comments of the default
display templates, and you have a framework in place for basic tasks such as mapping input fields. It also guarantees that your templates use the correct basic page structure.
When you create a display template by copying the HTML file for an existing display template in the Display Templates folder in the Master Page Gallery:
A .js file that has the same name is created in the location where you copied the HTML file.
All markup required by SharePoint is added to the .js file so that the display template displays correctly.
The HTML file and the .js file are associated, so that any later edits to the HTML file are synched to the .js file when the HTML file is saved.
NOTE

The syncing goes in one direction only. Changes to the HTML display template are synched to the associated .js file. Unlike master pages and page layouts, when working with display
templates you can't choose to work only with the .js file by breaking the association between the files. You must enter all the HTML and JavaScript in the HTML file.

Understanding the relationship between display templates and Search web parts
There are two primary types of display templates:
Control templates determine the overall structure of how the results are presented. Includes lists, lists with paging, and slide shows.
Item templates determine how each result in the set is displayed. Includes images, text, video, and other items.
For more information about these and other display templates, see Display template reference in SharePoint.
After you add a Search web part (such as the Content Search web part) to a page, to configure the web part, you select both a control display template and an item display template, as
shown in Figure 1.
Figure 1. Tool pane of Content Search web part

The control display template provides HTML to structure the overall layout for how you want to present the search results. For example, the control display template might provide the
HTML for a heading and the beginning and end of a list. The control display template is rendered only once in the web part.
The item display template provides HTML that determines how each item in the result set is displayed. For example, the item display template might provide the HTML for a list item that
contains a picture, and three lines of text that are mapped to different managed properties associated with the item. The item display template is rendered one time for each item in the result
set. So, if the result set contains ten items, the item display template creates its section of HTML ten times.
When used together in this way, the control display template and the item display template combine to create a cohesive block of HTML that is rendered in the web part, as shown in Figure
2.
Figure 2. Combined HTML output of a control display template and item display template

For more information about display templates, see the "Search-driven Web Parts and display templates" section in Overview of the SharePoint page model.

Understanding the display template structure


The HTML file that is used for a display template is a fully-formed HTML document, but it does not represent a full HTML webpage. SharePoint converts the pieces of the display template
HTML file into JavaScript. This section describes the four major sections of a display template.

Title tag
The text in the <title> tag in a display template file is used as the display name in the Display Templates section of the web part edit pane when the Search web part is in edit mode. The
following example is for the item display template named Item_Picture3Lines.html:

<title>Picture on left, 3 lines on right</title>

Header properties
Immediately after the <title> tag, there is a set of custom elements bounded by the following markup:

<!--[if gte mso 9]><xml>


<mso:CustomDocumentProperties>

</mso:CustomDocumentProperties>
</xml><![endif]-->

These elements and their properties provide important information to the SharePoint environment about the display template. Table 1 describes the custom properties that are used in
display templates.
NOTE

Not all custom properties are used in every display template. Also, some properties can be changed by editing the display template file properties in Design Manager.
Table 1. List of CustomDocumentProperties entries

PR O PER T Y D ES CR IPTIO N

TemplateHidden Boolean value that indicates whether to hide the display template from the list of available templates in
the web part. This value can be changed in the display template file properties.

ManagedPropertyMapping Maps fields exposed by search result items into properties available for JavaScript. Used only in item
templates.

MasterPageDescription Provides a friendly description of the display template. This is shown to users in the SharePoint editing
environment. This value can be changed in the display template file properties.

ContentTypeId The ID of the content type associated with the display template.

TargetControlType Indicates the context in which the display template is used. This value can be changed in the display
template file properties.

HtmlDesignAssociated Boolean value that indicates whether a display template HTML file has a .js file associated with it.

HtmlDesignConversionSucceeded Indicates whether the conversion process was successful. This value is automatically added to the file by
SharePoint, and is used only in custom display templates.

HtmlDesignStatusAndPreview Contains the URL to the HTML file and the text for the Status column (either Conversion successful or
Warnings and Errors). This value is automatically added to the file by SharePoint, and is used only in
custom display templates.

Script block
Inside the <body> tag, you can see the following <script> tag:

<script>
$includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Language Files/{Locale}/CustomStrings.js");
</script>

By default, this line is included in all display templates. You can add more lines of code inside the <script> tag to reference CSS files or other JavaScript files outside your main display
template HTML file. Table 2 shows examples for how to include other resources.
Table 2. Examples for including external resources in the <script> tag
IF YO U W ANT TO INCLU D E THE FO LLO W ING : U S E THE FO LLO W ING CO D E:

A JavaScript file that is part of the current site collection $includeScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Content
Web Parts/MyScripts.js");

An external JavaScript file $includeScript(this.url, "http://www.contoso.com/ExternalScript.js");

A CSS file that is part of the current site collection $includeCSS(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Content Web
Parts/MyCSS.css");

A CSS file that is in a location relative to the current display template $includeCSS(this.url,"../../MyStyles/MyCSS.css");

NOTE

If Content Approval is required for items in the Master Page Gallery, all resource files (including CSS and .js files) must be published before they are available to master pages and page
layouts. For more information, see Require approval of items in a site list or library.

DIV block
Following the <script> tag is a <div> tag with an ID. By default, the ID for this <div> tag matches the name of the HTML file. Any HTML or code that you want the display template to
provide must be included inside this <div> tag. But, the tag itself is not included in the markup that is rendered on the webpage at run time.
NOTE

If you want to assign a CSS style or an ID to the block of HTML that is rendered on the page at run time, you can add a new tag inside the first <div> tag. You can also assign a CSS style or
an ID to the HTML that surrounds the variable _#= ctx.RenderGroups(ctx) =#_ in the control template. The variable _#= ctx.RenderGroups(ctx) =#_ is used to render the HTML that
surrounds the query results that are rendered by the item template.
In the first <div> tag you'll see code inside comment blocks that begin with <!--#_ and end with _#-->. You use JavaScript code inside these blocks, and HTML outside the blocks. You can
also use these blocks to control the HTML with conditional statements. To do this, use a comment block with the conditional statement and opening bracket, followed by HTML, followed by
another comment block with the closing bracket. In the following example, the anchor tag is rendered on the page only if the value for the linkURL object is not empty.

<!--#_
if(!linkURL.isEmpty)
{
_#-->
<a class="cbs-pictureImgLink" href="_#= linkURL =#_" title="_#= $htmlEncode(line1.defaultValueRenderer(line1)) =#_" id="_#= pictureLinkId =#_">
<!--#_
}
_#-->

Mapping input properties and getting their values


The header section of an item display template has a custom document property named ManagedPropertyMapping. This property takes the managed properties that are used by search
and maps them to values that can be used by the display template. The property is a comma-delimited list of values that uses the following format: ' property display name'{ property name}:'
managed property'. For example, 'Picture URL'{Picture URL}:'PublishingImage;PictureURL;PictureThumbnailURL' .
Let's look at the format in more detail:
property display name is the property name that shows in the web part editing pane when the display template is selected.
property name is an identifier that uses localized string resources to look up the name of the managed property. It is also the value that appears in the Property Mappings section of
the web part settings menu. When you edit the settings for a web part, you can change this value to change what managed property is associated with the field that appears in the
web part.
managed property is a string of one or more managed properties, separated by semicolons. At run time, the list is evaluated from left to right, and the first value that matches the
name of a managed property of the current search item will have its value mapped to this slot. This enables you to write a display template that can work with multiple item types and
that can use consistent rendering if compatible properties are present.
After you map a property, you can get its value in script by using the following code: var pictureURL = $getItemValue(ctx, "Picture URL");

The second parameter that is passed to $getItemValue() must match the property display name in single quotes used in the ManagedPropertyMapping element. In this example,
Picture URL is the property name that is passed to $getItemValue().
This code returns a value information object ( valueInfoObj). This object contains a raw representation of the input value, together with the value with a default encoding applied to it.
You can use variables within the sections of JavaScript as you typically would, to manipulate variables and create HTML strings to be rendered on the page at run time. But, to reference
variables declared in the script directly in the HTML, you must use the following format: #= _variableName =#. For example, to use the variable pictureURL as the value for an image, you
use the following HTML: `<img src="#= pictureURL =#_" />`

Using jQuery with display templates


You can use jQuery with your display templates. But, be aware of two important factors:
To include the jQuery libraries in your display template, follow the directions described in the Script block section, earlier in this article.
If you use ID selectors in jQuery, use the following code to create a variable for the ID: var containerQueryId = '#' + '_#= containerId =#_';

Use the following code to reference the selector in jQuery: $('_#= containerQueryId =#_')

Create a display template


Before you can create a display template by using the following procedure, you must have a mapped network drive that points to the Master Page Gallery. For more information, see How
to: Map a network drive to the SharePoint Master Page Gallery.

To create a display template


1. Using Windows Explorer, open the mapped network drive to the Master Page Gallery.
2. Open the Display Templates folder, and then open the Content Web Parts folder.
3. Copy the HTML file for a display template that is similar to what you want to create. For a list of the default display templates and their descriptions, see Display template reference in
SharePoint.
At this point, SharePoint copies the HTML file into a .js file that has the same name. For example, if the copied HTML file is named Item_Picture3Line_copy.html, a corresponding .js
file named Item_Picture3Lines_copy.js is also created. If you choose to rename the file, the corresponding .js file name also changes.
4. To customize the display template, edit the HTML file that resides on the server by using an HTML editor to open and edit the HTML file in the mapped drive. Each time that you save
the HTML file, any changes are synched to the associated .js file.
5. Browse to your publishing site.
6. In the upper-right corner of the page, choose Settings, and then choose Design Manager.
7. In Design Manager, in the left navigation pane, choose Edit Display Templates. Your HTML file now appears with a Status column that shows one of two statuses:
Warnings and Errors
Conversion successful
NOTE

Unlike master pages and page layouts, you can't use the preview page to see a live server-side preview of your display template. To preview the display template, you must add a
Content Search web part to a page, and then apply the display template in the Content Search web part edit pane. If there are any errors in the display template, the Content Search
web part displays an error message. Errors must be fixed before the display template can display correctly.
1. To fix any errors, edit the HTML file that resides on the server by using an HTML editor to open and edit the HTML file on the mapped drive. Save the display template, and then reload
the page that contains the Content Search web part that uses the display template.

See also
Overview of Design Manager in SharePoint
Develop the site design in SharePoint
How to: Convert an HTML file into a master page in SharePoint
How to: Create a page layout in SharePoint
SharePoint Design Manager branding and design capabilities
SharePoint Design Manager image renditions
3/26/2018 • 11 minutes to read Edit Online

Learn how to create an image rendition, how to add it to a page, and how to crop it. An image rendition defines the dimensions that are used to display images in SharePoint publishing sites.
Image renditions enable you to display differently sized versions of an image on different pages in a publishing site, based on the same source image. When you create an image rendition,
you specify the width and/or height for all images that use that image rendition. The image renditions are available for every image that is uploaded to a library in that site collection. For
example, designers can create an image rendition to display thumbnail images and another image rendition to display banner images. When an image is added to a page, the author can
specify the image rendition to use on that image. Authors can also crop the image rendition to specify the portion of the image to use in the image rendition. The correct image size is
displayed when the page is rendered.
Image renditions enable you to render a single image in multiple ways. An image can be displayed in various sizes or with different cropping. The first time that an image is requested,
SharePoint Server uses the specified image rendition to generate the image. When a user views a SharePoint site, the correctly sized version of the image is downloaded to the client
computer. This reduces the size of the file that is downloaded to the client, which improves site performance.

Prerequisites for managing image renditions


Because image renditions have dependencies on other features in SharePoint, make sure that you meet the prerequisites in this section before you perform the procedures in this topic.
Prerequisites include:
A publishing site collection The site collection where you are adding image renditions must have been created by using the Publishing Portal or the Product Catalog site collection
template. Or, publishing features must be enabled on the site collection where you want to use image renditions. For more information, see Overview of publishing to Internet,
intranet, and extranet sites in the TechNet Library.
A configured BLOB cache The disk-based BLOB cache controls the caching for binary large objects (BLOBs), such as frequently used image, audio, and video files, and other files
that are used to display webpages, such as .css files and .js files. The BLOB cache must be enabled on each front-end web server where you want to use image renditions. If the BLOB
cache is not enabled, the original image is always used. For more information, see Configure cache settings for a Web application in the TechNet Library.
An asset library (recommended) You can use the Asset Library template to set up a library that makes it easy to store, organize, and find rich media assets, such as image, audio, or
video files. For more information, see Set up an Asset Library to store image, audio, or video files on Office.com.

Create an image rendition


When an image rendition is created, SharePoint creates a unique ID that identifies that image rendition. An image is generated when SharePoint Server first receives a request for the image
rendition.

To create an image rendition


1. Verify that the user account that is performing this procedure has, at minimum, Design permissions to the top-level site of the site collection.
2. In a browser, go to the top-level site of the publishing site collection.
3. Choose the Settings icon. On the Site Settings page, in the Look and Feel section, choose Image Renditions.
NOTE

The Image Renditions page can also be opened from the default home page of the publishing site. In the I'm the Visual Designer section, choose Configure image renditions.
4. On the Image Renditions page, choose Add new item.
5. On the New Image Rendition page, in the Name box, enter a name for the rendition. For example, enterThumbnail_Small.
6. In the Width and Height text boxes, enter the width and height, in pixels, of the rendition, and then choose Save.

Edit an image rendition


When an image rendition is edited, the new dimensions take effect the next time that the image is requested. If there is an image that was generated previously from the image rendition, the
image is regenerated with the new dimensions the next time that the image is requested.

To edit an image rendition


1. Verify that the user account that is performing this procedure has, at minimum, Design permissions to the top-level site of the site collection.
2. In a browser, go to the top-level site of the publishing site collection.
3. Choose the Settings icon. On the Site Settings page, in the Look and Feel section, choose Image Renditions.
NOTE

The Image Renditions page can also be opened from the default home page of the publishing site. In the I'm the Visual Designer section, choose Configure image renditions.
4. On the Image Renditions page, choose the image rendition that you want to edit.
5. On the Edit Image Rendition page, modify the name, width, or height of the image rendition.
NOTE

To use the same image rendition on all webs within the same site collection, go to the image file directly and edit renditions from there.

Add an image rendition


When you add an image to a page in a SharePoint publishing site, you can specify the image rendition to use for that image. When the page is rendered in a browser, the correct image size is
displayed. You can specify the image rendition in the Rich Text Editor, in an image field control, or in the image URL.

Specify the image rendition by using the Rich Text Editor


When an image is inserted in a page, you can specify the image rendition to use so that the correct image size is displayed when the page is rendered. You can specify the image rendition in
the Rich Text Editor only for images that are stored in the same site collection as the page that is being edited.

To specify an image rendition by using the Rich Text Editor


1. On the Page tab, choose Edit.
2. Choose the Settings icon, and then choose Add a page.
3. In the Add a page window, enter a name for the page, and then choose Create.
4. Place the pointer in the Page Content field.
5. On the Insert tab, choose Picture, and then choose From SharePoint.
6. Locate the image that you want to add to the page, select the image, and then choose Insert. The image will be displayed at full size.
7. On the Design tab, in the Select group, choose Pick Rendition, and then select an image rendition. The image will display according to the size specified for the image rendition.
NOTE

The Pick Rendition command is available only for images that are stored in the same site collection as the page that is being edited.
8. If you want to crop the image rendition, choose Pick Rendition, and then choose Edit Renditions.
For more information about cropping image renditions, see the Crop an image rendition section of this article.

Specify the image rendition in the image URL


You can specify the image rendition by adding the RenditionID, Width, or Height parameters to the image URL.
RenditionID Use the RenditionID parameter to specify the ID of the image rendition to use.
Width Use the Width parameter to specify the width, in pixels, of the image rendition. SharePoint Server tries to find an image rendition with the specified width. Next, SharePoint Server
tries to find an image rendition that has a width that is larger than the specified width. If there are multiple image renditions that match this criterion, SharePoint Server uses the image
rendition with the closest width to what was specified. If there is no image rendition with a width that is equal to or larger than the specified width the original image is used.
Height Use the Height parameter to specify the height, in pixels, of the image rendition. SharePoint Server tries to find an image rendition with the specified height. Next, SharePoint Server
tries to find an image rendition that has a height that is larger than the specified height. If there are multiple image renditions that match this criterion, SharePoint Server uses the image
rendition with the closest height to what was specified. If there is no image rendition with a height that is equal to or larger than the specified height the original image is used.
Width and Height If both the Width parameter and the Height parameter are specified, SharePoint Server tries to find an image rendition with the specified width and height. Next,
SharePoint Server tries to find a rendition that is closest to the width/height ratio specified. If there are multiple matches, the image rendition that has the closest larger width/height ratio to
the requested size is chosen.
NOTE

If the image URL includes the RenditionID parameter and Width and Height parameters, the Width and Height parameters are ignored.
The following example shows how to use the RenditionID parameter:

<img src="/sites/pub/Assets/Lighthouse.jpg?RenditionID=2" />

The following example shows how to use the Width and Height parameters:

<img src="/sites/pub/Assets/Lighthouse.jpg?Width=400&amp;Height=200" />

Specify the image rendition in the image field control


A developer can specify the image rendition to use in the image field control. Use the RenditionId property to set the ID of the image rendition. For more information, see RenditionId.

Crop an image rendition


By default, an image rendition is generated from the center of the image. You can adjust the image rendition for individual images by cropping the portion of the image that you want to use.
For example, if a photo shows a lighthouse scene but the image rendition does not show the whole lighthouse (see Figure 1), you can change the selected image area so that the whole
lighthouse is displayed (see Figure 2).
Figure 1. Original image rendition

Figure 2. Cropped image rendition


An image rendition can be cropped in the asset library or on a page, without changing the original image.
Image renditions can be cropped in the following ways:
Designers can crop an image rendition in the asset library. For example, a designer may want to specify how an image appears in the thumbnail image rendition.
Authors can crop an image rendition when they insert an image into a page. This enables them to customize the look of their page. When an author crops an image rendition, this also
changes the image rendition for that image. Anyone who uses that image rendition sees the cropped image.
NOTE

An author can crop an image rendition only when the original image is stored in a library that is in the same site collection as the page that is being edited. For example, in cross-site
publishing scenarios, an author can crop the image rendition only if the image is stored in the same site collection as the catalog content. Otherwise, the image rendition must be
cropped in the asset library.

Crop an image rendition in the asset library


Designers can crop an image rendition in the asset library.

To crop an image rendition in the asset library


1. Verify that the user account that is performing this procedure has Write permissions to the asset library where the image is located.
2. In a browser, go to the asset library.
3. Position the pointer in the lower-right corner of the image whose rendition you want to change, select the ellipses ( ...) that appears, and then choose EDIT RENDITIONS.
NOTE

You can also open the Edit Renditions page by placing the pointer over the preview image in the asset library, and then selecting the check box that appears at the bottom of the
preview image. Then, on the Design tab, choose Edit Renditions.
The Edit Renditions page displays a preview image for each image rendition that is defined in the site collection.
4. Locate the image rendition that you want to change, and then choose Click to change.
5. In the Crop Rendition window, use the image tool to select the portion of the image that you want to use in the image rendition.
6. Choose Save.
If the image and the page that is being edited are in the same site collection, you also can crop an image rendition by using the Rich Text Editor.

Crop an image rendition on a page


Authors can crop an image rendition when they insert an image into a page. This enables them to customize the look of their page. When an author crops an image rendition, this also
changes the image rendition for that image. Anyone who uses that image rendition sees the cropped image.

To crop an image rendition on a page


1. Verify that the user account that is performing this procedure has Write permissions to the asset library where the image is located.
2. In a browser, go to the SharePoint site that contains the image.
3. On the Page tab, choose Edit.
4. Select the image that you want to crop.
5. On the Image tab of the ribbon, in the Select group, choose Pick Rendition, and then choose Edit Renditions.
The Edit Renditions page displays a preview image for each image rendition that is defined in the site collection.
NOTE

The Pick Rendition command is available only for images that are stored in the same site collection as the page that is being edited.
6. Locate the image rendition that you want to change, and then choose Click to change.
7. In the Crop Rendition window, use the image tool to select the portion of the image to use in the image rendition.
8. Choose Save.

Delete an image rendition


When an image rendition is deleted, that image rendition is no longer generated for images. If a site requests the deleted image rendition, the original image is returned.

To delete an image rendition


1. Verify that the user account that is performing this procedure has, at minimum, Design permissions to the top-level site of the site collection.
2. In a browser, go to the top-level site of the publishing site collection.
3. Choose the Settings icon. On the Site Settings page, in the Look and Feel section, choose Image Renditions.
NOTE

The Image Renditions page can also be opened from the default home page of the publishing site. In the I'm the Visual Designer section, choose Configure image renditions.
4. On the Image Renditions page, locate the image rendition that you want to delete, and then choose Delete.

See also
Develop the site design in SharePoint
SharePoint Design Manager branding and design capabilities
Build sites for SharePoint
SharePoint Design Manager snippets
5/3/2018 • 8 minutes to read Edit Online

A snippet is an HTML representation of a SharePoint component or control such as a navigation bar or a web part. By using the Snippet Gallery in Design Manager, you can quickly add
SharePoint functionality to your HTML master page or page layout.

Introduction to snippets and the Snippet Gallery


After you convert a master page or create a page layout, you have an HTML version of that page. With the Snippet Gallery, you can quickly add specific SharePoint functionality, such as
search or navigation or device channel panels, to the HTML file associated with your master page or page layout. The Snippet Gallery is a page in Design Manager where you can:
Choose a SharePoint component from those available on the ribbon.
Configure the properties for that component.
Preview its appearance in the browser.
Copy the HTML code snippet to the Clipboard so that you can paste the snippet at the location you want in the HTML file.
The Snippet Gallery displays different options on the ribbon, depending on whether you're editing a master page or page layout—for example, navigation controls are displayed only for
master pages, and web part zones and page field controls are displayed only for page layouts. Also, when you are editing a page layout, the page fields that are available depend on the
content type of the page layout that you're editing.
After you paste a snippet into your HTML file, you get a design-time preview from the HTML provided in the snippet. You can also use the server-side preview in Design Manager to see how
the control will appear on the live site. The design-time preview may include static sample data, but the server-side preview uses live data, if available. For example, a navigation control that
draws navigation links from a term set will display those terms dynamically in the server-side preview, but the design-time preview will have a static snapshot of the terms at the time you
created the snippet. Live data is not available in the server-side preview for some snippets, however, including many web parts. In this case, the server-side preview may say Preview Not
Available.
NOTE

A snippet contains HTML markup that gives you a design-time preview in your HTML editor, but the HTML markup contained in "start preview" and "end preview" comments should not be
edited because it affects only the design-time preview, not how SharePoint ultimately renders that snippet. Instead, to style your snippet, you typically have to identify and override the
default SharePoint styles that are applied to the snippet.

Insert a snippet from the Snippet Gallery


The Snippet Gallery displays different options depending on the file that you're editing. For example, different page layouts have different sets of page fields available to them. For this
reason, to navigate to the Snippet Gallery, you must first select a master page or page layout to edit.

To insert a snippet
1. Browse to your publishing site.
2. In the upper-right corner of the page, choose the Settings gear, and then choose Design Manager.
3. In Design Manager, in the left navigation pane, choose Edit Master Pages or Edit Page Layouts, depending on what type of file you're editing.
4. Select the name of the master page or page layout that you want to add snippets to.
5. To open the Snippet Gallery, choose Snippets in the upper-right corner of the server-side preview.
6. On the ribbon, on the Design tab, choose the snippet that you want to add to your page.
When you select a snippet, the Snippet Gallery refreshes so that the page shows you a preview of that snippet, the properties available for that snippet, and the HTML code snippet
that you can copy into your HTML master page or page layout.
7. On the right side of the Snippet Gallery, under About this Component, click or select section headers to expand or collapse groups of properties, and then configure any custom
settings that you want.
The properties that are most important for the core purpose of the snippet appear in the top section named Important. These are the key properties that you have to understand when
using a snippet.
NOTE

If the property grid has a header that ends with AjaxDelta, you should ignore those properties because they apply to the controls related to the Minimal Download Strategy, which is
disabled for master pages and page layouts created through Design Manager.
8. After you configure any properties, choose Update. This updates both the preview and the HTML snippet on the left side of the page, so that the markup reflects your custom
settings. You can always choose Reset to return all properties to their default settings.
9. On the left side of the Snippet Gallery, under HTML Snippet, choose Copy to Clipboard.
10. In your HTML editor, open the mapped network drive on your computer, and then open the HTML file for the master page or page layout that you're adding the snippet to.
11. In the HTML file, paste the snippet where you want the markup to appear.
Each snippet contains HTML that provides a visual preview of the component and sample data. You shouldn't modify this HTML for the read-only preview inside the <!--PS> and <!--
PE> tags because this markup affects only the design-time preview of the snippet, not how the snippet will appear on the live site.
12. To see the server-side preview of the snippet, save the HTML file to sync the changes to the associated ASP.NET file, and then refresh the server-side preview in Design Manager.
Unlike the design-time preview, the server-side preview shows the control as rendered by SharePoint.

Understand the markup in an HTML snippet


A snippet contains four basic sections:
Header with starting
and <!--CS> tags (except custom ASP.NET snippets, which are not wrapped in a
tag)
SharePoint markup where snippets are enclosed in <!--MS> start and <!--ME> end tags
HTML preview enclosed in <!--PS> start and <!--PE> end tags
Footer with closing <!--CE> and tags
All sections of a snippet, except the HTML preview, are enclosed in HTML comments to avoid interactions with the Document Object Model (DOM) and existing styling. A snippet starts with
the name of a component, and then includes its actual ASP.NET markup, an HTML preview for design-time rendering, and then ending tags. The ASP.NET markup is commented out, but
SharePoint strips out the comment tags and uses this markup when the HTML file is synced to the .master or .aspx file. If you know ASP.NET, you can customize this markup in the snippet.
As an example, the following is the default markup for an Edit Mode Panel, which is simply a container that conditionally displays other content and controls.

Header

<div data-name="EditModePanelShowInEdit">
<!--CS: Start Edit Mode Panel Snippet-->

SharePoint markup

<!--SPM:<%@Register Tagprefix="Publishing" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e


<!--MS:<Publishing:EditModePanel runat="server" CssClass="edit-mode-panel">-->

HTML preview

<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><!--PE: End of READ-ONLY PREVIEW-->
<div class="DefaultContentBlock" style="border:medium black solid; background:yellow; color:black; margin:20px; padding:10px;">
You should replace this div with content that renders based on your Edit Mode Panel Properties.

</div>
<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><!--PE: End of READ-ONLY PREVIEW-->

Footer

<!--ME:</Publishing:EditModePanel>-->
<!--CE: End Edit Mode Panel Snippet-->
</div>

The following is the default markup for a Top Navigation snippet, which is more complex because this snippet contains several different controls, with some nested inside each other,
including a data source for the navigation terms, a delegate control, and a content placeholder.
NOTE

Some of the controls, such as the content placeholder, contain empty tags for an HTML preview because that element does not require a visual representation on the page.

Header

<div data-name="TopNavigationNoFlyoutWithStartNode">
<!--CS: Start Top Navigation Snippet--> <!--SPM:<%@Register Tagprefix="Publishing" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15
<!--MS:<Publishing:EditModePanel runat="server" CssClass="edit-mode-panel">-->

SharePoint markup

<!--SPM:<%@Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>-->


<!--MS:<SharePoint:AjaxDelta ID="DeltaTopNavigation" BlockElement="true" CssClass="ms-displayInline ms-core-navigation ms-dialogHidden" runat="server">-->

HTML preview

<!--PS: Start of READ-ONLY PREVIEW (do not modify)-->


<!--PE: End of READ-ONLY PREVIEW-->

SharePoint markup

<!--MS:<SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource" Id="topNavigationDelegate">-->

HTML preview
<!--PS: Start of READ-ONLY PREVIEW (do not modify)-->
<span style="display:none">
<table cellpadding="4" cellspacing="0" style="font:messagebox;color:buttontext;background-color:buttonface;border: solid 1px;border-top-color:buttonhighlight;border-left-color:buttonhighlight;bor
<tr><td nowrap="nowrap">
<span style="font-weight:bold">PortalSiteMapDataSource</span> - topSiteMap</td></tr><tr><td></td></tr></table></span>
<!--PE: End of READ-ONLY PREVIEW-->

SharePoint markup

<!--MS:<Template_Controls>-->
<!--MS:<asp:SiteMapDataSource ShowStartingNode="True" SiteMapProvider="SPNavigationProvider" ID="topSiteMap" runat="server" StartingNodeUrl="sid:1002">-->

SharePoint markup

<!--ME:</asp:SiteMapDataSource>-->
<!--ME:</Template_Controls>-->
<!--ME:</SharePoint:DelegateControl>--><a name="startNavigation"></a>

SharePoint markup

<!--MS:<asp:ContentPlaceHolder ID="PlaceHolderTopNavBar" runat="server">-->


<!--MS:<SharePoint:AspMenu ID="TopNavigationMenu" runat="server" EnableViewState="false" DataSourceID="topSiteMap" AccessKey="&amp;#60;%$Resources:wss,navigation_accesskey%&amp;#62;" UseSimpleRen

HTML preview

<!--PS: Start of READ-ONLY PREVIEW (do not modify)-->


<link rel="stylesheet" type="text/css" href="/_layouts/15/1033/styles/menu-21.css" />
<div id="zz7_TopNavigationMenu" class=" noindex ms-core-listMenu-horizontalBox">
<ul id="zz9_RootAspMenu" class="root ms-core-listMenu-root static">
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" tabindex="0" title="Default Publishing Site" href="/sites/PubSite/Pages/default.aspx" accesskey="1">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Default Publishing Site</span></span></a></li></ul></div>
<!--PE: End of READ-ONLY PREVIEW-->

SharePoint markup

<!--ME:</SharePoint:AspMenu>-->
<!--ME:</asp:ContentPlaceHolder>-->

HTML preview

<!--PS: Start of READ-ONLY PREVIEW (do not modify)-->


<!--PE: End of READ-ONLY PREVIEW-->

SharePoint markup

<!--ME:</SharePoint:AjaxDelta>-->

Footer
<!--CE: End Top Navigation Snippet-->
</div>

Types of markup
Here is a breakdown of the types of markup that are included in a snippet.
SharePoint namespace registration SPM ("SharePoint markup") indicates a line registering a SharePoint namespace.

<!--SPM:<%@Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>-->

Comments CS and CE ("Comment start" and "comment end") help you parse the lines of markup.

<!--CS: Start Top Navigation Snippet-->



<!--CE: End Top Navigation Snippet-->

Snippets MS and ME ("markup start" and "markup end") denote the beginning and end of a SharePoint control or a snippet. Some snippets, like the ribbon or the Top Navigation control
above, contain several controls nested within a single snippet.
<!--MS:<SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource" Id="topNavigationDelegate">-->

<!--ME:</SharePoint:DelegateControl>--><a name="startNavigation"></a>

<!--MS:<Template_Controls>-->

<!--ME:</Template_Controls>-->

<!--MS:<asp:SiteMapDataSource ShowStartingNode="True" SiteMapProvider="SPNavigationProvider" ID="topSiteMap" runat="server" StartingNodeUrl="sid:1002">-->



<!--ME:</asp:SiteMapDataSource>-->

Preview blocks PS and PE ("Preview start" and "preview end") surround a section of HTML code that you should not edit. These preview sections are a snapshot in time of the SharePoint
control that snippet is inserting. A preview makes it possible for you to work more meaningfully on the HTML file in a client-side HTML editor. But, changing the content or styling within that
preview has no lasting effect on the .master file, which is what SharePoint is ultimately using. To style a snippet, you have to identify and override the SharePoint styles with your own custom
CSS.

<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><span style="display:none"><table cellpadding="4" cellspacing="0" style="font:messagebox;color:buttontext;background-color:buttonface;border:

<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><link rel="stylesheet" type="text/css" href="/_layouts/15/1033/styles/menu-21.css" /><div id="zz7_TopNavigationMenu" class=" noindex ms-core-l

See also
How to: Convert an HTML file into a master page in SharePoint
How to: Create a page layout in SharePoint
How to: Add an Edit Mode Panel snippet in SharePoint
How to: Add a Security Trim snippet in SharePoint
Add a Device Channel Panel snippet in SharePoint
5/3/2018 • 6 minutes to read Edit Online

A Device Channel Panel is a snippet that you can add to a master page or page layout to control what content is rendered for each channel that you create. The primary purpose of a Device
Channel Panel is to selectively display different page fields on different channels from a single page layout.

Introduction to the Device Channel Panel snippet


A Device Channel Panel is a control that you can add to a master page or page layout to control what content is rendered in each channel that you create. A Device Channel Panel is a
container that specifies one or more channels; if one or more of those channels are active when the page is rendered, all of the contents of the Device Channel Panel are also rendered. A
Device Channel Panel can include almost any type of content, including a link to a CSS file or a .js file. It is an easy way to include specific content for specific channels.
Perhaps the most common scenario for using Device Channel Panels is to selectively include parts of a page layout for specific channels. For example, you may have a page layout with
separate text fields for a long greeting and a short greeting. By placing the page fields inside Device Channel Panels, you can display the short greeting only to phones and the long greeting
only to the desktop. The content of a Device Channel Panel is not displayed on non-included channels—in fact, the content is not rendered at all, which prevents bytes from going across the
wire. For this reason, using Device Channel Panels is a better way to display content on specific channels than using a CSS class with Display:None because Device Channel Panels help to
reduce the page weight for a specific channel.
You can also use Device Channel Panels on master pages. For example, if you have a master page that can accommodate two different devices (or two different browsers) with only minimal
changes, you can use Device Channel Panels to hold the content on the master page that is specific to either of those devices.
There are two limitations to using a Device Channel Panel:
Display templates Because display templates are rendered on the client side and Device Channel Panels run on the server side, you cannot use a Device Channel Panel within a
display template. Instead, you should use two different Content Search web parts within Device Channel Panels on your page layout, or use the JavaScript variable to trigger the
behavior you want within the display template itself.
Web part zones You cannot insert a web part zone inside a Device Channel Panel. If you want to allow authors to add web parts to a page, and if you are not concerned about the
page weight for mobile devices, you can add a Rich Text Editor page field to a Device Channel Panel, and then instruct authors to add web parts there. You can add web parts directly
to a Device Channel Panel (without a web part zone).

Inserting a Device Channel Panel snippet


Like all snippets, you add a Device Channel Panel snippet from the Snippet Gallery. To navigate to the Snippet Gallery, you must first select a master page or page layout to edit.

To insert a Device Channel Panel snippet


1. Browse to your publishing site.
2. In the upper-right corner of the page, choose the Settings gear, and then choose Design Manager.
3. In Design Manager, in the left navigation pane, choose Edit Master Pages or Edit Page Layouts, depending on what type of file you're editing.
4. Select the name of the master page or page layout that you want to add the snippet to.
5. To open the Snippet Gallery, choose Snippets in the upper-right corner of the server-side preview.
6. On the ribbon, on the Design tab, choose Device Channel Panel.
7. On the right side of the Snippet Gallery, under About this Component, click or select section headers to expand or collapse groups of properties, and then configure any custom
settings that you want.
The section named Important contains the properties that are key to how this particular snippet works. For a Device Channel Panel, the IncludedChannels property is the most
important. For this property, enter the alias of each Device Channel that you want to display the content contained in this Device Channel Panel. If you enter more than one alias,
separate each with a comma.
NOTE

If you edit the alias of a channel in the Device Channels list, you must manually find and update that alias wherever it appears in your design files, including updating the
IncludedChannels property for every Device Channel Panel that uses that alias.
8. After you configure any other properties, choose Update. This updates the HTML snippet on the left side of the page, so that the markup reflects your custom settings. You can always
choose Reset to return all properties to their default settings.
9. On the left side of the Snippet Gallery, under HTML Snippet, choose Copy to Clipboard.
10. In your HTML editor, open the mapped network drive on your computer, and then open the HTML file for the master page or page layout that you're adding the snippet to.
For more information, see How to: Map a network drive to the SharePoint Master Page Gallery.
11. In the HTML file, paste the snippet where you want the markup to appear.
If you are adding the snippet to a page layout, make sure to paste the snippet inside PlaceHolderMain.
12. Replace the
where class="DefaultContentBlock" with your own specific content.
Typically, if you're adding a Device Channel Panel to a page layout, you replace the
by copying page fields inside the panel.
13. Save the page, and then refresh the server-side preview in Design Manager to make sure the Device Channel Panel appears as expected.
To preview the panel on different channels, you can add query string parameters to the URL. For example, you can append the query string variable "DeviceChannel=YourChannelAlias"
to the URL of any page in the server-side preview.

Understanding the snippet markup


The two most important parts of a Device Channel Panel snippet are the IncludedChannels property and the
where class="DefaultContentBlock" . By default, the IncludedChannels property is empty. In the Important section of the property grid, you should enter the aliases, separated by commas, of
the device channels that you want to display the content in this panel.
NOTE

If you change an alias in the Device Channels list, you must also change that alias wherever it appears in your markup, including in the IncludedChannels property for every Device
Channel Panel that uses that alias.
The
where class="DefaultContentBlock" should be replaced with whatever specific content you want to display for the included channels. A Device Channel Panel can include almost any type of
content, including a link to a CSS file or a .js file. The most common scenario for using Device Channel Panels is to include specific page fields from a page layout for specific channels. In this
case, you copy the page field markup where the
is positioned inside the Device Channel Panel.

<div data-name="DeviceChannelPanel">
<!--CS: Start Device Channel Panel Snippet-->
<!--SPM:<%@Register Tagprefix="Publishing" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken
<!--MS:<Publishing:DeviceChannelPanel runat="server" IncludedChannels="MyPhoneChannel, MyTabletChannel">-->
<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><!--PE: End of READ-ONLY PREVIEW-->
<div class="DefaultContentBlock" style="border:medium black solid; background:yellow; color:black; margin:20px; padding:10px;">
You should replace this div with content that renders based on your Device Channel Panel Properties.
</div>
<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><!--PE: End of READ-ONLY PREVIEW-->
<!--ME:</Publishing:DeviceChannelPanel>-->
<!--CE: End Device Channel Panel Snippet-->
</div>

See also
SharePoint Design Manager snippets
SharePoint Design Manager device channels
Build sites for SharePoint
Develop the site design in SharePoint
Add an Edit Mode Panel snippet in SharePoint
3/26/2018 • 5 minutes to read Edit Online

An Edit Mode Panel is a snippet that you can use to display instructions or other content to content authors, who see the contents of that panel only when they edit a page. Conversely, this
snippet can also be configured to display its contents only in regular (view) mode instead of in edit mode.

Introduction to the Edit Mode Panel


In a publishing site, content authors with the necessary permissions can create or edit pages that reside in the Pages library. Typically, an author chooses to create or edit a page, and then
adds content to the various page fields.
As a designer, you can add an Edit Mode Panel to a master page or page layout, and the contents of that snippet will be visible to content authors only when they choose to edit a page based
on that page layout or a page associated with that master page. For example, you can use an Edit Mode Panel to display the following content only to content authors when the page is in edit
mode:
A page field, such as Schedule Publishing Date, that's important to the content author but not to visitors viewing the page on the live site.
A description of what kind of content should be entered in a page field.
A note to content authors that they should consider how the page looks for different device channels.
You can also put links to different style sheets in an Edit Mode Panel so that you can provide different styling for edit mode vs. view mode.
You should add the Edit Mode Panel to a page layout when the notes for content authors are specific to the content type on which that page layout is based. You can also add this snippet to a
master page when the notes for authors are applicable to all pages that will be associated with that master page—for example, if the panel will contain instructions for supplying content for a
specific device channel that uses that master page.
You can also set an Edit Mode Panel to display its contents only in regular mode, instead of edit mode, if you have a scenario where it's useful or helpful to display content only to site visitors
(but not content authors) when they're editing a page.

Insert an Edit Mode Panel


Like all snippets, you add this snippet from the Snippet Gallery. To navigate to the Snippet Gallery, you must first select a master page or page layout to edit.

To insert an Edit Mode panel


1. Browse to your publishing site.
2. In the upper-right corner of the page, choose the Settings gear, and then choose Design Manager.
3. In Design Manager, in the left navigation pane, choose Edit Master Pages or Edit Page Layouts, depending on what type of file you're editing.
4. Select the name of the master page or page layout that you want to add the snippet to.
5. To open the Snippet Gallery, choose Snippets in the upper-right corner of the server-side preview.
6. On the ribbon, on the Design tab, choose Edit Mode Panel, and then choose the mode that you want your snippet to be displayed in.
7. On the right side of the Snippet Gallery, under About this Component, click or select section headers to expand or collapse groups of properties, and then configure any custom
settings that you want.
The section named Important contains the properties that are most important to how this particular snippet works. For an Edit Mode Panel, the PageDisplayMode property will be
set to either Edit or Display, depending on the mode that you selected on the ribbon.
8. After you configure any properties, choose Update. This updates the HTML snippet on the left side of the page, so that the markup reflects your custom settings. You can always
choose Reset to return all properties to their default settings.
9. On the left side of the Snippet Gallery, under HTML Snippet, choose Copy to Clipboard.
10. In your HTML editor, open the mapped network drive on your computer, and then open the HTML file for the master page or page layout that you're adding the snippet to. For more
information, see How to: Map a network drive to the SharePoint Master Page Gallery.
11. In the HTML file, paste the snippet where you want the markup to appear.
If you're adding the Edit Mode Panel to a page layout, make sure to paste the snippet inside PlaceHolderMain so that the panel is visible to content authors in edit mode. You can
paste the snippet immediately before a specific page field, or you can put one or more page fields inside the Edit Mode Panel.
12. Replace the
where class="DefaultContentBlock" with your own specific content—for example, with notes or instructions to content authors, or specific page fields that are useful for authors but not
site visitors.
13. Save the page, and then refresh the server-side preview in Design Manager to make sure the Edit Mode Panel appears as expected.

Understand the snippet markup


The two most important parts of an Edit Mode Panel snippet are the PageDisplayMode property and the
where class="DefaultContentBlock" . The PageDisplayMode property determines whether the contents of the panel are displayed only in edit mode or in regular/display mode (meaning
whenever the page is not in edit mode).
NOTE

This property doesn't appear in the markup unless you change the value to Display. When the property does not appear in the markup, the default mode for the snippet is Edit mode.
The
where class="DefaultContentBlock" is what you replace with your own content, which can include other snippets and controls.
<div data-name="EditModePanelShowInEdit">
<!--CS: Start Edit Mode Panel Snippet-->
<!--SPM:<%@Register Tagprefix="Publishing" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken
<!--MS:<Publishing:EditModePanel runat="server" PageDisplayMode="Display" CssClass="edit-mode-panel">-->
<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><!--PE: End of READ-ONLY PREVIEW-->
<div class="DefaultContentBlock" style="border:medium black solid; background:yellow; color:black; margin:20px; padding:10px;">
You should replace this div with content that renders based on your Edit Mode Panel Properties.
</div>
<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><!--PE: End of READ-ONLY PREVIEW-->
<!--ME:</Publishing:EditModePanel>-->
<!--CE: End Edit Mode Panel Snippet-->
</div>

See also
SharePoint Design Manager snippets
How to: Add a Security Trim snippet in SharePoint
Build sites for SharePoint
Develop the site design in SharePoint
Add a web part zone snippet in SharePoint
5/3/2018 • 9 minutes to read Edit Online

A web part zone is a snippet that you can add to a page layout so that content authors can add, edit, or delete web parts in that zone.

Introduction to the web part zone snippet


A web part is a server control that provides a specific piece of SharePoint functionality, and a web part zone is a container that determines the layout, behavior, and other properties of the
web parts contained in that zone. For example, a web part zone can specify whether the web parts in the zone:
Are arranged in a horizontal or vertical layout.
Display common user interface (UI) elements such as a title bar or border.
Can be customized by content authors when they edit a page in the browser.
Can be personalized by site visitors who create a personal view of a web part when they view a page in the browser.
In a publishing site, content authors with the necessary permissions can create or edit pages that reside in the Pages library. As a designer, you can add a web part zone to a page layout.
When a content author creates or edits a page based on that page layout, the author can add, edit, or delete web parts in that zone. For example, you may want to add a web part zone to a
page layout so that content authors can:
Display the results of a search query by using a Content Search web part. Authors can update or modify the search query when a search-driven web part resides inside a web part
zone.
Embed video or audio clips in a webpage by using a Media web part.
Create lists of hyperlinks that are easily edited, grouped, or reordered by using a Summary Link web part.
Create a site map that lists all pages in a site and that is automatically updated whenever a page is added, deleted, renamed, or moved by using a Table of Contents web part.

When to use web part zones


When a page layout includes one or more web part zones, the web part zones are available on all pages that use that layout, which enables authors to insert web parts onto those pages. If
you enable authors to insert web parts on pages, you reduce your control over the users' experience of the site. For example, an author could insert a Table of Contents web part onto a page
that exposes parts of your site that you don't want visitors to navigate to from the current page.
If you want complete control over how a web part appears on your site, and if you want that web part to appear on all pages of a certain type, add the web part directly to a page layout. If
you want a web part to appear on all pages in a site, you can also add a web part directly to a master page.
NOTE

Web part zones are available on page layouts but not on master pages—the purpose of zones is to allow authors to modify web parts, and authors typically don't edit a master page.
You can also add web part zones to a page layout but restrict their use. For example, you can add web parts to a zone, and then set a property of that zone so that content authors can edit the
properties of existing web parts but not add or remove web parts from the zone. web part zones have a set of properties that serve a dual purpose. You can use one subset of properties to
organize the layout and format of web parts on the page. You can use another subset of properties to provide an additional level of protection from modification (or "lock down") of the web
parts within the zone.
For varying levels of control over how web parts are presented on your site, you can:
Add web parts directly to a master page or page layout. This means content authors cannot modify the web parts.
Add web parts to zones on page layouts, but restrict those zones to only the default web parts that you add.
Add web part zones to page layouts, and give content authors complete control over what web parts appear in those zones and how they are configured.
The properties of a web part zone can specify whether content authors are allowed to change:
The layout of web parts in the zone by adding, deleting, resizing, or moving the web parts.
The web part settings for all users (the shared view of a web part).
Their personal web part settings (the personal view of a web part).
Table 1 shows important properties to consider when you want to restrict a web part zone.
Table 1. Web part zone properties used to restrict content authors

PR O PER T Y NAME D ES CR IPTIO N

AllowLayoutChange Specifies whether web parts within the zone can be closed, minimized, deleted, or restored.
If set to False, users cannot close, minimize, delete, or restore web parts in the zone, drag web parts to a
different zone, or rearrange or move web parts within the zone. Users also cannot add web parts from
the web part catalog, and several properties that affect the UI of web parts in the zone are disabled. This
property does not affect the ability to change the layout programmatically.
If set to True, users with appropriate permissions can perform these actions.

LockLayout Specifies whether web parts within the zone can be added, deleted, resized, or moved. This property
works the same whether the web part page is in personal view or shared view.
If set to True, the specific web part properties for each web part in the zone that are affected are: Zone
(ZoneID), Part Order (PartOrder), Visible on Page (IsVisible), Height (Height), Width (Width),
Allow Close (AllowRemove), and IsIncluded (the Close command on the web part menu). Other
web part properties are not affected.
If set to False, the web part properties determine whether modifications can be made (together with the
appropriate site permissions).

AllowCustomization Specifies whether shared property values of web parts within the zone can be modified.
If set to True, users with appropriate permissions can make changes to the web parts in the zone for all
users.
If set to False, users cannot make changes to the web parts in the zone in the UI in shared view. But,
changes can still be made programmatically and by using the web part Maintenance page.
PR O PER T Y NAME D ES CR IPTIO N

AllowPersonalization Specifies whether personal property values of web parts within the zone can be modified.
If set to True, users with appropriate permissions can make personal changes to the web parts in the
zone.
If set to False, users cannot make personal changes to the web parts through the UI, unless the web
part is a private web part and they have appropriate permissions.
NOTE

You cannot insert a web part zone inside a Device Channel Panel. If you want to allow authors to add web parts to a page, and if you are not concerned about the page weight for mobile
devices, you can add a Rich Text Editor page field to a Device Channel Panel, and then instruct authors to add web parts there. You can add web parts directly to a Device Channel Panel
(without a web part zone). For more information, see How to: Add a Device Channel Panel snippet in SharePoint.

Inserting a web part zone snippet


Like all snippets, you add this snippet from the Snippet Gallery. To navigate to the Snippet Gallery, you must first select a page layout to edit. Web part zones can be added to page layouts
but cannot be added to master pages.

To insert a web part zone snippet


1. Browse to your publishing site.
2. In the upper-right corner of the page, choose the Settings gear, and then choose Design Manager.
3. In Design Manager, in the left navigation pane, choose Edit Page Layouts.
4. Select the name of the page layout that you want to add the snippet to.
5. To open the Snippet Gallery, choose Snippets in the upper-right corner of the server-side preview.
6. On the ribbon, on the Design tab, choose web part zone.
7. On the right side of the Snippet Gallery, under About this Component, click or select section headers to expand or collapse groups of properties, and then configure any custom
settings that you want.
The section named Important contains the properties that are key to how this particular snippet works. For a web part zone, the snippet has a unique ID. After you copy the snippet
into your page layout, you should not reuse this ID. If you want to add another web part zone snippet, choose Refresh to generate a new ID for the next snippet.
For descriptions of properties that are necessary for restricting a web part zone ( LockLayout, AllowCustomization, and AllowPersonalization), see Table 1.
NOTE

You may notice that some property names are bold in the property grid of the Snippet Gallery. These properties have values that have been changed from the default setting for this
component, but these properties are not necessarily relevant to a designer scenario. In other words, a property may be bold but not necessarily important for your scenario.
8. After you configure any properties, choose Update. This updates the HTML snippet on the left side of the page, so that the markup reflects your custom settings. You can always
choose Reset to return all properties to their default settings.
9. On the left side of the Snippet Gallery, under HTML Snippet, choose Copy to Clipboard.
10. In your HTML editor, open the mapped network drive on your computer, and then open the HTML file for the master page or page layout that you're adding the snippet to.
For more information, see How to: Map a network drive to the SharePoint Master Page Gallery.
11. In the HTML file, paste the snippet where you want the markup to appear.
When you are adding the snippet to a page layout, make sure to paste the snippet inside PlaceHolderMain.
12. Replace the
where class="DefaultContentBlock" with your own specific content.
13. If you want to prepopulate the zone with web parts—for example, if the zone will restrict content authors to modifying only existing web parts and not adding new ones—insert web
part snippets where the tag appears.
14. Save the page, and then refresh the server-side preview in Design Manager to make sure the page appears as expected.

Understanding the snippet markup


The two most important parts of a web part zone snippet are the ID property and the comment. Each zone should have a unique ID. If you want to add more than one web part zone to your
page layout, make sure to choose Refresh in the Snippet Gallery before copying each snippet so that a new ID is generated. The comment should be replaced with any web parts that you
want to appear in the zone by default.
Additional properties that can be used to restrict how content authors can use zones ( AllowCustomization, AllowPersonalization, and LockLayout) are shown in the following code.
NOTE

The AllowCustomization, AllowPersonalization, and LockLayout properties appear in the markup only if you change their default values in the property grid.

<div data-name="WebPartZone">
<!--CS: Start web part zone Snippet-->
<!--SPM:<%@Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%
<div xmlns:ie="ie">
<!--MS:<WebPartPages:WebPartZone runat="server" ID="x0e5f5212505f48a9aac43df13eeae4f9" AllowCustomization="True" AllowPersonalization="False" FrameType="TitleBarOnly" LockLayout="True" Or
<!--MS:<ZoneTemplate>-->
<!--DC: Replace this comment with default web parts for new pages. -->
<!--ME:</ZoneTemplate>-->
<!--ME:</WebPartPages:WebPartZone>-->
</div>
<!--CE: End web part zone Snippet-->
</div>

See also
SharePoint Design Manager snippets
WebPartZone class
WebPartZoneBase properties
Build sites for SharePoint
Develop the site design in SharePoint
Add a Security Trim snippet in SharePoint
5/3/2018 • 5 minutes to read Edit Online

You can use a Security Trim snippet to display content only to specific users, based on a specific permission that those users must have and whether the users are authenticated or
anonymous.

Introduction to the Security Trim snippet


You can use a Security Trim snippet to display content only to specific users, based on a specific permission that those users must have, and whether those users are authenticated or
anonymous. You can add a Security Trim panel to a master page or page layout. A Security Trim panel is a container that can include other components or snippets, such as web parts, in
addition to static content.
For example, you can use a Security Trim panel to display the following content to specific users:
A Content by Search web part that displays which documents an authenticated user is currently working on.
A list view of recently modified documents so that authenticated users can see what's new on the site.
A Content by Search web part that displays to non-authenticated visitors a list of recommended links based on the current article. Such a list of recommendations might be noise to
authenticated content authors working in the site, but it's important for non-authenticated visitors.
A sign-in link separate from the ribbon, for non-authenticated users or users who have yet to be authenticated.
NOTE

This sign-in link is inserted automatically into a master page that is created by using Design Manager, but you can delete it if it's not needed.
A Security Trim panel has two important property settings, one for authentication and one for permissions (or authorization). For example, you can use a Security Trim panel to display the
following content to specific users:
AuthenticationRestrictions With this property, you can restrict the panel to either authenticated or anonymous users, or choose all users (all users is the default setting).
Permissions With this property, you can select a specific permission that users must have to view the content in the panel.
NOTE

You are selecting an individual permission, not a permission level. (A permission level is a set of granted permissions.) Of course, if you restrict the authentication to only anonymous
users, it's typically not necessary to specify a specific permission because anonymous users have usually not been given any SharePoint permissions. It makes sense to use
permissions only with all users or with all authenticated users.
The Security Trim panel has three options on the ribbon, listed in the left column of Table 1. Table 1 shows how these settings determine the specific permission that users are required to
have, the lowest default permission level that includes that specific permission, and the group that is linked to that permission level by default.)
NOTE

These are the default settings, which can be changed for any given scope, such as a site collection, site, list, or item.
For example, if you set a Security Trim panel to Show to authors, by default content inside that panel is visible to users in the Members group and the Owners group.
Table 1. Mapping of panel options to default permission levels and groups

S ECU R IT Y TR IM PANEL O PTIO N PER MIS S IO NS PR O PER T Y PER MIS S IO N PER MIS S IO N LEV EL G ROUP

Show to authors AddAndCustomizePages Add and Customize Pages Contribute (or higher) Members

Show to Authenticated Users ViewPages View Pages Read (or higher) Visitors

Show to Administrators FullMask Select All Full Control Owners

Inserting a Security Trim panel


Like all snippets, you add the Security Trim snippet from the Snippet Gallery. To navigate to the Snippet Gallery, you must first select a master page or page layout to edit.

To insert a Security Trim panel


1. Browse to your publishing site.
2. In the upper-right corner of the page, choose the Settings gear, and then choose Design Manager.
3. In Design Manager, in the left navigation pane, choose Edit Master Pages or Edit Page Layouts, depending on what type of file you're editing.
4. Select the name of the master page or page layout that you want to add the snippet to.
5. To open the Snippet Gallery, choose Snippets in the upper-right corner of the server-side preview.
6. On the ribbon, on the Design tab, choose Security Trim.
Optionally, in the drop-down list on the Security Trim button, you can select the users to whom the panel content will be visible, or you can see more options by configuring the
important property values for the panel.
7. On the right side of the Snippet Gallery, under About this Component, click or select section headers to expand or collapse groups of properties, and then configure any custom
settings that you want.
8. After you configure any properties, choose Update. This updates the HTML snippet on the left side of the page, so that the markup reflects your custom settings. You can always
choose Reset to return all properties to their default settings.
9. On the left side of the Snippet Gallery, under HTML Snippet, choose Copy to Clipboard.
10. In your HTML editor, open the mapped network drive on your computer, and then open the HTML file for the master page or page layout that you're adding the snippet to.
11. In the HTML file, paste the snippet where you want the markup to appear.
If you are adding the snippet to a page layout, make sure to paste the snippet inside PlaceHolderMain.
12. Replace the
where class="DefaultContentBlock" with your own specific content.
13. Save the page, and then refresh the server-side preview in Design Manager to make sure the Security Trim panel appears as expected.

Understanding the snippet markup


The most important parts of a Security Trim snippet are the AuthenticationRestrictions property and the Permissions property, and the
in bold below. AuthenticationRestrictions appears in the markup only when changed from AllUsers, which is the default. If you choose Reset for the snippet in the Snippet Gallery,
AuthenticationRestrictions is removed from the markup, which means the snippet uses the default value, AllUsers.
The
where class="DefaultContentBlock" is what you replace with your own content, which can include other snippets and controls.

<div data-name="SecurityTrimmedAuthors">
<!--CS: Start Security Trim Snippet-->
<!--SPM:<%@Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>--
<!--MS:<SharePoint:SPSecurityTrimmedControl runat="server" AuthenticationRestrictions="AuthenticatedUsersOnly" Permissions="AddAndCustomizePages" PermissionContext="RootSite">-->
<!--PS: Start of READ-ONLY PREVIEW (do not modify)--><span><!--PE: End of READ-ONLY PREVIEW-->
<div class="DefaultContentBlock" style="border:medium black solid; background:yellow; color:black; margin:20px; padding:10px;">
You should replace this div with content that renders based on your Security Trim Properties.
</div>
<!--PS: Start of READ-ONLY PREVIEW (do not modify)--></span><!--PE: End of READ-ONLY PREVIEW-->
<!--ME:</SharePoint:SPSecurityTrimmedControl>-->
<!--CE: End Security Trim Snippet-->
</div>

See also
Introduction: Control user access with permissions
Understanding permission levels
SharePoint Design Manager snippets
Build sites for SharePoint
Develop the site design in SharePoint
Brand snippets by using CSS in SharePoint
3/26/2018 • 10 minutes to read Edit Online

To style a snippet, you override the default styles with custom CSS. You can use CSS IDs and element selectors to override all the default styles applied to elements, or you can use an HTML
editor or a tool such as the F12 developer tools in Internet Explorer to identify and override specific default styles.

Introduction to styling snippets with CSS


After you convert an HTML master page or create an HTML page layout, you can preview that page in the Design Manager server-side preview. From the preview page, you can navigate to
the Snippet Gallery and then copy snippets to your HTML file. A snippet is an HTML representation of a SharePoint control such as a top navigation control or a search box.
After you copy a snippet into the HTML file in your mapped drive and then save the changes, you can refresh the server-side preview of the HTML file to see how the control is rendered.
Snippets contain markup that provides a design-time preview in your HTML editor of choice, but you shouldn't edit this markup because it's read-only and doesn't affect how the control is
rendered on the server. By contrast, the server-side preview shows a full-fidelity preview with live data, if available—for example, a navigation control will show the site's current navigation
structure with live data from your data source, such as a SharePoint term store for managed navigation.
NOTE

For more information about mapping a network drive, see How to: Map a network drive to the SharePoint Master Page Gallery.
By default, snippets inherit their styles from SharePoint style sheets such as corev15.css. To style a snippet, you have to override these default styles with your custom CSS. To do this, you
can:
Use CSS IDs and element selectors to completely override the default styles applied to the chosen elements.
Use a browser-based tool such as the F12 developer tools in Internet Explorer to inspect the default styles in the server-side preview in Design Manager, and then identify specific
styles to override.
Use the features of your HTML editor to inspect the default styles in the read-only preview of a snippet, and then identify specific styles to override.
To identify the default styles by using the developer tools in Internet Explorer, you should use the server-side preview in Design Manager to view your HTML master page or page layout,
press F12 to start the developer tools, choose the Find menu, and then choose Select element by click. This enables you to click elements on the page and see exactly what styles to
override by adding CSS to the custom style sheet that your HTML master page or page layout links to.
The default SharePoint style sheets contain many styles, which can make it challenging to identify specific styles. As an alternative to browser-based tools, and depending on your HTML
editor, you may find it easier to copy the snippet from the Snippet Gallery into your HTML file, and then use the HTML editor to identify the styles. In the Snippet Gallery, when you choose
Update and then choose Copy to Clipboard, the snippet contains an HTML preview of that snippet. After you copy the snippet into your HTML file, you can inspect the styles used in the
read-only preview contained in the snippet. This way, you are parsing a smaller subset of the default styles.
Depending on the snippet and the extent of your customization, you may want to use CSS IDs and element selectors to completely override all of the default styles, instead of choosing
specific default styles to override. The following example demonstrates how to use this method to apply custom styles to the top navigation snippet.

Example: Style the top navigation snippet


The top navigation snippet is one of the most commonly used snippets, so it's also one of the most commonly branded snippets. In a SharePoint site, you can select an option to use
managed navigation, so that a term store becomes the data source for the top navigation snippet. This way, you can use the Term Store Management tool in Site Settings to add or delete
navigation terms and to manage the navigation taxonomy that is displayed by the Top Navigation snippet.
In this example, the site uses managed navigation, so the top navigation control pulls its entries from a term store. There is one level of flyouts that appear when you hover over a top-level
navigation term, such as Computers. This section demonstrates how these custom styles override the default SharePoint styles.

Sample 1: Navigation <div> from the HTML mockup file


Before you use Design Manager, when you design the HTML mockup for your master page, you'll likely use HTML and CSS to design a functional top navigation element. This HTML
sample uses a basic structure for the top navigation: a <div> element with an ID and class name, a list for the top-level navigation entries, and a nested list for each flyout submenu.

<div id="navigation" class="msax-Navigation">


<ul>
<li><a href="#">Cameras</a>
<ul>
<li><a href="#">Camcorders</a></li>
<li><a href="#">Digital cameras</a></li>
<li><a href="#">Disposable cameras</a></li>
<li><a href="#">Film cameras</a></li>
</ul>
</li>
<li><a href="#">Computers</a>
<ul>
<li><a href="#">Desktops</a></li>
<li><a href="#">Laptops</a></li>
<li><a href="#">Netbooks</a></li>
<li><a href="#">Tablets</a></li>
</ul>
</li>
<li><a href="#">Media</a>
<ul>
<li><a href="#">Movies</a></li>
<li><a href="#">Music</a></li>
<li><a href="#">TV shows </a></li>
<li><a href="#">Video games </a></li>
</ul>
</li>
<li></li>
</ul>
</div>

Sample 2: Navigation <div> styled with custom CSS


To override the default SharePoint styles, in the mockup HTML file, include a standard link to your CSS file (<link rel="stylesheet" type="text/css" href="URLtoYourCustomCSSFile"/> ) just
before the closing </head> tag.
In these HTML and CSS samples, note the following:
Navigation entries are styled by using the format .msax-Navigation ul li instead of applying classes directly to the <ul> or <li> tags.
Styles use the syntax .msax-Navigation ul li instead of .msax-Navigation ul>li because the snippet markup may contain intervening <div> tags between the selected elements.
The HTML mockup contains an empty <li></li> element as the last entry of the top-level <ul>. This is because, with managed navigation turned on, SharePoint adds an Edit Links
command as the final entry to the top-level navigation, and the final site typically does not need to display this option. The CSS sample uses .msax-Navigation ul li:last-child to
select this entry and set the display value to none . The empty <li></li> element in the HTML file is a temporary substitute for the default Edit Links entry. Be aware of this final <li>
element if your site uses managed navigation and your CSS uses any li:last-child selectors.

.msax-Navigation {
margin: 10px 0px; top: 0px; position: relative;
z-index:200;
}
.msax-Navigation a {
margin: 0px; padding: 0px; border: 0px currentColor;
}
.msax-Navigation ul {
list-style: none; margin: 0px; padding: 0px; font-size: 16px; z-index:200;
}
.msax-Navigation ul li {
padding: 10px; display: inline-block; position: relative; z-index:200;
}
.msax-Navigation ul li:first-child {
margin: 0px;
}
.msax-Navigation ul li:last-child {
margin: 0px; padding: 0px; display: none;
}
.msax-Navigation ul li a.selected, .msax-Navigation ul li.selected {
background-color: rgb(58,60,62) !important;
color:rgb(255,255,255) !important;
}
.msax-Navigation ul li a {
width: 100%; color: rgb(58,60,62); font-size: 16px;
}
.msax-Navigation ul li:hover {
background-color: rgb(58,60,62);
color:rgb(255,255,255) !important;
}
.msax-Navigation ul li a:hover {
text-decoration: none;
color:rgb(255,255,255) !important;
}
.msax-Navigation li ul {
left: 0px; top: 35px; display: none; position: absolute; min-width: 100px; box-shadow: 5px 5px 10px 0px rgb(0,0,0); background-color: rgb(58,60,62);
}
.msax-Navigation li:hover ul {
display: block; z-index: 150;
}
.msax-Navigation li li {
margin: 0px; padding: 5px 10px 5px 0px; border-top-width: 0px; display: block; min-width: 100px;
}
.msax-Navigation li li:last-child {
margin: 0px; padding: 5px 10px 5px 0px; border-top-width: 0px; display: block; min-width: 100px;
}
.msax-Navigation li li a {
width: 100%; padding-left: 10px; display: block; color:rgb(255,255,255) !important;
}
.msax-Navigation li li:hover {
background-color: rgb(120, 120, 120);
}

Sample 3: Read-only preview of the top navigation snippet


After your custom styles are implemented in your HTML mockup and you have a functional top navigation element, follow the usual steps:
1. Map a network drive.
2. Upload your design files.
3. Convert the HTML file into a master page.
4. Preview and fix any issues.
5. Add the top navigation snippet to the HTML master page by using the Snippet Gallery.
In the Snippet Gallery, when you configure the properties of the top navigation snippet, note the following:
In the Important section at the top, do not make any changes to the CssClass property.
Do not make any changes to properties under the AjaxDelta heading because these properties are related to the MDS properties that SharePoint uses to convert the HTML snippet
into the corresponding ASP.NET snippet. This applies to any snippet, not just the top navigation snippet.
If you're planning to override the default SharePoint styles, in the Snippet Gallery, in the Behavior section under AspMenu (there may be more than one Behavior section if the
snippet contains more than one control, such as a delegate control), set ClientIDMode to Static. If you leave ClientIDMode set to the default setting, Inherit, the snippet's applied
CSS classes will change based on the ordering of snippets on the page. For more information about ClientIDMode, see Control.ClientIDMode property.
For example, by default, the top navigation control uses default SharePoint ID attributes such as zz5_TopNavigationMenu and zz6_RootAspMenu. By changing ClientIDMode to
Static, you make it possible to use these default IDs as selectors in your own CSS to override the default SharePoint styles.
Some properties are already configured to make branding the top navigation snippet easier by eliminating the default dynamic CSS and JavaScript behaviors—for example, by
default UseSimpleRendering is set to True and MaximumDynamicDisplayLevels is set to 0. For more information about specific properties of the top navigation snippet, see
AspMenu properties and Menu properties.
After you configure the top navigation snippet in the Snippet Gallery, choose Update, and then choose Copy to Clipboard. In the HTML master page, delete the contents of the navigation
<div id="navigation" class="msax-Navigation"> that contains your mockup control (delete just the contents of the <div> tag, not the <div> tag itself), and then copy the snippet into the
navigation <div>. If necessary, reposition the navigation <div>, typically just after the start of the <div id="s4-bodyContainer"> tag but before the <div> containing PlaceHolderMain .
For easy comparison with the HTML of the navigation <div> above, the following sample contains the navigation <div> portion of the top navigation snippet. Note that this is not the entire
snippet.

<div id="zz7_TopNavigationMenu" class=" noindex ms-core-listMenu-horizontalBox">


<ul id="zz9_RootAspMenu" class="root ms-core-listMenu-root static">
<li class="static">
<a accesskey="1" class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/cameras" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Cameras</span></span></a><ul class="static">
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/cameras/camcorders" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Camcorders</span></span></a></li>
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/cameras/digital-cameras" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Digital cameras</span></span></a></li>
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/cameras/disposable-cameras" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Disposable cameras</span></span></a></li>
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/cameras/film-cameras" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Film cameras</span></span></a></li>
</ul>
</li>
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/computers" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Computers</span></span></a><ul class="static">
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/computers/desktops" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Desktops</span></span></a></li>
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/computers/laptops" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Laptops</span></span></a></li>
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/computers/netbooks" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Netbooks</span></span></a></li>
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/computers/tablets" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Tablets</span></span></a></li>
</ul>
</li>
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/media" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Media</span></span></a><ul class="static">
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/media/movies" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Movies</span></span></a></li>
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/media/music" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Music</span></span></a></li>
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/media/tv-shows" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">TV shows</span></span></a></li>
<li class="static">
<a class="static menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" href="/sites/PubSite/media/video-games" tabindex="0">
<span class="additional-background ms-navedit-flyoutArrow">
<span class="menu-item-text">Video games</span></span></a></li>
</ul>
</li>
<li class="static ms-verticalAlignTop ms-listMenu-editLink ms-navedit-editArea">
<span id="zz7_TopNavigationMenu_NavMenu_Edit" class="ms-navedit-editSpan">
<a id="zz7_TopNavigationMenu_NavMenu_EditLinks" class="ms-navedit-editLinksText" href="#" onclick="g_QuickLaunchMenu = null; EnsureScriptParams('quicklaunch.js', 'QuickLaunchInitEditMod
<span class="ms-displayInlineBlock">
<span class="ms-navedit-editLinksIconWrapper ms-verticalAlignMiddle">
<img class="ms-navedit-editLinksIcon" src="/_layouts/15/images/spcommon.png?rev=23" /></span><span class="ms-metadata ms-verticalAlignMiddle">Edit Links</span></span></a><span id="zz7_T
</div>
</span></li>
</ul>
</div>

Instead of using only custom styles, you may have a scenario where you want to override just a specific style. For example, to hide the Edit Links node, you can create a custom style that
uses the default id zz7_TopNavigationMenu_NavMenu_Edit to set the display setting to none .

See also
SharePoint Design Manager snippets
Overview of Design Manager in SharePoint
How to: Convert an HTML file into a master page in SharePoint
How to: Create a page layout in SharePoint
Develop the site design in SharePoint
Themes overview for SharePoint
3/26/2018 • 4 minutes to read Edit Online

Learn about the theming experience in SharePoint and how themes can be used to customize the look and feel of sites.

Themes overview
Themes provide a quick and easy way to apply lightweight branding to a SharePoint site. A theme lets a site owner, or a user who has designer rights, customize a site by changing the site
layout, color palette, font scheme, and background image.
The theming experience in SharePoint was redesigned to simplify the process of customizing sites. The themes user interface was redesigned and there is a set of new file formats related to
themes. The Change the look wizard is the entry point to the theming experience where you can change the look and feel of your site. You can select a design for the site. Then, you can
customize the design by changing the site layout, background, color palette, or font scheme. You can preview the site before applying the design. For more information, see Choose a theme
for your publishing site on Office.com.
NOTE

Themes created in SharePoint 2010 cannot be used on SharePoint sites. But, themes created in SharePoint 2010 can still be used on site collections that have not been upgraded or on site
collections that use the 2010 experience version.

Theming experience components


The theming experience includes the following:
Color palette A color palette, or color scheme, defines the combination of colors that are used in a site. Thirty-two color palettes are installed with SharePoint. They are available to users
when they choose to modify a design in the design gallery.
Color palettes are XML files (.spcolor files). They are stored in the Theme Gallery of the root site of the site collection in the 15 folder (http:// SiteCollectionName/_catalogs/theme/15/).
Font scheme A font scheme defines the fonts that are used in a site. Seven font schemes are included in SharePoint. They are available to users when they choose to modify a design in the
design gallery.
Font schemes are XML files (.spfont files). They are stored in the Theme Gallery of the root site of the site collection in the 15 folder (http:// SiteCollectionName/_catalogs/theme/15/).
Background image The background image that is used in the site.
Master page A master page defines the chrome (the shared framing elements) of a site. The theming experience lets users select the master page to apply to a site.
Master page preview A master page preview is used to render a preview image of the selected theme components. Each master page must have a corresponding master page preview file
for the master page to be available in the theming experience.
Master page preview files (.preview files) are stored in the Master Page Gallery of the site (http:// SiteName/_catalogs/masterpage/).
Composed look A composed look, or design, is the color palette, font scheme, background image, and master page that determine the look and feel of a site. Design and theme can be used
interchangeably to describe the overall look of a site.
The theming experience uses the Composed Looks list to determine the available designs. You can create additional designs by creating list items in the Composed Looks list. To access the
composed looks list, on the Site Settings page, under Web Designer Galleries, choose Composed looks.
Change the look The Change the look wizard is the entry point to the theming experience that lets users change the look and feel of their site. To access the Change the look wizard,
choose the Settings icon, and then choose Change the look.
Design gallery The design gallery is the first page in the Change the look wizard. The design gallery shows a thumbnail view of available designs.

Using themes
SharePoint includes preinstalled themes (also referred to as designs or composed looks). You can use the preinstalled themes or create custom themes.

Preinstalled themes
The theming experience lets users customize the preinstalled themes by changing the colors, fonts, layout, or background image. You do not have to create custom themes unless you want
additional font schemes or color palettes.
When a preinstalled theme is modified, a new theme named Current is created automatically after the theme changes are applied. There is only one Current theme for a site. SharePoint does
not give the user a way to save themes from the user interface. If you modify a preinstalled theme, apply the changes (creating a new theme named Current), and then modify a second
preinstalled theme, the second preinstalled theme becomes the Current theme when the settings are applied. To save a modified theme, you can create a list item in the Composed Looks list
that contains the same master page, color palette, font scheme, and background image URLs of the modified theme (the modified theme is listed as Current in the Composed Looks list).

Custom themes
You can create custom themes by creating additional color palettes and font schemes and uploading them to the Theme Gallery. The new color palettes and font schemes are then available
to you in the theming experience or when you want to apply a theme programmatically. Similarly, if you want to have additional site layouts to choose from, you can upload additional master
pages, and corresponding preview files, to the Master Page Gallery.
You can create new designs by creating new list items in the Composed Looks list. Create a list item and specify the master page, color palette, font scheme, and background image for the
new design.

See also
SharePoint Design Manager branding and design capabilities
How to: Create a master page preview file in SharePoint
How to: Deploy a custom theme in SharePoint
Color palettes and fonts in SharePoint
SharePoint Team Blog: Show off your style with SharePoint theming
Create a master page preview file in SharePoint
3/26/2018 • 7 minutes to read Edit Online

Learn how to create master page preview files that are used in the SharePoint theming experience to display a preview of selected theme components.
The Change the look wizard is the entry point to the SharePoint theming experience. The design gallery is the first page in the Change the look wizard and shows a thumbnail view of
available designs. Users select a design for their site and then continue to the next page where they can customize the design. Users can then preview the site before applying the design to
their site. The master page preview file is used to generate the thumbnail and preview images. If a master page does not have a corresponding preview file, it cannot be used in the theming
experience.
For more information, see Themes overview for SharePoint.

Core concepts to know for working with master page preview files
Table 1 lists articles that can help you understand the core concepts for working with master page preview files.
Table 1. Core concepts for working with master page preview files

AR TICLE TITLE D ES CR IPTIO N

Themes overview for SharePoint Learn about the theming experience in SharePoint.

Choose a theme for your publishing site Learn how to change the look and feel of a SharePoint site by using the Change the look wizard.

What is a master page preview file?


Master page preview files (.preview files) are specially formatted files that have sections for default color palette, default font scheme, tokenized CSS, and tokenized HTML. The master page
preview file must use the same name (excluding the extension) as the corresponding master page. For example, if you have a master page named article.master, the corresponding master
page preview file is named article.preview. Master pages and master page previews are stored in the Master Page Gallery.
A master page preview file has the following structure:

Default color palette


[SECTION]
Default font scheme
[SECTION]
CSS
[SECTION]
HTML

In the master page preview file:


Default color palette is the .spcolor file in the Theme Gallery (http:// SiteColltionName/_catalogs/theme/15/) that you want to use as the default. The default color palette corresponds
to the colors that are used in the master page in its default state. That is, before a user has selected a color palette in the Change the look wizard.
Default font scheme is the .spfont file in the Theme Gallery (http:// SiteCollectionName/_catalogs/theme/15/) that you want to use as the default. The default font scheme corresponds
to the fonts that are used in the master page in its default state. That is, before a user has selected a font scheme in the Change the look wizard.
CSS is the section that contains cascading style sheets (CSS). All CSS classes must be prefixed with[ID]. The following example shows a portion of the CSS section in a master page
preview file.

[ID] #dgp-pageContainer
{
background-color: [T_THEME_COLOR_PAGEBACKGROUND];
color: [T_THEME_COLOR_BODYTEXT];
width: 100%;
height:100%;
background-image: url('[T_IMAGE]');
background-size: cover;
font-family: [T_BODY_FONT];
}

HTML is the HTML section that defines the HTML structure of the preview.
NOTE

All dimension values should be specified as relative units in the master page preview file. For example, dimension values can be specified as a percent or as an em measurement. For more
information about em measurements, see section 5.1.1. Font-relative lengths: the 'em', 'ex', 'ch', 'rem' units in the W3C CSS Values and Units Module Level 3 Working Draft.
Tokens are used throughout the master page preview file. Tokens are string values that will be replaced with text, color values, or font values in the generated preview. The following sections
describe the available tokens and how they are used.

Miscellaneous tokens
The miscellaneous tokens are replaced with specified height and width values in the preview.
Table 2. Miscellaneous tokens

TO K EN NAME D ES CR IPTIO N

[T_HEIGHT] The height of the preview.

[T_WIDTH] The width of the preview.

[T_IMAGE] The URL of an optional background image.


TO K EN NAME D ES CR IPTIO N

[T_IMGHEIGHT] The height of the image, if needed.

[T_IMGWIDTH] The width of the image, if needed.

Color tokens
Color tokens are replaced with color values in the preview image. Table 3 describes two formats for color tokens. Replace ColorSlot with the annotation name of the color slot. The color
tokens must be uppercase (for example, [T_THEME_COLOR_PAGEBACKGROUND]). To see the list of available color tokens, see the Color slot mapping section in Color palettes and fonts in
SharePoint.
Table 3. Color tokens

TO K EN NAME D ES CR IPTIO N

[T_THEME_COLOR_ ColorSlot] Use this format if you want the color value of the color slot.

[T_THEME_COLOR_ _ColorSlot__AA] Use this format if you want the 8-digit hexadecimal value of the color slot. This format is useful for filter
values to enable opacity and gradients in Internet Explorer.

Font tokens
The font tokens are replaced with font values in the preview image.
[T_ _SlotName__FONT]

Replace SlotName with the name of the font slot. The font tokens must be uppercase (for example, [T_BODY_FONT]).To see the list of font slots and where they are used in a page, see the
Font slots section in Color palettes and fonts in SharePoint.

Text content tokens


The tokens listed in Table 4 are used in the HTML section of the master page preview file. The tokens are replaced with sample text in the preview image in the design gallery. The sample text
is shown in the same language as the rest of the site.
Table 4. Text content tokens

TO K EN NAME D ES CR IPTIO N

[BRANDSTRING] The brand text that appears on the page. In the preinstalled themes, it appears on the top-left corner
"Brand".

[SUITELINK1] The suite links that appear in the suite bar. See "First Item", "Second Item", "Third Item" in Figure 1.
[SUITELINK2]
[SUITELINK3]

[WELCOME] The user name text. See "User Name" in Figure 1.

[RIBBONTAB1] The names of ribbon tabs. See "TAB 1", "TAB 2", "TAB 3" in Figure 1.
[RIBBONTAB2]
[RIBBONTAB3]

[SEARCHBOX] The text inside the search box. See "Search text" in Figure 1.

[TN1] The horizontal navigation items. "NAVIGATION 1", "NAVIGATION 2", "NAVIGATION 3".
[TN2]
[TN3]

[TITLE] The page title. "Page Title".

[QL1] The vertical navigation items. "First menu item", "Second menu item", "Third menu item".
[QL2]
[QL3]
[QL4]

[QLADD] The link below the vertical navigation items. See "COMMAND LINK" in Figure 1.

[CA TABLE HEADER] The heading above the page text. In Figure 1, "Welcome to the preview of your theme!".

[CA TABLE DESCRIPTION] The description text. In Figure 1, "You are looking at an example of how the colors will be used in this
theme for your content. This is an example of a…".

[CA ACCENT COLORS] The list of accent colors and blocks.

[CA LIST TITLE] The heading of the list. In Figure 1, "Example of a list".

[CA TABLE] The sample list.

[SITETITLE] The title of the site. See "Site Title" in Figure 1.

Figure 1. Preinstalled theme with sample text


Create a master page preview file
To create a master page preview file, use an existing master page preview as a starting point.

To create a master page preview


1. Make a copy of a master page preview. SharePoint includes oslo.preview and seattle.preview.
2. Rename the copy of the master page preview to match its corresponding master page. For example, if your master page is named article.master, rename the master page preview
article.preview.
3. Use an HTML editor to edit the master page preview file. Update the file to reflect the layout and appearance of your master page.

Tip: Dimension values are specified as percentages in the master page preview file. The following example shows one method for converting an absolute measurement (pixels)
into a relative measurement (percentage). Assume you have a browser size of 1024x768. If the master page has an element height of 32 pixels and the parent element is the body
of the page, you calculate the percentage by dividing the element height by the browser height. The relative measurement is 4%(32/768).

4. Upload the master page preview file to the Master Page Gallery.
5. Use the Change the look wizard to test the master page preview with your site content.
NOTE

You can also create a design that uses the new master page by adding an item to the Composed Looks list. The design will be available in the design gallery (the first page of the
Change the look wizard). For more information, see the Deploy a theme by using the user interface procedure in How to: Deploy a custom theme in SharePoint.
6. Repeat steps 3 to 5, as necessary.

See also
Develop the site design in SharePoint
How to: Deploy a custom theme in SharePoint
Color palettes and fonts in SharePoint
SharePoint Team Blog: Show off your style with SharePoint theming
Deploy a custom theme in SharePoint
4/10/2018 • 7 minutes to read Edit Online

Learn how to deploy a custom theme to a SharePoint site by using the user interface or by implementing a feature receiver. SharePoint includes preinstalled themes. You can create custom
themes by creating additional color palettes, font schemes, and master pages. After the files are uploaded to the Theme Gallery and the Master Page Gallery, you can deploy a theme to a site
by using the user interface or by using code. For more information about color palettes and font schemes, see Color palettes and fonts in SharePoint.
NOTE

This article only applies in the context of classic SharePoint site experience. If you are looking details around modern SharePoint sites and their theme support, please have a look on the
following article - SharePoint site theming

Core concepts to know to deploy a theme


Table 1 lists articles that can help you understand the core concepts of deploying themes.
Table 1. Core concepts to deploy a theme

AR TICLE TITLE D ES CR IPTIO N

Themes overview for SharePoint Learn about the theming experience in SharePoint.

Feature Events Learn about feature events, which enable you to trap and respond to an event that occurs when a
feature is installed in the server farm.

Upload files to the Theme Gallery and the Master Page Gallery
You can create custom themes by creating additional color palettes and font schemes and uploading them to the Theme Gallery. The new color palettes and font schemes are then available
to you when you modify a design in the theming experience or when you apply a theme programmatically. Similarly, if you want to have additional site layouts to choose from, you can
upload additional master pages, and corresponding preview files, to the Master Page Gallery. The following list describes where to place the files:
Master Page Gallery Lists the master page files, and their corresponding preview files (.preview files). A master page preview file is required if you want the master page to be
available in the Change the look wizard. JavaScript files and other design assets can also be uploaded to the Master Page Gallery.
To access the Master Page Gallery from the SharePoint user interface, on the Site Settings page, under Web Designer Galleries, choose Master pages. You can also navigate
directly to the site (http:// SiteName/_catalogs/masterpage/).
Theme Gallery Lists the color palettes and font schemes that are available to the theming experience. SharePoint looks in the 15 folder to determine the available color palettes and
font schemes.
To access the Theme Gallery from the SharePoint user interface, on the Site Settings page, under Web Designer Galleries, choose Themes. You can also navigate directly to the site
(http:// SiteCollectionName/_catalogs/theme/15/).
Style library Lists custom CSS files that you want to use in the theming experience. You can navigate directly to the Style library (replace SiteCollectionName and language in this
URL: http:// SiteCollectionName/Style Library/ language/Themable/).
NOTE

Place the custom CSS files in the Themable folder in the Style library, not the Themable folder in the Master Page Gallery. Only CSS files that are stored in the Themable folder in the
Style library are recognized by the theming engine.
NOTE

If you have versioning enabled on the Master Page Gallery and the Theme Gallery, you must also publish the design files before they can be used by the theming engine.

Deploy a theme by using the user interface


A composed look, or design, is the color palette, font scheme, background image, and master page that determine the look and feel of a site. The Composed Looks list contains the composed
looks that are available in the design gallery. You create a design by adding a list item in the Composed Looks list and specifying the master page, color palette, font scheme, and background
image to use.
NOTE

A master page preview file is required if you want the master page to be available in the design gallery.

To add a composed look


1. Choose the Settings icon, and then choose Site settings.
2. Under Web Designer Galleries, choose Composed looks.
3. In the Composed Looks list, select new item.
4. In the Title text box, enter a title for the design.
5. In the Name text box, enter a name for the design. The name appears in the Composed Looks list and in the design gallery.
6. In the Master Page URL text box, enter the URL of the master page. The URL can be a relative URL.
7. In the Theme URL text box, enter the URL of the color palette (the URL to the .spcolor file). The URL can be a relative URL.
8. In the Image URL text box, enter the URL of the background image. This is optional. The URL can be a relative URL.
9. In the Font Scheme URL text box, enter the URL of the font scheme (the URL to the .spfont file). This is optional. The URL can be a relative URL.
10. In the Display Order text box, enter the display order number. This determines where the design appears in the design gallery.
11. Choose Save.
NOTE

If there is an issue with the composed look values, the composed look is not added to the design gallery, and no message is recorded in the log files. The following are possible
reasons why a composed look cannot be added: a file cannot be found, there is a formatting issue with one of the files, or SharePoint is unable to access the files.
You can now use the design gallery to apply the new design to your site. For more information, see Choose a theme for your publishing site on Office.com.

Deploy a theme by using code


You can deploy a theme by implementing a feature receiver.

To deploy a theme by using a feature receiver


1. Create a feature receiver class that inherits from the SPFeatureReceiver class.
2. In the FeatureActivated method, create an SPTheme object that uses the color palette and font scheme, and then apply the theme to your site.
The following code example shows how to deploy a custom color palette and font scheme to a site.

// Get the SPColor file. Replace with the path to your SPColor file.
SPFile colorPaletteFile = Web.GetFile("path to .spcolor file");
if (null == colorPaletteFile || !colorPaletteFile.Exists)
{
// TODO: handle the error.
return;
}

// Get the SPFont file. Replace with the path to your SPFont file.
SPFile fontSchemeFile = Web.GetFile("path to .spfont file");
if (null == fontSchemeFile || !fontSchemeFile.Exists)
{
// TODO: handle the error.
return;
}

// Open an SPTheme with the two files. Replace NewTheme with the name for your theme.
// Note: If you have a background image, you can specify the following:
// SPTheme.Open("NewTheme", colorPaletteFile, fontSchemeFile, backgroundURI)
SPTheme theme = SPTheme.Open("NewTheme", colorPaletteFile, fontSchemeFile);

// Now apply your theme to the site.


// The themed CSS output files are stored in the Themed folder of the Theme Gallery of the root web
// of the site collection. To specify that the files should be stored in the _themes folder within the root
// web, pass false to the ApplyTo method.
theme.ApplyTo(Web, true);

> [!NOTE]
> The _shareGenerated_ parameter in the **ApplyTo** method specifies whether the themed files can be shared across sites in a site collection. In general, it is set to **true** for SharePoint Se

When a user applies a theme in the **Change the look** wizard, the wizard also updates a theme named Current in the Composed Looks list and the design gallery. When you apply a theme programmatic

SPList designGallery = Web.GetCatalog(SPListTemplateType.DesignCatalog);


if (null == designGallery)
{
// TODO: Handle the error.
return;
}

SPQuery q = new SPQuery();


q.RowLimit = 1;
q.Query = "<Where><Eq><FieldRef Name='DisplayOrder'/><Value Type='Number'>0</Value></Eq></Where>";
q.ViewFields = "<FieldRef Name='DisplayOrder'/>";
q.ViewFieldsOnly = true;

SPListItemCollection currentItems = designGallery.GetItems(q);

If (currentItems.Count == 1)
{
// Remove the old Current item.
currentItems[0].Delete();
}

SPListItem currentItem = designGallery.AddItem();

currentItem["Name"] = SPResource.GetString(CultureInfo.CurrentUICulture, Strings.DesignGalleryCurrentItemName);


currentItem["Title"] = SPResource.GetString(CultureInfo.CurrentUICulture, Strings.DesignGalleryCurrentItemName);

// Change this line if you want to specify a different master page.


currentItem["MasterPageUrl"] = Web.MasterUrl;

// Replace with the path to your SPColor file.


currentItem["ThemeUrl"] = "path to .spcolor file";

// Delete the following line if you do not have a background image. Otherwise, replace with the path to
// the background image.
currentItem["ImageUrl"] = "path to background image";

// Replace with the path to your SPFont file. Or, you can delete this line if you want to use
// the default font scheme of the selected master page.
currentItem["FontSchemeUrl"] = "path to .spfont file";

currentItem["DisplayOrder"] = 0;
currentItem.Update();

See also
Develop the site design in SharePoint
Color palettes and fonts in SharePoint
How to: Create a master page preview file in SharePoint
SharePoint Team Blog: Show off your style with SharePoint theming
Make custom CSS files themable in SharePoint
3/26/2018 • 5 minutes to read Edit Online

Learn how to add comment-style markup to a CSS file so that it can be used in the SharePoint theming engine.

Introduction to annotations
Annotations are special comment-style markup that tell the SharePoint theming engine how to theme properties in a CSS file. When a theme is applied to a site, the theming engine replaces
the CSS property values with the appropriate theme values. In SharePoint, you can use annotations to change the color, font, or background image. You can also recolor an image. If you are
using custom CSS files, you must add these annotations to the CSS files if you want to use them with the SharePoint theming engine. If you apply a theme to a site that uses custom CSS
files, and you haven't added annotations, the CSS properties remain unchanged. This can result in a site that has a mismatched design.
This article describes the available annotations and how to register CSS files.
For more information about custom themes, see How to: Deploy a custom theme in SharePoint and How to: Create a master page preview file in SharePoint.

Add annotations to custom CSS files


Annotations tell the SharePoint theming engine how to theme properties in a CSS file. This section describes the available annotations and how they can be used.

ReplaceColor annotation
The ReplaceColor annotation replaces the color value with the specified theme color. It can be used with CSS properties that define a color value, such as color, background-color,
border, and so on.
The following shows the format for the ReplaceColor annotation.

/* [ReplaceColor(themeColor:"ColorSlot"[, themeShade:"ShadeValue"][, themeTint:"TintValue"][, opacity:"OpacityValue"])] */

Replace ColorSlot with the annotation name of the color slot to use. To see a list of available color slots, see the Color slot mapping section in Color palettes and fonts in SharePoint.
Use the optional themeShade parameter if you want to darken the theme color. Replace ShadeValue with a numeric value from 0.0 (no change) to 1.0 (darkest).
Use the optional themeTint parameter if you want to lighten the theme color. Replace TintValue with a numeric value from 0.0 (no change) to 1.0 (lightest).
Use the optional opacity parameter if you want to specify the opacity of the theme color. Replace OpacityValue with a numeric value that specifies the opacity setting. The opacity setting
ranges from 0.0 (fully transparent) to 1.0 (fully opaque).
The following shows examples of the ReplaceColor annotation being used in a CSS file.
/* [ReplaceColor(themeColor:"BodyText")] */ color:#444;

/* [ReplaceColor(themeColor:"BackgroundOverlay",opacity:"0.5")] */ background-color:#fff;

/* [ReplaceColor(themeColor:"EmphasisBackground",themeTint:"0.05")] */ background-color:#f2faff;

ReplaceFont annotation
The ReplaceFont annotation adds the specified theme font to the list of available fonts. It can be used with the font and font-family CSS properties.
The following shows the format for the ReplaceFont annotation.

/* [ReplaceFont(themeFont:"FontSlot")] */

Replace FontSlot with the name of the font slot to use. To see a list of available font slots, see the Font slots section in Color palettes and fonts in SharePoint.
The following shows an example of the ReplaceFont annotation. In this example, if the body font slot is defined as Courier in the theme, Courier will be added as the first item in the list of
available fonts in the Choose the Look wizard.
/* [ReplaceFont(themeFont:"body")] */ font-family:"Segoe UI","Segoe",Tahoma,Helvetica,Arial,sans-serif;

ReplaceBGImage annotation
The ReplaceBGImage annotation replaces the background image in the CSS file with the theme background image. It can be used with the background and background-image CSS
properties.
The following shows the format for the ReplaceBGImage annotation. The ReplaceBGImage annotation can also be used with the AlphaImageLoader filter to support earlier versions of
Internet Explorer.

/* [ReplaceBGImage] */

RecolorImage annotation
The RecolorImage annotation recolors the image specified.
The following describes the format of the RecolorImage annotation.

/* [RecolorImage(themeColor:"ColorSlot"[, method:["Tinting"|"Blending"|"Filling"]][, includeRectangle: {x:x-Setting,y:y-Setting,width:RegionWidth,height:RegionHeight})] */

Replace ColorSlot with the annotation name of the color slot. To see a list of available color slots, see the Color slot mapping section in Color palettes and fonts in SharePoint.
Use the optional method parameter if you want to specify the recoloring method.
Use the optional includeRectangle parameter if you want to recolor only a specific region of an image. Replace x-Setting, y-Setting, RegionWidth, and RegionHeight with the x-coordinate,
y-coordinate, width, and height of the region that you want to recolor.
The following shows examples of the RecolorImage annotation being used in a CSS file.
/* [RecolorImage(themeColor:"SubtleBodyText",method:"Tinting")] */ background-image:url("/_layouts/15/images/tabtitlerowbottombg.png?rev=23");

/* [RecolorImage(themeColor:"BodyText",method:"Filling",includeRectangle:{x:161,y:178,width:16;height:16})] */ background:url("/_layouts/15/images/spcommon.png?rev=23") no-repeat


-161px -178px;

Upload the CSS file to the Themable folder in the Style library
Place the custom CSS files in the Themable folder in the Style library (not the Themable folder in the Master Page Gallery). Only CSS files that are stored in the Themable folder in the Style
library are recognized by the theming engine. The Themable folder is created automatically for publishing sites. Otherwise, you can create the Themable folder in the correct location (http://
SiteCollectionName/Style Library/ language/Themable/).
NOTE

The name of the language folder must be in the 4-digit format ll-cc to identify the language and culture, respectively. For example, en-us or ar-sa. For more information, see Language
identifiers and OptionState Id values in Office 2013.
CSS files must be checked in and published. If CSS files are changed, you must reapply the theme for the changes to be recognized.

Register the CSS file


You must register the CSS file with a master page before the CSS file can be used by the theming engine. This directs the master page to the CSS file when you apply a theme to a site. To
register a CSS file, you add a <SharePoint:CssRegistration> element to the element of the master page. The following shows the format of the <SharePoint:CssRegistration> element.

<SharePoint:CssRegistration Name="CSSFileLocation" runat="server" />

Replace CSSFileLocation with the location of the CSS file.


The following is an example of an <SharePoint:CssRegistration> element.

<head>

<SharePoint:CssRegistration Name="<%$SPUrl:~SiteCollection/Style Library/~language/Themable/MyCustomFile.css%>" runat="server" />
</head>

NOTE

The %$SPUrl token cannot be used on SharePoint Foundation 2013. You must use a URL to specify the location of the CSS file.

See also
Themes overview for SharePoint
How to: Deploy a custom theme in SharePoint
Upgrade custom themes and CSS to SharePoint
How to: Create a master page preview file in SharePoint
Color palettes and fonts in SharePoint
SharePoint Team Blog: Show off your style with SharePoint theming
SharePoint Design Manager branding and design capabilities
Upgrade custom themes and CSS to SharePoint
3/26/2018 • 5 minutes to read Edit Online

Learn about upgrade issues with themes customizations, such as custom CSS and custom master pages, and how to update customizations to work in SharePoint.

Introduction to themes customizations and upgraded SharePoint sites


The theming experience in SharePoint was redesigned to simplify the process of customizing sites by changing the site layout, color palette, font scheme, and background image. The themes
user interface was redesigned and there is a set of new file formats related to themes. Custom themes that were created in SharePoint 2010 cannot be used on SharePoint sites, you must re-
create them. Custom CSS files may not work successfully on SharePoint sites until after they are updated to work with the new master pages, color slots, and other theming changes.
This article describes the issues that may occur when you try to use custom SharePoint 2010 themes, SharePoint 2010 CSS, and custom CSS with the new theming experience. It also
explains the changes you have to make to your custom SharePoint 2010 themes, SharePoint 2010 CSS, and custom CSS if you want to use them in SharePoint sites.
NOTE

SharePoint 2010 themes can be used on site collections that are running in 2010 mode. For more information about site collection modes, see Plan for site collection upgrades in SharePoint
or Plan for upgrade to SharePoint.
For more information about themes, see Themes overview for SharePoint.

Custom SharePoint 2010 themes in SharePoint


In SharePoint 2010, themes were stored in THMX files. In SharePoint, there is a set of new file formats related to themes. Color palettes and font schemes are stored in separate XML files
(.spcolor and .spfont files, respectively).
You cannot upgrade a THMX file from SharePoint 2010 to SharePoint. If you applied a custom theme to your SharePoint 2010 site, when you upgrade to SharePoint, the theme files remain
in place, but the theme is no longer applied to the site, and the site reverts to the default theme. If you want to use your SharePoint 2010 themes customizations on SharePoint sites, you
must re-create them using the SharePoint theming guidance.
For more information about creating themes customizations, see How to: Deploy a custom theme in SharePoint and Color palettes and fonts in SharePoint. You can also use the SharePoint
color palette tool to help you create SharePoint designs. You can download the SharePoint color palette tool from the Microsoft Download Center.

Tip: You can open a THMX file in PowerPoint to see how the colors are defined in the custom theme and then use the color palette tool to re-create the colors as a color palette file (an
.spcolor file). A color palette is the combination of colors that are used in a SharePoint site.

You can also decide to use one of the preinstalled SharePoint themes. For more information, see Choose a theme for your publishing site on Office.com.

Upgrading customized master pages


When you upgrade a SharePoint 2010 site to SharePoint, the site is configured to use the default master page for SharePoint. If you had a custom master page for your SharePoint 2010 site,
it still resides in the site and you can apply it to the SharePoint site. You can use the SharePoint user interface or the SPWeb class to apply the custom master page to the upgraded site. For
more information about how to change the master page, see How to: Apply a master page to a site in SharePoint.
Consider the following before you decide whether to apply the SharePoint 2010 custom master page to the upgraded SharePoint site:
If the custom master page depends on custom CSS files: Applying the custom master page to the upgraded site should return the site to its original 2010 experience. But, you
will be unable to apply a SharePoint theme to the site.
If you want to use the custom master page and custom CSS files together with the SharePoint theming experience, you must update the CSS files to use the new SharePoint color
slots. If you want to access the custom master page from the themes user interface, you also have to create a master page preview file. For more information, see How to: Create a
master page preview file in SharePoint.
If the custom master page depends on SharePoint 2010 CSS files: CSS files have changed significantly from SharePoint 2010 to SharePoint. In many cases, you will have to
rework the master page so that it can work with new classes before you can successfully apply it to the upgraded site. For more information about CSS classes, see the Using the
host web CSS in apps for SharePoint section in SharePoint Add-ins UX design guidelines.

SharePoint 2010 CSS and custom CSS files


Unmodified SharePoint 2010 CSS files and custom CSS files cannot be used on SharePoint sites. The following describes SharePoint changes that apply to SharePoint 2010 CSS and
custom CSS files:
Color slots. The number of available color slots has increased significantly in SharePoint. You must update the color slots in SharePoint 2010 CSS files before they can be used in the
new theming experience. For more information, see the Color slot mapping section in Color palettes and fonts in SharePoint.
Font slots. You should review the list of available font slots and verify that the CSS files you want to use in SharePoint are using the correct font slots. For more information, see the
Font slots section in Color palettes and fonts in SharePoint.
New annotation. SharePoint has a new annotation that lets you replace the background image. For more information, see How to: Make custom CSS files themable in SharePoint.
New classes. You may have to update CSS files to work with the new classes in SharePoint. For more information about CSS classes (also referred to as CSS styles), see the Using
the host web CSS in apps for SharePoint section in SharePoint Add-ins UX design guidelines.

See also
Themes overview for SharePoint
How to: Create a master page preview file in SharePoint
How to: Deploy a custom theme in SharePoint
Color palettes and fonts in SharePoint
SharePoint Team Blog: Show off your style with SharePoint theming
SharePoint Design Manager branding and design capabilities
Color palettes and fonts in SharePoint
5/3/2018 • 14 minutes to read Edit Online

Use this reference to define the color palette or font scheme that is used in a SharePoint site.

Color palettes
A color palette is the combination of colors that are used in a SharePoint site. The color palette for a SharePoint site is defined in a color palette file. Color slots are also used by the master
page preview file to generate thumbnail and preview images of a site. The following describes the structure of the color palette file and the master page preview file:
Color palette file (.spcolor)
Color palette files are used in the Change the look wizard, which enables users to change the look and feel of their site by using the SharePoint themes user interface. By default, 32
color palette files are installed with SharePoint. You can also create additional color palette files. The following example shows the format of a color palette file.

<s:colorPalette isInverted="InvertedSetting" previewSlot1="Slot1" previewSlot2="Slot2" previewSlot3="Slot3" xmlns:s="http://schemas.microsoft.com/sharepoint/">


<s:color name="ColorSlot" value="Color" />
<!--additional color slots-->
</s:colorPalette>

In a color palette file, the following placeholders are replaced:


InvertedSetting is a Boolean value. true if the color palette is generally light text on a dark background. false if the color palette is generally dark text on a light background.
Slot1 is the annotation name of the color slot to use as the first block of the palette icon in the color palette picker of the theming experience.
Slot2 is the annotation name of the color slot to use as the second block of the palette icon in the color palette picker of the theming experience.
Slot3 is the annotation name of the color slot to use as the third block of the palette icon in the color palette picker of the theming experience.
ColorSlot is the annotation name of the color slot that you are defining (for example, SiteTitle).
Color is the hexadecimal value of the color to use for the specified color slot. This may be in 6 digits (RRGGBB) or 8 digits (AARRGGBB). If the hexadecimal value is 8 digits, the first
two digits represent the opacity level (00-FF, which maps to 0-255). If the hexadecimal value is 6 digits, the default opacity is 100% or FF.
The color palette files are located in the Theme Gallery of the root site, in the site collection in the 15 folder (http:// SiteCollectionName/_catalogs/theme/15/). To access the Theme Gallery
from the SharePoint user interface, on the Site Settings page, under Web Designer Galleries, select Themes, and then select 15.
Master page preview file (.preview)
Master page preview files are used to generate thumbnail images and preview images when you use the Change the look wizard. A master page must have a corresponding preview
file to be used in the Change the look wizard. A preview file is a specially formatted file that has sections for the default color palette, default font scheme, tokenized CSS, and
tokenized HTML. It uses string tokens to get the value of color slots, font names, and localized UI strings. The following example shows color slots being used in the master page
preview file.

[ID] #dgp-pageContainer
{
background-color: [T_THEME_COLOR_PAGEBACKGROUND];
color: [T_THEME_COLOR_BODYTEXT];
width: 100%;
height:100%;
background-image: url('[T_IMAGE]');
background-size: cover;
font-family: [T_BODY_FONT];
}

For more information, see How to: Create a master page preview file in SharePoint

Tip: You can use the SharePoint color palette tool to help you create SharePoint designs. You can download the SharePoint color palette tool from the Microsoft Download Center.

Color slot mapping


Table 1 describes the color slots that are available and where color slots are used in a SharePoint site.
NOTE

When discussing navigation items,pressed applies to when a user clicks or touches a navigation item.Selected applies to when a user is navigated to the page.> The following summarizes a
normal flow of actions and the color slot that applies to the navigation item link at each step:> The base text of a navigation item link: HeaderNavigationText> A user hovers the cursor over
the navigation item link: HeaderNavigationHoverText> A user clicks, touches, or chooses the navigation item link: HeaderNavigationPressedText> The user is navigated to the chosen page.
The color slot that applies to the navigation item for the page the user is now on: HeaderNavigationSelectedText
Table 1. Color slots

ANNO TATIO N NAME W HER E THE CO LO R IS U S ED IN THE U I TO K EN NAME

BodyText Normal body text. [T_THEME_COLOR_BODYTEXT]

SubtleBodyText Body text that must be lighter than normal. An example is metadata [T_THEME_COLOR_SUBTLEBODYTEXT]
text.

StrongBodyText Body text color for text that must stand out from normal body text. [T_THEME_COLOR_STRONGBODYTEXT]

DisabledText Disabled text. For example, unavailable items in menus. [T_THEME_COLOR_DISABLEDTEXT]

SiteTitle The text color of the page title. [T_THEME_COLOR_SITETITLE]


ANNO TATIO N NAME W HER E THE CO LO R IS U S ED IN THE U I TO K EN NAME

WebPartHeading Text color for web part headings. [T_THEME_COLOR_WEBPARTHEADING]

ErrorText The main error color that is used for error text, borders, and [T_THEME_COLOR_ERRORTEXT]
backgrounds, as needed.

AccentText Text color for accented body text. [T_THEME_COLOR_ACCENTTEXT]

SearchURL Text color for the URL found in search results. Also used to highlight [T_THEME_COLOR_SEARCHURL]
new items or successful status notifications.

Hyperlink Text color for hyperlinks. [T_THEME_COLOR_HYPERLINK]

HyperlinkFollowed Text color for followed hyperlinks. [T_THEME_COLOR_HYPERLINKFOLLOWED]

HyperlinkActive Hyperlink color when pressed. [T_THEME_COLOR_HYPERLINKACTIVE]

CommandLinks Large command links that must be a bit lighter than body text [T_THEME_COLOR_COMMANDLINKS]
because of their size.

CommandLinksSecondary Command link color for links that are smaller, and therefore have a [T_THEME_COLOR_COMMANDLINKSSECONDARY]
stronger color to stand out.

CommandLinksHover Command link color on hover. [T_THEME_COLOR_COMMANDLINKSHOVER]

CommandLinksPressed Command link color when pressed. [T_THEME_COLOR_COMMANDLINKSPRESSED]

CommandLinksDisabled Command link color when command link is disabled. [T_THEME_COLOR_COMMANDLINKSDISABLED]

BackgroundOverlay The main background color that is visible between the optional [T_THEME_COLOR_BACKGROUNDOVERLAY]
background image and the page content.

DisabledBackground Background for disabled elements such as browser controls, for [T_THEME_COLOR_DISABLEDBACKGROUND]
example, input box or select box (except buttons).

PageBackground The background color of the page. Appears behind the optional [T_THEME_COLOR_PAGEBACKGROUND]
background image.

HeaderBackground The background color for the header area of the page. [T_THEME_COLOR_HEADERBACKGROUND]

FooterBackground The background color for the footer area of the page. [T_THEME_COLOR_FOOTERBACKGROUND]

SelectionBackground The background color for selected list items and drop-down menu [T_THEME_COLOR_SELECTIONBACKGROUND]
items.

HoverBackground The background color for list items and drop-down menu items on [T_THEME_COLOR_HOVERBACKGROUND]
hover.

RowAccent The accented left border on selected list items. [T_THEME_COLOR_ROWACCENT]

StrongLines Borders for browser controls on hover. [T_THEME_COLOR_STRONGLINES]

Lines Borders for browser controls. [T_THEME_COLOR_LINES]

SubtleLines Subtle border color. For example, gridlines for inline editing. [T_THEME_COLOR_SUBTLELINES]

DisabledLines Border color for disabled browser controls such as input boxes and [T_THEME_COLOR_DISABLEDLINES]
select boxes.

AccentLines Focused border color for selected browser controls. [T_THEME_COLOR_ACCENTLINES]

DialogBorder Dialog box border color. [T_THEME_COLOR_DIALOGBORDER]

Navigation Text color for horizontal and vertical navigation items. [T_THEME_COLOR_NAVIGATION]

NavigationAccent Text color for a selected horizontal navigation item. [T_THEME_COLOR_NAVIGATIONACCENT]

NavigationHover Navigation text color on hover. Applies to top navigation, and to [T_THEME_COLOR_NAVIGATIONHOVER]
Quick Launch in horizontal mode.

NavigationPressed Text color of navigation item when pressed. Applies to top [T_THEME_COLOR_NAVIGATIONPRESSED]
navigation, and to Quick Launch in horizontal mode.

NavigationHoverBackground Background color of Quick Launch items in vertical mode on hover [T_THEME_COLOR_NAVIGATIONHOVERBACKGROUND]
over the navigation item.

NavigationSelectedBackground Background color of Quick Launch items in vertical mode after the [T_THEME_COLOR_NAVIGATIONSELECTEDBACKGROUND]
navigation item is selected.

EmphasisText The text color that appears on top of emphasis background. [T_THEME_COLOR_EMPHASISTEXT]
ANNO TATIO N NAME W HER E THE CO LO R IS U S ED IN THE U I TO K EN NAME

EmphasisBackground The accented background color that appears directly behind [T_THEME_COLOR_EMPHASISBACKGROUND]
emphasis text.

EmphasisHoverBackground Background color on hover, for elements that are using emphasis [T_THEME_COLOR_EMPHASISHOVERBACKGROUND]
background.

EmphasisBorder Border color for elements that are using emphasis background. [T_THEME_COLOR_EMPHASISBORDER]

EmphasisHoverBorder Border color on hover for elements that are using emphasis [T_THEME_COLOR_EMPHASISHOVERBORDER]
background.

SubtleEmphasisText Text that appears on top of subtle emphasis background. [T_THEME_COLOR_SUBTLEEMPHASISTEXT]

SubtleEmphasisCommandLinks Command link color for links that appear on top of subtle emphasis [T_THEME_COLOR_SUBTLEEMPHASISCOMMANDLINKS]
background.

SubtleEmphasisBackground Background that appears directly behind subtle emphasis text. [T_THEME_COLOR_SUBTLEEMPHASISBACKGROUND]

TopBarText Text and glyph color for the welcome menu, quick access toolbar [T_THEME_COLOR_TOPBARTEXT]
icons, and closed ribbon tabs.

TopBarBackground The background color for the top bar, which is seen below and to [T_THEME_COLOR_TOPBARBACKGROUND]
the right of the suite navigation.

TopBarHoverText Text and glyph color on hover for the welcome menu, quick access [T_THEME_COLOR_TOPBARHOVERTEXT]
toolbar icons, and closed ribbon tabs.

TopBarPressedText Text and glyph color for when the welcome menu, quick access [T_THEME_COLOR_TOPBARPRESSEDTEXT]
toolbar icons, or closed ribbon tabs are pressed.

HeaderText The base text color for anything in the header area. [T_THEME_COLOR_HEADERTEXT]

HeaderSubtleText Helper text for the search box when in the header area. [T_THEME_COLOR_HEADERSUBTLETEXT]

HeaderDisableText Text for the search box, if the search box is disabled when in the [T_THEME_COLOR_HEADERDISABLETEXT]
header area.

HeaderNavigationText Base text color for navigation links in the header area. [T_THEME_COLOR_HEADERNAVIGATIONTEXT]

HeaderNavigationHoverText Text color for navigation links in the header area when you hover [T_THEME_COLOR_HEADERNAVIGATIONHOVERTEXT]
over the link.

HeaderNavigationPressedText Text color for navigation links in the header area when you press the [T_THEME_COLOR_HEADERNAVIGATIONPRESSEDTEXT]
link.

HeaderNavigationSelectedText Text color for navigation links in the header area after the link is [T_THEME_COLOR_HEADERNAVIGATIONSELECTEDTEXT]
selected.

HeaderLines Search box lines when the search box is in the header area. [T_THEME_COLOR_HEADERLINES]

HeaderStrongLines Search box lines on hover when the search box is in the header area. [T_THEME_COLOR_HEADERSTRONGLINES]

HeaderAccentLines Search box lines on focus when the search box is in the header area. [T_THEME_COLOR_HEADERACCENTLINES]

HeaderSublteLines Subtle lines found inside the header area. Not used in default CSS. [T_THEME_COLOR_HEADERSUBTLELINES]

HeaderDisabledLines Search box lines if the search box is disabled when it's in the header [T_THEME_COLOR_HEADERDISABLEDLINES]
area.

HeaderDisabledBackground Search box background if the search box is disabled when it's in the [T_THEME_COLOR_HEADERDISABLEDBACKGROUND]
header area.

HeaderFlyoutBorder Border for drop-down menus when originating from the header [T_THEME_COLOR_HEADERFLYOUTBORDER]
area.

HeaderSiteTitle Text color for the site title when in the header area. [T_THEME_COLOR_HEADERSITETITLE]

SuiteBarBackground Background color for the suite navigation. [T_THEME_COLOR_SUITEBARBACKGROUND]

SuiteBarHoverBackground Background color on hover for the suite navigation. [T_THEME_COLOR_SUITEBARHOVERBACKGROUND]

SuiteBarText Text and glyph color for the suite navigation items. [T_THEME_COLOR_SUITEBARTEXT]

SuiteBarDisabledText Text and glyph color for disabled suite items. Not used in default [T_THEME_COLOR_SUITEBARDISABLEDTEXT]
CSS.

ButtonText Text color for buttons. [T_THEME_COLOR_BUTTONTEXT]

ButtonDisabledText Text color for disabled buttons. [T_THEME_COLOR_BUTTONDISABLEDTEXT]

ButtonBackground Background color for buttons. [T_THEME_COLOR_BUTTONBACKGROUND]


ANNO TATIO N NAME W HER E THE CO LO R IS U S ED IN THE U I TO K EN NAME

ButtonHoverBackground Background color for buttons on hover. [T_THEME_COLOR_BUTTONHOVERBACKGROUND]

ButtonPressedBackground Background color for buttons while pressed. [T_THEME_COLOR_BUTTONPRESSEDBACKGROUND]

ButtonDisabledBackground Background color for disabled buttons. [T_THEME_COLOR_BUTTONDISABLEDBACKGROUND]

ButtonBorder Border color for buttons. [T_THEME_COLOR_BUTTONBORDER]

ButtonHoverBorder Border color for buttons on hover. [T_THEME_COLOR_BUTTONHOVERBORDER]

ButtonPressedBorder Border color for buttons while pressed. [T_THEME_COLOR_BUTTONPRESSEDBORDER]

ButtonDisabledBorder Border color for buttons that are disabled. [T_THEME_COLOR_BUTTONDISABLEDBORDER]

ButtonGlyph Glyph color for a glyph that appears in a button. [T_THEME_COLOR_BUTTONGLYPH]

ButtonGlyphActive Glyph color on hover, for a glyph that appears in a button. [T_THEME_COLOR_BUTTONGLYPHACTIVE]

ButtonGlyphDisabled Glyph color for a disabled button. [T_THEME_COLOR_BUTTONGLYPHDISABLED]

TileText The text that appears on top of the tile background overlay. [T_THEME_COLOR_TILETEXT]

TileBackgroundOverlay The background overlay color for tiles. [T_THEME_COLOR_TILEBACKGROUNDOVERLAY]

ContentAccent1 The first accent color that a user can select from the Rich Text Editor [T_THEME_COLOR_CONTENTACCENT1]
color picker.

ContentAccent2 The second accent color that a user can select from the Rich Text [T_THEME_COLOR_CONTENTACCENT2]
Editor color picker.

ContentAccent3 The third accent color that a user can select from the Rich Text [T_THEME_COLOR_CONTENTACCENT3]
Editor color picker.

ContentAccent4 The fourth accent color that a user can select from the Rich Text [T_THEME_COLOR_CONTENTACCENT4]
Editor color picker.

ContentAccent5 The fifth accent color that a user can select from the Rich Text Editor [T_THEME_COLOR_CONTENTACCENT5]
color picker.

ContentAccent6 The sixth accent color that a user can select from the Rich Text Editor [T_THEME_COLOR_CONTENTACCENT6]
color picker.

Font schemes
Fonts are defined in the font scheme (.spfont file) and the master page preview (.preview file) for a given SharePoint site. The font scheme defines the fonts that are used in four areas: title,
navigation, heading, and body. Seven font schemes are included in SharePoint. You can create additional font schemes. The font scheme files are located in the 15 subfolder of the Theme
Gallery of the root site of the site collection (http:// SiteCollectionName/_catalogs/theme/15/). To access the Theme Gallery from the SharePoint user interface, on the Site Settings page,
under Web Designer Galleries, select Themes, and then select 15.
The following example describes the format for an .spfont file.

<?xml version="1.0" encoding="utf-8"?>


<s:fontScheme name="FontSchemeName" previewSlot1="Slot1" previewSlot2="Slot2" xmlns:s="http://schemas.microsoft.com/sharepoint/">
<s:fontSlots>
<s:fontSlot name="FontSlotName">
<s:latin typeface="LatinScriptFont" />
<s:ea typeface="EAScriptFont"/>
<s:cs typeface="CSFont" />
<s:font script="Language" typeface="ScriptFont" />
<!--Additional fonts-->
</s:fontSlots>
<!--Additional font slots-->
</s:fontScheme>

In an .spfont file, the following placeholders are replaced:


FontSchemeName is the name of the font scheme.
Slot1 is the name of the font slot that you want to use as the first block of the font icon in the font scheme picker in the Change the look wizard.
Slot2 is the name of the font slot that you want to use as the second block of the font icon in the font scheme picker in the Change the look wizard.
FontSlotName is the name of the font slot that you are defining (for example, title).
LatinScriptFont is the font to use for Latin scripts. This font is also the fallback font. That is, this is the font that is used for a language that does not have a script that is explicitly set in
the font scheme.
NOTE

You must provide additional information to use web fonts in your font scheme. For more information, see the Web fonts section in this article.
EAScriptFont is the font to use for East Asia scripts. The <s:ea> element is not currently used by SharePoint. But, the <s:ea> element is still required in the font scheme.
CSFont is the font to use for complex scripts. The <s:cs> element is not currently used by SharePoint. But, the <s:cs> element is still required in the font scheme.
Language is the language script.
ScriptFont is the font to use for the specified language script.
The following example shows a portion of an .spfont file.

<s:fontScheme name="Georgia" previewSlot1="title" previewSlot2="body" xmlns:s="http://schemas.microsoft.com/sharepoint/">


<s:fontSlots>
<s:fontSlot name="title">
<s:latin typeface="Georgia"/>
<s:ea typeface=""/>
<s:cs typeface="Segoe UI Light" />
<s:font script="Arab" typeface="Tahoma" />
<s:font script="Deva" typeface="Mangal" />
<s:font script="Grek" typeface="Segoe UI Light" />
<s:font script="Hang" typeface="Malgun Gothic" />
<s:font script="Hans" typeface="Microsoft YaHei" />
<s:font script="Hant" typeface="Microsoft JhengHei" />
<s:font script="Hebr" typeface="Tahoma" />
<s:font script="Hira" typeface="Meiryo" />
<s:font script="Thai" typeface="Tahoma" />
<s:font script="Armn" typeface="Tahoma" />
<s:font script="Beng" typeface="Vrinda" />
<s:font script="Cher" typeface="Plantagenet Cherokee" />
<s:font script="Ethi" typeface="Nyala" />
<s:font script="Geor" typeface="Sylfaen" />
<s:font script="Gujr" typeface="Shruti" />
<s:font script="Guru" typeface="Raavi" />
<s:font script="Knda" typeface="Tunga" />
<s:font script="Khmr" typeface="DaunPenh" />
<s:font script="Laoo" typeface="DokChampa" />
<s:font script="Mlym" typeface="Kartika" />
<s:font script="Mymr" typeface="Myanmar Text" />
<s:font script="Orya" typeface="Kalinga" />
<s:font script="Sinh" typeface="Iskoola Pota" />
<s:font script="Syrc" typeface="Estrangelo Edessa" />
<s:font script="Taml" typeface="Latha" />
<s:font script="Telu" typeface="Gautami" />
<s:font script="Thaa" typeface="MV Boli" />
<s:font script="Tibt" typeface="Cordia New" />
<s:font script="Yiii" typeface="Microsoft Yi Baiti" />
</s:fontSlot>
???

SharePoint includes support for web fonts. You must provide additional information to use web fonts in your font scheme. For more information, see the Web fonts section in this article.

Web-safe fonts
Web-safe fonts are a set of fonts that are widely used and available on most devices by default. To specify a web-safe font in the font scheme, include the name of the font in the typeface
attribute of the font slot. The following example shows a web-safe font used in a font scheme.

<s:fontSlot name="title">
<s:latin typeface="Georgia"/>
???
</s:fontSlot>

Web fonts
Web fonts are fonts that are available on the Internet. When a user views a site that uses web fonts, the web browser downloads the necessary font files along with the rest of the page. To
specify a web font, you must provide the URL to your web font files in four font formats (for support across browsers), and a small and large thumbnail image to use to render the font
names in the font scheme picker.
The following example describes the information that is required to use a web font in an <s:latin> element.

<s:latin typeface="FontName"
eotsrc="EotFile"
woffsrc="WoffFile"
ttfsrc="TtfFile"
svgsrc="SvgFile"
largeimgsrc="LargeImgFile"
smallimgsrc="SmallImgFile" />

In this example of using a web font, the following placeholders would be replaced:
FontName is the name of the web font.
EotFile is the relative URL to the Embedded Open Type font file.
WoffFile is the relative URL to the Web Open Font Format font file.
TtfFile is the relative URL to the TrueType font file.
SvgFile is the relative URL to the Scalable Vector Graphics font file.
LargeImgFile is the relative URL to the large thumbnail image that you want to use in the font scheme picker.
SmallImgFile is the relative URL to the small thumbnail image that you want to use in the font scheme picker.

Font slots
Table 1 describes the available font slots and where they are used in a page.
Table 1. Font slots
FO NT S LO T NAME D ES CR IPTIO N

title Used for the page title.

navigation Used for the horizontal and vertical navigation elements on the page.

large-heading Used for the H1 heading.

heading Used for H2 and H3 headings, web part titles, dialog box titles, and callout titles.

small-heading Used for H4 headings.

large-body Used for large body text (15 pixels and 19 pixels).

body The base font that is used everywhere else on the page.

See also
Themes overview for SharePoint
How to: Deploy a custom theme in SharePoint
Upgrade custom themes and CSS to SharePoint
How to: Create a master page preview file in SharePoint
SharePoint Team Blog: Show off your style with SharePoint theming
SharePoint Design Manager branding and design capabilities
Managed metadata and navigation in SharePoint
5/3/2018 • 4 minutes to read Edit Online

Learn about enterprise managed metadata (EMM) and navigation features in SharePoint.

Managed metadata feature enhancements in SharePoint for developers


You can use managed metadata to build taxonomies and tagging strategies that meet specific, detailed business needs. In SharePoint, the basic managed metadata API set is expanded and
enhanced to provide more capabilities and scenario support.

.NET client object model (CSOM) support for managed metadata APIs
The SharePoint CSOM supports taxonomy customization and development. Taxonomy is available in .NET client (CSOM), Silverlight, and JavaScript programming models. Developing with
it is logically similar to developing with the .NET server programming model. You may find it useful to develop CSOM solutions to support scenarios where reading content is more
common than authoring or administering it. You need to use CSOM to enable taxonomy use in a cloud scenario like SharePoint Online or for a subset of scenarios that are available on
premises.
When you want to create a new CSOM project in Visual Studio that uses taxonomy functionality, set the following references:
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Runtime.dll
Microsoft.SharePoint.Client.Taxonomy.dll
Developing customizations with CSOM is very similar to developing .NET server taxonomy solutions: get a reference to the TaxonomySession object and the TermStore object, Group
objects, TermSet objects, and Term objects required for the session.

Code Examples: Basic operations with the Taxonomy CSOM


You can use the following code examples to complete basic operations with the taxonomy CSOM. The first example creates a Group object, a TermSet object, and Term objects. The second
example iterates on a Group object and writes its contents.
private void CreateColorsTermSet(string siteUrl)
{
ClientContext clientContext = new ClientContext(siteUrl);

TaxonomySession taxonomySession = TaxonomySession.GetTaxonomySession(clientContext);


clientContext.Load(taxonomySession,
ts => ts.TermStores.Include(
store => store.Name,
store => store.Groups.Include(
group => group.Name
)
)
);
clientContext.ExecuteQuery();

if( taxonomySession != null )


{
TermStore termStore = taxonomySession.GetDefaultSiteCollectionTermStore();
if (termStore != null)
{
//
// Create group, termset, and terms.
//
TermGroup myGroup = termStore.CreateGroup("MyGroup",Guid.NewGuid());
TermSet myTermSet = myGroup.CreateTermSet("Color",Guid.NewGuid(), 1033);
myTermSet.CreateTerm("Red", 1033,Guid.NewGuid());
myTermSet.CreateTerm("Orange", 1033,Guid.NewGuid());
myTermSet.CreateTerm("Yellow", 1033,Guid.NewGuid());
myTermSet.CreateTerm("Green", 1033,Guid.NewGuid());
myTermSet.CreateTerm("Blue", 1033,Guid.NewGuid());
myTermSet.CreateTerm("Purple", 1033,Guid.NewGuid());

clientContext.ExecuteQuery();
}
}
}

private void DumpTaxonomyItems(string siteUrl)


{
ClientContext clientContext = new ClientContext(siteUrl);

//
// Load up the taxonomy item names.
//
TaxonomySession taxonomySession =TaxonomySession.GetTaxonomySession(clientContext);
TermStore termStore = taxonomySession.GetDefaultSiteCollectionTermStore();
clientContext.Load(termStore,
store => store.Name,
store => store.Groups.Include(
group => group.Name,
group => group.TermSets.Include(
termSet => termSet.Name,
termSet => termSet.Terms.Include(
term => term.Name)
)
)
);
clientContext.ExecuteQuery();

//
//Writes the taxonomy item names.
//
if( taxonomySession != null )
{
if (termStore != null)
{
foreach( TermGroup groupin termStore.Groups)
{
Console.WriteLine("Group " + group.Name);

foreach( TermSet termSetin group.TermSets )


{
Console.WriteLine("TermSet " + termSet.Name);

foreach(Term term in termSet.Terms)


{
//Writes root-level terms only.
Console.WriteLine("Term " + term.Name);
}
}
}
}
}

Pinning
In Microsoft SharePoint Server 2010, users could reuse terms (and all terms nested under the reused terms) in other locations in the term hierarchy. After these terms were reused, they
could be modified and changes would be seen everywhere the terms were reused. SharePoint introduces term pinning. A pinned term is just like a term that is reused, except it is read only
and cannot be changed in the locations where the term is reused. For an example, see How to: Use code to pin terms to navigation term sets in SharePoint.

Datasheet view support for managed metadata column types


In SharePoint, the datasheet view functionality has changed. Now, the datasheet uses a double-click action to open standard view for grid editing. You can now edit metadata columns using
the same features that are available when you edit individual items. This includes access to the term set that is behind the column. This feature is all about bringing the metadata modification
functionality available when editing an individual item to datasheet editing.
Managed navigation
Managed navigation uses managed metadata features, such as the ability to tag items with terms and manage terms in a term store, to provide highly customized site navigation. The
structured navigation that depends on the SharePoint infrastructure is also still available in SharePoint.

Friendly URLs
Friendly URLs are a shorter URL format displayed in the address bar of most SharePoint publishing pages, including the Welcome Page of your site. They are SEO-friendly and appear in
search results.

Support for new scenarios


A term store manager can enhance and expand term usage models based on more flexible and powerful managed metadata functionality in :
Link to another site collection and view others' terms. If you want to make your term set available to other site collections connected to the managed metadata service, create a global
term set. If you want to create a private term set that is available only to a specific site collection when it is stored in the managed metadata service, create a local term set.
Block users from using keywords outside of a specific term set.
Gain additional multilingual support, including support for automated translation and flexible LCIDs.

Unsupported scenarios for working with custom site definitions


SharePoint does not support creating taxonomy fields (managed metadata site columns) declaratively by way of XML definition.
SharePoint does not support the use of taxonomy fields (managed metadata site columns) in site templates.
For more information, see Microsoft Support Article #898631: Supported and unsupported scenarios

See also
Managed navigation in SharePoint
Content Search web part in SharePoint
Managed navigation in SharePoint
5/12/2018 • 5 minutes to read Edit Online

Learn about the taxonomy-driven managed navigation feature in SharePoint.

Introducing managed navigation


A well-designed navigation tells your site's users a lot about the business, products, and services that the website offers. By updating the taxonomy behind the navigation, businesses can
drive and keep up with change without having to recreate their site navigation in the process. In SharePoint, the managed navigation feature enables you to design site navigation that is
driven by managed metadata and create SEO-friendly URLs that are derived from the managed navigation structure. Managed navigation provides an alternative to the traditional
SharePoint navigation feature—structured navigation—that is based on the structure of SharePoint. Because managed navigation is driven by taxonomy, you can use it to design site
navigation around important business concepts without changing the structure of your sites or site components.

How managed navigation works


Managed navigation provides a framework for dynamically generated pages and provides an associated SEO-friendly URL. Each generated page is represented in the navigation hierarchy.
Instead of requiring separate pages to be authored for each category in the taxonomy, the framework provides a templating and inheritance mechanism that creates the landing pages for
each navigation link. You can use the topic pages feature to customize the landing page experience.
Managed navigation APIs are built into the taxonomy and publishing libraries in SharePoint. Managed metadata components like term sets and the term store are used to enable taxonomy-
driven navigation for your site. In the .NET server class library, the Microsoft.SharePoint.Publishing.Navigation namespace contains term, term set, and other class objects that mirror the
Term class and TermSet class in the Microsoft.SharePoint.Taxonomy navigation namespace, providing methods and properties specifically designed to associate those metadata items with
navigation elements. Other classes, like TaxonomySiteMapNode , enable you to provide metadata with various site navigation elements, such as site map nodes and other parts of your site's
navigation. Other classes enable caching and context for managed navigation.
You can display taxonomy-driven navigation links in the Global Navigation. The Global Navigation is a navigation layer with one or more layers that's always present, which often appears at
the top of a site and displays the top-level content categories. You can also display these links in the current navigation control that often appears on the left side of a page. The current
navigation control represents the next level of hierarchy for the category chosen in Global Navigation, or a set of links that belong to that category.

Friendly URLs and the managed navigation provider


When you browse to a SharePoint site for the first time, you may notice that the URL format has changed. Instead of an address with a /Pages/default.aspx extension, the page URL ends
with only / . Managed navigation provides a scheme for friendly URLs that is consistent across site, category, and item pages.
The managed navigation provider enables this experience. When you navigate to the root of any site that uses the managed navigation provider, the Site Welcome Page setting controls the
page that's loaded and displayed in the browser, but the URL you see (and that appears in search results) is rewritten to this friendlier format.
Any page, including your site's Welcome Page, can have a friendly URL. Depending on how you configure your site, most pages automatically get a friendly URL. Friendly URLs can be
localized.

Managed Navigation APIs


The taxonomy API provides several new methods and properties in SharePoint that you can use to customize terms, term sets, and other metadata elements in the term store for use in site
navigation scenarios. These APIs are available in the .NET client, .NET server, Silverlight, and JavaScript programming models.

Code Example: Customizing managed navigation with the .NET client object model (CSOM) API
When you use the .NET client object model for taxonomy, you can create a new navigation term set if a term store exists for the current site collection, or convert an existing term set into one
that supports managed navigation.
public class NavigationTermSetTests
{
public void CreateNavigationTermSet()
{
ClientContext clientContext = new ClientContext(TestConfig.ServerUrl);

TaxonomySession taxonomySession = TaxonomySession.GetTaxonomySession(clientContext);


taxonomySession.UpdateCache();

clientContext.Load(taxonomySession, ts => ts.TermStores);


clientContext.ExecuteQuery();

if (taxonomySession.TermStores.Count == 0)
throw new InvalidOperationException("The Taxonomy Service is offline or missing");

TermStore termStore = taxonomySession.TermStores[0];


clientContext.Load(termStore,
ts => ts.Name,
ts => ts.WorkingLanguage);

// Does the TermSet object already exist?


TermSet existingTermSet;

// Handles an error that occurs if the return value is null.


ExceptionHandlingScope exceptionScope = new ExceptionHandlingScope(clientContext);
using (exceptionScope.StartScope())
{
using (exceptionScope.StartTry())
{
existingTermSet = termStore.GetTermSet(TestConfig.NavTermSetId);
}
using (exceptionScope.StartCatch())
{
}
}
clientContext.ExecuteQuery();

if (!existingTermSet.ServerObjectIsNull.Value)
{
Log("CreateNavigationTermSet(): Deleting old TermSet");
existingTermSet.DeleteObject();
termStore.CommitAll();
clientContext.ExecuteQuery();
}

Log("CreateNavigationTermSet(): Creating new TermSet");

// Creates a new TermSet object.


TermGroup siteCollectionGroup = termStore.GetSiteCollectionGroup(clientContext.Site,
createIfMissing: true);
TermSet termSet = siteCollectionGroup.CreateTermSet("Navigation Demo", TestConfig.NavTermSetId,
termStore.WorkingLanguage);

termStore.CommitAll();
clientContext.ExecuteQuery();

NavigationTermSet navTermSet = NavigationTermSet.GetAsResolvedByWeb(clientContext,


termSet, clientContext.Web, "GlobalNavigationTaxonomyProvider");

navTermSet.IsNavigationTermSet = true;
navTermSet.TargetUrlForChildTerms.Value = "~site/Pages/Topics/Topic.aspx";

termStore.CommitAll();
clientContext.ExecuteQuery();

NavigationTerm term1 = navTermSet.CreateTerm("Term 1", NavigationLinkType.SimpleLink, Guid.NewGuid());


term1.SimpleLinkUrl = "http://www.bing.com/";

Guid term2Guid = new Guid("87FAA433-4E3E-4500-AA5B-E04330B12ACD");


NavigationTerm term2 = navTermSet.CreateTerm("Term 2", NavigationLinkType.FriendlyUrl,
term2Guid);

NavigationTerm childTerm = term2.CreateTerm("Term 2 child", NavigationLinkType.FriendlyUrl, Guid.NewGuid());

childTerm.GetTaxonomyTerm().TermStore.CommitAll();
clientContext.ExecuteQuery();
}
}

Code Example: Customizing managed navigation with the .NET server object model API
You can use the .NET server taxonomy classes and methods in the Microsoft.SharePoint.Taxonomy and Microsoft.SharePoint.Publishing.Navigation namespaces to create a new navigation
term set.
///Create a navigation term set.
using (SPSite site = new SPSite(TestConfig.ServerUrl))
{
using (SPWeb web = site.OpenWeb())
{
TaxonomySession taxonomySession = new TaxonomySession(site, updateCache: true);

/// Use the first TermStore object in the list.


if (taxonomySession.TermStores.Count == 0)
throw new InvalidOperationException("The Taxonomy Service is offline or missing");

TermStore termStore = taxonomySession.TermStores[0];

/// Does the TermSet object already exist?


TermSet existingTermSet = termStore.GetTermSet(TestConfig.NavTermSetId);
if (existingTermSet != null)
{
Log("CreateNavigationTermSet(): Deleting old TermSet");
existingTermSet.Delete();
termStore.CommitAll();
}

Log("CreateNavigationTermSet(): Creating new TermSet");

/// Create a new TermSet object.


Group siteCollectionGroup = termStore.GetSiteCollectionGroup(site);
TermSet termSet = siteCollectionGroup.CreateTermSet("Navigation Demo", TestConfig.NavTermSetId);

NavigationTermSet navTermSet = NavigationTermSet.GetAsResolvedByWeb(termSet, web,


StandardNavigationProviderNames.GlobalNavigationTaxonomyProvider);

navTermSet.IsNavigationTermSet = true;
navTermSet.TargetUrlForChildTerms.Value = "~site/Pages/Topics/Topic.aspx";

NavigationTerm term1 = navTermSet.CreateTerm("Term 1", NavigationLinkType.SimpleLink);


term1.SimpleLinkUrl = "http://www.bing.com/";

Guid term2Guid = new Guid("87FAA433-4E3E-4500-AA5B-E04330B12ACD");


NavigationTerm term2 = navTermSet.CreateTerm("Term 2", NavigationLinkType.FriendlyUrl,
term2Guid);

/// Verify that the NavigationTermSetView is being applied correctly.


Assert.AreEqual(web.ServerRelativeUrl + "/term-2", term2.GetResolvedDisplayUrl(null).ToString());

string expectedTargetUrl = web.ServerRelativeUrl


+ "/Pages/Topics/Topic.aspx?TermStoreId=" + termStore.Id.ToString()
+ "&amp;TermSetId=" + TestConfig.NavTermSetId.ToString()
+ "&amp;TermId=" + term2Guid.ToString();
Assert.AreEqual(expectedTargetUrl, term2.GetResolvedTargetUrl(null, null).ToString());

NavigationTerm childTerm = term2.CreateTerm("Term 2 child", NavigationLinkType.FriendlyUrl);


Assert.AreEqual(web.ServerRelativeUrl + "/term-2/term-2-child", childTerm.GetResolvedDisplayUrl(null).ToString());

/// Commit changes.


childTerm.GetTaxonomyTerm().TermStore.CommitAll();
}
}

See also
Content Search web part in SharePoint
Content Search web part in SharePoint
5/3/2018 • 2 minutes to read Edit Online

Learn about the Content Search web part (CSWP) in SharePoint.

Introducing the Content Search web part (CSWP)


The Content Search web part (CSWP) is a web part introduced in SharePoint that uses various styling options to display dynamic content on SharePoint pages.

How the Content Search web part works


Content Search web part displays search results in a way that you can easily format. Each Content Search web part is associated with a search query and shows the results for that search
query.
You can use display templates to change how search results appear on the page. Display templates are snippets of HTML and JavaScript that render the information returned by SharePoint.
The information to be displayed gets inserted into the page in JSON format.

When to use the Content Search web part (CSWP) or the Content Query web part (CQWP)
The CSWP can return any content from the search index. Use it on your SharePoint sites when you are connecting to a search service and want to return indexed search results in your
pages.
The CSWP returns content that is as fresh as the latest crawl of your content, so if you crawl often, the content that the CSWP returns is more up-to-date than if you crawl infrequently. If you
need to display instant content or the refreshed version of content, use the Content Query web part (CQWP) instead.
Search crawls only the major versions of content, never the minor versions. If you want to display the minor versions of your content, do that by using a CQWP.
Some site collection administrators mark sites to not be indexed. Content marked in this way is not available in a CSWP. If you want to return results from a site that is marked to not index,
use the CQWP instead.

See also
Managed navigation in SharePoint
What's new in SharePoint search for developers
Use code to pin terms to navigation term sets in SharePoint
3/26/2018 • 3 minutes to read Edit Online

Learn how to use code to pin terms to navigation term sets.


In taxonomy creation, pinning is the ability to attach a term to a target. SharePoint introduces term pinning. A pinned term is just like a term that is reused, except it is read-only and cannot
be changed in the location where the term is used.
In SharePoint managed navigation, the API enables you to pin new or existing terms to a NavigationTermSet object. In Microsoft SharePoint Server 2010, users could reuse terms (and all
terms nested under the reused terms) in other locations in the term hierarchy. After these terms were reused, they could be modified in any location and changes would be seen everywhere
the terms were reused.

Term pinning essentials


To understand pinning in SharePoint, you may want to learn about managed metadata, terms, term sets, managed navigation, the term store, and other related concepts and APIs. Table 1
describes articles that give more information about pinning.
Table 1. Core concepts for pinning

AR TICLE TITLE D ES CR IPTIO N

A Brief Introduction to Enterprise Metadata Management for Microsoft SharePoint Server 2010 Written for SharePoint Server 2010, this article provides a basic overview of the enterprise managed
Developers metadata programming model and core concepts, such as terms and term sets.

Managed navigation in SharePoint An introduction to the taxonomy-driven managed navigation feature in SharePoint.

Use code to complete pinning tasks


You can use custom code from the .NET server, .NET client (CSOM), Silverlight, or JavaScript programming models to complete pinning operations on terms and term sets. The following
.NET server code examples include a test for pinning terms to navigation term sets, and a method that you can use to test whether a Term object is pinned to a specified TermSet object.
Then, the test creates Term objects, and pins one of them to the specified NavigationTermSet object.

To pin terms to navigation term sets


The following sample tests pinning terms to navigation term sets. It uses the NavigationTermSet object, which contains methods and properties that are handy in managed navigation
scenarios, such as creating taxonomy-driven site navigation menus.
The sample first checks whether a NavigationTermSet object exists. If one doesn't exist, then the code creates a NavigationTermSet. (If one already exists, the code deletes the old
one before it creates a new one). Then, after the code creates some Term objects to pick from, it creates a publishing page (.aspx) file for demonstration purposes, sets it as the custom
target page for pinned terms, and then pins some navigation properties to the page.
public void TermPinningTest()
{
using (SPSite site = new SPSite(TestConfig.ServerUrl))
{
using (SPWeb web = site.OpenWeb())
{
TaxonomySession taxonomySession = new TaxonomySession(site, updateCache: true);

// Create the navigation term set.


NavigationTermSet menuNavTermSet = DemoUtilities.SetUpSampleNavTermSet(
this.TestContext, taxonomySession, web);
TermSet menuTaxTermSet = menuNavTermSet.GetTaxonomyTermSet();

TermStore termStore = menuTaxTermSet.TermStore;


Group group = menuTaxTermSet.Group;

// Does the tagging Taxonomy term set already exist?


TermSet taggingTaxTermSet = group.TermSets.FirstOrDefault(
ts => ts.Id == TestConfig.TaggingTermSetId);

if (taggingTaxTermSet != null)
{
Log("Deleting old tagging term set");

// If the tagging Taxonomy term set already exists, delete the old one.
taggingTaxTermSet.Delete();
termStore.CommitAll();
}

Log("Creating the tagging term set");

taggingTaxTermSet = group.CreateTermSet("Demo Tagging TermSet", TestConfig.TaggingTermSetId);

int lcid = termStore.WorkingLanguage;

// Create some terms.


Term taggingProductsTaxTerm = taggingTaxTermSet.CreateTerm("Products", lcid);
taggingProductsTaxTerm.CreateTerm("Electronics", lcid);
taggingProductsTaxTerm.CreateTerm("Footwear", lcid);
taggingProductsTaxTerm.CreateTerm("Sports", lcid);

termStore.CommitAll();

/// Pinning the products subtree. Pins the "Products" Term object to the NavigationTermSet object.
Term menuProductsTaxTerm = menuTaxTermSet.ReuseTermWithPinning(taggingProductsTaxTerm);
termStore.CommitAll();

/// Creating the publishing page template DemoTargetPage.aspx");


PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);

SPListItem pageListItem = null;


PublishingPage publishingPage;
try
{
pageListItem = web.GetListItem(web.Url + "/Pages/DemoTargetPage.aspx");
publishingPage = PublishingPage.GetPublishingPage(pageListItem);

}
catch (FileNotFoundException)
{
Log("Creating new target page");
publishingPage = publishingWeb.AddPublishingPage("DemoTargetPage.aspx", publishingWeb.DefaultPageLayout);
Log("Checking in target page draft");
publishingPage.CheckIn("TermPinningTest");
}

// Set a custom target page for the pinned terms and then set some navigation properties.

// Normally the navigation objects are obtained by way of an optimized function such as
// TaxonomyNavigation.GetTermSetForWeb() or TaxonomyNavigationContext.Current.NavigationTerm.
// The function guarantees that URLs will be resolved using a valid NavigationTerm.View.
// But because we are populating totally new data, the cache will probably not be updated
// yet, so instead we manually construct a view using GetAsResolvedByWeb().
NavigationTerm menuProductsNavTerm = NavigationTerm.GetAsResolvedByWeb(menuProductsTaxTerm,
web, StandardNavigationProviderNames.GlobalNavigationTaxonomyProvider);

menuProductsNavTerm.TargetUrl.Value = publishingPage.Uri.AbsolutePath;
menuProductsNavTerm.TargetUrlForChildTerms.Value = publishingPage.Uri.AbsolutePath;

termStore.CommitAll();

Log("TermPinningTest completed successfully");


}
}

See also
Managed metadata and navigation in SharePoint
Microsoft.SharePoint.Publishing.Navigation
Publish SharePoint sites
5/3/2018 • 2 minutes to read Edit Online

After you design or develop site components and content, you can deploy them to the current site collection and other site collections—even to site collections that cross the intranet/Internet
boundary.

Cross-site publishing
Learn about cross-site publishing and how it affects how you plan and publish sites and their content and associated design elements.

Publishing considerations for variations and multilingual sites


Different markets have different tastes. The variations feature helps accommodate those tastes by providing functionality that you can use to localize and translate content, but also to publish
that content and its associated design elements to site collections all over the world. To help make publishing content to local markets successful, consider these tips that show how design
and content management decisions you make can affect how published site contents and structure may render:
Duplication of design assets positively affects the performance of site publishing and rendering and helps make managing complex sites that are enabled for variations less complex. A
master page is an ASP.NET file that contains content placeholders that are populated by page layouts and individual instances of pages.
If certain content types apply to all locales in your site collection, it's best to create them as site content types of the root web. You can also create content types under variation sites.
If you add additional columns to a source list by adding an item with a content type that did not previously exist in that list, variations updates the schema of each target list to reflect
the new columns the next time you add an item to that target list.
Managed navigation works with variations. Structured navigation—based on the SharePoint website structure—also still works: it synchronizes the content and structure between the
source and target variations labels.
The device channels feature abstracts the problem of varying the presentation of content for mobile devices from the underlying site content and structure. You can create master
pages that present to users based on the user's user agent. Avoid hard-coding in a master page content that will need to be localized.
Sites with dynamic content assembled from multiple sources risk having content rendered in multiple languages on the same page. For example, avoid cases where article page
content is one language while content rendered by a Content Search web part is rendered in another language.
If you work with display templates that are used with multiple languages, create language files and place them under folders that are named with the locale that they apply to. You can
then reference the language files with the $includeLanguageScript function and the {Locale} token.
If the Content Search web part relies on the Language property to find the appropriate CustomStrings.js file to include and one doesn't exist, and code in the template requests a
string to display that cannot be found by using the $resource() or Srch.U.loadResource() functions, the Content Search web part displays an error message.

See also
Build sites for SharePoint
What's new with SharePoint site development
Cross-site publishing in SharePoint
5/3/2018 • 5 minutes to read Edit Online

SharePoint introduces a cross-site publishing feature that enables you to reuse content across multiple site collections. It uses built-in search capabilities to enable publishing scenarios and
architectures. For the first time, you can design sites that cross SharePoint farms—enabling your sites to span the boundary between intranets and the Internet.
Consider a site with one authoring site collection that feeds multiple publishing site collections, with different domains, all crawled by public search engines and optimized for search engine
optimization (SEO). Cross-site publishing enables this scenario and others like it, without requiring you to use content deployment. Cross-site publishing was designed with some common
scenarios in mind, including:
Share an item list or a page library as a publishing catalog
Consume a catalog from search
Combine cross-site publishing with the variations feature to enable authoring multilingual sites from a common authoring site collection

Catalogs
Catalogs, introduced in SharePoint, include a list or library that is shared out to search for consumption on publishing sites. Catalogs enable content to be published across site collections—
the cross-site publishing features depend on catalogs. You can use catalogs to really reuse content across your sites and across the boundary between your intranet sites, extranet sites, and
Internet sites. For predefined search queries, catalogs are flagged in search. You can surface content stored in catalogs across site collections by using the Content Search web part in
SharePoint.

When should I use cross-site publishing?


There are some cases where cross-site publishing is not efficient or appropriate. Whether you have external data sources and how you connect to them, variations, site type, search database
implementation, and use of the product catalog are all factors that should influence your decision. Table 1 provides more information about these design considerations.
Table 1. Design considerations for cross-site publishing

D ES IG N CO NS ID ER ATIO N D ES CR IPTIO N

Lag time If the delay between the time an author publishes a page and when it shows up on the site is too long
for someone who depends on it, you may want to consider using content deployment instead.

Search database implementation If you connect your search database to an external data source and you use an external (non-
SharePoint) connector, you can't use cross-site publishing. If you use business connection services (BCS),
you can use cross-site publishing.
Using cross-site publishing with the search database makes sense in some cases but not others. You
should not use cross-site publishing to publish from a source site directly to the Internet in a way that
does not include your search database in the planning or custom code implementation.

Variations implementation If you are implementing a basic variations site that makes a pages library, document library, and general
lists available in a few languages, cross-site publishing makes sense. The same is true if you choose to
implement managed navigation or structured navigation on a variations site.
Cross-site publishing works for some architectures but not others. For example, you can use cross-site
publishing to publish content from a variations SPSite to a publishing site with variations enabled if the
source SPSite is not consuming data from another variations site or site collection.

Catalog implementation Whether you implement the product catalog into your site architecture and how you implement it may
affect whether cross-site publishing is the most effective or appropriate choice. If you are using the
product catalog to support a multilingual variations site configuration and are publishing to an Internet
site, you can implement cross-site publishing.

Managed navigation Cross-site publishing works with most implementations of managed navigation and the term store. In
some implementations, navigation metadata transfer may not work as expected. For example, when one
variations site depends on metadata from another variations site to drive site navigation, and you use
cross-site publishing to publish content to the target site, navigation metadata transfer may not work as
expected.

How can I set up a catalog?


Category pages and catalog item pages are page layouts that you can use to show structured catalog content consistently across a site. SharePoint enables you to create and customize page
layouts for SharePoint and above. For more information, see Customize page layouts for a catalog-based site in SharePoint.

Cross-site publishing APIs


SharePoint introduces classes that you can use to support cross-site publishing implementation in your code. These APIs are available in the .NET server publishing library. Use them to
customize how SharePoint shares lists as catalogs for content reuse or consumes a catalog from search. You can use the members of the following classes in custom code to support cross-
site publishing tasks:
Use the PublishingCatalogUtility class to retrieve a list of available catalogs, get information about catalogs and their statuses, get information about lists and libraries that can be
connected to catalogs, and start or stop sharing catalogs.

/// Retrieve available catalogs.


public static List<CatalogConnectionSettings> GetPublishingCatalogs(SPSite site, int startRow, int numberOfRows, string filterText, out int totalNumberOfCatalogs)

///Get catalog information that is saved for a list.


public static bool GetCatalogConfiguration(SPList list, out CatalogShareSettings catalogSettings, out string selectedTaxonomyField)
///Stop sharing a list or library as a publishing catalog for cross-publishing content reuse.
public static void UnPublishCatalog(SPList list)

Use the CatalogCollectionManager class to consume catalogs from search. Learn about the connection that a catalog has to search, and get information about it. Add or remove a
catalog from the internal collection of catalogs, and queue an operation to queue up a connection that is configured to rewrite URLs when the Update method is called.

/// Add catalog or site source into the internal CatalogInfo collection, but the source is not persisted into the property bag.
public void AddCatalogConnection(CatalogConnectionSettings catalogInfo)

/// Queues an Add operation to add a connection configured to rewrite URLs. The connection is added to the store when the Update method is called.
public void AddCatalogConnection(CatalogConnectionSettings catalogInfo,
string[] orderedPropertiesForUrlRewrite,
string webUrl,
string catalogTaxonomyManagedProperty,
bool isManualRule)

/// Update existing catalog/site source in the internal CatalogInfo collection. Edits are not committed until the Update method is called.
public void UpdateCatalogConnection(CatalogConnectionSettings catalogInfo)

/// Remove a catalog or site source. Deletion is not committed until the Update method is called.
public void DeleteCatalogConnection(string catalogPath)

/// Determine whether a connection exists to this source from the site.
public bool Contains(string catalogPath)

/// Get the settings for a catalog connected to this site.


public CatalogConnectionSettings GetCatalogConnectionSettings(string catalogPath)

See also
Publish SharePoint sites
User segmentation in SharePoint
5/3/2018 • 7 minutes to read Edit Online

Display content you tailor for user segments you define—for example, based on locale, interests, gender, or referral links—by using a combination of term sets, the Content Search web part,
and query rules in SharePoint. SharePoint provides the building blocks to tailor content you show on a SharePoint site, depending on certain attributes of end-users, for example their
gender, where they live, their interests, or referral links. These groupings of user attributes are known as user segments.
In SharePoint, this user segmentation functionality can be beneficial in many scenarios, such as:
Displaying different banners on a page depending on the end-user's gender
Displaying different discount offers depending on the end-user's locale
Displaying different articles on a page depending on the end-user's referrer link (the website that brought the end-user to your page).
To implement user segmentation in SharePoint, you'll do three things: create a term set for each user segment, extend the Content Search web part to make it aware of your user segments,
and then use query rules to perform specific actions for each user segment.

Prerequisites
Before you get started implementing user segmentation in SharePoint, be sure to have the following installed in your development environment:
SharePoint
Visual Studio 2012
This article assumes that you have experience with developing web parts in SharePoint. For more information on developing web parts, refer to Building Block: web parts

Overview on adding user segmentation functionality to your SharePoint site


Figure 1 shows the basic steps to add user segmentation functionality to your SharePoint site.
Figure 1. Steps to add user segmentation functionality to your SharePoint site

Create a term set


A term is a word or a phrase that can be associated with an item in SharePoint. Aterm set is a collection of related terms. For more information, see Overview of managed metadata in
SharePoint. You can create term sets either through the SharePoint Term Store Management Tool, or programmatically.
NOTE

See the following topics for detailed instructions on how to use the Term Store Management Tool to create your term set:> Set up a new term set> Create and manage terms in a term set
You can create a term set programmatically by using the types exposed via Microsoft.SharePoint.Taxonomy . The following code example shows how to create a TermSet object and obtain
the NavigationTermSet. Next, you create Term objects within your TermSet. Finally, commit these changes to the TermStore and load the TermSet to use for navigation.
Each term you add to your term set receives a unique identifier. This identifier is the key to making the ContentBySearchWebPart aware of your user segments.
static void CreateNavigationTermSet(string siteUrl)
{
using (SPSite site = new SPSite(siteUrl))
{
using (SPWeb web = site.OpenWeb())
{
TaxonomySession taxonomySession = new TaxonomySession(site);
taxonomySession.UpdateCache();
TermStore termStore = taxonomySession.DefaultSiteCollectionTermStore;

// Create a TermSet object in a default site collection term group.


Group siteCollectionGroup = termStore.GetSiteCollectionGroup(site, createIfMissing: true);
TermSet termSet = siteCollectionGroup.CreateTermSet("Navigation Demo", Guid.NewGuid(), lcid: 1033);

// Obtain navigation term set.


NavigationTermSet navigationTermSet = NavigationTermSet.GetAsResolvedByWeb(termSet, web, "GlobalNavigationTaxonomyProvider");

// Create a term that points to a SharePoint page set at the term set level of hierarchy.
NavigationTerm term1 = navigationTermSet.CreateTerm("Term 1", NavigationLinkType.FriendlyUrl, Guid.NewGuid());

// Create a term that points to an already existing URL outside of SharePoint.


NavigationTerm term2 = navigationTermSet.CreateTerm("Term 2", NavigationLinkType.SimpleLink, Guid.NewGuid());
term2.SimpleLinkUrl = "http://www.bing.com/";

// Create a term that points to an existing SharePoint page.


NavigationTerm term3 = navigationTermSet.CreateTerm("Term 3", NavigationLinkType.FriendlyUrl, Guid.NewGuid());

// Save all changes to the term store.


termStore.CommitAll();
}
}
}

Create a custom web part for user segmentation


In Visual Studio 2012, create a custom web part by using the Visual web parts template from the SharePoint category. Your custom web part must inherit from the
ContentBySearchWebPart object.
NOTE

This article assumes that you have experience with developing web parts in SharePoint. For more information on developing web parts, refer to Building Block: web parts

Configure a custom web part with user segmentation logic


In your custom web part, you can re-implement either the OnLoad() method or the OnInit() method to carry out your custom logic. Both these methods are useful to set or customize
properties of the ContentBySearchWebPart object.

Example 1: Add Male and Female user segments to your SharePoint site
To add Male and Female user segments, you can re-implement the OnLoad() method as shown in the following code.

protected override void OnLoad(EventArgs e)


{
if (this.AppManager != null)
{
if (this.AppManager.QueryGroups.ContainsKey(this.QueryGroupName) &amp;&amp; this.AppManager.QueryGroups[this.QueryGroupName].DataProvider != null)
{
this.AppManager.QueryGroups[this.QueryGroupName].DataProvider.BeforeSerializeToClient += new
BeforeSerializeToClientEventHandler(AddMycustomProperties);
}
}
base.OnLoad(e);
}

The corresponding AddMycustomProperties method would look like the following code.

private void AddMycustomProperties(object sender, BeforeSerializeToClientEventArgs e)


{
DataProviderScriptWebPart dp = sender as DataProviderScriptWebPart;
string gender = (string)Page.Session["DataProvider.Gender"];
// Depends on what your DataProvider is: Facebook, LinkedIn, etc.

if (dp != null &amp;&amp; gender != null)


{ try
{
// Set property to male or female GUID.
if (gender.CompareTo("female") == 0)
{
dp.Properties["TermSetName"] = new String[] { "TermUniqueIdentifier" };
// E.g. 47ba9139-a4c5-4ff0-8f9a-2864be32da92
}
else if(gender.CompareTo("male") == 0)
{
dp.Properties["UserSegmentTerms"] = new String[] { "TermUniqueIdentifier" };
// E.g. f5bf2195-2170-4b11-a018-a688a285e579
}
}
catch (ArgumentException exp)
{
// Do something with the exception.
}
}
}
Example 2: Create user segments based on the type of Web browser your end-user is using when
To create user segments based on the type of web browser the end-user is using, to view your SharePoint site, re-implement the OnLoad method as shown in the following code.

protected override void OnLoad(EventArgs e)


{
if (this.AppManager != null)
{
if (this.AppManager.QueryGroups.ContainsKey(this.QueryGroupName) &amp;&amp; this.AppManager.QueryGroups[this.QueryGroupName].DataProvider != null)
{
this.AppManager.QueryGroups[this.QueryGroupName].DataProvider.BeforeSerializeToClient += new
BeforeSerializeToClientEventHandler(AddMycustomProperties);
}
}
base.OnLoad(e);
}

The code for the AddMycustomProperties method would look like the following example.

private void AddMycustomProperties(object sender, BeforeSerializeToClientEventArgs e)


{
DataProviderScriptWebPart dataProvider = sender as DataProviderScriptWebPart;
SPSite site = SPContext.Current.Site;

TaxonomySession session = new TaxonomySession(site);


TermStore defaultSiteCollectionStore = session.DefaultSiteCollectionTermStore;
List<string> userSegmentTerms = new List<string>();

var userAgentparts = Page.Request.UserAgent.Split(new char[] { ';', '(', ')' });

foreach (var part in userAgentparts)


{
var entry = part.Trim();
var terms = termStore.GetTermsWithCustomProperty("UserAgent", entry, false);

if (terms.Count > 0)
{
userSegmentTerms.Add(terms[0].Id.ToString());
}
}
dataProvider.Properties["UserSegmentTerms"] = userSegmentTerms.ToArray();
}

Upload the custom web part to the SharePoint Web Part Gallery
In order to use your custom web part in your page, you need to upload the web part to the SharePoint Web Part Gallery.
In the SharePoint Web Part Gallery, choose Site Settings, and then choose Web parts under Web Designer Galleries. On the Files tab, choose Upload Document.

Add query rules to carry out specific actions that depend on the user segment
A query rule transforms queries to improve the relevance of search results by reacting intelligently to what the user might be trying to find. In a query rule, you specify conditions and
correlated actions. When a query meets the conditions in a query rule, the search system performs the actions specified in the rule to improve the relevance of the search results, such as
narrowing down the results or changing the order in which results are displayed.
When implementing user segmentation, you use query rules to define conditions and actions for the defined user segments. When an end-user is part of a particular user segment, the
query rule will activate and the ContentBySearchWebPart will display content that is tailored for that particular user segment.

To create a query rule that will activate for a particular user segment
1. In your publishing site collection in Site Settings, choose Site Collection Administration, and then choose Search Query Rules.
2. Choose a result source, and then choose New Query Rule.
3. Type a rule name in the Rule Name field. Then, click to expand Context.
4. Under the Query is performed by these user segments section, choose One of these user segments, and then click Add User Segment.
5. In the Title field, type a name for this user segment query rule. Choose Add user segment term.
6. In the Import from term store dialog box, expand the Managed Metadata Service. Under Site Collection, locate the term set that holds the user segmentation terms that you
previously defined in Create a term set. Select the user segment for which you want to apply this query rule. Then, click Save.
7. Name your user segment n the Add User Segment dialog box.
You have now mapped a query rule to a user segment, which in turn is mapped to a user segment term.
8. Under Query Conditions, choose Remove Condition.
This specifies that the query configured in the ContentBySearchWebPart will act as the query condition.
9. Set the corresponding actions that your query rule will perform. Under the Actions section, select a corresponding action that you want to take as a result of -your query rule. You can
select to either Add Promoted Result or Add a Result Block.
10. Save your query rule.
11. Repeat steps 1 through 10 for your other user segments, depending on the actions you want to perform.

Add a custom web part to the SharePoint page and configure it to show the query rule
You need to add your custom web part to your SharePoint page.

To add your custom web part


1. Navigate to a category page, choose Edit page, and then choose Edit page template.
2. Select Add a web part in the top section of the page. Then, select your custom web part from the drop-down menu in the upper right corner of the web part.
3. Click Edit web part.
4. Expand the Settings section, and in the Result Table field, choose SpecialTermResults.
5. Save your configuration.

See also
Build sites for SharePoint
Set up User Segmentation to drive adaptive experiences in a Product Catalog in SharePoint
Minimal Download Strategy overview
5/3/2018 • 5 minutes to read Edit Online

Learn about Minimal Download Strategy (MDS), a new feature in SharePoint that reduces page load time by sending only the differences when users navigate to a new page. Minimal
Download Strategy (MDS) is a new technology in SharePoint that reduces the amount of data that the browser has to download when users navigate from one page to another in a
SharePoint site. When users browse an MDS-enabled site, the client processes only the differences (or delta) between the current page and the requested page. Figure 1 shows the sections
that change from page to page and therefore require an update. The delta usually includes the data in the (1) content areas, as well as other components such as (2) navigation controls.
Figure 1. Page processed with MDS

You can identify a site that has MDS enabled by looking at the URL. An MDS-enabled site has the (3) _layouts/15/start.aspx page in the URL followed by a hash mark ( # ) and the relative
URL of the requested resource, as shown in Figure 1. For example, the following is the MDS-formatted URL for the page newpage.aspx:
https://sp_site/_layouts/15/start.aspx#/SitePages/newpage.aspxIt is equivalent to the following non-MDS-formatted URL: https://sp_site/SitePages/newpage.aspxAs a developer,
you might have created SharePoint components that need some updates before they can work seamlessly with MDS.

Enable MDS
You can enable MDS in your site by using either the site administration pages or the SharePoint client object models.
To enable MDS by activating the feature in the administration pages, choose Site settings > Manage site features, and activate the Minimal Download Strategy feature.
Because the feature is activated by modifying the EnableMinimalDownload property, you can also use the client APIs. The following code shows how to enable MDS using the JavaScript
object model (JSOM).

var clientContext;

clientContext = new SP.ClientContext.get_current();


this.oWebsite = clientContext.get_web();

this.oWebsite.set_enableMinimalDownload(true);
this.oWebsite.update();

clientContext.load(this.oWebsite);

clientContext.executeQueryAsync(
Function.createDelegate(this, successHandler),
Function.createDelegate(this, errorHandler)
);

function successHandler() {
alert("MDS is enabled in this site.");
}

function errorHandler() {
alert("Request failed: " + arguments[1].get_message());
}

Benefits of using MDS


Using MDS provides several benefits, including:
Speed: This is the main objective of MDS. When you are using MDS, the browser doesn't have to reprocess the chrome user interface (UI). MDS also reduces the payload compared
to a full page load.
Smooth transitions: By updating only the areas that change, you draw the user's eye toward these areas, as opposed to a full page load where the whole page "flashes." When the
whole page is updated, the user must parse it in its entirety to detect what is new. Users have an easier time navigating a site that only updates the areas that changed from the
previous page.
Browser navigation controls: Other AJAX-based systems confuse the previous and next buttons in browsers. Because MDS updates the URL in the browser window, the previous
and next buttons work just as they are supposed to.
Backward compatibility: The MDS engine either provides MDS navigation immediately or detects when it isn't possible. In the case where MDS navigation isn't possible, a full page
load occurs instead. This process is called failover, and it ensures that all pages render properly regardless of whether they contain MDS-compliant components. MDS also works
nicely with search engines because the href attribute of anchor tags uses the regular, non MDS-formatted URLs. Instead, the MDS engine in the client captures the onclick event and
uses it to communicate with the server.
MDS architecture
The basic mechanics of MDS are pretty simple. The main components of MDS are two engines, one in the server and another in the client, that work together to calculate the changes and
render the pages in the browser when the user navigates from page to page in the site. Figure 2 shows the MDS flow when a user navigates through an MDS-enabled site.
Figure 2. MDS flow when a user navigates the site

1. The browser requests the changes between the current page and a new one in the SharePoint site.
2. The MDS engine in the server calculates the delta between the current and the new pages.
3. The MDS engine in the server sends the delta to the MDS engine in the client.
4. The MDS engine in the client replaces the changed areas on the current page with the new page content.
The resulting page is exactly as it would have been if the page had been downloaded without MDS.
The MDS engine in the client includes a download manager. All requests in the page are routed through the download manager. All controls in the page must subscribe to the download
manager to learn when a URL has changed. The download manager makes one request for all the new control data. To be able to work with search engines, the MDS engine doesn't directly
use the href attribute of anchor tags to store MDS-formatted URLs. Instead, the SPUpdatePage function handles the onclick event and uses it to communicate with the server. The
SPUpdatePage function is declared in the _layouts/15/start.js file.
The MDS engine in the server sends the information back to the client. This information can contain HTML with embedded scripts and styles, XML, or JavaScript Object Notation (JSON).
The URL plays an important role in MDS. An MDS URL looks like the following: https://sp_site/_layouts/15/start.aspx#/SitePages/newpage.aspx. Start.aspx contains minimal shared
UI and instructions for loading page changes. MDS considers the part following the hash mark (#) as the target page. The target page starts with a slash (/) followed by a URL relative to the
SharePoint website. When the browser receives the URL, it sees that the part to the left of the hash mark hasn't changed, so it fires a local navigation event. The MDS engine in the client
captures the local navigation event and uses it to perform an MDS update.
As mentioned previously in this article, in some situations it's not possible to determine whether the page can be updated properly. In these situations, the MDS engine issues a failover,
which consists of an extra round trip to redirect the browser to the full version of the new page. These are the most common reasons why failover occurs:
The new page has a different master page.
The current master page has changed.
The MDS engine detects non-compliant HTML, for example:
Pages using ASP.NET 2.0
CSS or scripts not registered in the MDS engine
Illegal HTML
There are non-compliant controls on the page, for example:
The control is not in the MDS engine whitelist.
The control assembly is not marked as compliant.
The control class doesn't have the MDS attribute.
The MDS engine tries to recover from a failover after the user navigates to yet another new page.

Developer controls
Thanks to the failover mechanism, your controls work seamlessly whether or not MDS is enabled in your users' websites. However, it is a good idea to update your SharePoint controls and
components to take full advantage of MDS. Users get a better experience when your pages and controls are MDS compliant. The following components are good candidates to get
optimized for MDS:
Master pages
ASP.NET pages
Controls and web parts

See also
EnableMinimalDownload
Modify SharePoint components for MDS
Build sites for SharePoint
Modify SharePoint components for MDS
7/6/2018 • 5 minutes to read Edit Online

Learn how to modify the components in your SharePoint project to take advantage of Minimal Download Strategy (MDS) in SharePoint. Minimal Download Strategy (MDS) improves the
user experience by returning from the server only the portions of a page required to render it properly in the browser. Because the fully-rendered page is not returned to the client, the server
must be able to accurately identify the portions that are required to render the page. You might need to modify the components in your SharePoint project so that they are identified as
MDS-compliant and can work with the MDS engine. Learn more about MDS in Minimal Download Strategy overview.

Why modify SharePoint components?


As explained in Minimal Download Strategy overview, SharePoint controls work whether or not you modify them to take full advantage of MDS. However, when your components are not
MDS compliant, the MDS engine issues a failover. In a failover, the MDS engine takes an extra round trip to redirect the browser to the full version of the new page, which takes time. Users
have the best experience when you modify components to work with MDS and avoid a failover every time they browse to a new page in SharePoint. You usually need to modify master
pages, ASP.NET pages, controls, and web parts.

Master pages
The master page provides a template that lets MDS identify the content regions that may need to be updated when someone navigates to a new page. Optimizing your master pages is one
of the most important steps to take when optimizing performance because master pages identify sections that require updated content.. The Seattle.master master page included with
SharePoint is a good example of an optimized master page. Figure 1 shows examples of components in the Seattle.master master page that change from page to page, such as the (1) main
content area, (2) left navigation bar, and (3) page title.
Figure 1. Components that require updates in a master page

NOTE

There are many more components in the Seattle.master master page that change from page to page, such as style sheets and JavaScript files. Figure 1 shows only a few examples.
There are different patterns to optimize the components in a master page. You can use a pattern for the following components:
HTML regions and controls
Style sheets
JavaScript files
Page title
HTML regions and controls are MDS compatible if they are wrapped in SharePoint:AjaxDelta tags. By wrapping the content in SharePoint:AjaxDelta tags, you are signaling that the
MDS engine should update the enclosed controls and HTML. If a control or HTML section doesn't change from page to page, it should not be sent to the client. Therefore, you should keep
these controls outside of AjaxDelta tags. In the Seattle.master master page shown in Figure 1, the (1) main content area is wrapped in AjaxDelta tags, as shown here.

<SharePoint:AjaxDelta
id="DeltaPlaceHolderMain"
BlockElement="true"
IsMainContent="true"
runat="server">
<a id="mainContent" name="mainContent" tabindex="-1"></a>
<asp:ContentPlaceHolder id="PlaceHolderMain" runat="server" />
</SharePoint:AjaxDelta>

Another example of the AjaxDelta pattern is the (2) left navigation bar in Figure 1. The following code shows how the control is wrapped in AjaxDelta tags along with many other controls
and HTML.
<SharePoint:AjaxDelta
id="DeltaPlaceHolderLeftNavBar"
BlockElement="true"
CssClass="ms-core-navigation"
role="navigation"
runat="server">
<asp:ContentPlaceHolder id="PlaceHolderLeftNavBar" runat="server">
<a id="startNavigation" name="startNavigation" tabIndex="-1"></a>
<asp:ContentPlaceHolder id="PlaceHolderLeftNavBarTop" runat="server" />
<asp:ContentPlaceHolder id="PlaceHolderQuickLaunchTop" runat="server" />
<asp:ContentPlaceHolder id="PlaceHolderLeftNavBarDataSource" runat="server" />
<asp:ContentPlaceHolder id="PlaceHolderCalendarNavigator" runat="server" />
<asp:ContentPlaceHolder id="PlaceHolderLeftActions" runat="server" />
<!-- There are more controls and HTML in this placeholder in the Seattle master page -->
</asp:ContentPlaceHolder>
</SharePoint:AjaxDelta>

One last thing to remember about AjaxDelta tags is that you can't nest them. You should specify AjaxDelta tags at the highest required level in the master page structure.
The last example in Figure 1 is the (3) page title, which requires a special pattern that uses the SharePoint:PageTitle tag. The following code shows the PageTitle tag as used in the
Seattle.master master page.

<SharePoint:PageTitle runat="server">
<asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server">
<SharePoint:ProjectProperty Property="Title" runat="server" />
</asp:ContentPlaceHolder>
</SharePoint:PageTitle>

Your master page can also include style sheets and JavaScript files. The server engine needs to identify both CSS and JavaScript files as required. To identify the CSS files resources as
required, use the following pattern.

<SharePoint:CssLink runat="server" Version="15"/>


<SharePoint:CssRegistration Name="my_styles.css" runat="server" />

Note that you can have only one CssLink tag per master page, but you can have many CssRegistration tags, so you can add many CSS files. Use the following pattern for JavaScript files.

<SharePoint:ScriptLink language="javascript" name="my_javascript.js" runat="server" />

Including CSS and JavaScript files using HTML style and script tags is not supported in MDS.

ASP.NET pages
If your project includes ASP.NET pages, you probably need to reference CSS and JavaScript files. The HTML style and script tags are not compatible with MDS. Instead, use the
CssRegistration and ScriptLink patterns explained in the previous section.
Your ASP.NET pages may also use the Response.Output method to write content to the page, which is not allowed in MDS. Instead, you can use the following MDS-compliant methods of
the SPHttpUtility class:
WriteNoEncode()
WriteHtmlEncode()
WriteEcmaScriptStringLiteralEncode()
WriteHtmlEncodeAllowSimpleTextFormatting()
WriteHtmlUrlAttributeEncode()
WriteUrlKeyValueEncode()
WriteUrlPathEncode()
Besides referencing JavaScript files, your ASP.NET pages can have inline JavaScript code. Use the following pattern to make your script blocks MDS compatible.

<SharePoint:ScriptBlock runat="server" >


// Your JavaScript code here.
</SharePoint:ScriptBlock>

Controls and web parts


You also need to mark your controls and web parts as MDS compliant. The following code shows the pattern to use.

[assembly: Microsoft.SharePoint.WebControls.MdsCompliantAttribute(IsCompliant = true)]


namespace VisualWebPartProject2.VisualWebPart1
{
// Rest of your control logic

Also, your controls and web parts need to register their resources using the methods in the SPPageContentManager class. The most common resources are JavaScript snippets and hidden
files, which can be registered using the RegisterClientScriptBlock and RegisterHiddenField, respectively.
Your controls and web parts can also use XSLT files to control the rendering process. Your XSLT files can have embedded JavaScript code or files. The MDS engine needs to know about
these resources. You can register the JavaScript resources using an XSLT extension object named pcm. A great example of how to use the pcm object is in the %ProgramFiles%\Common
Files\Microsoft Shared\web server extensions\15\TEMPL ATE\L AYOUTS\XSL\fldtypes.xsl file. The following code shows how the fldtypes.xsl file uses the pcm object to register JavaScript
resources.
<xsl:value-of select="pcm:RegisterScriptBlock(concat('block1',$ViewCounter), string($scriptbody1))"/>
<xsl:value-of select="pcm:RegisterScriptLink('/_layouts/15/wssactionmenu.js')"/>

See also
Minimal Download Strategy overview
Build sites for SharePoint
Optimize page performance in SharePoint
5/3/2018 • 20 minutes to read Edit Online

Learn about features to improve performance in pages in SharePoint. These features can be used to enhance the experience in geographically distributed implementations.
Provided by: David Crawford, Microsoft Corporation
This article provides instructions that will help optimize performance in SharePoint. SharePoint includes features that help optimize page loading over a Wide Area Network (WAN).
Designing pages to make them as small and responsive as possible complements these performance improvements.

Minimal Download Strategy (MDS)


Minimal Download Strategy (MDS) relies on the ability to download only specific portions of a page that is rendered fully on the server. Downloading only the specific portions provides a
very efficient loading model. The fully rendered page is not returned to the client. The server must be able to accurately identify those pieces that must be part of the response and those that
are not necessary. The pieces that may or may be not part of the response include scripts, styles, and markup.
The following table shows some benefits of using MDS.

Table 1. Benefits of using MDS

PER FO R MANCE V IS U ALS

Fewer amounts of data downloaded per page request. No browser flashing caused by full page reload.

Browser needs to update only the regions of the page that changed since the last request. Easy to identify animations.

Small amount of processing required on the client. Changes in the page attract user's attention.

Note: Half of client Page-Load-Time 1 (PLT1) is due to chrome cascading style sheet (CSS) rendering and
JavaScript parsing and execution.

Both AJAX and MDS are technologies that request only sections of the page to minimize data download and improve page responsiveness. The following figure shows the MDS
architecture.

Figure 1. MDS architecture

The MDS framework assumes that a master page defines a chrome and content regions. In MDS, SharePoint navigating to a page means requesting just the content for those regions and
the resources that the page depends on. Once that content downloads to the browser, script code applies the markup or resources to the page as appropriate. The browser behaves as if the
requested page had been loaded completely from the server.

Figure 2. Page chrome and regions in a SharePoint page


When users are browsing a SharePoint website in MDS mode, they will not cause full page postbacks and full page reloads. Instead, the URL for the page they are visiting will remain the
same, and the fragment identifier (a "#"sign) will change to contain the page they are visiting. The format of the URL is:
[Path to site (spweb)] + /_layouts/15/start.aspx# + [path to page] + [query string] .

The following table shows some examples of URLs formatted in MDS mode.

Table 2. URLs formatted in MDS mode

NO N- MD S U R L MD S U R L

http://server/SitePages/ http://server/_layouts/15/start.aspx#/SitePages/

http://server/subsite/SitePages/home.aspx http://server/subsite/_layouts/15/start.aspx#/SitePages/home.aspx

http://server/_layouts/15/viewlsts.aspx?BaseType=0 http://server/_layouts/15/start.aspx#/_layouts/viewlsts.aspx?BaseType=0

The object used for the AJAX navigation is AjaxNavigate. By default, there is an instance of AjaxNavigate available for you to use named ajaxNavigate. To use the ajaxNavigate
instance:

ajaxNavigate.update(serverRelativeURL, null);

If you want a control or web part to listen to the navigation events, you can use the add_navigate handler. When the handler is called, your callback function receives a reference to the
navigation object and the parsed hash values in a dictionary. The control or web part can retrieve the value for the parameter of interest from the dictionary, compare it to the current value,
and decide what action it needs to take. A common action is to send an AJAX request to the server to retrieve some data or reorder the items in the view. When a control has finished
listening to navigation events, it can use the remove_navigate handler.
MDS also supports multiple hash marks in key/value pairs. MDS appends the hash marks after the URL. The format of hash marks in the URL is:
http://server/_layouts/15/start.aspx#/SitePages/page.aspx#key1=value1#key2=value2 . The following code example shows how to update the hash marks.

var updateParts;
updateParts = {key1: "value1", key2: "value2", keyn: "valuen"}
ajaxNavigate.update(null, updateParts);

If you find that the pages in your website constantly fall back to download the full page, you might want to consider turning the MDS feature off. You might also want to turn the MDS
feature off if you need to use a different strategy to improve performance.
A particular element in the page must make sure that the critical resources needed to work are known to the MDS infrastructure at server rendering time. To convert an existing project to
use MDS, you need to update the following files and components:
Master pages
ASP.NET pages
Custom master pages for errors
JavaScript files
Controls and web parts

Master pages
The main change in the master page is to surround the regions of HTML markup that will be sent to the client with a special control named SharePoint:AjaxDelta. The most common parts
that need to be surrounded by a SharePoint:AjaxDelta control are the controls embedded in the master page chrome and the content place holders. If a control is the same on all pages
within a site, it should not be wrapped by a SharePoint:AjaxDelta control. The following markup shows a visible content placeholder surrounded by a SharePoint:AjaxDelta control.
<SharePoint:AjaxDelta id="DeltaPlaceHolderMain" IsMainContent="true" runat="server">
<asp:ContentPlaceHolder id="PlaceHolderMain" runat="server" />
</SharePoint:AjaxDelta>

Controls that have content dependent on the current URL must be wrapped in a SharePoint:AjaxDelta control. The following markup shows a menu surrounded by a
SharePoint:AjaxDelta control.

<SharePoint:AjaxDelta id="DeltaBreadcrumbDropdown" runat="server">


<SharePoint:PopoutMenu
runat="server"
ID="GlobalBreadCrumbNavPopout"
IconUrl=IMGCLUSTER_FG_IMG
IconAlt=LOC_ATTR_WSS(master_breadcrumbIconAlt)
IconOffsetX=IMGCLUSTER_FG_LEFT(BREADCRUMBBUTTON)
IconOffsetY=IMGCLUSTER_FG_TOP(BREADCRUMBBUTTON)
IconWidth=IMGCLUSTER_FG_WIDTH(BREADCRUMBBUTTON)
IconHeight=IMGCLUSTER_FG_HEIGHT(BREADCRUMBBUTTON)
AnchorCss="s4-breadcrumb-anchor"
AnchorOpenCss="s4-breadcrumb-anchor-open"
MenuCss="s4-breadcrumb-menu">
</SharePoint:PopoutMenu>
</SharePoint:AjaxDelta>

NOTE

The SharePoint:AjaxDelta control should not be nested within itself. Specify this control at the highest required level.
If you need to include a cascading style sheet (CSS) file, you need to use the SharePoint:CssLink and SharePoint:CssRegistration controls. These controls have been updated to work in
both MDS and non-MDS mode. The following markup shows how to use the SharePoint:CssLink and SharePoint:CssRegistration controls.

<SharePoint:CssLink runat="server" Version="15"/>


<SharePoint:CssRegistration Name="my_stylesheet.css" runat="server" />

C A U T IO N

You can have only one SharePoint:CssLink control per page. In MDS mode, you get an error if you have more than one SharePoint:CssLink control in a page. Including a CSS file using
an HTML style element is not supported in MDS mode, because the server logic cannot identify the file as a required resource when the response is rendered.
To include a JavaScript file, use the SharePoint:ScriptLink control. The following markup shows how to use the SharePoint:ScriptLink control.

<SharePoint:ScriptLink language="javascript" name="my_javascriptfile.js" runat="server" />

C A U T IO N

Including a JavaScript file using the HTML script tag is not supported in MDS mode, because the server logic cannot identify the file as a required resource when the response is rendered.
To render the title element inside the head element in the page, we use a special pattern using the SharePoint:PageTitle control. The following markup shows how to use the
SharePoint:PageTitle control.

<SharePoint:PageTitle runat="server">
<asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server" />
</SharePoint:PageTitle>

NOTE

Each individual page must override the title by providing a replacement for the asp:ContentPlaceHolder control inside the SharePoint:PageTitle control.

ASP.NET pages
To include a JavaScript or CSS file, use the same SharePoint:ScriptLink and SharePoint:CssLink controls described in the previous section.
In previous versions of SharePoint, some pages write content by using the Response.Output property. If you are using MDS, this is no longer allowed. You have to change the calls to
Response.Output to use a new API. The following table shows APIs that are commonly used in SharePoint pages and the new MDS-complaint API.

Table 3. Commonly used APIs and their MDS-compliant alternatives

CO MMO NLY U S ED API MD S - CO MPLIANT ALTER NATIV E

NoEncode() WriteNoEncode()

HtmlEncode() WriteHtmlEncode()

EcmaScriptStringLiteralEncode() WriteEcmaScriptStringLiteralEncode()

HtmlEncodeAllowSimpleTextFormatting() WriteHtmlEncodeAllowSimpleTextFormatting()

HtmlUrlAttributeEncode() WriteHtmlUrlAttributeEncode()

UrlKeyValueEncode() WriteUrlKeyValueEncode()

UrlPathEncode() WriteUrlPathEncode()

If a page, control, or web part directs its output to the Response.Output property, it causes MDS to fail back. When MDS fails back, it performs a full navigation to the requested page. You
can find the offending control by using the DeltaPage ._shipRender property while debugging the server component.
You should replace HTML inline script elements with SharePoint:ScriptBlock controls. The following shows an HTML inline script element and its MDS-compliant alternative
SharePoint:ScriptBlock control.
HTML inline script element
<script type="text/javascript">
// Your JavaScript code goes here.
</script>

MDS-compliant alternative
<SharePoint:ScriptBlock runat="server">
// Your JavaScript code goes here.
</SharePoint:ScriptBlock>

The introduction of the SharePoint:ScriptBlock in the page can change the scope of variables in page. Sometimes it is necessary to move the declaration of variables from <% %> to
<script runat="server"> <script> . To test this, load the page in the browser after you perform updates.

NOTE

The MDS infrastructure does not support VBScript, because it cannot be registered as a script in ASP.NET. Scripts have to be converted to JavaScript.
HyperLinks in ASP.NET pages must be updated to use SPUpdatePage type. The following shows hyperlinks in ASP.NET pages and the same links updated by using SPUpdatePage type.
Hyperlink in ASP.NET
<a
id=<%_STSWriteHTML("viewlist" + spList.BaseTemplate.ToString());%>
href=<%_STSWriteURL(listViewUrl);%>
>

MDS-compliant alternative
<a
id=<%_STSWriteHTML("viewlist" + spList.BaseTemplate.ToString());%>
href=<%_STSWriteURL(listViewUrl);%>
onclick="if (typeof(SPUpdatePage) !== 'undefined') return SPUpdatePage(this.href);"
>

Custom master pages for errors


You can display error messages in MDS mode, even when you are using a custom master page for errors. To use a custom master page for errors in MDS mode, you must define an
AjaxDelta in the error master page that has the id property set to the string "DeltaPlaceHolderMain". The content of the error message must be rendered into the AjaxDelta. When the
error page is returned to the browser from the server, the browser identifies this as the main content to display and shows it to the user.
Although the master page for the error page and the master page for start.aspx are not an explicit match, the browser can detect that an error has occurred. The browser allows MDS to use
the relevant error message content within the existing master page in order to maintain a consistent and smooth user experience.

JavaScript files
JavaScript files should include only function declarations. Nonetheless, there are many legacy scripts that contain global variable initializations. Global variables need to be reinitialized when
a new page is rendered in MDS mode. You can use the ExecuteAndRegisterBeginEndFunctions to initialize global variables. The following code example shows how to use the
ExecuteAndRegisterBeginEndFunctions.

function ExecuteAndRegisterBeginEndFunctions(tag, beginFunc, endFunc, loadFunc)

The ExecuteAndRegisterBeginEndFunctions has the following parameters:


tag: The name of the file that registers the callbacks; it is used only for debugging purposes.
beginFunc: A function that is called before you request the page delta.
endFunc: A function that is called after you retrieve the delta, but before the HTML and JavaScript for the new page are applied.
loadFunc: A function that is called after the HTML and JavaScript for the new page is applied.

Controls and web parts


To use MDS, controls and web parts have to register page resources by using the SPPageContentManager object. The most frequently registered resources using
SPPageContentManager are JavaScript snippets (functions or JSON variables) and hidden fields. The following table shows common patterns for inserting hidden fields and JavaScript
snippets, and how to do the same by using the SPPageContentManager object.

Table 4. Common practices for rendering content and their MDS-compliant alternatives

CO MMO N PR ACTICE FO R R END ER ING CO NTENT MD S - CO MPLIANT ALTER NATIV E

output.Write("<input type=\\"hidden\\" name=\\""); SPPageContentManager.RegisterHiddenField(this, "HiddenField", DigestValue);


output.Write(SPHttpUtility.NoEncode("HiddenField));
output.Write("\\" value=\\"");
output.Write(DigestValue);
output.Write("\\" />");

Page.ClientScript.RegisterClientScriptBlock(typeof(MyType), "MyKey", "var myvar=1", SPPageContentManager.RegisterClientScriptBlock(this, typeof(MyType), "MyKey", "var


true); myvar=1");

NOTE

The RegisterHiddenField and RegisterClientScriptBlock functions in the SPPageContentManager object expect an object of type Control or Page in the first parameter.
The MDS engine uses the first parameter to filter the scripts. Here are the rules for filtering when a page is rendered in MDS delta mode:
If the first argument is of type Page, the scripts will execute in the browser.
If the first argument is not of type Page and the control falls under a SharePoint:AsyncDelta, the scripts will execute in the browser.
If the first argument is a web part, the scripts will execute in the browser.
Many APIs in previous versions of SharePoint did not provide the current control as an argument. The public object model in SharePoint was designed to provide an alternate method to
register the resources. The methods that do not provide the current control as an argument are still in the API for backward compatibility.
You can navigate between two pages by using a new function named SPUpdatePage. When a control or web part is rendered in MDS delta mode, the HyperLink controls must add the
onclick handler and call SPUpdatePage.
You must update the XSLT used by web parts because all the resources must be added by using the SPPageContentManager object to make them MDS-compliant. You can add JavaScript
snippets to the XSLT by using the RegisterScriptLink and RegisterScriptBlock methods of the SPPageContentManager object.

Optimize page downloads


After you understand the composition of a page, you can use different methods to optimize the download experience for that page. In general, the goal is to minimize the number of round
trips between client and server computers and to reduce the amount of data that goes over the network. The guidance in this article includes recommendations that you can apply broadly to
a variety of different implementations of SharePoint.
Table 5 shows example loading times that illustrate the difference between the first, second, and subsequent page loads.
Table 5. Page loading times

First page load 3-4 seconds

Second page load 1.5 seconds

Subsequent page loads 1 second


NOTE

Loading times might be different in your particular scenario. Loading times are affected by many variables, including, but not limited to, page size, latency, and server load.
You should categorize page optimization techniques into one of two categories: first page request and subsequent page requests. Optimizations for the first page request (page load time 1 or
PLT1) are those kinds of optimizations that are effective the first time the page is requested, but that don't necessarily affect subsequent page requests. The following are some optimizations
for PLT1:
Optimize HTML markup.
Use consolidated images and files; for example, combine multiple CSS files into one. Combine images into an image strip or cluster.
Use compression (crunch) techniques. For more information, see Compress (crunch) JavaScript and CSS files.
Verify that you are referencing the production version of common JavaScript libraries, such as jQuery, instead of the debug versions.
Consider using a well-known content delivery network (CDN) such as the Microsoft Ajax Content Delivery Network. The files required in your pages may already be cached by the client
browser.
Optimizations for subsequent page requests are those that can improve the user experience for a subsequent page load. The key is that you need to balance loss in functionality against the
gain achieved. If gain is only realized the first time a user hits a site, the optimization might not be worth the loss in functionality.

Compress (crunch) JavaScript and CSS files


Files that contain JavaScript and styles may be significantly reduced in size by removing whitespaces, style inheritance, and code reuse. Some libraries come in both regular (debug) and
compressed (crunched) versions. You can find a variety of tools to automate file crunching by searching the Internet.
Verify that the compressed versions are deployed to production servers. This example shows how a CSS file can be reduced in size through some relatively simple rewriting.
.article-ByLine {
font-family: Tahoma,sans-serif;
font-size: 9.5pt;
font-style: normal;
line-height: normal;
font-weight: normal;
color: #000000
}
.article-Caption {
font-family: Tahoma,sans-serif;
font-size: 8pt;
font-style: normal;
line-height: normal;
font-weight: normal;
color: #000000
}
.article-Headline {
font-family: Tahoma,sans-serif;
font-size: 14pt;
font-style: normal;
line-height: normal;
font-weight: bold;
color: #000000
}
.article-SubHead {
font-family: Tahoma, sans-serif;
font-size: 11pt;
font-style: normal;
line-height: normal;
font-weight: normal;
color: #000000
}
.article-Text {
font-family: Tahoma, sans-serif;
font-size: 10pt;
font-style: normal;
line-height: normal;
font-weight: normal;
color: #000000
}

You can usually find ways to achieve the same styling and reduce the size of your files by efficiently rewriting your CSS files. The following example shows how to optimize the previous CSS
size by inheriting the styles from a parent element.

BODY {font:100% Tahoma,sans-serif}


.art-By {font: 79%}
.art-Cap {font: 67%}
.art-Head {font: bold 117%}
.art-Sub {font: 92%}
.art-Txt {font: 83%}

The first version of the CSS is 783 characters long, and the second is 140 characters long.

Entity tags
Entity tags (ETags) can cause the client to unnecessarily reload files. ETags are meant to uniquely identify files by using a number that the server generates. In clusters of servers, each server
will create a different number. For example, a browser is sending a Get method with an If-Modified header field for a file that it found in its cache. If there is only one server, the file will
probably match, and a 304 Not-Modified http status will be sent. But, if the user is accessing a large server farm, it will probably hit a different server with a different entity tag, causing that
server to send the file to the browser.

Cache settings
Use Fiddler or a similar tool to verify whether the cache is serving requests. Some common reasons caching not serving requests include:
Resources do not have an expiration date value.
The query string constantly changes.
The sum of max-age cache-control directive plus last-modified header results in a date previous to today.
The proxy servers do not support the max-age property.
The cache-control header has a value of no-cache. A value of private caches the resource only for the user that issues the request.

Number and size of images


You should minimize the number of images in your site. To help with that effort, you can embed multiple images in a single file and then reference individual images in your page. Not only
will file download size decrease, but fewer files result in less network traffic. It is more complicated to author pages by using this technique, but in situations where every round trip and file
size counts, it can prove to be valuable way to help improve performance.
Figure 3 shows an example of a single image file that contains multiple images.
Figure 3. Single image file that contains multiple images

Figure 4 shows how the image file is subsequently changed to display as individual pictures in a table.
Figure 4. Multiple images displayed in a table
Manipulation of the images was done entirely through style sheet classes. There were two primary classes used in div and img elements in each table cell. Those classes are as follows.

BODY {font:100% Tahoma,sans-serif}


.art-By {font: 79%}
.art-Cap {font: 67%}
.art-Head {font: bold 117%}
.art-Sub {font: 92%}
.art-Txt {font: 83%}

.cluster {
height:50px;
position:relative;
width:50px;
}
.cluster img {
position:absolute;
}

Each image has a class associated with it based on the identifier (ID) for the image. That style clips the picture and defines an offset from the initial picture in the cluster. Those classes are as
follows.

#person {
border:none;
clip:rect(0, 49, 49, 0);
}
#keys {
clip:rect(0, 99, 49, 50);
left:-50px;
}
#people {
clip: rect(0, 149, 49, 100);
left:-100px;
}
#lock {
clip:rect(0, 199, 49, 150);
left:-150px;
}
#phone {
clip:rect(0,249, 49, 200);
left:-200px;
}
#question {
clip: rect(0, 299, 49, 250);
left: -250px;
}

List view pages


Microsoft has worked to quantify and improve the performance of list view page rendering times. A list view page is the AllItems.aspx page that is used by each list and library to enable
browsing of content. The rendering time of that page can vary widely based on the number of columns that are visible in the view and the format of the columns. For example, displaying
options and enabling presence icons can greatly affect rendering time. The collapsed grouping option took significantly longer to render than the expanded grouping option, and both were
slower than no grouping option at all.
These sorts of nuances are why it is important to carefully consider how views are constructed in list view pages, especially over slow network connections. When working with lists that
contain a lot of data, it is important to carefully design all views, especially the default view. In general, you can speed up the rendering time of list view pages by using the following
recommendations:
Show only the strictly required columns.
If possible, exclude columns that include presence information.
Use a link instead of an edit menu to view the item details.
The following table describes customizations that reduce the time that is required for a view to render.

Table 6. Customizations that reduce the time required for the view to render

ITEM D ES CR IPTIO N

View type Create a view as a datasheet view instead of a standard view.

View: Item limit Anything over 1,000 will likely render slowly.
Over a slow connection, it is important to experiment to find the right balance between
the quantity of data shown at a time and the number of round trips necessary to view all the data.
The more rows that display at a time, the fewer round trips, but larger pages.

View: Filter Use [Today] and [Me] keywords to filter items by freshness or assignment.
Use Status fields to show only active items in default views.

View: Columns Include the smallest number of columns.


Create a default view with few columns that allows high-level browsing after which people can drill down.
The following table describes customizations that will increase the time that is required for a view to render. Each additional column increases rendering time by a slight amount: up to a half-
second per column over a fast network connection for a list of 1,000 items. Some columns increase rendering time more than others, as noted in the table.

Table 7. Customizations that increase the time required for the view to render

ITEM D ES CR IPTIO N

Group By Grouping adds HTML and JScript, which slows down rendering for large lists.
Making all groups collapsed by default actually increases rendering time further
because of additional operations on the browser object model.

Column - title linked to item with edit menu The option "linked to item with edit menu" takes the longest.
The similar option "linked to item" does not increase rendering time noticeably.

Developer Dashboard
The Developer Dashboard is rebuilt for SharePoint to provide more information, including MDS. It runs in a separate window to avoid affecting rendering of the actual page, and it provides
detailed request information per page with a chart view. It also includes a dedicated tab for Unified Logging System (ULS) log entries for a particular request. Additional detailed information
is included for request analysis. It uses a dedicated Windows Communication Foundation (WCF) service (diagnosticsdata.svc) designed to provide tracing information.
To learn more about the Developer Dashboard:
Overview of the SharePoint renewed developer dashboard (video).
Renewed Developer Dashboard (PowerPoint slide deck).
To enable the Developer Dashboard, use the following Windows PowerShell snippet code.

$content = ([Microsoft.SharePoint.Administration.SPWebService]::ContentService)
$appsetting =$content.DeveloperDashboardSettings
$appsetting.DisplayLevel = [Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::On
$appsetting.Update()

Figure 5 shows the Developer Dashboard.


Figure 5. Developer Dashboard

It is important to understand how these requests and the number of images and queries affect performance. There are similarities when it comes to server-side rendered list views (XSL or
CAML) as they follow the same size recommendations as client-side rendered list views. However, server list view guidance is to create only list views necessary to accomplish your
requirements when your goal is optimal performance, as thousands of views will cause greater degradation in performance due to compilation cache management. The physical
characteristics of the computer, such as memory and processor speed, will factor into the overall speed.
There is also consideration for where the requests route or how they are distributed. To better understand how SharePoint routes and distributes requests, you can use the Request Manager
tool. However, discussing request distribution is beyond the scope of this article. For more information, see Configure Request Manager in SharePoint.

Conclusion
Much of the guidance for SharePoint 2010 page performance optimization applies to SharePoint. This article provides some of the elements of guidance for SharePoint 2010 while diving
into new areas that would specifically benefit performance. We covered some obvious changes or enhancements, for example, MDS and the enhanced Developer Dashboard. We wrapped
up with the classic guidance: crunch down JavaScript and cascading style sheets, use a CDN for common JavaScript libraries if possible for caching, combine and compress images as much
as possible, limit or remove unnecessary data from view, and construct list views judiciously. The techniques and features discussed in this article contribute to supporting your performance
goals.
See also
Build sites for SharePoint
SharePoint Design Manager image renditions
Overview of Design Manager in SharePoint
Overview of the SharePoint page model
Optimize SharePoint site accessibility
5/3/2018 • 2 minutes to read Edit Online

Improve the accessibility of your SharePoint pages. Enhance the SharePoint site experience for users with a variety of accessibility needs. Some published SharePoint sites might not take
advantage of the accessibility features that are available, which can make them difficult for people with disabilities to use. This article provides information that will help you optimize your
SharePoint site for accessibility.

More Accessible Mode


SharePoint provides a "More Accessible Mode". To activate this mode, open a SharePoint webpage and press the TAB key until you find the "Turn on More Accessible Mode" link. This feature
recreates the webpage in standard HTML, which makes it friendlier for screen readers. In More Accessible Mode, JavaScript-based drop-down menus are converted to hyperlink lists and
objects are converted to simpler HTML to allow screen readers to understand the content.

Landmarks
Landmarks are programmatically determined markers in your published pages that allow screen-reader users to understand where they are currently located in the webpage. Screen reader
software can also create a list of all landmarks on a webpage, which allows a user to navigate the page more easily. Ensure that keyboard users can make use of landmarks to enhance the
accessibility of the SharePoint site.

Alternative text
Alternative text is required for screen readers to read non-text content on the page. Provide alternative text (ALT text) for graphics and figures that includes a clear and useful description of
the diagram or screen image. When you upload an image, the Site Image web part includes a field to enter custom alternative text. When you add images to the picture library, you can
define custom ALT text for each image. Add alternative text to links and images that open in a new window. This way, screen readers can indicate to users that a new window will open.

See also
Build sites for SharePoint
Accessibility in SharePoint
Microsoft Accessibility
Accessibility in SharePoint
Add SharePoint capabilities
7/12/2018 • 2 minutes to read Edit Online

Find overview and how-to information about adding SharePoint features and capabilities to custom apps.

What are SharePoint capabilities in SharePoint?


SharePoint capabilities represent the features that you work with on SharePoint sites, such as workflows, social feeds, and search. By adding SharePoint capabilities to your app, you can help
users to do things better and more quickly.
You can add SharePoint capabilities to whatever kind of app you're developing: SharePoint Add-ins, solutions, sites, components, and mobile apps.

Kinds of SharePoint capabilities you can add to your apps


The following table shows SharePoint capabilities that you can add to your app, and provides links to articles that give more information about each capability.
Table 1. SharePoint capabilities that you can add to apps in SharePoint

CAPAB ILIT Y AR TICLE TITLE

Model and automate business processes Workflows in SharePoint

Communicate and collaborate with people and track content Social and collaboration features in SharePoint

Add location and mapping features Integrating location and map functionality in SharePoint

Make search results more relevant Search in SharePoint

Access data from external data systems Business Connectivity Services in SharePoint

Work with data, convert file formats, and translate sites Office and SharePoint application services

Work with user access, roles, rights, and claims. Authentication, authorization, and security in SharePoint

Discover content in electronic format for legal purposes eDiscovery in SharePoint

See also
SharePoint development overview
Set up a general development environment for SharePoint
Programming models in SharePoint
Accessibility in SharePoint
Workflows in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn about the Workflow Manager Client 1.0 authoring framework and workflow scenarios for SharePoint. SharePoint marks the introduction of Workflow Manager Client 1.0 as the new
foundation for SharePoint workflows. Built on Windows Workflow Foundation 4, SharePoint workflows offer a new range of capabilities and enhancements. For an overview of the new
flavor of workflows for SharePoint, see What's new in workflows for SharePoint.
For information about setting up Workflow Manager Client 1.0 and pairing it to function correctly with SharePoint, see Set up and configure SharePoint Workflow Manager.

In this section
Get started with workflows in SharePoint
What's new in workflows for SharePoint
SharePoint workflow fundamentals
SharePoint workflow development best practices
Using the pairing cmdlet Register-SPWorkflowService
Workflow development in SharePoint Designer and Visio
Develop SharePoint workflows using Visual Studio
Workflow actions and activities reference for SharePoint

Related sections
SharePoint development overview
Add SharePoint capabilities
Set up and configure SharePoint Workflow Manager
For more information about SharePoint site workflows, see Blog article from Sympraxis Consulting: Looping Through Content in a SharePoint Site Workflow
Get started with workflows in SharePoint
3/26/2018 • 4 minutes to read Edit Online

Learn about the newly engineered Workflow Manager Client 1.0, which provides the infrastructure for workflows in SharePoint, and how SharePoint workflows are integrated with the new
model for SharePoint Add-ins.

Important: For instructions on setting up and configuring SharePoint and Microsoft Azure, see Set up and configure SharePoint Workflow Manager.

Overview of workflows in SharePoint


Workflows in SharePoint allow you to model and automate business processes. These business processes can be as simple as a document approval process with a single approver (shown in
Figure 1), as complex as customer-facing product catalog using web service calls and database support, or as formidable as virtually any structured business process, full of conditions, loops,
user inputs, tasks, and custom actions.
Figure 1. Simple SharePoint workflow

SharePoint marks the introduction of Workflow Manager Client 1.0 as the powerful new foundation for Visual Studio workflows. Build on Windows Workflow Foundation 4, Workflow
Manager Client 1.0 provides advantages over previous versions that reflect the commitment of SharePoint to the model for SharePoint Add-ins and cloud-based computing. For details of
these changes, see What's new in workflows for SharePoint and SharePoint workflow fundamentals.
Perhaps most importantly for workflow authors, the way that your create workflows has been vastly improved and simplified. Not only are workflows now entirely declarative (that is,
designer-based, no-code workflows), but the primary workflow authoring environments, both Visual Studio 2012 and SharePoint Designer 2013, have been simplified and streamlined.
The key enhancements to workflows in SharePoint include the following. For a more detail overview of what's new in workflows for SharePoint, see What's new in workflows for SharePoint
Enhanced connectivity to enable cloud-based execution of workflows. In fact, there is 100 percent parity in SharePoint between on-premises and Office 365 -based workflows.
There is full interoperability in SharePoint with SharePoint 2010 workflows, which is enabled by using the SharePoint workflow interop .
Enhanced authoring expressiveness by using Visual Studio events and action, web services, and classic programming structures, all in a declarative, no-code environment.
Scalability and robustness that is consistent with requirements for Office 365 and the Cloud App Model.
Enhanced connectivity to promote highly functional integrated systems. You can call and control your workflows from any external system. Additionally, your workflow can make web
service calls to any stream or data source using common protocols like HTTP, SOAP, the Open Data protocol (OData), and Representational State Transfer (REST).
Enhanced authoring capabilities for the non-developer in SharePoint Designer 2013, and the ability to compose workflow logic in Visio.
Enhanced, and yet simplified, workflow development in Visual Studio, including support for custom workflow actions, rapid development in a declarative environment, single-step
deployment, and support for developing SharePoint Add-ins.
Full support for workflow-powered SharePoint Add-ins, where workflows function as the middle tier for business process management.

Workflow Manager Client 1.0 and the model for SharePoint Add-ins
Visual Studio 2012 is optimized for developing workflow-driven SharePoint Add-ins and for exploiting the enormous power and flexibility of the model for SharePoint Add-ins. You can use
the SharePoint workflow object model to enable workflow logic underneath a SharePoint app in such a way that end users experience the app surface itself while underneath the app is
driven by your workflow logic.
Additionally, Visual Studio 2012 is ideal for developing Office Add-ins, which can run workflows from inside a Microsoft Office application.

Authoring SharePoint workflows


There are two primary authoring environments for Workflow Manager Client 1.0: SharePoint Designer 2013 and Visual Studio. Additionally, non-technical information workers can use Visio
to construct workflow logic that you can then import into SharePoint Designer and assemble into a SharePoint workflow project.
However, the primary authoring environments are Visual Studio 2012 and SharePoint Designer 2013. To help you decide which of these best suits your needs, see the decision matrix in
Comparing SharePoint Designer with Visual Studio.

SharePoint Designer 2013 as workflow authoring tool


In many respects, SharePoint Designer 2013 is the authoring tool of choice for SharePoint workflows. Although some advanced tasks (like creating custom actions, for example) require the
intervention of a developer using Visual Studio, SharePoint Designer 2013 provides the most flexible access to workflow development to the widest range of workflow authors.

Create a workflow using Visual Studio 2012


Visual Studio 2012 has SharePoint workflow project types built in. To create a SharePoint workflow project in Visual Studio, follow these steps.

To create a workflow using Visual Studio


1. Open Visual Studio 2012 and create a new project. In the New Project dialog box, choose Templates, Visual C#, Office SharePoint, SharePoint Solutions, and SharePoint
Project, as shown in Figure 2.
Figure 2. New Project dialog box

1. With the project created, choose Add New Item on the Project menu, and then choose Workflow under the Office SharePoint item, as shown in Figure 3.
Figure 3. Add New Item dialog box

1. After the workflow project is created, you are presented with a designer surface on which to create your workflow. The workflow development environment includes a custom toolbox
with a large palette of workflow authoring elements.
Figure 4. Visual Studio workflow authoring toolbox
See also
For more information about SharePoint Add-ins, see the following:
SharePoint Add-ins
Three ways to think about design options for SharePoint Add-ins
Important aspects of the SharePoint Add-in architecture and development landscape
Work with external data in SharePoint
For more information about developing workflows using Visual Studio 2012 and SharePoint Designer 2013, see the following:
Develop SharePoint workflows using Visual Studio
Workflow development in SharePoint Designer and Visio
For more information about Windows Workflow Foundation 4, see the following:
A Developer's Introduction to Windows Workflow Foundation (WF) in .NET 4
What's New in Windows Workflow Foundation
Beginner's Guide to Windows Workflow Foundation
The Workflow Way: Understanding Windows Workflow Foundation
Introduction to the Windows Workflow Foundation Rules Engine
Windows Workflow Foundation integration with Windows Communication Foundation
SharePoint workflow fundamentals
3/26/2018 • 8 minutes to read Edit Online

Provides a high-level overview of the workflow infrastructure in SharePoint, including a view of the platform architecture and the workflow interop bridge.

Overview of workflows in SharePoint


SharePoint workflows are powered by Windows Workflow Foundation 4, which was substantially redesigned from earlier versions. Windows Workflow Foundation (WF), in turn, is built on
the messaging functionality that is provided by Windows Communication Foundation (WCF).
Conceptually, workflows model structured business processes. Therefore, Windows Workflow Foundation 4 workflows are a structured collection of workflow "activities," each of which
represents a functional component of a business process.
The workflow platform in SharePoint uses the Windows Workflow Foundation 4 activity model to represent a SharePoint-based business process. Additionally, SharePoint introduces a
higher-level stage-gate model on which to create workflows.
It is important to note the relationship between workflow activities and SharePointactions. Workflow activities represent the underlying managed objects whose methods drive workflow
behaviors. Workflow actions, on the other hand, are wrappers that encapsulate the underlying activities and present them in a user-friendly form in SharePoint Designer. Workflow authors
interact with the workflow actions, whereas the workflow execution engine acts on the corresponding activities.
The activities, which are implementations of activity classes, are implemented declaratively by using XAML.
Workflow activities are invoked using loosely coupled web services that use messaging APIs to communicate with SharePoint. These APIs are built on the messaging functionality that is
provided by Windows Communication Foundation (WCF).
The messaging framework is very flexible and supports virtually any messaging pattern that you need. Note that on a SharePoint farm, Windows Workflow Foundation and WCF are hosted
in Workflow Manager Client 1.0.
Workflow Manager Client 1.0, SharePoint, and SharePoint Designer 2013 each provide significant parts of the new infrastructure:
Workflow Manager Client 1.0 provides the management of workflow definitions. It also hosts the execution processes for workflow instances.
SharePoint provides the framework for SharePoint workflows, which model SharePoint-based business processes that involve SharePoint documents, lists, users, and tasks.
Additionally, SharePoint workflows, associations, activities, and other workflow metadata are stored and managed in SharePoint.
SharePoint Designer 2013 is the primary business-user tool for creating workflow definitions and publishing them, as it was in previous versions. It can also be used to package a
workflow definition with or without associated SharePoint components.

Platform architecture
Figure 1 depicts a high-level view of the SharePoint workflow framework. Notice, first, how the new workflow infrastructure introduces Workflow Manager Client 1.0 as the new workflow
execution host. Whereas in previous versions workflow execution was hosted in SharePoint itself, this has changed in SharePoint. Workflow Manager Client 1.0 is external to SharePoint and
communicates using common protocols over the Microsoft Azure service bus, mediated by OAuth. Otherwise, SharePoint includes the feature that you would expect to see: content items,
events, apps, and so on. But notice that there is also an implementation of the SharePoint 2010 workflow host (that is, the Windows Workflow Foundation 3 engine) for backward
compatibility. You can read more about this in Use workflow interop for SharePoint.
Figure 1. High-level architecture of the workflow infrastructure

Workflow Manager Client 1.0 is represented in SharePoint in the form of the Workflow Manager Client 1.0 Service Application Proxy. This component allows SharePoint to communicate
and interact with the Workflow Manager Client 1.0 server. Server-to-server authentication is provided using OAuth.
SharePoint events for which a workflow is listening, like itemCreated, itemUpdated, and so on, are routed to Workflow Manager Client 1.0 using the Microsoft Azure service bus. For the
return trip, the platform uses the SharePoint Representational State Transfer (REST) API to call back into SharePoint.
There are also additions to the SharePoint workflow object model, called collectively the Workflow Services Manager, which allow you to manage and control your workflows and their
execution. The primary zones of interaction for the services manager are deployment, messaging, instance control, and (for backward compatibility) interoperability with SharePoint 2010
workflows.
Finally, there is the workflow authoring component. SharePoint Designer can now create and deploy both SharePoint 2010 and SharePoint workflows. Visual Studio 2012 not only provides
a designer surface for creating declarative workflows, but it can also create SharePoint Add-ins and solutions that fully integrate Workflow Manager Client 1.0 functionality.

Workflow subscriptions and associations


Because the most significant change to SharePoint workflows is the moving of workflow processing onto external workflow hosts like Microsoft Azure, it was essential for SharePoint
messages and events to connect to the workflow infrastructure in Microsoft Azure. In addition, it was necessary for Microsoft Azure to connect the infrastructure to customer data. Workflow
associations (which are built on the WF concept of subscriptions) are the SharePoint infrastructure pieces that support these requirements.

Microsoft Azure publication/subscribe service


Before you can discuss workflow associations and subscriptions, you must look at the Microsoft Azure publication/subscribe service, which is sometimes referred to as pub/sub, or simply
PubSub. PubSub is an asynchronous messaging framework. Message senders (publishers) do not send messages directly to message receivers (subscribers). Instead, messages are rendered
by publishers as classes that have no knowledge of the message subscribers. Subscribers, then, consume published messages by identifying messages of interest, regardless of the publisher,
based on subscriptions that they have created.
This decoupling of message creation from message consumption allows for scalability and flexibility. It enables multicast messaging on the publisher side, and for promiscuous message
consumption on the subscriber side.
NOTE

The PubSub feature is a part of the Microsoft Azure Service Bus, which provides connectivity options for WCF and other service endpoints. These include REST endpoints, which can be
located behind network address translation (NAT) boundaries, or bound to frequently changing, dynamically assigned IP addresses, or both. For more information about the Azure Service
Bus, see Service Bus.

Workflow associations and association scope


Workflow associations bind workflow definitions to specific SharePoint scope, with specific default values. The associations themselves represent a set of subscription rules that are stored in
the Azure publication/subscription service that process incoming messages to ensure that they are consumed by appropriate (that is, subscribed) workflow instances.
By default, the messaging infrastructure supports workflows at the following scopes:
SPList (for list workflows)
SPWeb (for site workflows)
Unlike previous versions, SharePoint does not support workflows that are scoped to a content type ( SPContentType ). However, the messaging infrastructure is extensible, so it can support
any arbitrary scope. As a developer, you can set the EventSourceId property on a given WorkflowSubscription instance to any guid. You can then use that EventSourceId value to call
PublishEvent(Guid, String, IDictionary<String, Object>), which triggers a new workflow instance of the specified WorkflowSubscription.

Workflow service in Microsoft Azure


Associations for SharePoint workflows are represented by their workflow service within Microsoft Azure. When an application has to acquire a workflow association and its data, it must first
query for all of the workflow services that are available at a given scope.
Similarly, workflow instances carry a pointer back to their respective workflow service. This is the means by which its correct association is determined.

Starting workflows
Workflows can be started either manually or automatically.
Manual workflows
Manual workflows are started when the PubSub service receives a StartWorkflow message. The message contains the following descriptive information:
The association identifier (that is, the WorkflowSubscription instance).
The ID of the originating item context. This is passed in with the ItemId parameter and the EventSource property on the PublishEvent method call.
The event type for a manual start ( WorkflowStart).
Additional workflow initiation parameters, either from the subscription or from the Init form, as appropriate. This would be CorrelationId for the subscription and WFInstanceId for
the Init form.
Auto-start workflows
Auto-start workflows are initiated by using an Add message to the PubSub service. The message contains the following descriptive information:
The ID of the originating item context.
The event itself is a normal SharePoint Add event.
The workflow initiation parameters.
NOTE

If a workflow automatically starts on a repeatable event (for example, the OnItemChanged event), it cannot start another workflow of a given association until the existing running instance
of the association's workflow has completed running.

Workflow subscriptions
The natural complement to associations are subscriptions, which allow the workflow to interact with associations. The workflow must create subscriptions on the Azure Service Bus using
create methods and delete methods.
The signatures of the methods that create the subscription and instantiate the workflow specify the parameters???both optional and required. The list of parameters is determined by the
workflow author, so they may differ from one workflow definition to another. The list of subscription parameters is specified as metadata of the workflow definitions. The subscription
parameters are provided when the subscription is created. The list of initialization parameters is specified in XAML as part of the workflow definition. The initialization parameters are
provided when the workflow is instantiated.
Subscriptions are bound to a specific SharePoint object???either an SPList instance or an SPWeb instance. The subscription object type is passed in as a value of a required parameter when
the subscription is created. The object type defines the subscription scope so that a subscription can only respond to events that occur on the object to which they are subscribed.

SharePoint workflow interop


SharePoint workflow interop enables SharePoint 2010 workflows (which are built on Windows Workflow Foundation 3) to be called from SharePoint workflows, which are based on
Windows Workflow Foundation 4. This allows you to execute 2010 workflows from within 2013 workflows.
This is important because you may have SharePoint 2010 that you may use to reuse in conjunction with your SharePoint workflows. Additionally, you may wish to use activities or features
from SharePoint 2010, which are not yet implemented in SharePoint
For a full discussion of SharePoint workflow interop, see Use workflow interop for SharePoint.

See also
Get started with workflows in SharePoint
Workflow actions and activities reference for SharePoint
Develop SharePoint workflows using Visual Studio
Workflow development in SharePoint Designer and Visio
Workflows in SharePoint
Use workflow interop for SharePoint
What's new in workflows for SharePoint 2013
7/12/2018 • 4 minutes to read Edit Online

Learn about the capabilities and features that are new to workflows in SharePoint Server 2013. The workflow framework in SharePoint is significantly changed from previous versions. The
following sections provide brief summaries of the most significant updates and enhancements to the workflow infrastructure.

Completely redesigned workflow infrastructure


SharePoint workflows are powered by Windows Workflow Foundation 4 (WF), which was substantially redesigned from previous versions. Windows Workflow Foundation, in turn, is built
on the messaging functionality that is provided by Windows Communication Foundation (WCF).
Perhaps the most prominent feature of the new workflow infrastructure is the introduction of Microsoft Azure as the new workflow execution host. The workflow execution engine now lives
outside of SharePoint, in Microsoft Azure. Figure 1 provides a generalized, high-level view of the new workflow infrastructure. For a more thorough discussion of the concepts presented in
Figure 1, see SharePoint workflow fundamentals.
Figure 1. High-level architecture of the workflow infrastructure

Fully declarative, no-code authoring environment


Another of the prominent changes is that workflows on the WF 4 platform are fully declarative. That is, workflows are no longer compiled into managed assemblies and deployed to an
assembly cache. Instead, XAML files define your workflows and frame their execution.

Enhanced SharePoint Designer 2013 authoring support


SharePoint Designer 2013 has been updated with the goal of making it the authoring environment of choice for authoring SharePoint workflows. SharePoint Designer 2013 provides
workflow authors with both a designer surface and a text-based workflow authoring environment. Additionally, you can develop workflow custom actions in Visual Studio 2012 and then
import them into SharePoint Designer 2013, where they can then be accessed from the Workflow Designer.
In short, the needs of both the information worker (the "power user") and the developer have been harnessed in SharePoint workflow authoring and development environments.

Visual Studio 2012 workflow project type support


To make collaboration easier between information worker and software developer, Visual Studio 2012 provides SharePoint workflow project types and a workflow custom action-item type.
For more information about developing workflows by using Visual Studio 2012, and for information about differentiating between SharePoint Designer 2013 and Visual Studio 2012 in
workflow development, see Develop SharePoint workflows using Visual Studio.

Support for creating custom actions


A lot of effort has gone into anticipating the business requirements of workflow authors in the providing of workflow templates, actions, and activities in SharePoint Designer 2013 and in
Visual Studio 2012. However, we also know that we cannot anticipate each person's specific needs. For this reason, Visual Studio 2012 provides a workflow custom action-item type that lets
developers create custom actions. For more information about workflow custom actions, see How to: Build and deploy workflow custom actions.

Tools support for SharePoint workflows


Visual Studio 2012 provides templates and support for creating workflows on the SharePoint workflow framework. SharePoint workflows are similar to previous versions of workflows
except that they are powered by WF 4 and run in Microsoft Azure. They are also declarative-only (XAML) and designed to interact with the cloud and work with SharePoint Add-ins. One of
their primary benefits is that they enable you to remotely host and run workflows outside SharePoint Server.

New workflow actions


Following are new workflow actions that are provided in SharePoint. For a full detailing of both new and deprecated actions, see Workflow actions and activities reference for SharePoint.
New to workflows in SharePoint are a set of workflow actions that allow you to integrate with Project 2013 and let you create Project-based workflows.
Table 1. New workflow actions in SharePoint

ACTIO N D ES CR IPTIO N

Assign a Task Assigns a single workflow task to a user or group.

Start a Task Process Initiates execution of a task process.

Go to This Stage Specifies the next stage in a workflow to which flow control should be handed.

Call HTTP Web Service Functions as a method call to a Representational State Transfer (REST) endpoint.
ACTIO N D ES CR IPTIO N

Start a List Workflow Starts a list-scoped workflow.

Start a Site Workflow Starts a site-scoped workflow.

Build DynamicValue Creates a new variable of type DynamicValue.

Get Property from DynamicValue Retrieves a property value from a specified variable of type DynamicValue.

Count Items in DynamicValue Returns the number of rows in a variable of type DynamicValue.

Trim String Removes all leading and trailing white-space characters from the current string.

Find Substring in String Returns 1-based index of the first occurrence of one or more characters, or the first occurrence of a
string, within a string.

Replace Substring in String Returns a new string in which all occurrences of a specified character or string are replaced with another
specified character or string.

Translate Document Functions as a wrapper around the HTTP activity that calls the synchronous translation API. You must
configure a Machine Translation Service Application for the SharePoint site on which you run the
workflow.

Set Workflow Status Updates workflow status as specified in message string.

Create a Project from Current Item [Microsoft Project] Creates a Project Server project based on the current item.

Set the current project stage status to this value [Microsoft Project] Sets the two status fields within the current stage of the project.

Set the status field in the idea list item to this value [Microsoft Project] Updates the status field of the original SharePoint list item.

Wait for Project Event [Microsoft Project] Pauses the current instance of the workflow to await a specified Project event: Project checked in, Project
committed, Project submitted.

Set this field in the project to this value [Microsoft Project] Sets the value for the enterprise custom field for a specified project.

See also
Get started with workflows in SharePoint
Workflow actions and activities reference for SharePoint
Workflow actions quick reference (SharePoint Workflow platform)
Prepare to set up and configure a SharePoint workflow development environment
3/26/2018 • 3 minutes to read Edit Online

Learn how to set up a workflow development environment to develop SharePoint workflows as free-standing apps for SharePoint by using Visual Studio 2012.

Overview of workflow development in SharePoint


Although workflows have been a part of SharePoint since early versions, workflows for SharePoint are a much enhanced and improved platform.
First, SharePoint workflows are now built on Windows Workflow Foundation 4.5, which is part of the .NET Framework 4.5.
Second, the workflow execution engine, Workflow Manager, has been decoupled from SharePoint and runs independently. This provides both flexibility and scalability. (Note that for
backward compatibility, the legacy 2010 workflow engine remains a part of SharePoint.)
Instead of developing workflows by writing C# code, you now build workflows in Visual Studio using a workflow designer that uses declarative expressions.
SharePoint workflows integrate with the new app model, which means you can now implement workflows in SharePoint Add-ins.
You can also develop SharePoint workflows using SharePoint Designer 2013. For more information, see Workflow development in SharePoint Designer and Visio.

Get started
First off, get acquainted with the new app model and the concepts underlying SharePoint Add-ins by dipping into the following:

SharePoint for developers Portal to the SharePoint developer site, where the emphasis is on apps for SharePoint.

SharePoint Add-ins Learn what apps for SharePoint are, why you should build them, and the concepts that are fundamental
to building them in SharePoint.

New name for apps for SharePoint Portal to a developer site devoted to building apps for Office and apps for SharePoint.

SharePoint development overview SharePoint is a development platform for apps for SharePoint and farm solutions. Get acquainted with
the capabilities and features of SharePoint to start your development.

SharePoint workflow fundamentals Provides a high-level overview of the workflow infrastructure in SharePoint, including a view of the
platform architecture and the workflow interop bridge.

Your next step is to ensure that you have an up-to-date workflow development environment installed. You don't need to develop on the SharePoint server machine, but of course you do
need a SharePoint Server installation to develop against.
Here are the components you need. It is important that you install these items in the order presented here:
1. Install the SharePoint environment
SharePoint update (KB2767999)
Optionally, you can subscribe to an Office 365 development environment
1. Install the Workflow Manager environment
Workflow Manager 1.0 Cumulative (KB2799754)
2. Install the Visual Studio 2012 development environment
Visual Studio 2012
Visual Studio 2012 Update 2 (KB2797912)
.NET Framework 4.5 update (KB2750149)
Office Developer Tools for Visual Studio 2012

If you have the "Preview" version


If you have pre-release (that is, "Preview") versions of SharePoint Server, Workflow Manager 1.0, or Office Developer Tools for Visual Studio 2013 (versions prior to March 2013), you must
update your installation. Following is a list of appropriate updates:
SharePoint update (KB2767999)
Microsoft Azure Service Bus 1.0 Cumulative Update (KB2799752)
Workflow Manager 1.0 Cumulative (KB2799754)

You must also update workflow projects created with the "Preview" version
The release version of the Visual Studio workflow components and their related updates introduce important changes that enhance performance, scalability, and reliability. Unfortunately,
these upgrades require you to update workflow projects that you created using the Preview tools.
To make this process easier, we provide a conversion tool that you can get through CodePlex. The tool is called the SharePoint Workflow Converter for Visual Studio 2012.
Here is a summary of changes that require you to update your workflow projects:
Activity references to Item Guid are replaced by Item Id. This change has important consequences:
The LookupSPListItemGuid and GetCurrentItemGuid activities are removed from the tooling; their replacement activities are LookupSPListItemId and GetCurrentItemId.
For other activities that use Item Guid, you will find Item Id added and Item Guid hidden. Your existing projects that use Item Guid will continue to work (except on very
large lists with more than 5000 items, which is one of the reasons for the change).
There is a new packaging format for workflows in apps.
The workflow activities assembly reference in XAML has been changed to point to a new design-time proxy assembly instead of the actual SP activities assembly.
See also
Set up an on-premises development environment for SharePoint Add-ins
What's new in workflows for SharePoint
Workflow development in SharePoint Designer and Visio
Workflows in SharePoint
Configure MSMQ for SharePoint workflows
3/26/2018 • 2 minutes to read Edit Online

Learn how to configure Microsoft Message Queuing (MSMQ) in SharePoint to support asynchronous event messaging in SharePoint workflows.

Enabling MSMQ
MSMQ is a Windows Server feature that you can enable on your SharePoint Server computer to allow asynchronous event messaging in SharePoint workflows. To support asynchronous
event messaging, you must enable MSMQ on your SharePoint Server computer.
MSMQ is provided as a "Feature" in Windows Server. To enable MSMQ, do the following:

Important: The screen shots included here are from Windows Server 2008 R2. The UI may change for enabling this feature in Windows Server 2012.

1. On your SharePoint Server computer, open Server Manager.


2. Select the Features icon in the left pane, then select Add Features, as depicted in Figure 1.
Figure 1. Adding the Message Queuing feature.

1. In the Add Features Wizard that appears, select Message Queuing. Accept the default selections and then click Next, then click Install.
2. You must now restart your computer.
3. Once restarted, open Server Manager and then open Message Queuing icon in the left pane. Notice that it now contains a Message Queuing folder and subdirectories, as
depicted in Figure 2.
NOTE

In Windows Server 2012 you will not find the queues in Server Manager. Instead, go to Computer Management, then select Services and applications.
4. Select the subdirectory named Private Queues. This is the directory in which your workflow event messages are stored.
Figure 2. The Message Queuing feature added to Server Manager.

NOTE

When you first add the Message Queuing feature, the Private Queues folder is empty. However, after a workflow runs that fires an event (or a workflow triggered by a SharePoint
content change event runs), the Private Queues folder is populated as shown in Figure 2.
5. To complete the installation, you must set the SPWorkflowServiceApplicationProxy.AllowQueue property to true using a Windows PowerShell script. In the SharePoint
Administration shell, run the following:

$proxy = Get-SPWorkflowServiceApplicationProxy
$proxy.AllowQueue = $true;
$proxy.Update();

Troubleshooting MSMQ
The Windows Developer Center provides extensive documentation of MSMQ. Following are some useful resources:
About Message Queuing
Message Queuing Reference
Message Queuing Error and Information Codes

See also
Message Queuing (MSMQ)
Workflow initiation and configuration properties
3/26/2018 • 2 minutes to read Edit Online

See an overview of the initiation and association properties that SharePoint sets on workflows.

When you launch a workflow, SharePoint automatically sets a number of association and initiation properties that support the workflow. These are listed below. The set of properties that are
set differs slightly depending whether it is a site workflows or a list workflow. These differences are identified in the lists.
Use the following guidelines to associate and launch (initiate) your workflows using the workflow object model:
To create an association for a list workflow, use the PublishSubscriptionForList method.
To create an association for a site workflow, use the PublishSubscription method.
To initiate a list workflow, use the StartWorkflowOnListItem method.
To initiate a site workflow, use the StartWorkflow method.
NOTE

The two methods for associating workflows are found on the WorkflowSubscriptionService class, while the two methods for launching workflows are found on the
WorkflowInstanceService class.

Association properties
The values of association properties are set when you call PublishSubscription . The association property values are association-level properties, meaning that all workflow instances with a
given association share the same property value. You can retrieve an association property value within the workflow itself by using the GetConfigurationValue activity.
Following is a list of association properties that are set by default for both list and site workflows when you call PublishSubscription .
AssociationTitle
AssociatorUserId
LayoutsFolder
ParentContentTypeId()
HistoryListId*
TaskListId*
FormData*
SharePointWorkflowContext.Subscription.EventSourceId*
SharePointWorkflowContext.Subscription.EventType*
SharePointWorkflowContext.Subscription.DisplayName*
SharePointWorkflowContext.Subscription.Id*
SharePointWorkflowContext.Subscription.Name*
SharePointWorkflowContext.Subscription.CreatedDate*

Important: Properties marked with an asterisk (*) are not defined in the Workflow APIs, so to access them simply use their string values.

In the case of list workflows, there are four additional association properties that are set by default when you call PublishSubscriptionForList(WorkflowSubscription, Guid) .
ListId
ListName
StatusColumnCreated*
StatusFieldName*
IM P O R T A N T

Properties marked with an asterisk (*) are not defined in the Workflow APIs, so to access them simply use their string values.
NOTE

You can add custom association properties by using an association form.

Initiation properties
Initiation properties are external variables whose values are set when the workflow is initiated - that is, when you call StartWorkflow. Note, however, that the property values can be updated
at runtime from within the workflow instance by using the ExternalVariableValue activity. You can retrieve the values of external variables from outside the workflow by using Properties .
External variable values are specific to each workflow instance (as opposed to association properties, where all workflow instances share the same property values).
All workflow instances (both list and site) have some external variables that are set by default when you call StartWorkflow:
InitiatorUserId
RetryCode
RelatedItems
List workflows instances have some additional external variables that are set by default when you call StartWorkflowOnListItem :
CurrentItemUrl
ItemId
ItemGuid
ContextListId
UniqueId
NOTE

You can add custom initiation properties by using an initiation form.

See also
Develop SharePoint workflows using Visual Studio
How to: Create SharePoint Workflows using Visual Studio
SharePoint workflow development best practices
3/26/2018 • 3 minutes to read Edit Online

Provides a collection of best practices for developers using Visual Studio to create workflows in SharePoint.

Workflow development best practices


To develop error-free workflows for SharePoint, it is best to follow some general guidelines, or "best practices." This is the case whether you are using SharePoint Designer 2013 or Visual
Studio 2012 for workflow development.
Apps for SharePoint that contain integrated workflows must edit a tag in the workflowmanifest.xml file
When you use the Log To History List action, more information is better
Write the value of every string and variable that you construct to the history list
Output a trace log before and after each step or important unit of work in the workflow
Verify that variables are non-null and contain expected values
Ensure that strings in workflow text fields do not exceed 255 characters
Use elevated permissions on a neutral account when using impersonation
In reusable workflows, use Association columns to ensure error-free list fields
Workflow design: Model a business process in a single workflow
Workflow design: Using the Approval action effectively

Apps for SharePoint that contain integrated workflows must edit a tag in the workflowmanifest.xml file
SharePoint Add-ins that contain integrated workflows (which can be associated with lists on the parent web) are differentiated from normal workflow apps by changing the following tag to
true in the workflowmanifest.xml file in the app package:

<SPIntegratedWorkflow xmlns="http://schemas.microsoft.com/sharepoint/2014/app/integratedworkflow">
<IntegratedApp>true</IntegratedApp>
</SPIntegratedWorkflow>

When you use the Log To History List action, more information is better
The Log To History List action (or LogToHistoryListActivity class if you are using Visual Studio) lets you record information about what a workflow has done at a given point in the
workflow's lifecycle. This makes it one of the most important troubleshooting tools you have. The more information you provide at important points in the workflow, the easier it is to
troubleshoot unexpected events.
For more information, see the following:
Workflow actions in SharePoint Designer 2010: A quick reference guide
LogToHistoryListActivity class
How to: Log to the History List from a Workflow Activity
Using the Log to History List SharePoint workflow action for debugging

Write the value of every string and variable that you construct to the history list
Debugging workflows that were created using SharePoint Designer is much easier if you write strings and variables to the history list by using the Log to History List action.
For more information, see the following:
Workflow actions in SharePoint Designer 2010: A quick reference guide
LogToHistoryListActivity class
How to: Log to the History List from a Workflow Activity
Using the Log to History List SharePoint workflow action for debugging

Output a trace log before and after each step or important unit of work in the workflow
To assist with debugging workflows, it is important that you capture meaningful information prior to and following each significant unit of work; this information should be committed to
trace logs. For more information, see the following:
Writing to the Trace Log
Using Event and Trace Logs in SharePoint

Verify that variables are non-null and contain expected values


Before using variables in your workflows, ensure there are no null variables. Also, ensure that variables contain expected values and are of the correct data type. For more information, see
Variables and Arguments.

Ensure that strings in workflow text fields do not exceed 255 characters
The maximum allowable length for strings in workflow text fields is 255 characters. If you set your text field to exceed this limit, its content will be truncated to 255 characters.

Use elevated permissions on a neutral account when using impersonation


When using impersonation steps in a workflow, you should author the workflow using a neutral account (that is, an account that is not tied to a specific user). This prevents your workflows
from breaking if the author's account becomes obsolete for any reason.
For more information, see Create a workflow with elevated permissions by using the SharePoint Workflow platform.

In reusable workflows, use Association columns to ensure error-free list fields


If you create a reusable workflow that relies on its list having a specific field, you may either (1) restrict the workflow to a content type that has the specified field, or (2) make the field an
association column. Option 2 is recommended because it's possible that a content type will change and cause the workflow to break.

Workflow design: Model a business process in a single workflow


Where possible, it is much better to model a business process in a single workflow than to break the workflow logic into several smaller workflows.

Workflow design: Using the Approval action effectively


Where possible, instead of creating multiple Approval actions, it is more effective to use the Stages feature within an Approval action.

See also
Workflows in SharePoint
SharePoint workflow fundamentals
Develop SharePoint workflows using Visual Studio
Debugging SharePoint workflows
3/26/2018 • 15 minutes to read Edit Online

Demonstrates how SharePoint now relies on Workflow Manager 1.0 for all workflow processing and management, and demonstrates debugging options. Provided by: Andrew Connell,
www.AndrewConnell.com
Microsoft has taken a different approach to workflows in SharePoint than in previous versions of SharePoint. The workflow team worked with the Azure team to create a new product called
Workflow Manager. Workflow Manager hosts the latest version of the Windows Workflow Foundation runtime and all the necessary services in an available and scalable way. It takes
advantage of the Microsoft Azure Service Bus for performance and scalability, and when deployed, it runs exactly the same in an on-premises deployment as in the cloud, similar to Office
365. SharePoint is then connected and configured to hand off all workflow execution and related tasks to the Workflow Manager farm.
This change in the architecture required some changes to the two primary workflow authoring tools (SharePoint Designer 2013 and Visual Studio 2012) customers used to create custom
workflows. However, the debugging techniques employed by developers in SharePoint 2007 and SharePoint 2010 still apply. The new architecture allows for a new option for workflows
created using either SharePoint Designer 2013 or Visual Studio 2012 in that Fiddler can be used to monitor traffic between SharePoint and Workflow Manager.

SharePoint workflow debugging overview


Debugging custom workflows created for SharePoint resembles previous versions, including SharePoint 2010 and SharePoint 2007. Some debugging options available will depend on the
tool that is used to create the workflow (SharePoint Designer 2013 or Visual Studio 2012) and the kind of SharePoint deployment, such as on-premises or Office 365 (hosted).
There are four workflow debugging techniques that can be leveraged by workflow authors:
Logging to the workflow history list
Setting breakpoints
Sending debug messages to the console
Monitoring traffic between SharePoint and Workflow Manager with Fiddler
Each option has advantages and disadvantages. It helps to have an understanding of what is possible when using the two workflow authoring tools (SharePoint Designer 2013 or Visual
Studio 2012), as well as the type of workflow deployment (on-premises or Office 365). The following table contains a matrix of authoring tools, deployment targets, and the options available
in each scenario.

S HAR EPO INT O N- PR EMIS ES O FFICE 3 6 5 S HAR EPO INT O NLINE

SharePoint Designer 2013, SharePoint Online Log to history list Log to history list
Fiddler

Visual Studio 2012 Log to history list Log to history list


Breakpoints Breakpoints
Console debug messages
Fiddler

Debugging with the workflow history list


The only debugging option that is available in every type of SharePoint deployment is writing log messages to the workflow history list. By using this method, you can use either the Log to
History List action in SharePoint Designer 2013 or the WriteToHistory activity in Visual Studio 2012 to write a string message as a new item to the list, specified in the workflow
association, which is the container for all history logging messages. These can be simple strings or constructed by concatenating the contents of variables within the workflow.
Using the history list as a debugging tool is not ideal because users can see the messages. Therefore, when the debugging session is complete and the workflow is used in production, the
workflow developer will want to remove these messages, creating an additional step between debugging and deployment. Nonetheless, this is the only option available in any scenario,
regardless of which tool is used to create the workflow or which type of SharePoint deployment.

Debugging using Visual Studio 2012 breakpoints


Another debugging option is to take advantage of breakpoints. Breakpoints are available only for workflows created using Visual Studio 2012, since SharePoint Designer 2013 has no
capability to set breakpoints or to attach a debugger to the running process. These are available in both SharePoint on-premises and hosted deployments such as Office 365. In this scenario,
you would set a breakpoint on an activity within the workflow and then start the workflow in debug mode.
Figure 1. Start the workflow

Visual Studio will deploy the workflow to the target SharePoint environment and attach a debugger. When the workflow process reaches the activity the breakpoint is set on, Visual Studio
regains focus and lets you examine the values of workflow variables and step through each activity from Visual Studio 2012, as shown in the following figure.
Figure 2. Workflow breakpoint
Debugging workflows using debug messages and the test service host
The introduction of Workflow Manager to the SharePoint workflow story introduces two new debugging opportunities available when you are creating custom workflows using Visual
Studio 2012 and testing them in an on-premises deployment. Visual Studio 2012 includes a WriteLine activity that accepts a single string-based message as an input.
Figure 3. WriteLine activity

This activity will write the message that resembles the System.Diagnostics.Debug.WriteLine() method in a standard .NET Windows Console Application. The Workflow Manager 1.0
development tool includes a console utility that is named the Test Service Host that Visual Studio 2012 will open when a new debugging session is started and when testing with an on-
premises SharePoint deployment. This console utility, Microsoft.Workflow.TestServiceHost.exe found in C:\Program Files (x86)\Workflow Manager Tools\1.0, attaches to the
registered Workflow Manager instance and listens for messages written using the WriteLine activity, as shown in the following figure.
Figure 4. Messages for WriteLine activity

These messages resemble code comments or debug messages in a console application. Unlike writing to the workflow history list, you don't need to remove these before deploying the
workflow to production. Unless the Test Service Host utility is connected to Workflow Manager, the messages are harmless.
This debugging option is not available for workflows created using SharePoint Designer 2013, because there is no action that maps to the WriteLine activity. Unfortunately, this debugging
option is available only to SharePoint on-premises installations, since the port used by the Test Service Host utility is typically not publically accessible outside an on-premises network. This
is also true for Office 365. The ports SharePoint uses to connect to Workflow Manager are the same ones used by the Test Service Host, and those are only accessible within the trusted
network. However, this does not mean that you need to change their workflows to remove any WriteLine activities before deployment to Office 365. These activities can be left in the
workflow as they are not seen unless the Test Service Host is connected to Workflow Manager.

Debugging using Fiddler to monitor HTTP traffic


The last debugging option for SharePoint workflows is a new addition for workflow developers due to the change in how workflows are handled in the current platform. Recall that in
SharePoint, all workflow processing is handed off to an external product, Workflow Manager 1.0. When a workflow has to communicate with SharePoint, such as updating the current state
of the workflow, collecting data from items or users in a SharePoint site, or when working with tasks, Workflow Manager's activities leverage the SharePoint REST API to perform these
operations. SharePoint communicates with Workflow Manager using a client library that serves as a proxy to REST services exposed by Workflow Manager. Both SharePoint and Workflow
Manager communicate with one another using the standard HTTP and HTTPS protocols.
This architecture yields a new debugging option for workflow authors. By using the HTTP debugging proxy tool Fiddler, you can monitor every request and corresponding response between
the two products. In addition, any custom services called by the custom workflows using the HttpSend activity in Visual Studio 2012 or corresponding Call HTTP Web Service action in
SharePoint Designer 2013 can also be monitored and inspected by Fiddler. This debugging model is also available, regardless of the tool that you use to create custom workflows
(SharePoint Designer 2013 or Visual Studio 2012).
The only time this option is not available is when you are testing workflows using an Office 365 deployment of SharePoint. Since all traffic between SharePoint and Workflow Manager
occurs server-side, it is not possible to connect to one of the servers in Office 365 and start Fiddler from the console.
This new option gives you transparency and insight into the workflow engine that was not possible when developing workflows in previous versions of SharePoint before SharePoint.
For example, you can see the raw responses coming back from Workflow Manager or SharePoint in a web service call. At times Workflow Manager may respond with a specific error
message. SharePoint includes user-friendly error messages but these may not be sufficiently specific. Using Fiddler, you can see the exact error message returned to help troubleshoot the
issue.
Another use case is examining the response from a successful web service call. When working with web services in workflows, regardless of the authoring tool, that you need to know the
exact property name (and path if it is a complex response) for a value that is contained in a response. By using Fiddler, you can see the complete response data.

Understanding SharePoint and Workflow Manager for debugging with Fiddler


To debug workflows in SharePoint and Workflow Manager 1.0 with Fiddler, some configuration and setup steps must be performed in a developer environment before debugging. Before
completing the steps, it helps to have an understanding of how Fiddler works and how workflows work in SharePoint.
Fiddler can only inspect traffic from the local server
The only traffic Fiddler can intercept and inspect are requests originating from the local server where Fiddler was started. This can present a challenge when Fiddler is used as a debugging
tool for SharePoint workflows.
If SharePoint and Workflow Manager 1.0 are installed on different servers and if Fiddler is started from SharePoint Server, the only traffic that Fiddler will display is the traffic where the
request originated from SharePoint. None of the traffic originating from Workflow Manager 1.0, even if it is targeted to the SharePoint Server, will be intercepted.
Therefore, when developing workflows, it is easier to debug them if both SharePoint and Workflow Manager 1.0 are installed on the same server. Note that this is not a requirement; you can
start Fiddler on both the SharePoint Server and Workflow Manager servers, although it is more complex to monitor two instances on two servers for the same workflow process.
Fiddler can only inspect traffic from the current logged-on user
Fiddler can only intercept and inspect traffic from the current logged-on user. To view traffic that originated from SharePoint, you must log on to SharePoint Server using the Windows
account that is configured as the identity of the application pool that hosts the web application for the SharePoint site initiating the workflow.
The same is true with Workflow Manager. To intercept and inspect traffic that originates from Workflow Manager, you must log on to the server using the Windows identity configured
during the provisioning of the Workflow Manager farm as the service account for Workflow Manager.
When using Fiddler to debug workflows, it is easier to debug them if not only both Workflow Manager and SharePoint are installed and configured on the same server, but they also use the
same Windows identity as the service account. All traffic from both Workflow Manager and SharePoint can then be intercepted and inspected by Fiddler.
SharePoint must trust Fiddler's certificate
Before using Fiddler for debugging SharePoint workflows, you need to understand how encrypted traffic is handled. Encrypted traffic over HTTP, known as HTTPS, is implemented by using
a certificate's private key to encrypt some data and then send it to another recipient. The recipient has the certificate's public key that is paired with the private key. When a request is received
by the recipient, the recipient can validate that the request came from the sender because the encrypted content's signature matches the public key, which can only be true if it was encrypted
with the certificate's private key.
Fiddler can intercept HTTPS traffic and be configured to decrypt it so it is in a human-readable format for inspection in the tool. After displaying the request, Fiddler then uses its own
certificate to re-encrypt the traffic and send it to the intended recipient. This can cause an issue, though, because now the recipient received the original response but it is not secured using
the certificate from the original sender. This can be an issue when debugging SharePoint workflows because Fiddler's certificate is not trusted by SharePoint. Therefore, in order to use
Fiddler to intercept and inspect HTTPS traffic between SharePoint and Workflow Manager, the Fiddler certificate must be trusted by SharePoint.

Configure SharePoint and Workflow Manager 1.0 for workflow debugging with Fiddler
The following sections explain how to configure Fiddler and SharePoint for workflow debugging.
Configure the .NET Framework default proxy configuration
The first step is to first define the default proxy configuration for .NET Framework. These changes will allow Fiddler to intercept the traffic coming from both SharePoint and the Workflow
Manager. Open the machine.config file in both of the following locations:
%systemdrive%\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\Config\\machine.config

%systemdrive%\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\Config\\machine.config

Next, add the following markup to the bottom of each file, just before the closing element:

<system.net>
<defaultProxy enabled="true">
<proxy bypassonlocal="false" usesystemdefault="true" />
</defaultProxy>
</system.net>

Save the changes and close the files.


Configure Fiddler to intercept and inspect HTTPS traffic
The next step is to configure Fiddler to intercept encrypted traffic and decrypt it for configuration.
1. Start Fiddler.
2. If you are using the local HOSTS file, ensure that the entries are included in Fiddler by selecting the Tools -> HOSTS menu option.
3. Check the Enable remapping of requests for one host to a different host or IP, overriding DNS,
4. Click the Import Windows Hosts File, and then click the Save button.
Figure 5. Host Remapping

Next, configure Fiddler's connection options.


1. Select the Tools -> Fiddler Options menu option.
2. Click the Connections tab.
3. Clear the Chain to upstream gateway proxy selection.
4. Select the Act as system proxy on startup and Monitor all connections options, as shown in the following figure.
Figure 6. Fiddler connection options.
1. Select the HTTPS tab in the Fiddler Options dialog.
2. Check the Capture HTTPS CONNECTs.
3. Select Decrypt HTTPS Traffic.
4. Select ??? from all processes.
5. Check Ignore server certificate errors.
6. Click the Export Root Certificate to Desktop button.
7. When prompted with a warning, click Yes to Trust the Fiddler Root certificate.
This process will configure Windows to trust the certificate, although SharePoint does not trust it yet.
Figure 7. HTTPS tab

NOTE

If a security WRning appears with a message instructing not to trust the Fiddler certificate, click Yes to continue installing the certificate.
Configure SharePoint to trust the certificate
The last step is to configure SharePoint to trust the Fiddler certificate that was exported in the previous step.
1. Log on as a SharePoint farm administrator.
2. Start the SharePoint Management Shell.
3. Load the SharePoint Snap-In.

PS C:\\> Add-PSSnapIn Microsoft.SharePoint.PowerShell

1. Use the certificate utility to install the Fiddler certificate.

PS C:\\> $fidderCertificatePath = [full path to exported FiddlerRoot.cer certificate file]


PS C:\\> certutil.exe -addstore -enterprise -f -v root $fidderCertificatePath
PS C:\\> $fiddlerCertificate = Get-PfxCertificate -FilePath $fidderCertificatePath
PS C:\\> New-SPTrustedRootAuthority -Name "Fiddler" -Certificate $fiddlerCertificate

1. Run IISRESET to make sure that SharePoint picks up the certificate trust change.

Walkthrough: Debugging a SharePoint workflow with Fiddler


This simple walkthrough demonstrates using Fiddler to debug a SharePoint workflow authored using Visual Studio 2012. When the workflow starts, it retrieves a customer ID from a field in
a custom list. This customer ID is used to query a publically accessible service to retrieve additional details about the customer. It then uses these values to update the original list item. The
workflow can be found in the following MSDN code sample: SharePoint Workflow: Call an External Web Service.
This walkthrough has the following prerequisites:
SharePoint and Workflow Manager 1.0 are installed on the same server.
The Windows identity CONTOSO\SP_Content is configured for the application pool identity that hosts the web application serving the SharePoint site that starts the workflow.
The SharePoint site used to start the workflow is http://intranet.contoso.com
The Workflow Manager 1.0 farm endpoint is w15sp.contoso.com.
SharePoint and Workflow Manager 1.0 are configured to allow OAuth over HTTP.

Caution: This should never be done on the production server, but only for testing and debugging.

1. Log on to the server where Workflow Manager and SharePoint are installed with the Windows identity configured as the Workflow Manager 1.0 farm account and SharePoint
application pool identity.
2. Start Fiddler. While Fiddler will now intercept traffic from the current user, if there are any existing connections or processes running, Fiddler may miss those as it was not running
when the connections were initially established. To force both Workflow Manager and SharePoint Server to recycle and have their traffic to each other get intercepted by Fiddler,
recycle SharePoint by running an IISRESET and recycle Workflow Manager by stopping and starting the Windows service Workflow Manager Backend. This can be done with the
following two commands at an administrative command prompt.

PS C:\\> IISRESET
PS C:\\> net stop WorkflowServiceBackend
PS C:\\> net start WorkflowServiceBackend

1. Start the workflow.


In the figure below, notice that sessions #18-36 originated from SharePoint and sessions #37-43 originated from Workflow Manager.
Figure 8. Starting the workflow

Notice that in session #36, SharePoint is requesting that Workflow Manager start a workflow (indicated as [A] in the figure) and Workflow Manager responds (indicated as [B] in the figure)
with a "Success" message:
Figure 9. "Success" message response

Session #40 is where Workflow Manager is retrieving the list item ID and GUID from SharePoint.
Figure 10. Retrieving item ID and GUID

Session #43 is where Workflow Manager is updating the list item in SharePoint with a new value for the announcement item's Body field by passing a JavaScript Object Notation (JSON)
object (indicated as [A] in the figure) along as the payload. SharePoint responds with an HTTP status of 204, which indicates that it successfully processed the request, but there is no
message in the response.
Figure 11. Updating the list item
Conclusion
The workflow story in the SharePoint release introduced a new layer of abstraction, Workflow Manager 1.0. This new architecture changed how workflows are processed. SharePoint now
relies on Workflow Manager 1.0 for all workflow processing and management.
One task you need to perform when creating custom applications and business processes in workflows is debugging your work. The new workflow architecture of SharePoint offers the
same debugging options that existed in previous versions of SharePoint. However, the new architecture offers two new options when creating custom workflows using the new architecture.
This article explained the legacy debugging options as well as the new options using the WriteLine activity and using Fiddler for intercepting and inspecting traffic between SharePoint and
Workflow Manager 1.0.

See also
Fiddler
Using the pairing cmdlet Register-SPWorkflowService
3/26/2018 • 2 minutes to read Edit Online

Learn how to use the cmdlet Register-SPWorkflowService to successfully pair SharePoint with Workflow Manager. Installing and configuring Microsoft SharePoint to support workflow
development requires "pairing" your installations of SharePoint and Workflow Manager. In most scenarios, this pairing is easily done by using the cmdlet Register-SPWorkflowService,
which is included with your SharePoint installation.
Importantly, this cmdlet is not useful for every pairing scenario. Register-SPWorkflowService is useful only in the following pairing scenarios:
One-computer server farm where SharePoint and Workflow Manager are co-located on the server box.
Three-computer server farm where SharePoint and Workflow Manager are co-located on all three computers. (Add a fourth computer is search needs to be on a separate computer
and Workflow Manager HA is required. If the latter is required, it must be installed on all three machines.
Three-computer SharePoint farm paired with a non-co-located Workflow Manager server farm.
Also note that Register-SPWorkflowService uses the credentials of the current user.

Cmdlet design
D E TAIL D ES CR IPTIO N

Verb Register

Noun SPWorkflowService

Description Pairs a sps15short farm with a Workflow Manager farm. You must run this cmdlet once per farm. Before
running the cmdlet, you must install root CA certificate in machine certificate store and SharePoint
certificate store. To do this, use the cmdlet New-SPTrustedRootAuthority. (See instructions below.)

Output type None.

Syntax Register-SPWorkflowService -SPSite <URI or GUID representing an SPSite object> -


WorkflowHostUri <workflow service endpoint URL> -ScopeName <string> [-PartitionMode] [-
AllowOAuthHttp] [-Force]

Cmdlet parameters
PAR AME TER T YPE D ES CR IPTIO N

SPSite (Required) SPSitePipeBind The URL of a long-lasting site collection on the SharePoint Server
farm that serves as the pairing endpoint. Information for pairing is
deduced from this URL.

WorkflowHostUri (Required) String The URL of the Workflow Manager endpoint for the pairing.
Provides the workflow host URI along with port number.

ScopeName String The name to be used by the workflow service to identify the paired
SharePoint Server farm. The default value is "SharePoint". You only
need to specify this parameter if trying to pair multiple SharePoint
farms to a Workflow Manager farm.

PartitionMode SwitchParameter Use this parameter only for multi-tenant SharePoint farm. The
partition mode is specified per SharePoint service. Note that you can
create multi-tenancy in a SharePoint farm after this cmdlet runs;
therefore, the cmdlet cannot deduce this parameter value implicitly
from the existing state of the SharePoint farm.

AllowOAuthHttp SwitchParameter Enables OAuth and metadata exchange over HTTP. This is useful in
testing, but not in production mode. Use this only when SharePoint
is configured to support HTTP. It is not necessary that the Workflow
Manager be configured to use HTTP.

Force SwitchParameter Enforces the creating of scope using ScopeName parameter, or


updates an existing scope corresponding to the same ScopeName
If not specified and scope with the same name exists, the cmdlet will
throw an error.

Example
PS> Register-SPWorkflowService -SPSite "https://myserver/mysitecollection" -WorkflowHostUri "http://workflow.example.com:12291" -ScopeName "SharePoint2" -PartitionMode -AllowOAuthHttp -Force

See also
Install and configure workflow for SharePoint
Video series: Install and configure Workflow in SharePoint
Workflow Manager 1.0
SharePoint workflow samples
5/12/2018 • 2 minutes to read Edit Online

Provides sample workflows to help illustrate how to create and implement SharePoint workflows in the new Workflow Manager Client 1.0 framework.

Workflow samples for SharePoint


This series of sample workflows was developed to demonstrate the large range of workflow capabilities in SharePoint. They were developed using Visual Studio 2012 and are available in the
MSDN Samples Gallery. Links to the individual samples are provided.

SharePoint workflow: Call an external web service


This sample uses Visual Studio to demonstrate creating a workflow that calls an external web service using the HttpGet activity. In calling the web service, the workflow also uses the new
DynamicValue data type.
The sample, along with a readme file, is available here: SharePoint workflow: Call an external web service

SharePoint workflow: Create a custom action


This sample uses Visual Studio to demonstrate creating a workflow that calls an external web service. In calling the web service, the workflow also uses the new DynamicValue data type.
The part of the workflow that calls the web service and extracts the details from the response is contained within a custom activity, GetNWCustomerDetailsWorkflow.
The sample, along with a readme file, is available here: SharePoint workflow: Create a custom action

SharePoint workflow: Sales tax calculator


In this end-to-end sample, the workflow uses a web service to obtain the appropriate tax rate based on a purchaser's location, and then uses the base price to calculate the sales tax and total
price.
The sample, along with a readme file, is available here: SharePoint workflow: Sales tax calculator

SharePoint workflow: Use a task action in SharePoint Designer


An extended walkthrough of the process of implementing task actions in a workflow created using Microsoft SharePoint Designer 2013.
The sample, along with a readme file, is available here: SharePoint workflow: Using a task action in SharePoint Designer

SharePoint workflow: Workflow OM in a SharePoint app


The SharePoint workflow: Workflow OM in a SharePoint app code sample is an example of an interactive SharePoint-hosted app that uses the SharePoint workflow JSOM to deploy
workflow definitions to both an app web and to a "parent web" (that is, a SharePoint web that is hosting the app).
You can locate the sample code here: SharePoint workflow: Workflow OM in a SharePoint app.

See also
Get started with workflows in SharePoint
Set up and configure SharePoint Workflow Manager
What's new in workflows for SharePoint
Workflow actions and activities reference for SharePoint
SharePoint Add-ins
Develop SharePoint workflows using Visual Studio
5/11/2018 • 8 minutes to read Edit Online

SharePoint supports two primary workflow development environments for authoring workflows: SharePoint Designer and Visual Studio. This article summarizes both and discusses the
advantages and disadvantages of each.

Authoring basics for SharePoint workflows


NOTE

For guidance on setting up and configuring Microsoft SharePoint and the Workflow Manager Client 1.0 server, see Set up and configure SharePoint Workflow Manager.
As with previous versions, Microsoft SharePoint provides two primary workflow development environments for authoring workflows: Microsoft SharePoint Designer and Microsoft Visual
Studio. However, what differs from previous versions is that using Visual Studio no longer provides a code-based authoring strategy. Instead, both SharePoint Designer and Visual Studio
provide a fully declarative, no-code authoring environment regardless of the development tool you select.
NOTE

As a complement to authoring workflows in SharePoint Designer, you can also use Microsoft Visio 2013 to structure your workflow logic by using Visio 2013 shapes, and then import your
logic into SharePoint Designer 2013. For information about using Visio 2013 to author your workflow logic, see Workflow development in SharePoint Designer and Visio.

Declarative workflows
Let's first be clear what is meant by "declarative" workflows. This term means that instead of being authored in code and then compiled into managed assemblies, the workflow is described
(literally) in XAML and then executed interpretively at run time.
The XAML is derived (or inferred) from the workflow building blocks that you manipulate in the Workflow Designer (if using Visual Studio) or SharePoint Designer workflow design surface
(or Visio, but more about that later). The building blocks themselves are the visual workflow design objects in the designer toolbox—stages, conditions, actions, events, and so on. The set of
tools in the respective toolboxes (Visual Studio or SharePoint Designer) differs somewhat, but the concept of the declarative workflow remains the same.

Decision tree: SharePoint Designer vs. Visual Studio


Among the greatest advantages of the workflow framework in SharePoint is the ease with which information workers can use the no-code environment of SharePoint Designer to create rich
and powerful workflows. Additionally, a high degree of flexibility and customization is available in a declarative authoring environment such as Visual Studio.
Both of these workflow authoring environments—SharePoint Designer and Visual Studio—offer specific advantages and disadvantages. In this section, we explore how to determine which
authoring environment best suits your workflow development needs.

Using SharePoint Designer


Target users: Information workers, business analysts, SharePoint developers.
Difficulty level: Familiarity with SharePoint Designer, including the core workflow components, such as stages, gates, actions, conditions, and loops.
With SharePoint Designer, users can create a workflow that is attached to a list, library, or site using a no-code, text-based designer. Or, they can use the new visual design environment in
which graphical elements are arranged on a design surface to represent the logical flow of a business process. SharePoint Designer excels at enabling rapid workflow development by non-
technical workers.

Using Visual Studio


Target users: Intermediate or advanced software developers.
Difficulty level: Familiarity with Visual Studio, including software development concepts such as event receivers, packaging and deployment, and security.
Authoring workflows in Visual Studio provides flexibility to create workflows to support virtually any business process, regardless of its complexity, and allows debugging and reuse of
workflow definitions. Perhaps most important, Visual Studio lets developers include SharePoint workflows as part of a broader SharePoint solution or SharePoint Add-in.
Visual Studio enables developers to create custom actions for consumption by SharePoint Designer, and provides the means to execute custom logic. With Visual Studio, developers can also
create workflow templates, which can be deployed to multiple sites.

Comparing SharePoint Designer with Visual Studio


The following table provides a side-by-side comparison of the features and requirements for using SharePoint Designer and Visual Studio to create SharePoint workflows.
Table 1. Workflow authoring tool comparison

FE ATU R E / R EQ U IR EMENT S HAR EPO INT D ES IG NER V IS U AL S TU D IO

Allows rapid workflow development Yes Yes

Enables reuse of workflows A workflow can be used only by the list or library on which it was A workflow can be written as a template so that after it is deployed,
developed. However, SharePoint Designer provides reusable it can be reused and associated with any list or library.
workflows that can be used multiple times within the same site.

Allows you to include a workflow as part of a SharePoint solution or No Yes


SharePoint Add-in

Allows you to create custom actions No. However, SharePoint Designer can consume and implement Yes. However, be aware that in Visual Studio, the underlying
custom actions that are created and deployed by using Visual activities, not their corresponding actions, are used.
Studio.

Allows you to write custom code No No


Note: This is changed from previous versions. In SharePoint,
workflows are declarative only and Visual Studio relies on the visual
design surface for workflow development.

Can use Visio Professional to create workflow logic Yes No


FE ATU R E / R EQ U IR EMENT S HAR EPO INT D ES IG NER V IS U AL S TU D IO

Deployment Deployed automatically to list, library, or site on which they were Create a SharePoint solution package (.wsp) file and deploy the
created. solution package to the site (SPWeb).

One-click publishing available for workflows Yes Yes

Workflows can be packaged and deployed to a remote server Yes Yes

Debugging Cannot be debugged. Workflow can be debugged by using Visual Studio.

Can use only actions that are approved by site administrator Yes Yes
Note: This is changed from previous versions. Previously, workflows
and actions that were authored by using Visual Studio were code-
based and deployed at the farm scope, so administrator approval
was not required.

Developing workflows using Visual Studio


Unlike earlier versions, workflows in SharePoint are entirely declarative. Built now on Windows Workflow Foundation 4, Visual Studio provides a visual workflow designer surface that lets
you create custom workflows, workflow templates, forms, and custom workflow activities entirely in the designer environment. Your workflow is then packaged and deployed as a SharePoint
Feature. For information about Feature packaging, see Using Features in SharePoint Foundation.
Perhaps the most significant change for Visual Studio developers is that custom workflows are no longer compiled and deployed as .NET Framework assemblies. Furthermore, SharePoint
no longer uses Microsoft InfoPath forms; instead, forms generation relies on Microsoft ASP.NET forms.
Finally, the Visual Studio workflow project templates have changed. Whereas formerly templates for state machine and sequential workflows were provided, these distinctions are no longer
meaningful. Rather, Visual Studio project templates are available in the Visual Studio build provided on your virtual machine (VM).

Enabling on-premises workflow debugging


To debug on-premises workflows in Visual Studio, you need to temporarily allow the Workflow Manager Tools to access your system through the firewall.
1. In Control Panel, choose System and Security, Windows Firewall.
2. In the Control Panel Home list, choose the Advanced Settings link.
3. In the left pane of Windows Firewall, choose Inbound Rules.
4. In the Inbound Rules list, choose Workflow Manager Tools 1.0 for Visual Studio 2012 - Test Service Host.
5. In the Actions list, choose Enable Rule.
6. On the properties page of your SharePoint project, choose the SharePoint tab, and then select the Enable Workflow debugging check box.

Debugging SharePoint Online workflows using Visual Studio


To debug SharePoint Online workflows in Visual Studio, perform the following steps:
1. If you're behind a firewall, you may need to install a proxy client (such as the Forefront Threat Management Gateway (TMG) Client), depending on your company's network topology.
2. Register for a Microsoft Azure account if you haven't already, and then sign into that account.
For information about how to register for a Microsoft Azure account, see Microsoft Azure.
3. Create a Microsoft Azure Service Bus namespace, which you can use to debug remote workflows. You can do this on the Microsoft Azure portal.
For more information about the Microsoft Azure Service Bus, see Managing Service Bus Service Namespaces.
NOTE

SharePoint Online workflow debugging uses the Relay Service component of the Microsoft Azure Service Bus, so you'll be charged for using the Service Bus. See Service Bus Pricing
FAQ. You get free access to Microsoft Azure each month that you subscribe to Visual Studio Professional with MSDN, Visual Studio Premium with MSDN, or Visual Studio Ultimate
with MSDN. With this access, you can use the Service Bus relay for 1,500, 3,000, or 3,000 hours, depending on your MSDN subscription. See Get some amount of Microsoft Azure
Services each month at no additional charge.
4. In Microsoft Azure, choose your service namespace, choose the Access Key link, and then copy the text in the Connection String box.
5. On the properties page of your SharePoint Add-in project, choose the SharePoint tab, and then select the Enable Workflow debugging check box.
You must enable this feature to debug workflows in SharePoint Online. This property applies to all of your SharePoint projects in Visual Studio. Visual Studio automatically turns off
workflow debugging if you package your app for distribution on the Office store.
6. Select the Enable debugging via Microsoft Azure Service Bus check box. Then, in the Microsoft Azure Service Bus connection string box, paste the connection string that you
copied.
After you enable workflow debugging and provide a valid connection string for the Microsoft Azure Service Bus, you can debug SharePoint Online workflows.
NOTE

If you haven't disabled workflow debugging and don't want to receive a notification whenever your project contains a workflow, clear the Notify me if Microsoft Azure Service Bus
debugging is not configured check box.

See also
A great deal of developing SharePoint workflows remains unchanged for the Visual Studio developer. The key sections of the documentation for SharePoint 2010 remain relevant:
For information about using the Visual StudioWorkflow Designer, see Visual Studio Designer for Windows Workflow Foundation Overview.
For information about creating forms by using Microsoft ASP.NET, see Workflow Forms Overview.
For information about Feature packaging, see Using Features in SharePoint Foundation.
Create a SharePoint workflow app using Visual Studio 2012
5/10/2018 • 12 minutes to read Edit Online

Walk through the process of creating a workflow SharePoint Add-in using Microsoft Visual Studio 2012.

Prerequisites
This development scenario presumes that a SharePoint farm and a Workflow Manager 1.0 farm are installed and paired. These two farms can be located on the same or on separate server
computers. The scenario further presumes that workflow development is taking place remotely - that is, on a computer separate from either of the server computers - and is using Microsoft
Visual Studio 2012 or later.
On the server platforms:
Windows Server 2008 R2.
Microsoft SharePoint
Workflow Manager 1.0
On the development platform:
Microsoft Visual Studio 2012 or later.
Office Developer Tools for Visual Studio 2013.
NOTE

Office Developer Tools for Visual Studio 2013 is only required when using Visual Studio 2012. Later versions of Visual Studio include the Office Developer Tools. For assistance
setting up and configuring your SharePoint workflow development environment, see the following:
Prepare to set up and configure a SharePoint workflow development environment
Configure workflow in SharePoint
Video series: Install and configure Workflow in SharePoint

Get started
A common workflow scenario in business settings is the document review and approval process. In this walkthrough, we create an SharePoint Add-in that automates the routing,
notifications, and approval (or rejection) of a document using a SharePoint workflow. We create this workflow using the SharePoint workflow designer in Microsoft Visual Studio 2012.
Here's a flowchart that depicts the course of the workflow we're going to create.
Figure 1. Flowchart depicting the document approval workflow.

In summary, the workflow does the following:


1. A document change event associated with a specific document library launches the workflow instance.
2. If the document's status is set to "Ready For Review," the workflow assigns a task to a prearranged reviewer, then sends the reviewer an email notification about the task.
3. If the reviewer fails to approve the document, the document file remains in the Draft Documents library; however, the document status is set to "Rejected."
4. If the reviewer approves the document, the workflow copies the document into a Published Documents library. The original file remains in the Draft Documents library, but its status is
set to "Published."

Important: Before you start this walkthrough, ensure that you have a properly installed and configured workflow development environment. For more information, see Prepare to set
up and configure a SharePoint workflow development environment. Also, ensure that you have a SharePoint instance that you can develop your workflow against. For more information,
see Install SharePoint.

Prepare your environment


The first step is preparing our SharePoint site with document libraries that our workflow will use.
1. Launch Visual Studio 2012 and create a new project using the App for SharePoint template, as depicted in Figure 2.
NOTE

In this walkthrough, the solution file is named "DocApprovalWorkflow1". It is recommended that you use the same name. However, if you name your solution differently, be sure that
you make necessary adjustments in the instructions that follow.
Figure 2. Create new project in Visual Studio 2012

1. On your associated SharePoint site, create two new document libraries by doing the following:
In Solution Explorer, right-click on the "DocApprovalWorkflow1" icon and select Add > New Item and then select List.
In the resulting SharePoint Customization Wizard, enter "Draft Documents" in the name field; then select "Document Library" in the drop-down under the first radio button, as
depicted in Figure 3.
Click Next, then take default settings, and then click Finish.
Figure 3. SharePoint customization wizard for List settings.

1. Create the second document library using the same steps as above, except name this second library "Published Documents".
2. Add two custom columns to both of the new document libraries that you just created:
Create a custom column named "Approver" and make it a Person or Group list column type.
Create a custom column named "Document Status" and make it a Choice list column type (see Figure 4).
1. On the Document Status column, add five choices by expanding the Type property in the property grid, then clicking the ellipsis button ( …) on the Items property. Enter the choice
values in the dialog box that appears, as shown in Figure 4.
Draft in Progress
Ready for Review
Approved for Publishing
Rejected
Published
Create the basic workflow
Now we're ready to create the workflow itself.
1. In Visual Studio, create a new workflow by right-clicking on the DocApprovalWorkflow1 icon (in Solution Explorer) and selecting Add > New Item, and then selecting Workflow
(see Figure 5).
Figure 5. Add New Item > Workflow wizard.

1. When prompted, name the workflow "DocumentApprovalWorkflow" and select List Workflow as the workflow type (see Figure 6).
Figure 6. Specify workflow name and type.

1. In the SharePoint Customization Wizard, associate the new workflow with the Draft Document library; then, opt to create a new history list and a new workflow task list, as shown
in Figure 7. Then click Next.
Figure 7. Completing the SharePoint Customization Wizard for the new workflow.
1. Set the workflow to start automatically when an item in the Draft Documents library is changed. You can also leave the check box for manually starting the workflow selected; this
allows you to easily test the workflow without needing to change a document. See Figure 8.
Figure 8. Set the activation parameters for the workflow.

> [!NOTE]
> You can change the workflow association type after the workflow has been created by using the property grid with the workflow selected in **Solution Explorer** (see Figure 9). Then click **Fini

Figure 9. The workflow property grid.

1. Finally, configure your SharePoint Server to manage outgoing email using the SMTP service. For instructions, see Configure outgoing email for a SharePoint farm. This is necessary to
allow the workflow to send email notifications related to workflow tasks.

Implement the workflow logic


Now that we have our SharePoint Server set up and our basic workflow created, we can now design the workflow logic.
1. Open the workflow designer by double-clicking on the workflow project item in Solution Explorer. You will see the workflow designer surface (and the workflow toolbox); the
designer is populated with an initial workflow stage named Sequence.
2. Our first step is to grab the LookupSPListItem activity from the toolbox (see Figure 10) and drop it in the Sequence stage on the designer surface. We use this activity to get the
status of the document at any given time, which the LookupSPListItem activity returns as a DynamicValue object that contains a set of SharePoint list item properties as key-value
pairs.
Figure 10. LookupSPListItem activity selector.
1. To configure the LookupSPListItem activity, first click on it in the designer to select it. This activates the property grid for the activity.
2. Use the combo boxes in the property grid to configure the LookupSPListItem activity to use "current item" for ItemId and "current list" as ListId, as shown in Figure 11.
Figure 11. Configuring LookupSPListItem properties.

1. On the LookupSPListItem activity tile, click the Get Properties link. This completes two important steps for you:
2. First, it creates a variable of type DynamicValue and binds it to the out-argument (named Result) of the of the LookupSPListItem activity. Properties of the list item are stored in this
variable.
3. Second, it adds a new activity named GetDynamicValueProperties (see Figure 12) and sets the newly created DynamicValue variable as the in-argument of this new activity. This
activity lets you extract the list item properties from the DynamicValue variable.
4. On the GetDynamicValueProperties activity, click on Define… to open a dialog box that lets you pick the properties you wish to extract. In selecting properties, refer to Figure 12,
which shows a portion of the designer surface merged with the open Properties dialog box.
Figure 12. Selecting the DynamicValue properties that you wish to extract.

1. For Entity Type, select List Item of Draft Documents.


2. In the data grid, in the Path column, click Create Property to open a combo box that contains available properties for list items in the Draft Documents library. Select Document
Status from the combo box.
3. On the next row in the data grid, click Create Property again; this time, select Approver from the combo box.
4. Now click the Populate Variables link on the dialog box. This creates a variable of the appropriate data type for each row and assigns it in the Assign To column of the data grid, as
shown in Figure 13.
Figure 13. Get Document Status and Approver properties.

1. We now have the list item values that we need. Next step is to set up the workflow to check whether the document is "ready for review" and to take the appropriate action when it is.
2. From the toolbox, drag the If activity onto the workflow designer surface. (You'll find the If activity in the Control Flow section of the toolbox.)
3. Set the If condition to DocumentStatus.Equals("Ready for Review") , as shown in Figure 14.
Figure 14. Creating an If/Then clause to trigger a task.

1. Next, from the SP - Task section of the toolbox, drag a SingleTask activity and drop it in the Then box of your If activity. In effect, you have configured the workflow such that If the
document is ready for review, Then it will then complete this task.
2. Our next step is to configure the task that we just created using the configuration dialog box, shown in Figure 15.
Figure 15. Task configuration dialog box.

1. First, we assign the task to an approver. To do this, click the Configure link in the SingleTask activity tile.
2. Set the Assigned to: field to "Approver".
3. Notice that the Task title: field is automatically populated with "Workflow task".
4. In the Body: field, enter a simple message with instructions for the approver, such as "Please review this document for approval to publish."
5. Click OK to save.
Notice that at this point you have a validation error on the **SingleTask** activity. With the **SingleTask** tile selected, look at the **AssignedTo** property in the property grid and note that

To correct this error, cast the variable to a **String** data type by appending ".ToString()" to "Approver" in the **AssignedTo** row on the property grid, as shown in Figure 16.

Figure 16. Casting the "Approver" variable to string data type in the property grid.

At the present point in this walkthrough you have created and configured a workflow task that does two things: It sets a document to be reviewed, but also sends an email to the task assignee (the

1. Let's look at the property grid for the SingleTask activity. Scroll to the bottom of the property grid and note in the Output section there are two properties, Outcome and
TaskItemId, which are out-arguments.
Note the name of the Outcome variable: outcome_0 (or similar). We use this variable to check the outcome of the task - that is, whether the approver has approved or rejected the
document.
NOTE

The Outcome out-argument returns an Int32 value corresponding to the index of the outcome - that is, 0 for "Approved" and 1 for "Rejected". These integers are the default values
provided in the out-of-the-box SharePoint site column named "Task Outcome."
2. Now, in order for the workflow to check the outcome of the task, we need to add another If activity and place it following the SingleTask activity, but inside the Then area, as shown
in Figure 17. Setting the If condition to " outcome_0 == 0 " tells us whether the document was approved.
Figure 17. Adding the IF activity to check the task status.

1. If the approver has set the task to "Approved," we update the document status to "Approved for Publishing," then copy the document file to the Published Documents library.
Alternatively, if the approver has rejected the document, we need to set the document status to "Rejected."
2. In this new If activity, drag an UpdateListItem activity into the Then box.
3. Configure the UpdateListItem activity in its property grid such that ItemId is set to "(current item)" and ListId is set to "(current list)", as shown in Figure 18.
4. Next, with the UpdateListItem activity selected, click the ellipsis button ( …) adjacent to the ListItemPropertiesDynamicValue field in the property grid. This action opens a dialog
box that allows you to specify which list item properties you want to update.
Figure 18. Setting the list item properties to update.
1. In the dialog box, first use the combo box to set Entity Type to List Item of Draft Documents (shown in Figure 18). Then, in the data grid, click Create Property and from the drop-
down list select "Document Status." Then, under the Value column, type "Approved for Publication" (including quotation marks) and click OK.
2. In the Then area of the current If activity, drag a CopyItem activity and place it directly below the UpdateListItem activity, as shown in Figure 19.
Figure 19. Adding a CopyItem activity to the workflow.

Then, configure properties of the **CopyItem** activity in the property grid as depicted in Figure 20. Property values are highlighted.

Figure 20. Configuring the CopyItem activity.

> [!NOTE]
> For the purpose of this walkthrough we are going to assume that all of our published documents come out of the Draft Documents library; therefore, we do not need to worry about controlling for

1. Finally, we need to add an activity to handle the case where the reviewer rejects the document. We do this by adding an UpdateListItem activity to the Else area of our current If
activity. Configure this UpdateListItem activity just as you did the prior one in step 9(c), except that now we want to set the document status to "Rejected," as shown in Figure 21.
Figure 21. Configuring properties of UpdateListItem activity for rejected documents.
This completes "Creating a SharePoint document approval workflow." The completed workflow is shown in Figure 22.
Figure 22. Completed SharePoint document approval workflow.

Package and deploy the workflow


Following are resources that provide guidance for packaging and deploying your workflow as an SharePoint Add-in:
Deploying and installing apps for SharePoint: methods and options
Publish apps for SharePoint
How to: Create and Deploy Declarative Workflows in Sandboxed Solutions (Using SharePoint Designer 2013)

Caution: SharePoint Add-ins that contain integrated workflows (which can be associated with lists on the parent web) are differentiated from normal workflow apps by changing the
following tag to true in the workflowmanifest.xml file in the app package:

<SPIntegratedWorkflow xmlns="http://schemas.microsoft.com/sharepoint/2014/app/integratedworkflow">
<IntegratedApp>true</IntegratedApp>
</SPIntegratedWorkflow>

See also
Workflows in SharePoint
Prepare to set up and configure a SharePoint workflow development environment
SharePoint workflow development best practices
Develop SharePoint workflows using Visual Studio
Create SharePoint workflows using Visual Studio
3/26/2018 • 13 minutes to read Edit Online

Learn the basics of creating a SharePoint workflow in the new SharePoint workflow platform.
Provided by: Andrew Connell, AndrewConnell.com
NOTE

This article is accompanied by an end-to-end code sample that you can use to follow the article, or as a starter for your own SharePoint workflow projects. You can find the downloadable
code here: LINK.
Microsoft has taken a very different approach to workflows in SharePoint than in previous versions. SharePoint workflows are now based on Windows Workflow Foundation 4, and their
execution is driven by a new component called Workflow Manager, which runs externally to SharePoint.Workflow Manager serves the role as host for the Windows Workflow Foundation
runtime and all the necessary services in a highly available and scalable way. It leverages Service Bus for performance and scalability, and when deployed it runs exactly the same in an on-
premises deployment as when deployed to a cloud-based service, such as Office 365, because it is configured to hand off all workflow execution and related tasks to the Workflow Manager
farm.The dramatic change in the workflow architecture required some changes to the two primary workflow authoring tools for creating custom workflows - Visual Studio and SharePoint
Designer. This article will explore using Visual Studio 2012 as your workflow authoring tool to create custom workflows for use in sp15allshort deployments - either on-premises or Office
365 deployments

Types of workflows in Visual Studio 2012


While SharePoint Designer 2013 can only create workflows comprised of stages, Visual Studio supports another powerful type of workflow: the state machine workflow. Effectively, then, the
Visual Studio 2012 (and Visual Studio 2013) workflow development environments support three types of workflow authoring: sequential, flowchart, and state machine.

Sequential
A sequential workflow is one that follows a specific path. There may be decision branches, loops, and the workflow may not have a termination point, but it is easy to follow the predictable
path in the design process. In fact, is how all workflows start out when you are using the Workflow project template in Visual Studio.
A sequential workflow contains a single Sequence activity and then any number of activities within it. Some of these could be other Sequence activities that you use to group together a
series of smaller steps.

Flowchart
In flowchart workflow, the execution pathway can transition to different sections of the workflow according to conditions that you specify, as shown in the Figure 1. The flowchart activity,
along with the associated FlowDescision and FlowSwitch activity, are typically placed within a Sequence activity and act like either a traditional if statement, or like switch statement in
common programming languages.
The stage construct within a SharePoint Designer 2013 based workflow is based on the principles of a flowchart. These types of workflows, unlike a sequential workflow, do not have a
prescribed path in which they follow. Rather the things that happen during the workflow dictate the path the workflow follows.
Figure 1. Flowchart workflow in Visual Studio 2012

NOTE

You can find the workflow depicted in Figure 1 as a workflow sample on MSDN here: SharePoint: Approval workflow that uses a custom initiation form.

State machine
State machine workflows, like flowchart workflows, do not typically follow a specific path of execution. Rather, they consist of two or more states as shown in Figure 2.
Figure 2. State machine workflow in Visual Studio 2012
NOTE

You can find the workflow depicted in Figure 1 as a workflow sample on MSDN here: SharePoint: Route workflows to states depending on actions and events.
Think of each state as a smaller workflow that contains multiple workflow activities. You can set specific activities to start when the workflow enters or exits a given state. What really makes
state machines interesting is the transitions that you can define. Each state can have one or more transitions that tell the workflow engine how to move from one state to another state.
The workflow is always going to be in one of the states in a state machine workflow. A transition will dictate the trigger for the workflow to move from one state to another. Many people
favor state machine workflows over the other types of workflows because they can be made to more closely mirror real world business processes. However these types of workflows can get
complicated quickly.

Visual Studio 2012 workflow development interface


When adding a new workflow to a SharePoint project, the template adds a single Sequence activity which serves as the main container. If you want to create a flowchart or state machine
workflow simply delete this default activity and drag either a StateMachine or Flowchart activity onto the design surface.
Before building a custom workflow, developers should have a good understanding on the tool windows and design surface that Visual Studio 2012 provides. Many of the elements are quite
common, as shown in Figure 3:
Figure 3. Visual Studio 2012 workflow authoring interface

The workflow development interface - that is, the workflow designer - has the following key elements:
1. Solution Explorer displays your project as a file tree.
2. Workflow toolbox contains all of the activities that you can use to assemble a workflow. You drag and drop from the toolbox to the designer surface.
3. Workflow designer surface is where you assemble and link the workflow elements.
4. Property grid displays properties of a selected activity or item in Solution Explorer. Use this to set or change property values.
5. Output pane displays information about workflow activity elements - variables, arguments, and import.
6. Breadcrumb navigation tabs allows you to zoom in and out on various portions of a workflow under development.
The Output pane (#5 in Figure 3) is important because it allows you to see all of the variables in your workflow at the current scope. Scoping works the same way as it does in standard
programming object oriented design: a variable scoped at the root is accessible to all lower scopes (such as methods within a class), but a variable within a lower scope (such as a method in a
class) is only accessible within that scope and its children, but not parallel or parent scopes.
Click on the Arguments tab to see a list of the arguments that are used to pass values into the workflow, such as those passed from an initiation form.

How to create a custom workflow


To create a custom workflow using Visual Studio 2012 or later, ensure that you have access to a SharePoint developer site. For this walkthrough, it is recommended that you use a local
SharePoint installation. This is because workflows tested locally can write debugging information to the Test Service Host console utility using the WriteLine activity. This utility is included
with the Office Developer Tools for Visual Studio 2013, which are part of the default installation of Visual Studio 2012 and later in the Professional, Premium, and Ultimate editions.

Create a new app project


1. In Visual Studio, create a new SharePoint Add-ins project and configure it to be a SharePoint-hosted app.
2. In this project, add a new Announcement list instance. We use this list as a container for items that we are going to use to test the workflow.
3. Add a workflow item to the project by right-clicking the project icon in Solution Explorer and selecting Add, then New Item.
4. In the Add New Item dialog box, select the Workflow project item from the Office/SharePoint category and name it "My First Workflow". Click Next.
5. When prompted by the SharePoint Customization Wizard for a name, leave the default, then set it to be a List Workflow. Click Next.
6. On the next page of the wizard, check the box to create an association, then select the Announcements list that we just created; select for the required workflow history and task lists
and then click Next.
7. On the final page of the wizard, check the box to start the workflow manually, leaving the two automatic start options unchecked; then click Finish. Visual Studio automatically adds
the required elements to the project and loads the Workflow.xaml file into the designer, as shown in Figure 4.
Figure 4. Default designer surface after adding the workflow item

Organize workflow steps


To automate a given business process, workflows can contain any number of activities that you group together into a step, or Sequence. However, if you group too many of these activities in
a single Sequence, the workflow becomes cluttered and difficult to follow and debug. This is similar to how in a common programming language it is ill-advised to create extremely long
and complex methods. Instead, you should group activities that work together to perform a specific task in a common sequence.
This workflow sample will illustrate this practice of segmenting your workflows. In your new project, on the designer surface, to the existing default Sequence activity, add two new Sequence
activities and rename them "Child Sequence 1" and Child Sequence 2", as depicted in Figure 5. Also (though not shown in Figure 5), change the name of the original Sequence activity to
"Root".
Figure 5. Adding child sequences to the default, or root, sequence

Comment your workflow using annotations


When using a common programming language like C#, VB.NET, or C++, you can comment your code by using appropriate comment specifiers. Commenting code is important for testing
and maintaining a code base. Well, Visual Studio allows you also comment your workflow development by providing a feature called annotations.
You can comment a given workflow activity by selecting the activity, the selecting Annotations, then Add Annotation. A small icon of inverted chevrons on the right side of the activity's
title bar signals that it has an annotation. Hover over or click on the icon to see the message (shown in Figure 6). You have the option to pin the annotation to the activity so it is always
visible, as shown in Figure 6.
Figure 6. Annotation on an activity

Obtain values from list items


A common task you will encounter when creating workflows is getting properties of a list item. To accomplish this task, use the LookupSPListItem activity. What this activity does is make a
web service call using the SharePoint REST API to lookup information on the list item. The following procedure shows how to do this:
First, drag a LookupSPListItem activity from the toolbox and drop it in the Child Sequence 1 activity.
After adding the activity to the designer, you have to set a couple of properties: ListId and ItemId. These properties can be set to lookup information in any list, but using the shortcuts for
current list and current item tell Workflow Manager to figure these values out automatically.
Because we are making a web service call, the return value from this activity, reflected in the Result property, is of type DynamicValue. Therefore, we need a variable of that data type in
which to store the output output of the web service call. This is actually pretty easy to do because clicking the Get Properties link in the LookupSPListItem activity much of this
automatically:
First, it creates a new variable of type DynamicValue.
Next, it sets this new variable to be the source for the Result property on the LookupSPListItem activity.
It then adds a GetDynamicValueProperties activity to the workflow so that we can retrieve the value from the variable.
Finally, it binds the variable to the Source property on the GetDynamicValueProperties activity.
Of course, you could have done all of this manually, but the tools simplify the process. If necessary, you can change the names of the variables.
The point, of course, is to get some values from the list item that triggered the workflow: Now the Assigned To column is where the values of these properties are bound to variables
previously created or use the Populate Variables link that will create the variables automatically.
1. On the Properties property on the GetDynamicValueProperties activity, click on the ellipses button [ ???] to open the Properties dialog box, shown in Figure 7.
Figure 7. Extract values using the Properties dialog box

1. Next change the Entity Type to match the type of the item; in this case it is the List Item of Announcements list item.
2. Select the two properties to retrieve: the Title and Created By fields.
3. The Assign To column is where you bind these properties to the variables that we created. Alternatively, you can use the Populate Variables link, which assigns the variables
automatically.
Notice in Figure 7 how the tool created the variables and even matched the data types correctly. Also notice how the Created By field is an integer. It is not really useful to show the user a
number for the author is it? This will be addressed later in the workflow.

Get user properties


Another common task in custom workflow development is looking up users. For instance, our workflow currently knows who created the announcement item, but only knows them by their
ID. This ID is the ID of the user that has been added to the site's User Information List, which is a cached copy of their profile information. What is really desired is their name or login
name.
To get user information, do the following:
1. Rename our first sequence ( Child Sequence 1) to "Get Item Properties" and name the second sequence to "Get Author Properties".
NOTE

Make certain the variable that contains the user ID is scoped to the whole workflow and not just to the sequence we were working on. Let's change the scope of the variable now, as
shown in Figure 8.
Figure 8. Changing the scope of variables

1. Now, to get the user information, drag-and-drop a LookupSpUser activity in the workflow and rename it to "Get Announcement Author". This activity will call the SharePoint REST
API and pass in a specific ID. Verify what the REST service looks like by using the browser and navigating to http://../_api/web/SiteUsers . Take notice of the properties returned, too,
as we will need these in a moment.
2. Notice that each user has a specific URL that includes their ID to get the user information. Also notice that the activity is likely calling the GetUserById service operator and passing in
the ID of the user to lookup. Pass this in by specifying the PrincipalId property of the LookupSPUser activity to be the CreatedBy variable, which is the integer of the author of the
announcement item.
3. Just like the LookupSPListItem activity, the LookupSPUser activity returns a value of type DynamicValue, so create a variable of that type to associate with our response and then
bind this variable to the Result properties of the LookupSPUser activity, as shown in Figure 9.
Figure 9. Updating the output of the LookupSPUser activity

1. As we did earlier, use a GetDynamicValueProperties activity to pull the results out of the AuthorProperties value. However, notice this time around that the Entity Type does not
have an option that we can set. This is not a problem, because the actual web service response the LookupSPUser can be seen in the browser. To see it, enter the path to the property
you are looking for, which, in this case is d/results/(0)/LoginName ; then, enter another to get the display name of the author, as shown in Figure 10.
Figure 10. Retrieving values from the LookupSPUser activity

Test the workflow


Finally, let's test the workflow. Start by adding two WriteLine activities. These allow us to show the contents of our two variables. When testing the workflow, the Test Service Host console
utility will write out the two values as shown in Figure 11.
Figure 11. Test using Test Service Host Console

Conclusion
This article first explained the different types of workflows that can be created using Visual Studio 2012 and later for SharePoint when it has been connected to a Workflow Manager farm.
Next it demonstrated how to create a workflow that not only collected values from the list item that triggered the workflow, but it also demonstrated how to perform a common task such as
obtaining a user's login name and display name using the LookupSPUser activity. In addition, the article touched on a few good practices for keeping workflows organized and adding
comments using annotations.

See also
Workflows in SharePoint
SharePoint workflow development best practices
SharePoint workflow samples
Working with the SharePoint Workflow Services Client Side Object Model
3/26/2018 • 18 minutes to read Edit Online

Demonstrates how to use the SharePoint client-side object model (CSOM) API to create and control Workflow Manager 1.0 workflow definitions and instances. Provided by: Andrew
Connell, AndrewConnell.com

Working with the SharePoint Workflow Services Client Side Object Model
The implementation of workflows in SharePoint 2007 and SharePoint 2010 remained largely the same from version to version. Microsoft did add some new functionality in SharePoint
2010, such as the ability to associate workflows with sites, and improved the workflow authoring tools, SharePoint Designer 2010 and Visual Studio 2010, from their predecessors. However,
the implementation of workflow tasks, workflow forms, and the workflow server-side APIs remains largely unchanged.
In SharePoint 2010, Microsoft introduced features and capabilities that encouraged customers to move their customizations into sandboxed solution. These would run in an isolated process
and were friendly to both types of SharePoint deployments: on-premises, where the SharePoint was installed on company servers and maintained by the company , and to the cloud, or more
specifically, Office 365.
In SharePoint, Microsoft added even more capabilities; these updates were oriented toward cloud deployments. Specifically, Microsoft introduced the new SharePoint app model, which went
further than the sandboxed solution in that, unlike sandboxed solution, they explicitly blocked server-side code from running in the SharePoint process. Microsoft also built up existing
technologies in SharePoint, such as the client-side object model (CSOM), and introduced new capabilities, like support for app identities using OAuth.
And then, with the introduction of SharePoint, Microsoft introduced an entirely new workflow architecture and platform that reflect fundamental shifts in the product direction.
The most prominent change in the new architecture is that workflow execution in SharePoint no longer takes place in SharePoint. Instead, SharePoint uses a completely new execution
engine: Workflow Manager 1.0. Workflow Manager hosts the Windows Workflow Foundation runtime and all the necessary services required by Windows Workflow Foundation. When a
workflow is published, or a new instance of a published workflow is started, SharePoint notifies Workflow Manager, which in turn processes the workflow episodes. When the workflow
access information in SharePoint, such as list item properties or user properties, it authenticates using the OAuth support and communicates over new and improved REST APIs.
These changes in the workflow architecture had significant impacts in certain areas, such as custom workflow forms, as discussed in the MSDN article How to: Create Custom SharePoint
Workflow Forms with Visual Studio 2012. This article touches on one of the things that Microsoft added to SharePoint to support the new style of creating custom workflow forms: the
improvements to the CSOM and addition of the Workflow Services CSOM API.

Introduction to the Workflow Services CSOM API in SharePoint


In SharePoint 2007 and SharePoint 2010, the workflow API was manifested only in the server-side object model. In SharePoint, this same workflow API is still present, since SharePoint
includes the old workflow execution engine in SharePoint for backward compatibility.
However, the new and preferred workflow architecture introduced with SharePoint that uses Workflow Manager includes a brand new server-side API. In SharePoint, Microsoft extended the
CSOM to include a robust API for the new workflow architecture. Note that this addition to the CSOM only applies to the new SharePoint and Workflow Manager 1.0 workflow architecture,
not the legacy version that is still hosted by SharePoint.
The Workflow Services CSOM API, like the rest of the CSOM, is implemented both in a .NET Silverlight managed API and a JavaScript API known as the JavaScript Object Model (JSOM).
JSOM is what developers must use when creating custom workflow forms as those forms will be ASP.NET web forms that must not have any server-side code. Thus the Workflow Services
JSOM API is used in custom association forms to create workflow associations as well as on initiation forms to start new workflow instances.
However, the possibilities do not stop there. The Workflow Services CSOM and JSOM is very robust and enables developers to do almost anything with workflows in SharePoint. Aside
from creating workflow associations and instances, developers can also programmatically deploy new workflow definitions and even communicate with running workflow instances from the
CSOM and JSOM, as is discussed in the remainder of this article.
This article focuses on the topic of workflow forms in the context of SharePoint Sever 2013. It is based on the SharePoint with the March 2013 Public Update applied and Office Developer
Tools for Visual Studio 2013. Everything in this article applies to both SharePoint on-premises deployments as well as Office 365.

Workflow Services CSOM and JSOM API components


This article focuses on the Workflow Services CSOM API and thus, by extension, the JSOM API as well; the server side Workflow Services API is not discussed here. The Workflow Services
CSOM consists of several different services that are used to perform different tasks. Each of these is discussed in the following sections.
NOTE

There is one additional service that is not present in the CSOM, but is present instead with the server-side API. This is the Messaging Service, which is used to manage message queuing and
message transport.
To work with the Workflow Services CSOM and JSOM APIs, developers must add the necessary references to their projects (in the case of CSOM) and pages (in the case of JSOM). Both
implementations have the same requirements:
Reference the core SharePoint CSOM and JSOM libraries:
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Runtime.dll
Microsoft.SharePoint.Client.WorkflowServices.dll
Reference the Workflow Services CSOM and JSOM libraries:
SP.js
SP.Runtime.js
SP.WorkflowServices.js

Workflow Service Manager


The gateway to all services included in the Workflow Services CSOM API is the Workflow Service Manager. This object is what developers use to obtain instances to all the other services
described in the following sections. Similar to other CSOM API implementations, the WorkflowServicesManager has a dependency on the core SharePoint CSOM and, therefore, you must
pass in a valid client context and reference to the SharePoint site you want to connect to, as shown in the following CSOM and JSOM code examples.
CSOM: Creating a WorkflowServicesManager instance
var clientContext = new ClientContext(siteCollectionUrl);
var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web);

JSOM: Creating a WorkflowServicesManager instance

var clientContext = SP.ClientContext.get_current();


var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web());

Deployment service
When you create custom workflows using Visual Studio 2012, either using a solution package (.wsp) or as a SharePoint app (.app), you are creating workflow definitions. A definition is the
workflow process and all business rules and attributes defined within it, such as the location of custom association and initiation forms. On their own, these definitions are not very useful
because they cannot be run outside the context of an association with a site, list, or document library. The workflow definitions published and available in a site can be found by going to the
page where a new workflow association can be created, as shown in the following figure.
Figure 1. Add a workflow association

The collection of published workflow definitions is accessible through the deployment service. This service enables you to get a list of all currently saved and published definitions on the site,
as well as to publish both saved and new definitions, remove existing definitions, and determine what workflow actions are available to SharePoint Designer 2013-authored workflows.
The WorkflowDeploymentService object is available through the WorkflowServicesManager class, as shown in the following code examples.
CSOM: Obtaining a WorkflowDeploymentService instance

var clientContext = new ClientContext(siteCollectionUrl);


var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web);
var workflowDeploymentService = workflowServicesManager.GetWorkflowDeploymentService();

JSOM: Obtaining a WorkflowDeploymentService instance

var clientContext = SP.ClientContext.get_current();


var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web());
var workflowDeploymentService = workflowServicesManager.getWorkflowDeploymentService();

Subscription service
Recall from the previous section that you create workflows and publish them to SharePoint as definitions. To use these definitions, a user must create an association that links the definition to
a specific SharePoint site, list, or document library along with additional metadata. This process basically works and behaves the same way in SharePoint 2010 but the implementation in
SharePoint is very different. Workflow Manager 1.0 takes advantage of an instance of Microsoft Azure Service Bus 1.0.
Service Bus is instrumental because it supports the publication and subscription service (also known as PubSub). This is an asynchronous messaging framework that supports a publisher
sending a message to a topic stored in Service Bus. Any number of subscribers can request to be notified when a message is published to that topic that meets specific criteria.
SharePoint and Workflow Manager 1.0 use the PubSub model to create associations. Workflow associations are created as subscriptions on topics. For instance, an association for workflow
definition may be created on list and set to start automatically when items are added to the list. When an item is added to the list, SharePoint publishes an event to Workflow Manager 1.0,
which it sends to the Service Bus topic. The message is evaluated and the registered subscriptions are notified of the event. The subscribed association is found and the workflow is started.
For more information about how this process works, see the MSDN article, SharePoint workflow fundamentals.
This should clarify, then, why workflow associations are now called subscriptions within the API (that is, under the covers). You can use a Subscription Service in the Workflow Services
CSOM to explore existing associations and subscriptions, create and delete associations and subscriptions, and request to be notified of events.
The WorkflowSubscriptionService object is available through the WorkflowServicesManager class, as shown in the following code examples.
CSOM: Obtaining a WorkflowSubscriptionService instance

var clientContext = new ClientContext(siteCollectionUrl);


var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web);
var workflowSubscriptionService = workflowServicesManager.GetWorkflowSubscriptionService();

JSOM: Obtaining a WorkflowSubscriptionService instance

var clientContext = SP.ClientContext.get_current();


var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web());
var workflowSubscriptionService = workflowServicesManager.getWorkflowSubscriptionService();
Instance service
The final service that we'll cover is the instance service. You can use this service to perform several tasks with workflow instances, such as starting, suspending, resuming, terminating, and
cancelling workflow instances. You can also use it to collect debug information, as well as enumerate through all currently running workflows, as well as those that have already completed.
Finally, you can use this service to publish events to workflows that are currently running, as we'll see later in this article.
The WorkflowInstanceService object is available through the WorkflowServicesManager class, as shown in the following code examples.
CSOM: Obtaining a WorkflowInstanceService instance

var clientContext = new ClientContext(siteCollectionUrl);


var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web);
var workflowInstanceService = workflowServicesManager.GetWorkflowInstanceService();

JSOM: Obtaining a WorkflowInstanceService instance

var clientContext = SP.ClientContext.get_current();


var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web());
var workflowInstanceService = workflowServicesManager.getWorkflowInstanceService();

Interop service
In previous versions of SharePoint, specifically SharePoint 2007 and SharePoint 2010, SharePoint hosted the Windows Workflow Foundation runtime. As previously explained, Microsoft
moved away from this approach in SharePoint by introducing a dependency on Workflow Manager 1.0, which hosts the workflow runtime outside of SharePoint. Consequently, workflows
are no longer executed and managed within SharePoint; instead, SharePoint hands off workflow management and execution responsibilities to Workflow Manager 1.0.
However, to provide backward compatibility, Microsoft retained the legacy model of hosting pre-SharePoint-style workflows within SharePoint by keeping the Windows Workflow
Foundation runtime engine. Therefore, all workflows created in SharePoint 2010 will still run as expected in a SharePoint environment. In addition, Microsoft included a new activity,
InvokeSharePointWorkflow, which can be used in a SharePoint workflow to start an existing workflow in the SharePoint 2010 workflow host that is included in SharePoint. This allows
you to take advantage of existing workflow investments migrated from previous versions.
NOTE

The InvokeSharePointWorkflow activity is a wrapper for the CSOM method, StartWorkflow .


The SharePoint Workflow Services CSOM also includes a special service that enables developers to interact with these legacy workflows. The InteropService lets you start and stop
workflows, as well as enable and disable event notifications for running workflows.
The WorkflowDeploymentService object is available through the WorkflowServicesManager class, as shown in the following CSOM and JSOM code examples.
CSOM: Obtaining an InteropService instance

var clientContext = new ClientContext(siteCollectionUrl);


var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web);
var workflowInteropService = workflowServicesManager.GetWorkflowInteropService();

JSOM: Obtaining an InteropService instance

var clientContext = SP.ClientContext.get_current();


var workflowServicesManager = SP.WorkflowServices.WorkflowServicesManager.newObject(context, context.get_web());
var workflowInteropService = serviceManager.getWorkflowInteropService();

Example: Workflow Services CSOM scenarios


The following sections demonstrate how to use the different services in the Workflow Services CSOM to perform common tasks in custom solutions.

Get all workflows installed


Most of the other services in the Workflow Services CSOM require that you get references to the workflow definition that was previously published. Workflow definitions are usually
referenced by their IDs, which are GUIDs.
To get a list of all the published workflow definitions, first get an instance of the deployment service by using the GetWorkflowDeploymentService method. Then, retrieve the collection of all
workflow definitions by using the EnumerateDefinitions(Boolean) method. Here is example code:

// connect to the workflow services via a CSOM client context


var clientContext = new ClientContext(siteCollectionUrl);
var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web);

// connect to the deployment service


var workflowDeploymentService = workflowServicesManager.GetWorkflowDeploymentService();

// get all installed workflows


var publishedWorkflowDefinitions = workflowDeploymentService.EnumerateDefinitions(true);
clientContext.Load(publishedWorkflowDefinitions);
clientContext.ExecuteQuery();

// display list of all installed workflows


foreach (var workflowDefinition in publishedWorkflowDefinitions) {
Console.WriteLine("{0} - {1}", workflowDefinition.Id.ToString(), workflowDefinition.DisplayName);
}

Get all associations and subscriptions


To start a new workflow instance, you need to first get a reference to an existing workflow association. Building on the previous code example, the following example demonstrates how to
get a list of all workflow associations for a specific workflow definition in a site.
Once you have obtained a workflow definition using the example above, use the GetWorkflowSubscriptionService method to create an instance of the subscription service. Next, use the
EnumerateSubscriptionsByDefinition method (passing in the ID of a workflow definition) to get a list of all the associations that exist for the specified workflow. Note that there are several
methods available for getting workflow associations, including the following:
EnumerateSubscriptions
EnumerateSubscriptionsByDefinition
EnumerateSubscriptionsByEventSource
EnumerateSubscriptionsByList
The following code example demonstrates getting associations and subscriptions.

// connect to the workflow services via a CSOM client context


var clientContext = new ClientContext(siteCollectionUrl);
var workflowServicesManager = new WorkflowServicesManager(clientContext, clientContext.Web);

// connect to the deployment service


var workflowDeploymentService = workflowServicesManager.GetWorkflowDeploymentService();

// get all installed workflows


var publishedWorkflowDefinitions = workflowDeploymentService.EnumerateDefinitions(true);
clientContext.Load(publishedWorkflowDefinitions);
clientContext.ExecuteQuery();

// find the first workflow definition


var firstWorkflowDefinition = publishedWorkflowDefinitions.First();

// connect to the subscription service


var workflowSubscriptionService = workflowServicesManager.GetWorkflowSubscriptionService();

// get all workflow associations


var workflowAssociations = workflowSubscriptionService.EnumerateSubscriptionsByDefinition(firstWorkflowDefinition.Id);
clientContext.Load(workflowAssociations);
clientContext.ExecuteQuery();

foreach (var association in workflowAssociations) {


Console.WriteLine("{0} - {1}",
association.Id, association.Name);
}

Creating a workflow association


Creating a new workflow association, which can also be referred to as a subscription, requires additional effort before actually publishing the association to SharePoint. This is because each
subscription needs to have additional information, which is usually collected on the association page. This metadata includes the following:
The ID of the workflow definition the association is based on.
The ID of the SharePoint site, list or document library the workflow association is created on.
The display name of the association.
The startup options (whether started manually or automatically when a list item is added or updated).
The ID of the list that will store all history list messages for this association.
The ID of the list that will store all tasks for this association.
Optionally, a collection of any name/value pairs that should be sent to the workflow. These are the fields that are usually passed in from a custom association form.

Creating a custom workflow association


1. To create a custom association, first use the GetWorkflowSubscriptionService method to get a reference to the subscription service.

// connect to the deployment service


var workflowDeploymentService = workflowServicesManager.GetWorkflowDeploymentService();

// get all installed workflows


var publishedWorkflowDefinitions = workflowDeploymentService.EnumerateDefinitions(true);
clientContext.Load(publishedWorkflowDefinitions);
clientContext.ExecuteQuery();

// find the first workflow definition


var firstWorkflowDefinition = publishedWorkflowDefinitions.First();

// connect to the subscription service


var workflowSubscriptionService = workflowServicesManager.GetWorkflowSubscriptionService();

1. Create a new object instance of the WorkflowSubscription class.


2. Set the required properties on the WorkflowSubscription object, as illustrated in the following code example. In the example, code comments explain each of the property settings.
Note that some properties that are not relevant to CSOM workflow services have been left out for readability. These properties have been omitted:
3. listId. The ID of the list on which the association is created.
4. historyListId. The ID of the list that stores all history list messages for the association.
5. taskListId. The ID of the list that will store all tasks for the association.
6. Once created, the subscription must be published to SharePoint using the PublishSubscriptionForList method, as demonstrated in the following code example:
// create a new association / subscription
WorkflowSubscription newSubscription = new WorkflowSubscription(clientContext) {
DefinitionId = firstWorkflowDefinition.Id,
Enabled = true,
Name = "New Workflow Association"
};

var startupOptions = new List<string>();


// automatic start
startupOptions.Add("ItemAdded");
startupOptions.Add("ItemUpdated");
// manual start
startupOptions.Add("WorkflowStart");

// set the workflow start settings


newSubscription.EventTypes = startupOptions;

// set the associated task and history lists


newSubscription.SetProperty("HistoryListId", workflowHistoryListId.ToString());
newSubscription.SetProperty("TaskListId", workflowTaskListId.ToString());

// OPTIONAL: add any association form values


newSubscription.SetProperty("Prop1","Value1");
newSubscription.SetProperty("Prop2","Value2");

// create the association


workflowSubscriptionService.PublishSubscriptionForList(newSubscription, listId);
clientContext.ExecuteQuery();

Get all workflow instances


You can also use the Workflow Services instance service to view all workflow instances that are running on a SharePoint site, list, or document library. The instance object that is returned
contains information on the instance, such as when it was last updated, the current status, and any errors that may have occurred when it ran previously. Additionally, it provides a collection
of name/value pairs that were submitted to the workflow from the custom initiation form.
To do this, start by using the GetWorkflowInstanceService method to get a reference to the instance service. Note that the WorkflowInstanceService provides several methods for obtaining
the collection of running workflow instances:
Enumerate . Accepts a workflow association (that is, a subscription) as a parameter, and can be used to get all the instances that have been created based on the specified association.
EnumerateInstancesForSite : Gets a list of all workflow instances that have been started on the SharePoint site that was set when creating the original WorkflowServiceManager
object.
EnumerateInstancesForListItem . Accepts a list ID and item ID; use this method to get all workflow instances that have been created on a specific list item.
Each of theses methods also has an alternate **WithOffset()* method (for example, EnumerateWithOffset ). These alternative methods allow you to get a subset of the workflow instances in
cases where working with the entire collection would be cumbersome. To get a count of the number of workflow instances, use the CountInstances method, or the CountInstancesWithStatus
method.
The following code example illustrates getting workflow instances:

// connect to the instance service


var workflowInstanceService = workflowServicesManager.GetWorkflowInstanceService();

// get all instances


var workflowInstances = workflowInstanceService.EnumerateInstancesForListItem(listId, listItemId);
foreach (var instance in workflowInstances)
{
Console.WriteLine("{0} - {1} - {2}",
instance.Id.ToString(),
instance.LastUpdated,
instance.Status.ToString());
}

Start a workflow instance


Starting a new instance of a workflow association involves repeating many of the steps that have been demonstrated in the previous examples. To start a workflow on an item in a list or
document library, first obtain a reference to the workflow association and the ID of the item in the list. A collection of name/value pairs of information can be sent to the workflow when it is
started. This happens when there is a custom initiation form that is used to collect data from the user starting the workflow. Then pass in a collection, even if it is an empty collection, when
starting the workflow or the workflow will fail to start and return an error.
Building from previous examples, use the GetWorkflowInstanceService method to get an instance of the workflow instance service. Next, start the workflow by calling one of two methods.
One starts workflows on a site, while the other starts a workflow on a list item.
StartWorkflow . Starts a workflow on the SharePoint site that was set when creating the original WorkflowServicesManager object. When using this method, you must pass in the
workflow association and any additional startup properties present on the initiation form.
StartWorkflowOnListItem . Starts a workflow on a specific list item. Using this method requires you to pass in the ID of the desired list item, in addition to other parameter values
required by the StartWorkflow method.
The following code example demonstrates how to start a workflow instance.
// connect to the deployment service
var workflowDeploymentService = workflowServicesManager.GetWorkflowDeploymentService();

// get all installed workflows


var publishedWorkflowDefinitions = workflowDeploymentService.EnumerateDefinitions(true);
clientContext.Load(publishedWorkflowDefinitions);
clientContext.ExecuteQuery();

// find the first workflow definition


var firstWorkflowDefinition = publishedWorkflowDefinitions.First();

// connect to the subscription service


var workflowSubscriptionService = workflowServicesManager.GetWorkflowSubscriptionService();

// get all workflow associations


var workflowAssociations = workflowSubscriptionService.EnumerateSubscriptionsByDefinition(firstWorkflowDefinition.Id);
clientContext.Load(workflowAssociations);
clientContext.ExecuteQuery();

// find the first association


var firstWorkflowAssociation = workflowAssociations.First();

// connect to the instance service


var workflowInstanceService = workflowServicesManager.GetWorkflowInstanceService();

// start the workflow


var startParameters = new Dictionary<string, object>();
workflowInstanceService.StartWorkflowOnListItem(firstWorkflowAssociation, listItemId, startParameters);
clientContext.ExecuteQuery();

Publishing messages and events to running workflows


Another powerful feature that was added in SharePoint is the ability to publish custom events to running workflow instances. These workflows can have an activity, WaitForCustomEvent,
which listens for a specific event to be published to the workflow. The event can also contain a string as part of the message, which the activity can store as a variable.
To publish an event from the client using the Workflow Service CSOM, first get a reference to the specific workflow instance that the event should be published to. Then, using the instance
service, publish the event using the PublishCustomEvent method. When using this method, you must pass in the desired instance, event name, and an optional payload, as shown in the
following code example.

// connect to the instance service


var workflowInstanceService = workflowServicesManager.GetWorkflowInstanceService();

// get all instances


var workflowInstances = workflowInstanceService.EnumerateInstancesForListItem(listId, listItemId);

var targetInstance = workflowInstances.First();

// publish custom event


instanceService.PublishCustomEvent(targetInstance, "AdHocMaintenanceRequest", "Flat Tire");
clientContext.ExecuteQuery();

To receive the message in the workflow, add a WaitForCustomEvent activity and, using the Properties window, set the EventName property to the name of the event the activity is
listening for (in the example above, this would be the string, "AdHocMaintenanceRequest"). Then, set the Result property to the variable in which the event's payload is stored, as shown in
Figure 2.
Figure 2. Input EventName and output Result

This technique of publishing a custom event is demonstrated in the MSDN Code Sample: SharePoint: Route Workflows to States Depending on Actions and Events.

Conclusion
Microsoft introduced workflows into the SharePoint 2007 platform, and the workflow platform remained largely unchanged in SharePoint 2010. This was also true when it came to Custom
Forms in SharePoint workflows. SharePoint, on the other hand, introduced many changes to workflow platform and architecture.
One of the major improvements to workflows in SharePoint is the expansion of CSOM to include a complete Workflow Services API. This addition enables developers to interact with
workflow definitions, associations, and subscriptions, and to create and interact with instances of these workflows.

See also
Workflows in SharePoint
What is Workflow Manager 1.0?
Working with Web Services in SharePoint Workflows using Visual Studio 2012
3/26/2018 • 14 minutes to read Edit Online

Demonstrates how to use web services in SharePoint workflows using Visual Studio 2012. Provided by: Andrew Connell, AndrewConnell.com
NOTE

This article is accompanied by an end-to-end code sample that you can use to follow the article, or as a starter for your own SharePoint workflow projects. You can find the downloadable
code in the MSDN Code Gallery, here: Working with Web Services in SharePoint Workflows using Visual Studio 2012.
Microsoft has taken a very different approach to workflow in SharePoint than in previous versions of SharePoint. The workflow team worked with the Azure team to create a new product
called Workflow Manager. Workflow Manager serves the role of hosting the latest version of the Windows Workflow Foundation (version 4) runtime and all the necessary services in a
highly available and scalable way. It takes advantage of Microsoft Azure Service Bus for performance and scalability, and when deployed, it runs the same whether in an on-premises
deployment or a deployment in the cloud. SharePoint is then connected and configured to hand off all workflow execution and related tasks to the Workflow Manager farm.One of the more
important changes in the new workflow architecture is that all custom workflows in SharePoint completely declarative, including those built using Visual Studio 2012. In previous versions of
SharePoint, workflows developed with Visual Studio 2012 were not exclusively declarative. Instead, they were a pairing of declarative XAML with a compiled assembly. The managed
assembly contained the workflow's business logic.This might come as a shock to seasoned SharePoint developers who may be asking, "so how do I implement my custom business logic
without a compiled assembly?". Microsoft suggests that instead you create a custom web service, ideally a WCF, OData, or RESTful web service that returns data in the JavaScript Object
Notation (JSON) format, and to use some of the new activities and objects in this new version.

Scenarios for using web services in SharePoint workflows


It is not difficult to conceive of scenarios where you would leverage a custom web services in a SharePoint workflow. Developers who authored workflows using SharePoint 2007 or
SharePoint 2010 are accustomed to working with custom code, since these workflows were inherently programmatic. You were not required to add custom code to these workflows, but
doing so was quite common.
With SharePoint workflows to being purely declarative, many cases where you may have written custom code must now be handled with code written in an external web service that is called
and consumed by the workflow.
SharePoint workflows can consume any sort of web service. That said, it is easiest for workflows to interact with web services that pass data using the Open Data protocol ( OData ), as
provided in either of the formats Atom or json. OData is the best approach because it is fully supported by the SharePoint workflow authoring tools (both SharePoint Designer 2013 and
Visual Studio 2012).
In addition, both anonymous web services as well as those protected with different types of authentication are supported. In fact, you have full control over the request and response
handling for each service call. Thus, for example, you can use a series of activities within a workflow to first authenticate using one service to obtain an OAuth token, and then include that
token in future requests to services secured using OAuth 2.0.

Leveraging web services in workflows


Working with web services in SharePoint workflows involves two stages. The first is simply calling the web service, which you do by using a new HttpSend activity introduced with
SharePoint. HttpSend lets you call into the simplest web services or, for more complex tasks, provides HTTP verbs and provides specific HTTP headers. Figure 1 shows many of the
properties that are available on the HttpSend activity.
Figure 1. Properties Tool Window for the HttpSend Activity

You must also specify the method type you wish to use in the service request. Notice in Figure 1 that in the Request block you can specify the method type (in this case, GET). Available
options include GET, PUT, POST, and DELETE (although there are others). This is the primary way to tell web services, specifically RESTful services, what to do on the resource defined in
the URI of the activity.
For instance, to get all the properties of a specific item, the Uri would contain the unique address of the item, and the method would be set to GET. To delete the item, the Uri would remain
the same unique address of the item but the method would be set to DELETE. The same is true for updating an item except the method would be set to POST. In creating an item, the Uri
would point to the unique address of the collection where the item is to be created, and the method would be set to POST. When creating or updating items, services require the data to use
what is passed along as content in the request, indicated using the RequestContent property on the HttpSend activity.
The second stage of working with web services that we're going to cover involves submitting or receiving data from a web service. Regardless of whether you use the RequestContent or
ResponseContent properties on the HttpSend activity) you can pass the data as a complex structure, which are formatted as JavaScript Object Notation (JSON) strings. The good news is,
you don't have to create and manipulate these json strings manually. Instead, Microsoft gives you a new object type, the DynamicValue, that makes your task much easier.
DynamicValue objects can store hierarchal data as well as store the response of a web service call. Furthermore, there is a series of activities associated with DynamicValue objects that
you can use to count the number of items in the response, extract values from the response, or build up a new structure for updating or creating items.

Creating web services for SharePoint workflows


With the support for calling web services and the lack of supporting custom code within workflows, developers will now need to know how to create services. There are plenty of options for
creating custom web services for use in SharePoint workflows. The HttpSend activity and DynamicValue data type are best suited for RESTful services and those that conform to the
OData Protocol.
OData is a protocol for creating and consuming data based on the principles of REST services. It was developed in an effort to standardize exchanging data using the mature, reliable, and
robust HTTP protocol. Once the OData specification was complete, different organizations implemented the protocol on their own technology stacks. Microsoft implemented its own version
of OData and branded it Windows Communication Foundation (WCF) Data Services 5.0.
The RESTful services implemented by SharePoint actually support OData because they were built using WCF Data Services, specifically WCF Data Services 5.0, which implements the
OData 3.0 specification.

Implement OData Service CRUD-Q operations


A common use for web services is performing simple create, read, update, delete, and query (CRUD-Q) operations on data within a database. Creating an OData service for use with a
SharePoint workflow is quite simple using WCF. Assuming you have an existing database there are four short steps that require very little coding:
1. Create a model of your database using the Entity Framework. There is no code required (Visual Studio, provides a wizard).
2. Create a new WCF data service. There is no code required (Visual Studio provides a wizard).
3. In the service code file, set the name of the entity model (created in step #1) to the source of the service, then set the accessibility and permission for the entities in the model. Both
steps require as little as two lines of code.
4. Publish the service to a location that Workflow Manager can access.

Implement OData service operations


Another task you'll want to accomplish using web services is running business logic that may not fit into the CRUDQ model. For example, consider an OData service that supports CRUD-Q
operations for creating new bank loans. Suppose this service also supports consumers calling the service and providing a credit score to retrieve a current interest rate for a prospective loan.
This type of task does not fall into the CRUDQ model, since it calls a method and passes in an integer to receive a response.
OData and WCF data services support this scenario by providing you with service operations. Service operations are common and are even used within SharePoint services, for instance,
when retrieving a specific list using the address http://[..]/_api/web/lists/GetByTitle('ListTitle') . The GetByTitle method is a service operator the SharePoint team created. Developers
create their own custom service operations in custom web services created using WCF Data Services.

Walkthrough: Create a workflow with Visual Studio 2012


The following walkthrough demonstrates how to create a custom workflow that calls an OData web service on the Northwind database. You can find the Northwind database hosted at
OData.org.
When the workflow is completed, users will enter a customer ID, then start the workflow. When started, the workflow retrieves additional customer information and updates the list item with
the data it has retrieved.
1. Start Visual Studio 2012 and create a new SharePoint-hosted app project.
2. In this project, create a new custom list and name it "Customers".
3. In this new list, create the following fields. Leave the default data type for each field as string:
CustomerId (renamed from the default "Title" field)
Customer Name
Job Title
Address
Country/Region
Business Phone
Fax Number
1. Now, add a workflow to the project by clicking in Solution Explorer on Add > New Item; then, in the Add New Item dialog box, select the Workflow project item from the
Office/SharePoint category.
2. Name the workflow "CompleteCustomerDetails" and click Next.
3. When prompted by the Customization wizard, name the workflow "Complete Customer Details" and set it to be a List workflow. Cick Next.
4. On the next wizard page, check the box to create an association, select the Customer list, then select Create New for the workflow history and task lists. Click Next.
5. On the final wizard page, check the box to start the workflow manually; leave the option to start automatically un -checked. Click Finish.
6. At this point, Visual Studio displays the workflow designer surface that contains a single Sequence activity.
7. Change the name of the Sequence activity to Root.
8. Add four more Sequence activities inside the Root activity and name them as follows:
Init
Get Customer Data From Service
Process Service Response
Update List Item
1. At this point, the workflow will appear as shown in Figure 2.
Figure 2. Complete Customer Details Workflow with Four Empty Sequences
Get the customer ID entered by the user
The first thing the workflow needs to do is retrieve the customer ID, as entered by the user. To do this, you need to create two variable.
1. Click the Variables tab at near the bottom of the workflow designer and create two variables
CustomerItemProperties (data type = DynamicValue; scope = Init). Use this variable to store the result set returned by the activity that gets all properties from the list item.
NOTE

The DynamicValue data type is not shown by default. To find it, select the Browse for Types option in the Variable Type column. In the search box at the top of the dialog,
enter DynamicValue, and then select the Microsoft.Activities.DynamicValue.
CustomerId (data type = String; scope = Root): Use this variable to store the customer ID entered by the user.
2. Locate the LookupSpListItem activity in the SP - List section of the toolbox and drag it to the Init sequence. Set the activity properties as shown in Figure 3.
Figure 3. Properties Tool Window for the LookupSPListItem Activity

This activity tells Workflow Manager to use the SharePoint REST API to retrieve the properties of the current list item and to store the **JSON** response in the **DynamicValue** variable that yo

1. Retrieve the customer ID from the list item by clicking the Get Properties link in the LookupSpListItem activity. Doing this adds a GetDynamicValueProperties activity to the
design surface.
2. In the Properties dialog box, click the ellipsis ( ???) to open the Property selector, shown in Figure 4. In the wizard, set the Entity Type to List Item of Customers, then add a single
property, CustomerId, with the Path set to CustomerId and Assign To set to CustomerId (the variable previously created), as shown in the following figure.
3. Click Create Property and enter CustomerId in the Path column.
4. In the Assign To column, enter CustomerId, which is the variable we created earlier. Figure 4 shows the completed Properties dialog box.
Figure 4. Properties dialog for the GetDynamicValueProperties Activity.

Call the Northwind OData web service


The workflow now has a reference to the customer ID, so the next step is to call the web service. To do this, we'll be working primarily with the Get Customer Data from Service sequence.
1. Select the Get Customer Data from Service sequence and create two new variables:
NorthwindServiceUri (data type = String; scope = Get Customer Data from Service). This variable stores the URI that is used to query the web service.
NorthwindServiceResponse (data type = DynamicValue; scope = Root): This variable will store the web service response.
1. To create the URL to query the web service, start by locating an Assign activity in the workflow toolbox and drag it to the Get Customer Data from Service sequence. Notice that
the Assign activity has two parts representing a name-value pair.
2. Set the left portion of the Assign activity to NorthwindServiceUri.
3. Set the right portion of the activity to the string "http://services.odata.org/Northwind/Northwind.svc/Customers('" + CustomerId + "')?$format=json" . Figure 5 shows the completed
activity.
Figure 5. Assign Activity Used to Set a Variable Containing the OData Service

1. Drag an HttpSend activity from the toolbox to the Get Customer Data from Service sequence, immediately following the Assign activity.
2. Set the properties on the HttpSend activity using the values shown in Figure 6.
Figure 6. HttpSend Properties

Process the Northwind OData web service response


Once the web service request has been made and the results are stored in a local variable, the next step is to process the response. Each value in the response needs to be added to a different
variable.
1. Create a variable for each of the fields that we created at the start of this walkthrough (except the customer ID field), shown here:
Customer Name
Job Title
Address
Country/Region
Business Phone
Fax Number
1. Name each of these variables according to its respective field name.
2. All of the variables should be of type String; all of the variables should be scoped to Root.
3. Add a GetDynamicValueProperties activity to the Process Service Request sequence.
4. In the Properties window, set the Source value to NorthwindServiceResponse, as shown in Figure 7.
5. Click the ellipsis button ( ???) button on the Properties property and then provide values in the Path and Assign To columns as shown in Figure 7. Notice that the values in the
Assign To column are the variable you created for each of the Customers list fields.
Figure 7. Properties tool window for GetDynamicValueProperties and contents for Properties dialog
Update the customer list item
The last step is to update the list item.
1. Add an UpdateListItem activity to the Update List Item sequence and use the Properties window to set the following values:
ListId: (current list)
ItemId: (current item)
1. Click the ellipsis button ( ???) button on the ListItemPropertiesDynamicValues property and in the resulting dialog box, set Entity Type to List Item of Customers.
2. Finally, for each of the values extracted from the web service, set the values on the list item to the variables in the workflow, as shown in Figure 8.
Figure 8. ListItemPropertiesDynamicValue Dialog with Values Set

Test the workflow


The workflow is now complete and should function properly. To confirm its stability, you should test it.
1. Press F5 to start debugging; Visual Studio builds and deploys the SharePoint-hosted app.
2. When the browser opens, navigate to the Customers list, create a single customer record with a Customer Id of "ALFKI", as shown in Figure 9, and then save the item.
Figure 9. New List Item
1. Next, manually start the workflow and then go back to the list item. Keep refreshing the page to see the workflow update the list item, as shown in Figure 10
Figure 10. Updated List Item

Notice that the list item was updated by the SharePoint hosted app on behalf of the person who started the workflow. In this walkthrough, however, it was started by the administrator.

Conclusion
SharePoint introduced a new workflow architecture facilitated by a new product: Workflow Manager 1.0. To ensure that all custom workflows worked regardless of the SharePoint
deployment choice, either on-premises or hosted in Office 365, all workflows are now 100-percent declarative. Therefore, custom business logic previously implemented as custom code in
Visual Studio-authored workflows in previous versions of SharePoint are no longer supported.
Microsoft introduced support for calling web services in Workflow Manager using the new HttpSend activity. Workflow Manager also introduced support for creating structures to submit
to web services as well as consuming their responses called the DynamicValue data type. When creating workflows, use this data type and associated actions to facilitate creating and
leveraging robust business processes in SharePoint workflows by using external web services.

See also
Working with complex data in a workflow
Workflows in SharePoint
Working with Tasks in SharePoint Workflows using Visual Studio 2012
3/26/2018 • 17 minutes to read Edit Online

Learn about the new and revised workflow task framework that was introduced in SharePoint, which is built on the new Workflow Manager. Provided by: Andrew Connell,
AndrewConnell.com
NOTE

This article is accompanied by an end-to-end code sample that you can use to follow the article, or as a starter for your own SharePoint workflow projects. You can find the downloadable
code here.
One of the greatest benefits that the SharePoint brings to Windows Workflow Foundation is the implementation of a new and improved task management framework that incorporates the
new Workflow Manager as its hosting environment.

Reviewing workflow tasks in SharePoint 2007 and SharePoint 2010


Both SharePoint 2007 and SharePoint 2010 implemented workflow tasks in a similar manner. When you created a workflow association on a list, content type, or site (in SharePoint 2010),
you designated a specific list as the location where the workflow tasks would be created. This list was a standard SharePoint Task list (ID = 107) that used the standard SharePoint Task
content type (ID = 0x0108). Users then could access items in the list to view, edit, and complete the task. The workflow instances monitored the task items in the list for updates if the
workflow was configured to do so.
However, the default rendering of the task form in SharePoint was pre-determined, even for custom workflows. For full flexibility, you needed to use ASP.NET Web Forms or InfoPath Forms
when you created custom form solutions to support your tasks.

What's new with tasks in SharePoint


The manner in which tasks are created, managed, and handled in SharePoint has changed due to changes in the SharePoint architecture.
The central change is that workflows are no longer managed and processed inside of SharePoint. Instead, SharePoint utilizes a new component called Workflow Manager, which runs
externally. Workflow Manager hosts the Windows Workflow Foundation runtime and necessary services required by the Windows Workflow Foundation. When a workflow is published or a
new instance of a published workflow is started, SharePoint notifies Workflow Manager, which in turn processes the workflow episodes. When a workflow needs to access information in
SharePoint, such as list item properties or user properties, it authenticates itself using the OAuth and talks back to SharePoint with web service calls using the REST APIs.
The overall customization trend for the SharePoint platform also changed in SharePoint, although this change started with the implementation of sandboxed solutions in SharePoint 2010. In
SharePoint, Microsoft introduced changes that moved customizations off of SharePoint Server and onto either to the client's browser or to external resources. These changes include the new
SharePoint app model, support for assigning app identity, authentication using OAuth, improvements to the client-side object model (CSOM), and the REST APIs.

Architectural changes to workflow tasks in SharePoint


How do the architectural changes in SharePoint affect workflow tasks? For workflow tasks, the impact is not significant except when you are working with custom task forms. In the past, you
created task forms using InfoPath or ASP.NET Web Forms. SharePoint, on the other hand, uses the default list item rendering form for workflow tasks.
You may sometimes need to customize the appearance or the behavior of task fields. To do this, create a custom task content type that contains a site column. The site column can then use
the new client-side rendering framework in SharePoint, which requires creating a JavaScript file that defines how the field should look and act in the browser.
For more information about using client-side rendering, see How To Customize a List View in Apps for SharePoint Using Client-Side Rendering.
Individual task items are based on content types. Importantly, there are some changes to content types in SharePoint. In SharePoint 2007 and SharePoint 2010, workflow tasks were created
with the Task content type (ID = 0x0108). This is the same content type that is used to manually create non-workflow tasks in the task lists. SharePoint changes this by introducing a new
content type, Workflow Task (SharePoint) (ID = 0x0108003365C4474CAE8C42BCE396314E88E51F), which inherits from the Task content type and which indicates that the tasks are to
be used only for workflow.
This new Workflow Task content type differs from the earlier Task content type in that it has two new columns:
WorkflowInstanceId: Contains a reference to the workflow instance identifier that created the task, which is used in such places as the workflow instance status page. The status
page can use this field to query the associated workflow task list for all list items whose WorkflowInstanceId column contains the specified ID.
TaskOutcome: A choice field that is used in the presentation of the task form to allow the user to select different completion criteria options. The task edit form presents the specified
workflow task outcomes as buttons at the bottom of the form, next to the Save and Cancel buttons. Workflows in SharePoint are not limited to just the two options Approved and
Rejected, as shown in Figure 1.
Figure 1. Workflow task outcomes

Of course, content types are a part of workflow tasks. Content types simply dictate the structure of the task list items. Equally important is the task list template, which has also changed in
SharePoint.
Prior to SharePoint, the workflow task list used the same list template as the standard task list (ID = 107). It was a standard SharePoint task list that could also contain non-workflow tasks.
But in SharePoint the approach is different in that it introduces a new type of a list. This list, called the hierarchy tasks list, introduces a timeline view at the top of the page to show the
scheduling of tasks, as shown in Figure 2. Note that it also lets users view task dependencies.
Figure 2. Hierarchy tasks list
Creating workflow task options in SharePoint
Both SharePoint Designer 2013 and Visual Studio 2012 provide workflow authors two ways to create workflow tasks. One is to create a single task that is assigned to a person or a group.
The other is to create a task and assign it to multiple people. When creating a single task in a custom workflow using Visual Studio 2012, use the SingleTask activity. By using this activity,
you can modify the properties either in the Properties tool window, or with the wizard, as shown in Figure 3.
Figure 3. Single-task wizard

SharePoint lets you specify whether multiple tasks should run serially or in parallel, as well as specifying the criteria for task completion. Should SharePoint wait for all tasks to be completed,
or for a percentage of them to be completed with a specific outcome? To create multiple tasks in Visual Studio 2012, use the CompositeTask activity, whose wizard and properties resemble
the SingleTask activity, as shown in Figure 4.
Figure 4. Composite task wizard

How to: Create and assign tasks in custom workflows


Following is a walkthrough that demonstrates how to create and assign tasks in a custom workflow. Before starting, make sure that you have access to a SharePoint developer site.

1. Create a new SharePoint app project


1. Create a new SharePoint app project and configure the project as a SharePoint-hosted add-in.
2. To the project, add a new Announcement list instance to the project. This will be used as the container for items used to test the workflow.
3. Add a workflow item the project by right-clicking the project icon in Solution Explorer and selecting Add, followed by New Item.
4. In the Add New Item dialog box, select the Workflow project item from the Office/SharePoint category and name it "CustomTaskWorkflow", and then click Next.

2. Collect information on the New Announcement item


We are going to create a task in our workflow and assign it to the person who created the announcement list item that kicks off the workflow. The list item itself will provide the information
to the workflow. We will use a LookupSPListItemProperties activity, which returns a dynamic value from the REST web service that it calls in SharePoint. We're then going to store this
value in a new variable named AnnouncementItemProperties, whose data type we will change to DynamicValue.
1. Create an AnnouncementItemAuthorId variable to store the ID of the person who created the list item, as shown in Figure 5.
Figure 5. LookupSPListItemProperties activity
1. Drop the LookupSPListItem activity onto the workflow design surface and set the ListID property to (current list).
2. Set the ItemId to (current item).
3. Set the Result output to the AnnouncementItemProperties variable that we created earlier.
4. To get the author of the item from the variable, click the Get Properties link in the LookupSPListItem activity and add a GetDynamicValueProperties activity to the design
surface. Set its Source property to the output of the LookupSPListItem activity.
5. Click the [???] button on the Properties property to bring up the Properties dialog box.
6. In the Properties dialog box, change the Entity Type to List Item of Announcements, as shown in Figure 6.
7. Assign the Created By path to the variable AnnouncementItemAuthorId, as shown in Figure 6.
Figure 6. Properties dialog

3. Create and Assign the task


At this point we can create and assign the task to the author of the announcement item.
1. From the toolbox, add a SingleTask activity to the workflow design surface.
2. Click the Configure link in the activity to open the Task Options dialog box.
3. Set the Assigned To property to the variable used to store the author identifier.
4. Modify the title and body of the task, as shown in Figure 7.
Figure 7. Task Options dialog

There are several other options that can be set in the Task Options dialog box. For example, you can set the workflow to wait for the task to complete by simply checking the box (see Figure
7). Previous versions of SharePoint workflows required a difficult workaround to accomplish this.
Notice in Figure 8 the email options that you can set. Among other options, you can ensure that email messages are sent whenever the task is overdue as well as specifying how often the
reminders are sent.
Figure 8. Email Options settings
You can also set the task outcome options. You can select the workflow task content type, the Outcome Field, and the Default Outcome, as shown in Figure 9.
Figure 9. Outcome Options settings

4. Examine and modify the task properties


Once you have accepted values in the Task Options dialog box, select the SingleTask activity and then inspect the Properties property grid (see Figure 10).
Figure 10. Properties tool window

Using the Properties property grid, you can specify whether you want the task to wait for completion before proceeding, and you can configure the email messages that the task generates,
including the initial assignment email message, the overdue email message, and the task cancellation email message.
Notice that the Outcome property automatically created a variable named outcome_0 for the task. To see what is contained in this variable, add a WriteToHistory activity on the design
surface and update the message to write out the result, as shown in Figure 11.
Figure 11. Outcome property value

5. Test the workflow


To test the workflow, do the following:
1. Press F5 to build and run, or click the Start button in Visual Studio 2012. If you are testing in an on-premises installation of SharePoint, Visual Studio 2012 starts the Workflow
Manager Test Service Host utility and deploys the workflow to the developer site. After a moment, the developer site opens.
2. Navigate to the Announcements list and create a list item, then start the custom workflow manually.
3. Return to the workflow instance status page to find the task that was created by the workflow. Click on the task to see the form. Note the Task Name and Assigned To fields that
were defined in the workflow, as shown in Figure 12.
Figure 12. Task form

1. Finally, return to the task, edit the form, and then click the Approve or Reject to complete the task. Notice that the result of the task is shown in the Workflow History list for the
workflow instance, as shown in Figure 13.
Figure 13. Workflow History list

How to: Create a custom task type with a custom outcome


The previous walkthrough demonstrated how to create a simple task and configure its properties. However, sometimes the default options may not meet your needs. For example, consider a
task that asks someone to review a document. Upon reviewing the draft document, the reviewer should exercise one of two options: send the draft document back to the author for revision,
or forward the document to the editor. Unfortunately, neither of the default options ( Approved and Rejected) meets the reviewers needs. More appropriate options would be "Return to
Author" and "Proceed to Editor".
When creating workflows using either SharePoint Designer 2013 or Visual Studio 2012 you can create custom workflow tasks that include custom task outcomes. To do this, you create a
custom task as a special content type and then add a custom site column that defines the outcomes you desire. You can derive the custom column from the field type called
OutcomeChoice, which is a choice field.
This approach can pose a challenge, however, in that the content type that the custom task is derived from is the Workflow Task (SharePoint) content type, which includes the default
TaskOutcome site column that contains the Approved and Rejected options. However, you can work around the default setting by removing the TaskOutcome column from the custom
task content type and ensure it is not present in the workflow task list. Otherwise, it would result in showing multiple options. For example, consider a custom outcome that had two options,
"Red Pill" and "Blue Pill." If the default outcome is not removed, then the users completing the task would be presented with all available outcome options, as shown in Figure 14, even if
those outcome options do not apply.
Figure 14. Outcome options

As a best practice, you want to create a different workflow task list for each type of task that you create.

Create a SharePoint app project


To begin the walkthrough for creating a custom workflow task using Visual Studio 2012, you first want to ensure that you have access to a SharePoint developer site.
1. In Visual Studio 2012, create a new SharePoint app project that is configured as a SharePoint-hosted add-in.
2. To the project, add a new Announcement list instance. You will use this as the container for items used to test the workflow.
3. Next, add a workflow item the project by right-clicking the project icon in the Solution Explorer and selecting Add, followed by New Item.
4. In the Add New Item dialog box, select the Workflow project item from the Office/SharePoint category and name it "CustomTaskWorkflow"; then click Next.

Create the custom outcome column


Once we have the Announcements list created, we next want to create the custom content type that will contain the custom task and the site column for the custom outcome field.
1. Right-click the project and select Add, followed by New Item.
2. Now choose the Site Column project item template and set the name of this field to "CustomOutcomeColumn". Within the template for the site column there are a few changes that
need to be made.
3. Set the field type of the column to OutcomeChoice, which is the required field type for an outcome column.
4. Remove the Required column.
5. Next, because the OutcomeChoice field type is based on the choice field type, add a few choices of your own.
The new custom site column markup should now look like the following:

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field
ID="{7b7edd9e-f5d1-4558-a2c8-e733dcfb0a5e}"
Name="CustomSiteColumn"
DisplayName="Better State"
Type="OutcomeChoice"
Required="FALSE"
Group="Custom Site Columns">
<CHOICES>
<CHOICE>Florida</CHOICE>
<CHOICE>Georgia</CHOICE>
</CHOICES>
<Default>Florida</Default>
</Field>
</Elements>

Create a custom task content type


After creating the site column, the next step is to create a specialized content type for the custom task.
1. Add a new content type project item to the project with the name CustomTaskContentType.
2. When prompted to select which content type this is based on, select the Workflow Task (SharePoint) content type.
3. Next, add the custom outcome column to the list of available columns and also remove the default outcome column so the markup of the content type looks like the following
example.

<?xml version="1.0" encoding="utf-8"?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<!-- Parent ContentType: Workflow Task (SharePoint) (0x0108003365C4474CAE8C42BCE396314E88E51F) -->
<ContentType
ID="0x0108003365C4474CAE8C42BCE396314E88E51F00D368DFB2B31A447BB184BA1334E5119E"
Name="CustomContentType"
Group="Custom Content Types"
Description="My Content Type"
Inherits="TRUE" Version="0">
<FieldRefs>
<FieldRef
ID="{7b7edd9e-f5d1-4558-a2c8-e733dcfb0a5e}"
DisplayName="Better State"
Required="FALSE"
Name="CustomSiteColumn" />
<RemoveFieldRef
ID="{55B29417-1042-47F0-9DFF-CE8156667F96}"
Name="TaskOutcome" />
</FieldRefs>
</ContentType>
</Elements>

Create a workflow
Now we create a workflow so we can test the custom site column and content type.
1. Add a workflow to our project configure it to be a list workflow.
2. Create an association with this workflow using the Announcements list that we created earlier.
3. Create a new variable of type DynamicValue and name it "ItemProperties"; we are going to use this variable to store the item that kicks off the workflow's properties.
4. Create an Int32 variable and name it "ItemAuthorId", as shown in Figure 15.
Figure 15. Creating a workflow variable
Collect the list item properties
Now we collect the list item properties.
1. Drop the LookupSPListItem activity onto the design surface and set the ListID property to (current list) and the ItemId property to (current item).
2. Now set the Result output to the ItemProperties DynamicValue variable that we created a moment ago.
3. To get the author of the item from the variable, click the Get Properties link in the LookupSPListItem activity and add a GetDynamicValueProperties activity on the design
surface.
4. Set the item's Source property to the output of the LookupSPListItem activity automatically.
5. Click the [???] button on the Properties property to display the Properties dialog box.
6. Change the Entity Type to List Item of Announcements to give the dialog box a context and assign the Created By path to the variable ItemAuthorId, as shown in Figure 16.
Figure 16. Properties dialog

Create a single task


Now we can create the single task.
1. Add a SingleTask activity to the design surface.
2. Click the Configure link in the activity to open the Task Options dialog box.
3. Set the Body field to some string (it doesn't matter what), then set the Assigned To property to the variable you are using to store the author identifier (in our case, ItemAuthorId).
4. Change the title of the task, as shown in Figure 17.
Figure 17. Task Title setting

1. Finally, set the Outcome Options to use the new custom content type and custom outcome column.
The dialog box determines what is available by looking at all the content types that are derived from the Workflow Task (SharePoint) content type, as shown in Figure 18.
Figure 18. Outcome Options settings
Update the AssignedTo field
Before we go any further, we need to update the AssignedTo field on the SingleTask activity because it is expecting a string, not an integer. To remedy this, add ToString() to the end of the
expression.
Also, notice that the Outcome property automatically created a variable named outcome_0. To see what is in this variable, add a WriteToHistory activity on the design surface and update
the message to write out the result.

Update the workflow task list


The final step is to configure the workflow task list. By default, the task list that the app creates only accepts the content type Workflow Task (SharePoint). This workflow uses a custom
content type for the custom outcome. Open the Elements.xml file for the workflow task list and change the element's ContentTypeId attribute to match the content type in the project, as
shown in the code example following.

<?xml version="1.0" encoding="utf-8" ?>


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ListInstance
FeatureId="{f9ce21f8-f437-4f7e-8bc6-946378c850f0}"
TemplateType="171"
Title="WorkflowTaskList"
Description="This list instance is used for workflow Task items."
Url="Lists/WorkflowTaskList"
RootWebOnly="FALSE" />
<!-- CustomContentType -->
<ContentTypeBinding
ListUrl="Lists/WorkflowTaskList"
RootWebOnly="FALSE"
ContentTypeId="0x0108003365C4474CAE8C42BCE396314E88E51F00D368DFB2B31A447BB184BA1334E5119E"/>
</Elements>

Test the custom content task with a custom task outcome


Now let's test the workflow.
1. In Visual Studio 2012, press F5 or click the Start button. If testing in an on-premises local install of SharePoint, Visual Studio 2012 will start the Workflow Manager Test Service Host
utility and deploy the workflow to the developer site. After a moment, the developer site will open.
2. Navigate to the Announcements list and create a new item. After creating the item, start the custom workflow manually.
3. Next, return to the workflow instance's status page to find the task that was created by the workflow.
4. Click on the task and, using the Edit button in the ribbon, switch to edit mode. At the bottom of the form there should be four buttons. The first two buttons are the custom outcome
buttons that, when pressed, will mark the task as complete. The second two buttons are the default Save and Cancel buttons that simply update the list item without completing the
task, as shown in Figure 19.
Figure 19. Custom outcome buttons

Conclusion
Microsoft introduced workflows into the SharePoint 2007 platform, and they remained mostly unchanged in SharePoint 2010 in architecture, implementation, or process. This was also true
for tasks in SharePoint workflows. However, SharePoint has introduced many changes to workflows in architecture and implementation.
This article discussed the changes related to workflow tasks that were driven from changes to the workflow story in SharePoint. It demonstrated how to create a simple workflow that
leveraged tasks in SharePoint using Visual Studio 2012. These types of tasks are suitable for many developers, although at times custom tasks and custom outcomes are desired, which can
be accomplished using Visual Studio 2012 as has been shown.

See also
Workflows in SharePoint
Authorization and authentication for apps in SharePoint
How To Customize a List View in Apps for SharePoint Using Client-Side Rendering
Create custom SharePoint workflow forms with Visual Studio 2012
3/26/2018 • 23 minutes to read Edit Online

Presents workflow forms in SharePoint. This article uses SharePoint with the March 2013 Public Update applied and Office Developer tools for Visual Studio 2012. Everything in this article
applies to both SharePoint on-premises deployments as well as Office 365.
Provided by: Andrew Connell, www.AndrewConnell.com
Since the release of Microsoft SharePoint 2007, the SharePoint platform has supported using workflows to automate business processes. The SharePoint workflow platform is built on the
Windows Workflow Foundation, which is part of the .NET Framework. While the Workflow Foundation provides many capabilities for authoring custom workflows and managing
automated business processes, SharePoint also adds end-user integration. This integration is implemented in two parts:
Tasks assigned to users and groups that can be created and monitored by the workflows.
Forms that collect information from users when workflows are associated with a type of content (for example, a site, list, or library) or when a workflow is started.

Workflow forms in SharePoint 2007 and SharePoint 2010


The implementation of workflows in SharePoint 2007 and SharePoint 2010 provided steady improvements from version to version. In particular, Microsoft added new functionality in
SharePoint 2010, such as the ability to associate workflows with sites. It also improved the workflow authoring tools, SharePoint Designer 2010 and Visual Studio 2010, over their
predecessors. However, in SharePoint, the implementation of workflow tasks and workflow forms remained largely unchanged.
Prior to SharePoint, developers were presented with two options for creating workflow forms. In SharePoint 2007, InfoPath forms and ASP.NET Web Forms were both recommended
equally. Each had advantages and disadvantages. In SharePoint 2010, developers were encouraged to use ASP.NET Web Forms as that is what the SharePoint developer tools in Visual
Studio 2010 created using the association and initiation workflow form project item templates, but the implementation was very similar to that in SharePoint 2007.

Changes to workflow forms in SharePoint


SharePoint introduced a new workflow architecture and platform that reflects some fundamental shifts in the thinking about SharePoint. The primary change is that workflows in SharePoint
are no longer managed and executed by the SharePoint runtime engine. Instead, SharePoint utilizes a new component called Workflow Manager, which hosts the Windows Workflow
Foundation runtime and necessary services required by Workflow Foundation. The important point is that Workflow Manager runs outside of SharePoint. When a workflow is published, or
a new instance of a published workflow is started, SharePoint notifies Workflow Manager, which in turn processes the workflow episodes. When the workflow needs to access information in
SharePoint, such as list item properties or user properties, it authenticates the user with the OAuth authorization model and communicates over the REST APIs that were introduced in the
SharePoint release.
The overall direction for doing customizations on the SharePoint platform also changed in the SharePoint release, although this change actually started with SharePoint 2010 and sandboxed
solutions. In SharePoint, Microsoft introduced features that moved customizations away from SharePoint server and moved them to the client browser or to other external resources. These
features include the new SharePoint App Model, support for assigning apps an identity, authentication using the OAuth authorization model, and improvements to the client-side object
model (CSOM) and REST APIs.
How does this affect workflow forms? Recall that starting in SharePoint 2010 Microsoft began encouraging developers to use ASP.NET Web Forms when creating forms in workflows
authored using Visual Studio. Of course, this approach requires server-side code to process the form and handled communication between the form and the workflow engine. However, in
SharePoint, this is only possible in the solution-style development (that is, deployment of *.WSP packages). The new SharePoint App Model introduced in SharePoint does not allow server-
side code to run in the SharePoint process.
To alleviate this limitation, Microsoft extended CSOM to include an API for interacting with the workflow engine. To connect a SharePoint farm to the Workflow Manager farm, you must
install the Workflow Manager Client on the SharePoint servers. This component serves as a proxy that SharePoint uses to communicate with the Workflow Manager farm. The Workflow
Services CSOM API is effectively the client-side component that you use to interact with the new workflow engine. For more information about SharePoint Workflow Services CSOM, see
Working with the SharePoint Workflow Services Client Side Object Model.
How, then, does this benefit SharePoint workflow forms? Well, when authoring SharePoint workflows using Visual Studio 2012, you create workflow forms using ASP.NET Web Forms. You
can deploy these forms as a SharePoint solution or (and this is the important part) within . This gives you access to all the server controls that are already deployed to the server, such as the
ASP.NET Web Controls and other useful (and required at times) SharePoint controls. You can also use the new Workflow Services CSOM to perform all necessary tasks from association
and initiation forms including, but not limited to, the following:
Creating workflow task and history lists
Creating a new workflow association on a site, list, or document library
Starting a new instance of an existing workflow association
The Workflow Services CSOM is very robust and gives you a lot of room for innovation in workflows—all from the browser or a remote machine.

Workflow forms available in SharePoint Sever 2013


Prior the release of SharePoint, there were three types of custom workflow forms you could create: Initiation, Association, and Task Edit forms. Of these three types of forms, task edit
forms have been de-emphasized as a custom forms solution. The de-emphasis of Task Edit forms started with SharePoint 2010 because the Visual Studio 2010 SharePoint development
tools lacked a project item for task forms, relying instead on the standard list display and edit forms to render tasks.
SharePoint improves how you work with workflow tasks in that you can create custom outcome buttons for specific scenarios. You can also customize the rendering and behavior of specific
columns in task items using the new Client Side Rendering (CSR), which was introduced in SharePoint. Note that CSR uses JavaScript executed in the client. These topics are covered in the
article Working with Tasks in SharePoint Workflows using Visual Studio 2012. You can also get more information in the article Customize a list view in SharePoint Add-ins using client-side
rendering.

Understanding workflow initiation forms


An initiation form is opened when a user manually launches a workflow whose workflow definition is associated with the form. When the workflow kicks off, the user is presented with the
initiation form and is prompted to enter information that the workflow will need. For example, the user could enter a justification for a workflow initiating an approval for a new business
expense.
An important point about initiation forms is that they are only shown when a workflow is started manually. Workflows that are configured to start automatically will not launch the initiation
form when they are started. This condition can create complications for workflows that expect data to be passed in from the form. You should remember, then, that if your workflows are
configured to start automatically, and the workflow requires user inputs, you should use an association form, not an initiation form.

Understanding workflow association forms


Association forms are displayed to administrators when they first decide to add—or associate—a workflow to a particular list or document library. Use the association forms to let an
administrator specify parameters, default values, and other information for the workflow as it applies to items on the list or library.
This default association form lets the administrator select the workflow definition, provide a display name for the association, specify the lists that will be the containers for any tasks and
history list items created by the workflow selected in the association, and specify the conditions under which the workflow can start, such as manually or automatically, when list or library
items are created or updated.
You can also create custom association forms. If you have a custom association form on a workflow definition, SharePoint redirects the user to the custom form once the default form is
completed. Use the custom form to collect configuration information the workflow may need, such as calling an external web service that requires the caller to either authenticate with or
pass in a unique API key for access. This is the sort of information that a developer will not want to hard-code into the workflow. You would see this scenario if a workflow is included in an
app sold through the SharePoint Store. In this case, each customer needs their own account with the remote service. This is the sort of information you would collect from the user when they
create the workflow association.
Another common scenario is when you need to collect information that the initiator of the workflow would normally submit for workflows that are started automatically. As explained
previously, initiation forms are presented only when workflows are started manually. When workflows are configured to start automatically, on the other hand, and if the workflow is expects
data in some fields in the form, the preferred solution is using a custom association form.
Then, in the initiation form, these default values would be present when starting the workflow manually. When started automatically, the workflow could detect that no data was passed in
from the initiation form and instead revert back to the values specified in the association form.

Walkthrough: Create and deploy a custom association form


In this walkthrough we demonstrate how to create a custom association form and use it to collect information that is then passed to the workflow. Before you begin, ensure that you have
access to a SharePoint developer site.

Create the custom association form


1. Create a custom workflow using Visual Studio 2012.
2. In Visual Studio, create a new SharePoint app project and configure it as a SharePoint-hosted app.
3. Add a new Announcement list to the project. This list will be associated with the workflow and events on this list will trigger the workflow.
4. Add a workflow item the project by right-clicking the project in the Solution Explorer and selecting Add, followed by New Item. In the Add New Item dialog box, select the
Workflow project item from the Office/SharePoint category. Enter "SampleWorkflow" as the name and then click Next. When prompted by the SharePoint Customization Wizard,
set the new item to be a List Workflow.
5. The next page of the SharePoint Customization Wizard, shown in Figure 1., allows you to automatically create a workflow association. However, when you're creating a custom
association forms, you do not want to exercise this option. Instead, deselect this check box and click Finish.
Figure 1. Deselect the option to automatically associate the workflow.

1. Next, add the form to the Visual Studio project by right-clicking the workflow item in Solution Explorer, then selecting Add, New Item.
This last step is important because it tells the Add New Item dialog that the context is a workflow item. This then causes the Add New Item dialog to display the two form project
item templates (Initiation form and Association form) as options, as shown in Figure 2.
Figure 2. Selecting the Association Form template.
1. Select the Workflow Association Form item and remove the "1" from the field name. Click Add to complete the process.

Update HTML and JavaScript in the default association form


Once the new form is added to the project, Visual Studio automatically opens it. At this point, you only need to do two things to the form to make it compatible with your workflow:
Update the HTML form to reflect the data elements that you need to collect from the user, as well as indicate how the form should be rendered.
Update the default JavaScript to pull the values from the updated form and match the property names to the names of the arguments that you created in the workflow.
1. Open the form to view the code.
2. Locate the server control shown in the following code snipped:

<WorkflowServices:WorkflowAssociationFormContextControl ID="WorkflowAssociationFormContextControl1" runat="server" />

This server control performs two important tasks. First, it adds the JavaScript libraries needed by the association form. Second, it takes the form values that were submitted by the preceding for

1. Scroll down in the source file until you locate the sample HTML table and replace it with the following:

<table>
<tr>
<td colspan="2">
String:<br /><textarea id="strInput" rows="1" columns="50"/>
</td>
</tr>
<tr>
<td><button id="Save" onclick="return runAssocWFTask()">Save</button></td>
<td><button id="Cancel" onclick="location.href = cancelRedirectUrl; return false;">Cancel</button></td>
</tr>
</table>

This table displays a simple HTML textbox which is used to pass information into the workflow association. Note that the form has two buttons These buttons are used to save or cancel the workflow

Update the Workflow Services JSOM to create the workflow association


Immediately following the HTML form section in the source file there is a ecmascriptshort block of code that is about 200 lines long. This code block illustrates the new Workflow Services
JavaScript Client Side Object Model (JSOM) API implementation in SharePoint. For the most part, this JavaScript code should be left unchanged because it does some important things:
Determines whether a new associated workflow task list should be created and, if so, creates it.
Determines whether a new associated workflow history list should be created and, if so, creates it.
Creates a new workflow association with the specified name, workflow definition, startup options, and associated lists.
The critical part that you need to be concerned with when creating the custom association forms is where the values from the form are collected and passed into the new association. We
cover this in the following procedure.
1. In the workflow association JSOM script block, locate the JavaScript function associateWF().
2. Inside the script block for this function, locate the line that defines a new array named metadata:
var metadata = new Object();

1. Next, add a collection of name-value pairs representing your form fields that you wish to pass into SharePoint. For the custom form in this walkthrough, all you need is the following
JavaScript, so update the block that sets the metadata variable as follows:
var strInputValue = document.getElementById("strInput").value;
if (strInputValue) {
metadata['AssociationFormValue'] = strInputValue;
}

1. At this point the custom association form is complete.

Consume the association form values in the workflow


With the form complete, the next step is to configure the workflow to use the values being passed in from the association form. When a value is passed in from the association form, it is
passed in as a configuration value. To obtain this, use a special activity to extract the configuration value from the workflow's association metadata and store it in a variable for later use.
1. Open the workflow in Visual Studio, go to the Variables tab, and create a new string variable called AssociationFormValue, as shown in Figure 3.
Figure 3. Creating the AssociationFormValue variable.

1. Drag and drop a GetConfigurationValue activity on the workflow designer surface and set the Name property to the name of the metadata property used in the form, as shown in
Figure 4.
Figure 4.

1. Set the Result property to the name of the variable, as shown in Figure 4.
This activity pulls the AssociationFormValue property value out of the workflow's metadata and stores it in the local variable. To see the contents of the variable, add a
WriteToHistory activity to the workflow and set its Message property to write the value of the variable to the history list.
2. You have completed the steps necessary to associate the form values with the workflow. Save your work and test the form.

Test the custom association form


1. To test the workflow, press F5, or click the Start button in Visual Studio. This walkthrough presumes an on-premises, local installation of SharePoint, so Visual Studio launches the
Workflow Manager Test Service Host utility and deploys the workflow to the developer site.
2. Create the association by navigating to the Announcements list, then on the ribbon select the List tab and click the Workflow Settings, Workflow Settings button, then click the
Add a workflow link. At this point you are presented with the SharePoint association form.
3. In the association form, select the workflow you wish to test and give it a name.
4. Opt to create new task and history lists, set the workflow to start manually, and then click Next.
5. Because you have specified a custom association form in the workflow definition, the custom association form shown in Figure 5 opens.
Figure 5. The custom workflow association form.
1. Enter a value in the form field and click Save. This creates the association and stores the custom value in the metadata for the workflow association.
2. To verify the workflow can extract the value from the configuration settings, navigate back to the Announcements list and create a new item. After creating the item, start the custom
workflow manually. Once the workflow has started, navigate to the item's workflow instance status page and confirm that the value that has been written to the history list, as
illustrated in Figure 6.
Figure 6. Workflow status page.

Walkthrough: Creating a custom initiation form


This walkthrough demonstrates creating a custom association form and using it to collect information from the user when the workflow is started manually.

Create a new workflow project


1. Start by creating a custom workflow using Visual Studio 2012, ensuring you have access to a SharePoint developer site.
2. Create a new SharePoint project that is configured as a SharePoint-hosted app.
3. Add a new Announcement list to the project. We'll use this list as the container for items that we use to trigger the workflow.
4. Next, add a workflow item to the project by right-clicking on the project icon in Solution Explorer and selecting Add, New Item, and then, in the Add New Item dialog box,
selecting the Workflow project item. and
5. Name the new workflow "SampleInitFormWorkflow", then click Next.
6. When prompted, set the new workflow item to be a List Workflow associated with the Announcements list; set the workflow to start manually. (Note that the initiation form will not
be displayed if the workflow starts automatically.)
7. At this point, the project appears in Solution Explorer as shown in Figure 7. Note that some elements, like the WorkflowHistoryList and WorkflowTaskList, were added
automatically when the association was created.
Figure 7. Appearance of the project in Solution Explorer.

Add arguments to collect initiation form values


The workflow initiation form prompts users for two pieces of information that it needs for the workflow to start: a random string, plus a user that is selected using the people picker control.
To enable this, you configure two arguments whose values the Workflow Services CSOM API will take from the form when it is submitted.
1. In the workflow designer, click the Arguments tab at the bottom of the screen and create two arguments, as shown in Figure 8. Name them UserLoginName and
SomeRandomString.
Figure 8. Configuring the initiation form arguments.
1. Set the Argument type to String for both; also for both, set the Direction to In, as shown in Figure 8.
You can think of the Direction property as if it were a property on a .NET class. When the direction is set to In, the property would have a public Set method, but a private Get
method. When the direction is set to Out, the property would have a public Get but a private Set. Finally, when set to In/Out, both the Get and Set methods would be public.
2. To view the contents of these two arguments, add a pair of WriteToHistory activities to the workflow and configure each one to write the contents of the arguments to the history list.
You can use these arguments the same way you use variables, but keep in mind when setting Direction that you are dictating their read/write capability. Figure 9 shows what one of
these activities might look like when configured:
Figure 9. Configuring a WriteToHistory activity to test arguments

Add the initiation form project item


With the workflow configured to accept two input arguments from the form, the next step is to add the form to the project.
1. Right-click the workflow item in Solution Explorer and select Add, then select New Item.
2. Select the Workflow Initiation Form project item and remove the number "1" from the name so the form is called "InitForm.aspx", then click Add. This causes Visual Studio to add
the new ASPX page to the Pages module that is already present in the project tree. This ensures that the form will be provisioned to the Pages subfolder in the app. Visual Studio also
modified properties on the workflow item.
3. Select the workflow item SimpleInitFormWorkflow in Solution Explorer and in the Properties grid, notice which properties on the initiation form have been set. One of them is
actually pointing to the site relative path of the form that was just added to the Pages module.

Review and update the default initiation form


When you added the new initiation form to the project, Visual Studio 2012 automatically. As was the case with the association form, this new initiation form needs two tasks performed:
Update the HTML form to specify data elements that should be collected from the user, as well as specifying how the form should be presented.
Update the default JavaScript block to pull the user-input values from the form and match the property names to the names of the arguments that we created in the workflow.
NOTE

In the source file, note that first ASP.NET content placeholder, PlaceHolderAdditionalPageHead, contains references to the Workflow Services CSOM library ( sp.workflowservices.js )
and the core SharePoint CSOM libraries ( sp.js and sp.runtime.js ). Immediately following this section of code, there is a server-side comment that contains a commented note. Be mindful
that this note, shown in Figure 10, is irrelevant and should be ignored.
Figure 10. Code comment to disregard.

Update the HTML form


1. Scroll down in the form's code file until you reach the ASP.NET content placeholder named PlaceHolderMain . Notice that the first part of this section contains an HTML table that
contains three form fields. We only need two.
2. Update this HTML table by replacing it with the following:
<table>
<tr>
<td>
String:<br />
<input type="text" id="strInput" />
</td>
</tr>
<tr>
<td>
User Picker:<br />
<SharePoint:PeopleEditor AllowEmpty="false" ValidatorEnabled="true" MultiSelect="false" ID="peoplePicker" runat="server" />
</td>
</tr>
<tr>
<td>
<input type="button" name="startWorkflowButton" value="Start" onclick="StartWorkflow()" />
<input type="button" name="cancelButton" value="Cancel" onclick="RedirFromInitForm()" />
<br />
</td>
</tr>
</table>

The table now contains two input controls. The first is a standard HTML text box whose ID is strInput. The second is a SharePoint people picker control whose ID is peoplePicker. This
latter is a server-side control; however, it is allowed on the page because it has been deployed to every SharePoint computer. Further, the control is referenced at the top of the initiation form.
Now notice the two buttons on the form, Start ("startWorkflowButton") and Cancel ("cancelButton"). Clicking the Start button calls the StartWorkflow()JavaScript function. The function
itself is located in a script block farther down in the form file and is the subject of the next change that we need to make.

Update the JSOM code block to start the workflow


1. Locate the JavaScript code block that immediately follows the HTML table that we just modified. We'll leave the code in the script block largely unchanged.
This code demonstrates enormous power and flexibility available in the Workflow Services JavaScript Client Side Object Model (JSOM) API that has been implemented in
SharePoint. From a high level, the code performs the following steps.
2. Locate the following line of code: var wfParams = new Object();

3. Immediately following this line, replace the existing code with your own code to pull values from the two HTML form fields that we created a few moments ago: strInput and
peoplePicker. To do this, add the following reference to the jQuery library to the PlaceHolderAdditionalPageHead element in the HTML markup. This makes it easier to grab
values from the form.

<script type="text/javascript" src="../Scripts/jquery-1.8.2.min.js"></script>

1. Now, return to the portion of the JSOM script block where the parameters are collected from the form. Replace the existing JavaScript with the following code:

var wfParams = new Object();


// get people picker value
var html = $("ctl00_PlaceHolderMain_peoplePicker_upLevelDiv");
wfParams['UserLoginName'] = $("#divEntityData", html).attr("key");

// get string input


var strInputValue = $("strInput").value;
wfParams['SomeRandomString'] = strInputValue

1. Save your changes.


The code that we've modified in the preceding procedure does a large amount of work:
Obtains these three parameters from the query string in the URL:
The item ID that the new workflow instance will be associated with, saved in the JavaScript variable [itemId].
The ID of the workflow association on the current site, list, or document library, saved in the JavaScript variable [subscriptionId].
The URL that the user came from, saved in the JavaScript [redirectUrl] variable. This is where the user will be taken to when they complete the form and the workflow has
been started.
Creates an array of properties to be sent to the workflow, saved in the JavaScript variable [wfParams]. These are the values that you will need to collect from the form and the second
of the two minimal steps required for editing the custom initiation form.
Obtains references to a SharePoint CSOM client context as well as the necessary workflow services.
Once the script is connected to the Workflow Services Subscription Service (referenced in the variable [subscriptionService] ), it performs one of the following tasks:
If the script obtained an item ID from the query string in the first step, then it starts a new instance of the workflow on the specified list item by calling the function
[startWorkflowOnListItem()] from the Workflow Services instance service.
If no ID was found, it starts a new instance of the workflow on the current site by calling the function [startWorkflow()] from the Workflow Services instance service.

Test the custom initiation form


Test the workflow by pressing F5 or by clicking the Start button in Visual Studio 2012. If you are testing in an on-premises local installation of SharePoint, Visual Studio 2012 will start the
Workflow Manager Test Service Host utility and deploy the workflow to the developer site. After a moment, the developer site will open.
Navigate to the Announcements list and create a new item. After creating the item, start the custom workflow.
Because the workflow definition contains a reference to an initiation form, the user is taken to that form first. Fill in the requested values, then click the Start button. This triggers the
JavaScript on the page, which starts the workflow instance, as shown in Figure 11.
Figure 11. Triggering the workflow.
After starting the workflow, the page redirects the user back to the originating page. Give the workflow a few moments to start, then go back to the item and view the workflow instance's
status page. Notice that the history list contains the values that were submitted in the form and then sent to SharePoint once the workflow instance was created using the Workflow Services
JSOM.
Figure 12. On completing the workflow.

Conclusion
SharePoint introduced several improvements to workflows. This article detailed the changes related to workflow forms that were driven from changes to the workflow architecture in
SharePoint. This article also demonstrated how to create both custom association forms and initiation forms that can be used to meet the demanding requirements in automating today's
business process using Visual Studio 2012.

See also
Workflow Association and Initiation Forms (SharePoint Foundation)
Working with the SharePoint Workflow Services Client Side Object Model
Customize a list view in SharePoint Add-ins using client-side rendering
Build and deploy workflow custom actions
3/26/2018 • 6 minutes to read Edit Online

Learn how to model business processes whose requirements are not met by the existing library of workflow actions in SharePoint Designer by creating custom workflow actions in
SharePoint. SharePoint Designer provides a collection of workflow actions that are available through the Workflow Designer user interface (UI). Although the range of workflow actions that
are included in SharePoint Designer) is extensive, it is nevertheless finite. In some cases, you may need to model a business process whose requirements are not met by the existing library of
workflow actions that are available in SharePoint Designer.
Recognizing that business processes often have specialized requirements, SharePoint lets you create custom workflow actions. You can develop these custom actions by using Visual Studio,
and then package and deploy them to SharePoint. At that point, the custom action becomes available to workflow authors in SharePoint Designer, exactly as if it were among the library of
existing actions. This capability lets you customize the functionality in your workflow authoring environment to match any of your specialized business processes.
NOTE

A sample is provided that illustrates creating a custom action. The sample, along with a readme file, is available here: SharePoint workflow: Create a custom action
(http://code.msdn.microsoft.com/SharePoint-2013-workflow-41e5c0f9).

Core scenario for custom workflow actions


The core scenario for custom workflow actions is captured in the following narrative line:
1. A business analyst or other non-technical information worker is using SharePoint Designer to author a workflow to model an internal business process—for example, a document-
approval process. However, in this company, the final step of the process is, upon final approval, to automatically dispatch the document to an external printer who prints and binds a
specified number of copies of the document.
2. No workflow action that is included in SharePoint Designer 2013 supports dispatching a document to an external printer. Therefore, the company managers decide to invest in
providing this custom action (they call it the "Send Files to Printer" action) for the company's information workers.
3. Vendors expose printing web services. To capitalize, a developer creates a custom Send Files to Printer action, named SendFilesToPrinter. What the developer creates is a
declarative workflow activity. The developer also, then, creates the workflow action to provide the drag-and-drop UI for the action in SharePoint Designer.
4. The developer packages both the SendFilesToPrinter activity and the Send Files to Printer action in a SharePoint solution package (.wsp) file and deploys it as a site collection
feature to the SharePoint farm.
5. After the feature is deployed and activated, the information worker sees the new custom action, Send Files to Printer, in the SharePoint Designer UI along with all of the normally
included actions and can use it just like all the others.

Overview of custom actions


An action is a wrapper that abstracts the functionality of its underlying activity in SharePoint Designer. At run time, the underlying activity, not the action itself, is executed in the Windows
Server AppFabric. In this sense, actions are just design-time abstractions of underlying functions in the SharePoint Designer workflow authoring environment (in addition to being elements
of the SharePoint Designer using interface.
Like all actions, custom actions are "web scoped"—that is, they are activated at the level of the SharePoint website, or SharePoint.SPWeb instance.
Actions are defined in XML definition files that have the .actions4 file name extension. The underlying activity (or activities), on the other hand, are defined in a XAML file.

Writing custom activities in Visual Studio 2012


Visual Studio 2012 now provides a "workflow custom activity" item type within SharePoint projects. You can use the item type to create a custom activity that you can then import as a
custom action in SharePoint Designer 2013.

Example: Create, package, and deploy a custom activity


To create a workflow custom activity
1. Begin by opening Visual Studio 2012 and creating a new Visual C# project of type SharePoint Project, as shown in Figure 1.
Figure 1. New Project dialog box
1. In Solution Explorer, right-click the project name node, and choose Add, New Item. This opens the Add New Item dialog box, as shown in Figure 2.
Figure 2. Add New Item dialog box

1. In the Add New Item dialog box, choose the Workflow Custom Activity item type and give it a meaningful name. In the illustration, the name is "WorkflowActionsModule1". Then
choose Add. The new item is created, and you are presented with the activity design surface.
2. If the Toolbox tab is not already showing, click it to expose the toolbox nodes. Click the SharePoint Workflow node to show the workflow development objects. There is a partial
view of objects in the workflow toolbox in Figure 3.
Figure 3. Partial view of SharePoint workflow toolbox
1. Add new action (.actions4) and activity (.xaml) files to your workflow module, as needed. To add these files, right-click the actions module icon in Solution Explorer, choose Add, and
then choose either Add Action (to add a new action4 file) or New Activity (to add a new activity), as appropriate.
After you create your actions module and add your action and activity files, your project should look something like that depicted in Figure 5. You will see one .actions4 file for each action
that you added, and one .xaml file for each activity. Additionally, you will have an Elements.xml file and the module's .xaml file.
Figure 5. Workflow actions module in Solution Explorer

After you create your custom workflow activity, you can then package and deploy it. After it is deployed, the custom activity can be consumed by SharePoint Designer 2013 as a custom
action.
Custom actions are packaged and deployed as SharePoint Features in SharePoint solution package (.wsp) files. The solution package contains a custom actions module, which is a set of files
that are deployed on SharePoint. This module can contain any number of workflow activity definitions, each of which is a .xaml file. The module also contains actions (.actions4) files. Each
actions file contains multiple actions that refer to the activities in the module, or to native activities that are available on a default SharePoint installation.
After a solution package (.wsp) file is uploaded and activated on the target website (that is, the SharePoint site collection), the features that are contained in the package are installed and
available for activation. After the custom actions are activated, they are available for use in a workflow.

Updating and deleting custom actions


After your custom action is deployed, you can update or remove it very easily. All you have to do is open the activity project in Visual Studio, make the changes that you want, and then
package and redeploy as described in the preceding procedure. To remove the custom action, you can just uninstall the feature on the target site collection.

Feature activation
Activating a custom action feature on a site collection (that is, on an SPWeb instance) succeeds only if the Azure/ Workflow Manager Client 1.0 (the multitenant workflow engine) is correctly
configured. Two troubleshooting hints that may help ensure a correct configuration include:
Going to the Site Features page and ensuring that the feature that contains the custom action is activated.
Querying the Workflow Manager Client 1.0 database to ensure that the activity is successfully deployed.

See also
SharePoint workflow fundamentals
Workflow actions and activities reference for SharePoint
Develop SharePoint workflows using Visual Studio
Use workflow interop for SharePoint
3/26/2018 • 4 minutes to read Edit Online

Provides a discussion of using SharePoint workflow Interop in the Visual Studio 2012 workflow designer. Workflow interop allows you to invoke a SharePoint 2010 workflow from within a
SharePoint workflow. This is an important feature that allows you to reuse existing workflow features, and to call on workflow activities that are not integrated into SharePoint.

Important: To learn about using SharePoint workflow interop functionality in SharePoint Designer 2013, see Understanding Coordination actions in SharePoint Designer 2013.

SharePoint workflow interop


Here's the problem. You have legacy SharePoint 2010 workflows that you wish to reuse on your SharePoint platform. Or, worse, you are creating new SharePoint workflows and you need to
invoke activities that are only available in the SharePoint 2010 platform. And you don't know what to do. Actually, the solution is simple: use SharePoint workflow Interop.
SharePoint workflow interop enables SharePoint 2010 workflows (built on Windows Workflow Foundation 3) to work smoothly with the SharePoint workflow engine, which is based on
Windows Workflow Foundation 4. While the new Windows Workflow Foundation 4 execution engine is hosted in Workflow Manager, which runs as an external service, SharePoint still
contains the legacy SharePoint workflow host which it uses to process SharePoint 2010 workflows. SharePoint workflow interop negotiates the two execution environments, as depicted in
Figure 1.
Figure 1. SharePoint workflow interop in action

Let's walk through the process depicted in Figure 1. Use the letters to reference points of emphasis in the illustration:

( A ) An instance of a SharePoint workflow starts to run in then Windows Workflow Foundation 4-based Workflow Manager. Note that the Workflow Manager is not in SharePoint, but
instead runs as an external service.
( B ) You reach a point in the SharePoint workflow - step number 3 in the Workflow Manager - where you wish to invoke a SharePoint 2010 workflow. In the Visual Studio 2012
workflow designer, you do this by implementing the Start 2010 WF activity, as shown in Figure 2.

Figure 2. Stage tile for starting a SharePoint 2010 workflow.

From the perspective of the SharePoint object model, this is accomplished using the [StartWorkflow](https://msdn.microsoft.com/library/Microsoft.SharePoint.WorkflowServices.WorkflowInteropServic

( C ) At this point, the SharePoint 2010 workflow begins executing in the Windows Workflow Foundation 3.5 workflow host inside of SharePoint. But an important consideration comes
up. In some scenarios you may want the 2013 workflow to wait for the 2010 workflow to complete running (and perhaps return some data) before continuing to execute the 2013
workflow. In other scenarios, this may not be necessary and both workflows may run independently, in parallel.

To control this behavior, the [WorkflowInterop](https://msdn.microsoft.com/library/Microsoft.SharePoint.WorkflowServices.Activities.WorkflowInterop.aspx) class, which controls executing workflow

Figure 3. Start a Workflow properties dialog box.


( D ) The practical effect of selecting true or false on the Wait property (or Yes or No in the properties dialog box) is depicted here. If Wait is true, then the 2010 workflow passes a
WorkflowCompleted event (and, optionally, returns data as a DynamicValue property). For more information about dynamic values, see Understanding Dynamic Value.

Of course, if **Wait** is set to **false**, then your 2010 workflow executes, then terminates normally.

( E ) This step is only relevant if your invocation of the 2010 workflow specified Wait=true. In that case, your 2013 workflow received the WorkflowCompleted event and restarts the
workflow 2013 execution at the point it left off.
( F ) Your 2013 workflow then completes execution and terminates normally. If Wait=false, then your 2013 workflow executes and terminates independently of the 2010 workflow.

Workflow interop design


SharePoint workflow interop is a messaging framework that supports a one-to-one instance mapping between WF 3 and WF 4 workflow activities. WF 3 and WF 4 interoperate through
message exchanges that are wrapped by a set of WF 4 activities on WorkflowInteropService .
To support workflow interop, the workflow design surface in SharePoint Designer provides access to a new workflow activity, Start 2010 WF, which is a wrapper on the StartWorkflow
method. This activity allows you to start either a list workflow or a site workflow.
The activity is in fact a sequence of messages that take place between the Workflow Manager and the SharePoint 2010 Workflow Host that is running inside SharePoint. These two are
mediated by a messaging layer, as shown in Figure 4. The sequence begins in the SharePoint workflow manager with an invocation of the StartWorkflow method. The "start" message goes
to the workflow service inside of SharePoint, where in turn it launches the workflow inside the SharePoint 2010 workflow host. When execution of the 2010 workflow is complete, an event is
fired that sends a "completed" message through the event publisher back to the 2013 workflow manager.
Figure 4. SharePoint workflow interop messaging protocol

See also
Get started with workflows in SharePoint
SharePoint workflow fundamentals
Understanding Coordination actions in SharePoint Designer 2013
WorkflowInteropService
WorkflowInteropEventReceiver
Common error messages in SharePoint workflow development
3/26/2018 • 5 minutes to read Edit Online

A listing of common error messages that you might encounter while developing SharePoint workflows and guidance for solving the underlying problem.

Common SharePoint workflow errors


Although this list doesn't cover every possible error you may encounter when developing SharePoint workflows, it does cover those that you are most likely to face.
Timeout while waiting for sandboxed code execution request to complete within the worker process
Timeout while waiting for request to complete within the sandboxed appdomain
The worker process handling this request was ended because it exceeded the resource {0}
This workflow could not run because a sandboxed solution encountered an error
This workflow could not run because the sandbox failed: Could not get a process from the process pool
This workflow could not run because the sandbox failed: The sandboxed code worker process exited unexpectedly
The e-mail message cannot be sent. Make sure the outgoing e-mail settings for the server are configured correctly
The workflow could not update the item, possibly because one or more columns for the item require a different type of information
The workflow operation failed because the workflow lookup found no matching item
The workflow could not create the list item because the file name is either missing or invalid
Coercion Failed: Unable to transform the input lookup data into the requested type
The workflow operation failed because the action requires the document to be checked out
Errors were found when compiling the workflow. The workflow files were saved but cannot be run. Unexpected error on server associating the workflow

Timeout while waiting for sandboxed code execution request to complete within the worker process
Same issue and same solution as the item below, "Timeout while waiting for request to complete within the sandboxed appdomain".

Timeout while waiting for request to complete within the sandboxed appdomain
Both of these errors result from the same issue—exceeding the default timeout period for the workflow action to execute. The default timeout period is 30 seconds.
You can change the timeout value in on-premises installations, but you can't change it in SharePoint Online installations. To avoid getting this error in SharePoint Online installations, you
must modify your code to limit actions in the worker process or appdomain to fewer than 30 seconds.
To modify the timeout period in your on-premises installation, execute the following Windows PowerShell command. Note that the example code resets the timeout to 60 seconds, but you
can use another value.

Add-pssnapin microsoft.sharepoint.powershell
$userCodeSvc = [Microsoft.SharePoint.Administration.SPUserCodeService]::Local
#change to 60 second timeout
$userCodeSvc.WorkerProcessExecutionTimeout = 60
$userCodeSvc.Update()

The worker process handling this request was ended because it exceeded the resource {0}
In the error string, the value of {0} is a placeholder for the specific resource whose threshold has been exceeded. To alleviate this problem, you should modify your code so that it does not
exceed the resource threshold. These resource values are documented in Resource Usage Limits on Sandboxed Solutions in SharePoint 2010.

This workflow could not run because a sandboxed solution encountered an error
The workflow code threw an unhandled exception. Resolving this error requires debugging and revising your sandboxed code.

This workflow could not run because the sandbox failed: Could not get a process from the process pool
There is an error in your sandbox configuration. For information about configuring a sandboxed solution, see Sandboxed Solutions in SharePoint.

This workflow could not run because the sandbox failed: The sandboxed code worker process exited unexpectedly
There is an error in your sandbox configuration. For information about configuring a sandboxed solution, see Sandboxed Solutions in SharePoint.

The e-mail message cannot be sent. Make sure the outgoing e-mail settings for the server are configured correctly
There are two issues of note to consider when troubleshooting email issues. In both on-premises and SharePoint Online installations, ensure that all addresses on the To: and Cc: lines are
valid email addresses. In on-premises installations, ensure that email settings on the server are configured correctly.
Review the following to ensure that you have correctly configured incoming and outgoing emails.
Deployment guide for Microsoft SharePoint
How to configure Incoming and Outgoing emails in SharePoint Server

The workflow could not update the item, possibly because one or more columns for the item require a different type of information
This error commonly results from one of two situations:
One of the list fields was removed or changed, but the workflow was not updated to account for the change and is therefore trying to set a value for the old field. You should check all
Update List Item actions in your workflow and make sure they are setting appropriate values for fields and that those fields exist on the list.
There is a data type error wherein the workflow is trying to set a value in a field in the list item using the wrong data type. You should confirm that the Return Field As operation in
their lookup is of the correct data type.
The workflow operation failed because the workflow lookup found no matching item
This indicates there is an error in the workflow logic. Check to ensure that you are selecting the correct list and field in your lookup.

The workflow could not create the list item because the file name is either missing or invalid
This indicates there is an error in the workflow logic. Ensure that the file name entered in the Path and Name field is a valid file name. Common reasons for a file name to be invalid include
a missing or incorrect file extension or a file/path string that is too long and exceeds the allowable number of characters.

Coercion Failed: Unable to transform the input lookup data into the requested type
The operation failed to cast values between incompatible data types (for example, converting a random string to a Date/Time value). You should check the Return Field As settings in your
lookup to ensure that it is a valid data type for the expected data.

The workflow operation failed because the action requires the document to be checked out
You must check out the item using the Check Out Item action before using the Update Item action.

Errors were found when compiling the workflow. The workflow files were saved but cannot be run. Unexpected error on server associating the workflow
See Microsoft Support Knowledge Base article ID 2557533 ( http://support.microsoft.com/kb/2557533 ) for more information.

See also
SharePoint workflow development best practices
Develop SharePoint workflows using Visual Studio
SharePoint workflow object model
3/26/2018 • 2 minutes to read Edit Online

Get a brief introduction to the workflow object model in SharePoint.

SharePoint workflow object model


The SharePoint object model is built on top of the .NET Framework 4 object model for Windows Workflow Foundation 4, but with innovations that enable workflow functionality in
SharePoint generally, and in SharePoint Add-ins in particular. The native .NET Framework 4 object model for Windows Workflow Foundation 4 is located in the .NET Framework
System.Workflow namespaces.
One way to think of the SharePoint workflow object model is as a set of workflow services. There are four services:
Instance management service: Manages workflow instances and their execution.
Deployment service: Manages the deployment of workflow definitions.
Interop service: Manages the interop bridge for supporting legacy workflows.
Messaging service: Manages message queuing and transport.

SharePoint workflow namespaces


The SharePoint workflow object model, on the other hand, is contained in ten namespaces: five of them are SharePoint namespaces, and five others are Microsoft Office namespaces.
Microsoft.SharePoint namespaces:
Microsoft.SharePoint.Workflow
Microsoft.SharePoint.Workflow.Application
Microsoft.SharePoint.WorkflowActions
Microsoft.SharePoint.WorkflowActions.WithKey
Microsoft.SharePoint.WorkflowServices
Microsoft.SharePoint.WorkflowServices.Activities
Microsoft.Office namespaces:
Microsoft.Office.Workflow
Microsoft.Office.Workflow.Actions
Microsoft.Office.Workflow.Feature
Microsoft.Office.Workflow.Routing
Microsoft.Office.Workflow.Utility

SharePoint workflow schemas


Reference content for SharePoint schemas is contained in the reference node entitled Workflow schemas, and contain the following:
WorkflowActions4 schema reference
WorkflowActions3 schema reference
Workflow configuration schema reference
WorkflowInfo schema reference

See also
A Developer's Introduction to Windows Workflow Foundation (WF) in .NET 4
Windows Workflow Foundation 4.0: Hello, workflow!
Windows Workflow Foundation (WF) Screencasts
Workflow actions and activities reference for SharePoint
Develop SharePoint workflows using Visual Studio
Workflow development in SharePoint Designer and Visio
3/26/2018 • 13 minutes to read Edit Online

Learn to use Visio 2013 and SharePoint Designer 2013 to create and publish workflows to a SharePoint site without needing any code.

Introduction
Visio 2013 and SharePoint Designer 2013 make it easy for business analysts, process consultants, and IT professionals to collaborate and build workflows. Both Visio Professional 2013 and
the Visual Designer in SharePoint Designer 2013 provide a rich representation of workflows in a format that is understandable to programmers and non-programmers alike.
NOTE

For guidance on setting up and configuring SharePoint and the Workflow Manager server, see Configure workflow in SharePoint.
By using Visio 2013, you can visually create a SharePoint workflow, export the workflow to SharePoint Designer 2013, and then publish that workflow to a SharePoint site. After a workflow
has been created in Visio 2013, it must be exported to SharePoint Designer 2013. Then, a SharePoint site owner or IT professional adds parameters to the workflow by using either the
workflow text editor or the new Visual Workflow Designer, which is a Visio 2013 ActiveX control that is hosted in SharePoint Designer 2013. After the workflow has been completed, it can
be published to the SharePoint site.
This is ideal for business analysts and process consultants who are already familiar with flowcharts in Visio, because it allows them to design a workflow that represents business logic. The
person who designs the workflow can focus solely on the business intelligence (BI) needs of the workflow without needing to be an expert in declarative workflows.

About creating SharePoint Workflows in Visio 2013 and SharePoint Designer 2013
Visio 2013 includes a SharePoint Workflow template that can be used to build SharePoint workflows. The SharePoint Workflow template is associated with three stencils: SharePoint
Workflow Actions, SharePoint Workflow Conditions, and SharePoint Workflow Terminators. The shapes in these stencils correspond to specific actions and conditions that can be used
within a SharePoint workflow. To build a workflow, you need only to drag shapes onto the drawing canvas in Visio 2013 to model the business logic behind the workflow.

Stages, loops, and steps


Workflows in SharePoint Designer 2013 now include the notions of stages, loops, and steps. Workflow authors can group a number of individual actions and conditions as a single unit to
more clearly define the process. For example, there could be an Approval or Request Feedback stage or step. Within that stage or step would be all of the actions that are necessary for that
process. The stage or step itself might be one node of a longer workflow and would allow a viewer to see the status of that stage as a whole, rather than a set of individual actions.
The SharePoint Workflow template that is included in Visio 2013 also uses stages, loops, and steps as logical building blocks for creating a workflow.

Important: Because of the underlying differences between the Microsoft SharePoint 2010 Workflow template and the SharePoint Workflow template, you cannot use shapes from one
template within a diagram created by the other. Only shapes from the SharePoint Workflow Actions, SharePoint Workflow Conditions, and SharePoint Workflow Terminators stencils can
be used to build a SharePoint workflow.

Stage shapes
A stage can contain any number of shapes and may include branching. However, there can be only one path into a stage (and a step) and one path out. All actions in the workflow must be
contained by a stage. Stage shapes are visualized by using container shapes. A Stage shape requires that an Enter and an Exit shape be added to the edges of the container to define the paths
in and out of the stage. Visio 2013 and the Visual Designer in SharePoint Designer 2013 add the Enter and Exit shapes for you when you first drop the container.
Stages also have the following rules:
All diagrams must have at least one stage. A stage, complete with Enter, Exit, and Start shapes are present as part of the default SharePoint Workflow template.
When you add a new stage to the drawing canvas, Visio 2013 will add Start and End connectors when the stage is dropped.
Stages cannot have any connectors coming in or going out other than through the Enter and Exit shapes.
Stage containers cannot be nested. If you want to nest another sub-process within a stage, use a step.
Stop Workflow shapes may exist within a stage.
An explicit Start shape is required outside of the stage for the entire diagram. An explicit Terminate shape outside of the stage is not required.
At the top level, the workflow can contain only stages, conditional shapes, and Start and Terminate terminators. All other shapes must be contained within a stage.

Loop shapes
Loops are a series of connected shapes that will execute as a loop, returning from the last shape in the series to the first, until a condition is satisfied.
Like stages, loops are represented by a container shape that includes an Enter and Exit shape (added when the shape is dropped on the drawing canvas). A Loop shape also requires that an
Enter and Exit shape be added to the edges of the container to define the paths in and out of the loop.
Visio 2013 and SharePoint Designer 2013 support two types of loops: loop n times and loop until value1 equals value2 .
Loops must also conform to the following rules:
Loops must be within a stage, and stages cannot be within a loop.
Steps may be within a loop.
Loops may have only one entry and one exit point.

Step shapes
Steps represent a grouped series of sequential actions. Steps must be contained by a stage. A step shape must also have an Enter and Exit shape to define the paths in and out of the shape.
Both shapes are added by default when the shape is dropped onto the canvas.

Creating a workflow in Visio 2013


All of the master shapes in the SharePoint Workflow stencils correspond to actions, conditions, and other logical constructs within a SharePoint workflow. To build a workflow, you can drag
shapes onto the drawing canvas, just like any other flowchart in Visio. After you have finished building the workflow in Visio 2013, save the workflow before SharePoint Designer 2013 can
open it.
To open the SharePoint Workflow template in Visio 2013, do the following:
To open the SharePoint Workflow template in Visio 2013
1. Open Visio 2013.
2. Choose New.
3. Under Template Categories, choose Flowchart.
4. Under Choose a Template, choose SharePoint Workflow and then choose Create.
The template opens and the drawing canvas is prepopulated with Start, and Stage shapes. The Stage shape contains an Enter and an Exit shape, joined by a single connector.
With the SharePoint Workflow template open, drag actions, conditions, and other shapes onto the drawing canvas to design a workflow. For more information about individual shapes and
what they mean, see the article Shapes in the SharePoint Server workflow template in Visio.

Tip: When designing a workflow, keep the following additional considerations in mind:
To quickly build a workflow, drop action and condition shapes onto the internal connector that is contained by new stage shapes. Visio 2013 automatically splits the connector into
additional connectors, keeping the workflow connected from the Enter shape to the Exit shape.
Do not use any shapes from a stencil other than the SharePoint Workflow Actions, SharePoint Workflow Conditions, and SharePoint Workflow Terminators stencils. Use only the
Connector tool provided by the SharePoint Workflow template to add connections between shapes. All other connector shapes are not valid within a SharePoint workflow.
Action shapes, steps, and loops must always be contained within a Stage shape. Some conditional shapes can be outside of a stage.
A Stage shape must have exactly one Enter shape and one Exit shape. The workflow sub-process that is contained within the stage must start with the Enter shape and end with the
Exit shape.
A condition shape must have two connectors leaving the shape, one labeled "Yes" and the other labeled "No." You can right-click a connector to choose Yes or No.
A workflow must have only one Start shape. The Start shape must be outside of a stage.
You add text to shapes in the workflow, but the shape text will not affect the workflow.

Validating the workflow in Visio 2013 is like validating any other connected diagram: Visio checks the diagram against a set of rules and returns a list of errors that it found in the diagram.
See the article Troubleshooting SharePoint Server workflow validation errors in Visio to learn how to resolve validation issues.

To validate a SharePoint workflow in Visio 2013


1. On the Process tab, in the Diagram Validation group, choose Check Diagram.
2. If any errors are found in the workflow, the Issues pane opens below the diagram. Choose each item in the list to select the shape in the diagram that caused the error.
3. Resolve each validation error listed in the Issues list. Once all of the errors have been addressed, choose Check Diagram again. For more information about how to resolve validation
issues in Visio 2013, see the article Troubleshooting SharePoint Server workflow validation errors in Visio.
4. If no errors are found in the workflow, Visio displays a message stating that the diagram validation is complete and that no issues were found.
After the workflow has been successfully validated in Visio 2013, you can save the file and import it into SharePoint Designer 2013. Unlike the Microsoft SharePoint 2010 Workflow
template, you can save a copy of the SharePoint Workflow diagram as the default Visio 2013 file format (.vsdx) and SharePoint Designer 2013 can open the file.
Use the following procedure to save a SharePoint workflow in Visio 2013 as a Visio 2013 .vsdx file that can be opened in SharePoint Designer 2013:

To save a workflow in Visio 2013


1. Choose File, and then choose Save As.
2. Under Save As, choose Save, and then choose Browse.
3. In the Save As dialog box, select a location to save the file and type a name for the file ("My SP Workflow").
4. Choose Save.

Customizing and publishing a workflow in SharePoint Designer 2013


Once you have created the underlying business logic for a SharePoint workflow in Visio 2013 and saved the diagram, you can open the Visio .vsdx file in SharePoint Designer 2013 and
begin tailoring the workflow to your SharePoint site. The .vsdx file package contains XML documents that SharePoint Designer 2013 can translate into workflows.
Use the following procedure to open a SharePoint site in SharePoint Designer 2013:

To open a SharePoint site in SharePoint Designer 2013


1. Open SharePoint Designer 2013.
2. Under Open SharePoint Site, choose Open Site.
3. In the Open Site dialog box, select the site that you want to open.
4. Choose Open.
Once the SharePoint site is open, you can open the Visio 2013 .vsdx diagram within SharePoint Designer 2013.

To open a Visio Professional 2013 workflow in SharePoint Designer 2013


1. Choose File, and then choose Add Item.
2. To create a List Workflow, do the following:
3. Under Workflows, choose List Workflow.
4. In the left pane under List Workflow, type a name for your workflow (My First SP2013 Workflow) and select the list on the site that you want to publish the workflow to.
5. In the Choose the workflow platform for the new workflow list, select SharePoint Workflow.
6. Choose Create.
7. To create a Site Workflow, do the following:
8. Under Workflows, choose Site Workflow.
9. In the left pane, under Site Workflow, type a name for your workflow (My First SP2013 Workflow).
10. In the Choose the workflow platform for the new workflow list, select SharePoint Workflow.
11. Choose Create.
12. On the Workflow tab, in the Manage group, choose Workflow Settings.
13. On the Workflow Settings tab, in the Manage group, choose Import from Visio.
14. In the Import Workflow from Visio Drawing dialog box, browse to the location where the .vsdx file is located.
15. Select the file that you want to open (My SP Workflow), and then choose Open.
When you open a .vsdx file in SharePoint Designer 2013, the file is displayed in the Visual Designer, a Visio ActiveX control that is hosted within SharePoint Designer. The Visio 2013
diagram retains all of the shapes and shape text that was created in Visio.
NOTE

To switch between the Visual Designer and the Declarative Designer in SharePoint Designer 2013, on the Workflow tab, in the Manage group, choose Views. This process may take a few
moments, as SharePoint Designer 2013 validates the workflow and then converts the workflow information from one format to another. During this process, another shape level validation
will occur. If any errors are detected with the diagram, the errors will be displayed in an error pane at the bottom of the canvas ( just like in Visio).
The shapes that are displayed in the Visual Designer also have Action Tags (shown by a workflow settings type icon on the bottom left hand side of the shape). When you choose an Action
Tag, a drop-down menu displays the attributes for that action or condition in the workflow and Properties property. These properties will define the parameter values to be used for that
action: which lists to pull items from, what calculation operator to use, or which email address to send a message to. When you choose a property that is displayed in the list, a dialog box
appears in which you can customize the settings for that property.
For example, the Send an email shape has two properties associated with it: Create Email and Properties. When you choose Create Email, a Define Email Message dialog box appears
in which you can create the message to be sent by the action. If you choose Properties, a Send an Email Properties dialog box appears that displays all of the parameters for the action.
NOTE

For more information about individual actions, shapes, and their properties, see the articles Shapes in the SharePoint Server workflow template in Visio and Workflow actions quick
reference (SharePoint Workflow platform.md).
Once you have set the properties within the workflow and are ready to publish, you must first check the workflow for errors in SharePoint Designer 2013. When you choose Publish in the
Visual Designer tab in the ribbon, SharePoint Designer 2013 automatically checks the workflow for errors. If you want, you can also manually initiate the error checking.
Use the following procedure to check the SharePoint workflow in SharePoint Designer 2013:

To manually check a workflow for errors in SharePoint Designer 2013


1. On the Visual Designer tab, in the Save group, choose Check for Errors.
2. If any errors are found in the workflow, the Issues pane opens below the Visual Designer canvas. Choose each item in the list to select the action, condition, connector, terminator, or
container in the workflow that caused the error.
3. Resolve each validation error listed in the Issues list. Once all of the errors have been addressed, choose Check for Errors again.
4. If no errors are found in the workflow, SharePoint Designer displays a message stating that no issues were found in the workflow.
After the workflow has been checked and no issues have been found, you can publish the workflow to the SharePoint list. To publish the workflow from SharePoint Designer 2013, on the
Visual Designer tab, in the Save group, choose Publish. If any errors occur during the publishing process, SharePoint Designer 2013 returns to the Visual Designer and displays the errors
in the Issues pane.

See also
For more information, see the following resources:
Workflow actions quick reference (SharePoint Workflow platform)
Shapes in the SharePoint Server workflow template in Visio
Troubleshooting SharePoint Server workflow validation errors in Visio
Create, import, and export SharePoint workflows in Visio 2010
SharePoint Developer Center
Visio Developer Center
What's changed in SharePoint Designer 2013
5/3/2018 • 2 minutes to read Edit Online

Learn about features that are deprecated in or removed from SharePoint Designer 2013. Features that are deprecated are included in the SharePoint release for compatibility with previous
product versions but will be removed from future versions.

Discontinued features in SharePoint Designer 2013


The following features are deprecated in SharePoint Designer 2013 or have been removed.

SharePoint 2010 Workflow platform


Description of the change. Some features of the SharePoint 2010 Workflow platform that are dependent on Windows Workflow Foundation 3.0 are deprecated in SharePoint.
Reason for the change.SharePoint introduces a new SharePoint Workflow platform that is built upon Windows Workflow Foundation 4.0 and that is integrated with Workflow Manager
1.0.
Migration path. In SharePoint Designer 2013, you can still create a SharePoint 2010 Workflow and use all of the SharePoint 2010 Workflow features by choosing the SharePoint 2010
Workflow platform.
You can also integrate features from the SharePoint 2010 Workflow platform into the new SharePoint Workflow platform. To do this, create a SharePoint 2010 Workflow by choosing the
SharePoint 2010 Workflow platform; create a SharePoint Workflow by choosing the SharePoint Workflow platform; and then use the Start a list workflow and Start a site workflow
actions in the SharePoint Workflow to call the SharePoint 2010 Workflow.
The following features are available only on the SharePoint 2010 Workflow platform:
Actions:
Stop Workflow
Capture a Version of the Document Set
Send Document Set to Repository
Set Content Approval Status for the Document Set
Start Document Set Approval Process
Declare Record
Set Content Approval Status
Undeclare Record
Add List Item
Inherit List Item Parent Permissions
Remove List Item Permissions
Replace List Item Permissions
Lookup Manager of a User
Assign a Form to a Group
Assign a To-Do Item
Collect Data from a User
Start Approval Process
Start Custom Task Process
Start Feedback Process
Copy List Item (SharePoint Designer 2013 supports only the document-copying action.)
Conditions:
If current item field equals value
Check list item permission levels
Check list item permissions
Steps:
Impersonation Step:
Data sources:
User Profile lookup
Other features:
Visio integration
Association Column
Content Type Association for reusable workflow
'Require Manage List/Web Permission' feature for list/site workflow
Globally reusable workflow type
Workflow visualization option
SharePoint page-design features
The following feature is not available in SharePoint.
Design view and Split view
Description of the change.SharePoint Designer 2010 has three views for editing HTML and ASPX pages: Code view, Design view, and Split view. Design view and Split view are removed
from SharePoint Designer 2013. The removal of Design view and Split view affects the features of SharePoint Designer 2013 that are used for editing web parts and master pages. If you
edit pages in SharePoint Designer 2013, you must use Code view.
Reason for the change. Compared to current versions of Internet Explorer, Design view is an older technology that does not support many new HTML5 and CSS tags.
Migration path. If you edit pages in Code view, you can press F12 to preview the page in the browser. Alternatively, you can use Visual Studio to edit pages.
If you want to visually design or brand your site, and you want a WYSIWYG ("what you see is what you get") page-editing experience, you can use any professional HTML editor, such as
Microsoft Expression Web. Then you can import your HTML files into SharePoint by using the new Design Manager, which is a feature included in publishing sites, such as the Publishing
Portal Site Collection site template.

See also
Workflow actions quick reference (SharePoint Workflow platform)
Changes from SharePoint 2010 to SharePoint
What's new in workflow in SharePoint
Creating a workflow by using SharePoint Designer 2013 and the SharePoint Workflow platform
3/26/2018 • 2 minutes to read Edit Online

Learn how to install, open, and create a workflow by using SharePoint Designer 2013 and the SharePoint Workflow platform.

Install SharePoint Designer 2013


SharePoint Designer 2013 is a free download. To download and install SharePoint Designer 2013 follow these steps:

To install SharePoint Designer 2013


1. Open your web browser and navigate to the Microsoft Download Center: http://www.microsoft.com/download.
2. Type SharePoint Designer 2013 in the search field.
3. Click the link for "SharePoint Designer 2013".
4. Read the overview, system requirements, and installation instructions. Make sure your system is compatible.
5. Select your platform type: 64-bit ( x64) or 32-bit ( x86) as shown in the figure.
6. Follow the instructions to install SharePoint Designer 2013.
Figure: SharePoint Designer 2013 download page

Open SharePoint Designer 2013 and connect to a SharePoint site


SharePoint Designer 2013 installs as an Office 2013 application. To open SharePoint Designer 2013 and connect to a SharePoint site follow these steps:
2013

To open SharePoint Designer 2013 and connect to a SharePoint site


1. Open SharePoint Designer 2013 by selecting it on the Start menu. Click Start icon, click All Programs, click Microsoft Office 2013, and then click SharePoint Designer 2013.
2. Click Open Site on the SharePoint Designer 2013 start page.
3. Enter the SharePoint site that you want to connect to. For example, http://www.contoso.com/sites/a-sharepoint-site.
4. Click Open to open the site.
5. Enter your credentials, if prompted. (If security is not integrated with the computer you signed in on then you are prompted to enter your credentials.) Make sure to use credentials
that have access to the SharePoint site.

Create a List workflow based on the SharePoint Workflow platform


SharePoint Designer 2013 can be used for many important tasks. The navigational pane is used to switch between different aspects of SharePoint Designer 2013. To create a new List
workflow based on the SharePoint Workflow platform, follow these steps:

To create a workflow based on the SharePoint Workflow platform


1. Click the Workflows node in the Navigation pane.
2. Click the List Workflow drop-down in the New section of the ribbon, as shown in the figure.
3. Select the list that you want to associate with the new workflow.
4. On the Create List Workflow dialog box, enter a name and description for the workflow and then make sure that the Platform Type is set to SharePoint 2013 Workflow, as shown
in the figure.
NOTE

If you do not see SharePoint Workflow as an available platform type then Workflow Manager is not configured to work with the SharePoint farm. See Configure Workflow Manager
to work with the SharePoint Server 2013 Farm.
5. Click OK to create the workflow.
Figure: The ribbon button for creating a new list workflow

Figure: Create List Workflow dialog box

Now that the workflow is created, you can add Actions, Conditions, Stages, Steps, and Loops to build your workflow. These workflow components are available in the ribbon of SharePoint
Designer 2013, as shown in the figure.
Figure: Workflow items for the SharePoint Workflow platform

NOTE

The previous procedure is used to create a List workflow. A Reusable workflow or Site workflow can be created using the same procedure with the following modification. Instead of
selecting the List Workflow button in the ribbon select the Reusable Workflow or Site Workflow button when creating the workflow.
To learn more about the available components of workflow development, see Workflow actions quick reference (SharePoint Workflow platform).

See also
What's new in workflow in SharePoint
Getting started with SharePoint workflow
Workflow development in SharePoint Designer and Visio
Shapes in the SharePoint Server workflow template in Visio
3/26/2018 • 11 minutes to read Edit Online

Learn about the shapes in the SharePoint Workflow template in Visio 2013.

Introduction
This article lists the shapes contained in the SharePoint Workflow template in Visio 2013 and in the Visual Designer in SharePoint Designer 2013. When the template is opened, also opens
the SharePoint Workflow Actions, SharePoint Workflow Conditions, and SharePoint Workflow Terminators stencils. Many of the shapes listed in the stencils correspond to specific actions,
conditions, or other logical constructs in the Declarative Designer for building workflows in SharePoint Designer 2013.

Important: The following is a reference for workflow actions that are supported in SharePoint Designer 2013. Most of these actions are available in SharePoint Designer 2010, although
one of those (Wait for List Item Event) has been revised and enhanced in the present version. Twelve new actions are introduced in the present version, and 25 actions have been
removed. (To see a list of actions, conditions, and blocks that have been removed, see Workflow actions available using the workflow interop bridge..md)

Action shapes
The following table shows a list of all the shapes that are contained in the SharePoint Actions stencil in the SharePoint Workflow template in Visio 2013.

Note: Each shape listed in the following table will have the properties listed and a Properties property.

S HAPE IN V IS IO 2 0 1 3 AND S HAR EPO INT ACTIO N IN THE S HAR EPO INT D ES IG NER 2 0 1 3 PR O PER TIES IN S HAR EPO INT D ES IG NER 2 0 1 3
D ES IG NER 2 0 1 3 V IS U AL D ES IG NER D ECL AR ATIV E D ES IG NER V IS U AL D ES IG NER D ES CR IPTIO N

Add a Comment Add a Comment Comment Enables you to leave informative comments in the
workflow designer for reference purposes. This is
especially helpful when there are other users
collaborating on the workflow.

Add Time to Date Add Time to Date Months Adds a specific time in minutes, hours, days, or
Days months to a date, and stores the output value as
Hours a variable. The date can be a current data, specific
Minutes date, or a lookup. The 'Current Date' value returns
Date UTC midnight.
Output

Assign a Task Assign a Task Task Settings Assigns a workflow task to a user and establishes
Task Outcome a due date for completion of the task.
Task Item ID

Call HTTP web service Call HTTP Web Service HTTP Request Functions as a method call to a HTTP web service.
Parameters Note: The current build supports SharePoint calls
Response Content Variable only to anonymous HTTP services and only using
Response Header Variable string parameters and return types. Also, we do
Response Code Variable not support composite XML elements. Note, too,
that we currently support classic ASMX only and
do not provide support for the WCG service.

Check In Item Check In Item Item Checks in an item that is checked out. You can
Comment check in items only from a document library.
Caution: The workflow crashes if you try to check
in an item that is not checked out.

Check Out Item Check Out Item Item Checks out an item. The workflow verifies whether
the item is checked in before it checks out a
document. You can check out items only from a
library in your site.
Caution: The workflow crashes if you try to check
out an item that is not checked in.

Copy document Copy Document Document Copies a document from the current list to a
Library different Document Library list.

Count items in dictionary Count Items in a Dictionary Dictionary Counts the number of items in a dictionary
Output Variable variable.

Create a project from current item Create Project From Current Item Enterprise Project Type Takes the current item and creates a new project
in the SharePoint farm PWA site.

Create List Item Create List Item Item Creates a new list item in the list that you specify.
Output Variable You can supply the fields and values in the new
item. You can use this action whenever you want
a new item to be created with specific
information.

Delete Item Delete Item Item Deletes an item.


Note: This action is terminated on the computer
running the Workflow Manager workflow engine
and throws a
System.InvalidOperationException exception.
There is no workaround.
S HAPE IN V IS IO 2 0 1 3 AND S HAR EPO INT ACTIO N IN THE S HAR EPO INT D ES IG NER 2 0 1 3 PR O PER TIES IN S HAR EPO INT D ES IG NER 2 0 1 3
D ES IG NER 2 0 1 3 V IS U AL D ES IG NER D ECL AR ATIV E D ES IG NER V IS U AL D ES IG NER D ES CR IPTIO N

Discard Check Out Discard Check Out Item Item Discards the changes and checks the item back in
if an item is checked out and changes have been
made to it.
Caution: The workflow crashes if you try to check
in an item that is not checked out.

Do Calculation Do Calculation LeftOperand Performs an arithmetic calculation and stores the


Operator output value in a variable.
RightOperand Note: For SharePoint, this action supports only
To the Double numeric type. Integers are not
supported. Use of the "+" operator
(concatenation) for strings is not supported.

Extract Substring from End of String Extract Substring from End of String Number of Characters Copies a specified number of characters starting
String from the end of a string and stores the output in
Output a variable.

Extract Substring from Index of String Extract Substring from Index of String String Copies a substring starting at a specified index in
Index the string and places the value in a variable.
Output Note: Be aware that although the index value in
the present Technical Preview build of SharePoint
Designer is zero-based, values in SharePoint
Designer 2010 were indexed starting at 1.

Extract Substring from Start of String Extract Substring from Start of String Number of Characters Copies a specified number of characters
String beginning at the start of a string and stores the
Output output in a variable.

Extract Substring of String from Index with Length Extract Substring of String from Index with String Copies out a substring comprising a specified
Length Index number of characters, starting at a specified index
Number of Characters in the string, and places the value in a variable.
Output Note: Be aware that although the index value in
the present Technical Preview build of SharePoint
Designer is zero-based, values in SharePoint
Designer 2010 were indexed starting at 1.

Find Interval Between Dates Find Interval Between Dates Units Calculates the time interval in minutes, hours, or
Start Date days between two dates and stores the output in
End Date a variable.
Output

Find substring in string Find Substring in String Substring Finds a particular substring inside of a string and
String returns the index of the substrings's starting
Output position.

Get item from dictionary Get Item From Dictionary Item Name of Path Returns a particular item from a dictionary
Dictionary variable.
Output Variable

Log to History List Log to History List Message Writes a message from a list of predefined
message items to the workflow history list.

Pause for Duration Pause for Duration Days Causes a workflow to pause executing for a
Hours specified time interval, in days, hours, and
Minutes minutes.

Pause until Date Pause Until Date Date Causes a workflow to pause executing until a
specified date and time.

Replace substring in String Replace Substring in String Search String Replaces a particular substring with another
Replace String substring.
String
Output

Send an Email Send an email Email Automatically sends an email message that
contains a predetermined message to a user or
group when a specified workflow event occurs.
Important: If the site is not added to the Trusted
Sites list then emails are routed to the Outlook
Junk folder.

Set field in Current Item Set Field in Current Item Field Sets a field in the current item to a value.
Value

Set Time Portion of Date/Time Field Set Time Portion of Date/Time Field Hours Creates a timestamp, and stores the output value
Minutes in a variable. You can set the time in hours and
Date minutes and add a current date, specific date, or
Output lookup.

Set workflow status Set Workflow Status Status Sets the status of the workflow.

Set Workflow Variable Set Workflow Variable Variable Sets a workflow variable to a value. You can also
Value use this action when you want the workflow to
assign data to a variable.
S HAPE IN V IS IO 2 0 1 3 AND S HAR EPO INT ACTIO N IN THE S HAR EPO INT D ES IG NER 2 0 1 3 PR O PER TIES IN S HAR EPO INT D ES IG NER 2 0 1 3
D ES IG NER 2 0 1 3 V IS U AL D ES IG NER D ECL AR ATIV E D ES IG NER V IS U AL D ES IG NER D ES CR IPTIO N

Start a list workflow Start a List Workflow Association Name Starts a SharePoint 2010 List workflow.
Inputs Note: The Start a list workflow has the following
Item issues:
The 'Assignments' type field cannot be
used as a parameter when the 2010
workflow has a TaskProcess action in it.
When multiple calls are made to the same
2010 workflow the result will be multiple
data sources in the 2013 workflow lookup
functionality. These data sources are all the
same.
Variable names in 2013 cannot contain
special characters such as '?' and '#'. If a
2010 workflow contains special characters
then they will be converted to
hexadecimal code in the 2013 workflow.

Start a site workflow Start a Site Workflow Association name Starts a SharePoint 2010 Site Workflow.
Parameters Note: The Start a list workflow has the following
issues:
The 'Assignments' type field cannot be
used as a parameter when the 2010
workflow has a TaskProcess action in it.
When multiple calls are made to the same
2010 workflow the result will be multiple
data sources in the 2013 workflow lookup
functionality. These data sources are all the
same.
Variable names in 2013 cannot contain
special characters such as '?' and '#'. If a
2010 workflow contains special characters
then they will be converted to
hexadecimal code in the 2013 workflow.

Start a task process Start a Task Process Process Settings Creates tasks on multiple users and enables the
Process Outcome tasks to be taken through a customized process.

Translate document Translate Document Document Translates a document into a particular language
Language Note: Requires a preconfigured Machine
Document Library Translation Service Application.

Trim String Trim String String Removes white spaces from the beginning and
Output end of a string.

Update List Item Update List Item Item Updates a list item. You can specify the fields and
the new values in those fields.

Wait for Event in List Item Wait for Event in List Item Event [Enhanced version of Office 2010 action.] Pauses
Related Item the current instance of the workflow to await a
specified list item event. This action listens for two
events: ItemUpdated and ItemAdded.

Wait for field change Wait for Field Change Field Waits for a field on the current item to equal a
Value particular value.

Set Project Field Set Project Field Field Sets a value for a particular field on Project Server.
Value Note: This action requires the project to be
checked in first. If the project is not checked in,
the workflow will be terminated and users cannot
open that project in Project Web App.

Set Project Stage Status Set Project Stage Status Stage Status Sets the status of the Project Stage.
Stage Information Note: An exception occurs when a current project
is checked out.

Set status field in idea list Set Status Field in Idea List Status Updates the status on the original list item that is
associated to the current project.

Wait for Project Event Wait for Project Event Event Name Waits for a particular Project Event.

Condition shapes
The following table shows a list of all the shapes that are contained in the SharePoint Conditions stencil in the SharePoint Workflow template.

S HAPE IN V IS IO 2 0 1 3 AND S HAR EPO INT ACTIO N IN THE S HAR EPO INT D ES IG NER 2 0 1 3 PR O PER TIES IN S HAR EPO INT D ES IG NER 2 0 1 3
D ES IG NER 2 0 1 3 V IS U AL D ES IG NER D ECL AR ATIV E D ES IG NER V IS U AL D ES IG NER D ES CR IPTIO N

If Any Value Equals Value If any value equals value Value Compares two values. You can specify whether
Operand the values should be equal or not equal.
Value

Person is a Valid SharePoint User Person is a valid SharePoint user User Checks to see whether a specific user is a
registered user or a member of a group on the
SharePoint site.
S HAPE IN V IS IO 2 0 1 3 AND S HAR EPO INT ACTIO N IN THE S HAR EPO INT D ES IG NER 2 0 1 3 PR O PER TIES IN S HAR EPO INT D ES IG NER 2 0 1 3
D ES IG NER 2 0 1 3 V IS U AL D ES IG NER D ECL AR ATIV E D ES IG NER V IS U AL D ES IG NER D ES CR IPTIO N

Skip Project Stage Skip Project Stage NA This condition checks to see if the skip to stage
feature has been activated on the server for the
current workflow instance.

Terminator shapes
The following table shows a list of all the shapes that are contained in the SharePoint Terminators stencil in the SharePoint Workflow template.

S HAPE IN V IS IO 2 0 1 3 AND S HAR EPO INT ACTIO N IN THE S HAR EPO INT D ES IG NER 2 0 1 3 PR O PER TIES IN S HAR EPO INT D ES IG NER 2 0 1 3
D ES IG NER 2 0 1 3 V IS U AL D ES IG NER D ECL AR ATIV E D ES IG NER V IS U AL D ES IG NER D ES CR IPTIO N

Start NA NA Begins the workflow. Every SharePoint workflow


diagram must have only one Start shape.

Stage Stage NA Contains any number of shapes and may include


branching. All actions in the workflow must be
contained by a stage. Stage shapes are visualized
by using container shapes. A Stage shape requires
that an Enter and an Exit shape be added to the
edges of the container to define the paths in and
out of the stage.
For more information, see the section titled
"Stages, loops, and steps" in the article Workflow
development in SharePoint Designer and Visio.

Step Step NA Represents a grouped series of sequential actions.


Steps must be contained by a stage. A step shape
must also have an Enter and Exit shape, which are
added when the shape is dropped onto the
canvas.
For more information, see the section titled
"Stages, loops, and steps" in the article Workflow
development in SharePoint Designer and Visio.

Simple Stage Stage NA Adds new stages to the top level of the workflow
when in Stage View in Visio 2013.

Loop n Times Loop n Times Loop Count Defines a series of connected shapes that will
execute as a loop, returning from the last shape in
the series to the first, until the loop has executed
a specified amount of times. Like stages, loops are
represented by a container shape that includes an
Enter and Exit shape.
For more information, see the section titled
"Stages, loops, and steps" in the article Workflow
development in SharePoint Designer and Visio.

Loop with condition Loop with Condition Loop Count Loops until a specific condition is met.

Start Parallel Action Parallel Block NA

End Parallel Action Parallel Block NA

See also
Workflow development in SharePoint Designer and Visio
Workflow actions quick reference (SharePoint Workflow platform)
SharePoint Workflow template shapes guide
SharePoint Developer Center
Visio Developer Center
Troubleshooting SharePoint Server workflow validation errors in Visio
3/26/2018 • 7 minutes to read Edit Online

Use this reference to resolve validation and error-checking issues in the Microsoft SharePoint Workflow template in Microsoft Visio 2013 and Microsoft SharePoint Designer 2013.

SharePoint workflow validation issues


The following table lists all of the validation issues that can appear in the Issues pane in Microsoft Visio 2013 or the Visual Designer in Microsoft SharePoint Designer 2013. Each error has a
suggested action to take for resolving the problem.

ER R O R TE X T S U G G ES TED ACTIO N

Duplicate connections exist between workflow shapes. Remove the redundant connector by selecting and deleting it.

Loop back to parent shape is not allowed within a stage or step. Neither Visio Professional 2013 nor SharePoint Designer 2013 supports workflows with implicit loops
inside of a stage. Check your workflow for loops and delete the looping connections. If you want to
create a SharePoint workflow that includes a set of looping steps inside of a stage, you must use the
loop containers. Any actions inside of these containers will loop. Another option is to use stages that go-
to a previous stage.

Parallel activities that are also sequential are not allowed. Activities can be either parallel or sequential, but not both simultaneously. For parallel activities, remove
the sequential connectors. For sequential activities, remove the parallel connectors. Sometimes,
simultaneously parallel and sequential activities can be difficult to identify. The following validation errors
show other common instances of parallel and sequential arrangement and offer alternative
arrangements.
To avoid having connectors point to the same activity from multiple paths, try duplicating the activity.

The condition shape does not have connections labeled with Yes or No. Right-click the connector to assign the label "Yes" or "No."

The condition shape must have outgoing connections with label Yes and No. Ensure that condition shapes have outgoing connectors attached to other workflow shapes. Each
condition shape must have a "Yes" and a "No" outgoing connection.

The connector is not a SharePoint workflow connector. Use AutoConnect or the connector tool to Avoid reusing connectors from other diagrams as they are not necessarily designed to be used with
connect your shapes. SharePoint workflows. Delete the selected connector and use the connector tool or AutoConnect to
replace with a new connector.

The connector must be connected to two workflow shapes. Remove dead-end connectors or attach them to a second shape.

The diagram must only have one workflow and one Start shape. All paths must originate from the same Start shape. Remove extra Start shapes and arrange the
connectors so that the path starts in one place.

The shape is not a SharePoint workflow shape. Only SharePoint workflow shapes can be connected in a Only workflow shapes from the SharePoint Workflow stencils can be used in the Microsoft SharePoint
workflow. Workflow template. Other flowchart shapes are not recognized and prevent the workflow from being
exported to SharePoint Designer.

The Start shape must not have incoming connections. Remove the incoming connector to the Start shape.

The workflow must have a Start shape. Add a Start shape to the beginning of the workflow and connect it to the first activity.

The workflow shape is not connected to the workflow. If the workflow shape is necessary, add connectors to attach it to the workflow path. Otherwise, delete
the shape.

Workflow nesting levels must not exceed a maximum of 10. Visio 2013 can recognize a maximum of 10 levels of nesting workflow activities. Rearrange the workflow
to reduce complexity by eliminating activities or dividing the workflow path into more than one branch.

The start shape can only be connected to a workflow stage shape. All workflow diagrams must begin with only one Start shape. The Start shape must be connected to a
Stage shape. If necessary, add a Start shape to the beginning of the workflow. You can also add a Start
shape to the beginning of the workflow in Stage view in Visio 2013.

A stage cannot be nested within any other shape. Stages are top-level shapes in SharePoint workflow diagrams. You cannot place a shape within any other
container shape, including steps, loops, or other stages.
If possible, move the stage so that it is outside of all other container shapes and reconnect the stage. If
you want to create a logical grouping of actions and conditions within a stage or loop, use a Step shape
instead.

A stage can only be connected to another stage, condition shape, or a terminator. Stages can be connected only to other top-level shapes, including conditions, terminators, or other
stages. A stage cannot be connected to actions, steps, or loops at the top level. Rearrange the workflow
diagram so that the stage is connected only to other top-level shapes.

Stage, step, and loop containers cannot be overlapped. The boundaries of container shapes, such as stages, steps, and loops, cannot touch or overlap. If you
want to include one container shape within another (for example, include a loop within a stage), be sure
that the contained shape is entirely within the bounds of the container. If you do not want one container
shape to be contained by the other, space out the shapes in your diagram so that the bounds of the
container shapes no longer cross or touch each other.

Workflow shapes from other templates/versions are not valid workflow shapes. You can use shapes only from the SharePoint Workflow Actions, SharePoint Workflow Conditions, and
SharePoint Workflow Terminators stencils, and connectors that are created with AutoConnect or the
Connector tool associated with the template in a Microsoft SharePoint Workflow diagram. All other
shapes are not valid connections within the workflow validation rules. You can place other shapes on the
design canvas as long as they are not connected to the Workflow.
If you need to include an action or condition that is not represented with a shape in one of the stencils
associated with the Microsoft SharePoint Workflow template, consider creating a custom workflow
action. Custom workflow actions can be created in Microsoft Visual Studio 2012 and incorporated into
SharePoint workflows in SharePoint Designer 2013. For more information about how to create custom
actions in Visual Studio 2012, see the article Develop SharePoint workflows using Visual Studio.
ER R O R TE X T S U G G ES TED ACTIO N

A shape cannot be connected outside of the start/end path of the current shape's container. All shapes contained within a stage, loop, or step must be entirely contained within that container shape.
Shapes cannot connect to any shapes that are not contained in the same container. Rearrange the
workflow diagram so that all actions, conditions, loops, and steps within the container shape connect to
other shapes in the container.
If the shape must connect to an activity outside of the container, connect the shape to the Exit shape
associated with the container.

Invalid transition shape. When a non-condition or non-stage shape is added at the base level of the workflow. Only stages and
conditions may exist at the base level of a workflow. Any other shapes that are added to this level will
cause this error. You should encapsulate non-condition and non-stage shapes in a condition or stage
shape.

Stages, steps, and loops may have only one incoming and one outgoing connection. All container shapes can have only one incoming connector to the Enter shape that is associated with
them. Similarly, container shapes can have only one outgoing connector from their Exit shape. Rearrange
the diagram so that each container has a single incoming and outgoing path. You may need to add
additional stages or Junction shapes to the workflow to fix this error.

A stage name must be unique and cannot be empty. Each stage in the workflow must have a unique name. Switch to Stage view and be sure that each stage
has its own name.

The Project stage has not been configured. For Project based workflows, every stage must be linked to a stage on the Project Server. If a stage has
not been linked to a stage on the server, you will see this error. To correct this issue, open the Stage
property grid and set a stage from the stage drop-down.

A parallel activity must begin with a Start Parallel Branch shape. Check each parallel activity in the workflow to be sure that it has a Start Parallel Branch shape before the
parallel activity begins.

See also
Workflow development in SharePoint Designer and Visio
Shapes in the SharePoint Server workflow template in Visio
Workflow actions quick reference (SharePoint Workflow platform)
Create, import, and export SharePoint workflows in Visio 2010
SharePoint Developer Center
Visio Developer Center
Understanding Dictionary actions in SharePoint Designer 2013
3/26/2018 • 4 minutes to read Edit Online

The Dictionary variable type is a new variable type in the SharePoint Workflow platform that you can use with SharePoint Designer 2013.

Understanding the Dictionary variable type


A workflow is a series of actions that perform a desired outcome. As you build a workflow you often need to save values in a variable (storage container) to use in other parts of the
workflow.
When you create a variable you need to tell the workflow engine what type of data will be contained in the variable. For example, you might want to save the name of an employee in a
variable. The name of an employee is a string of characters so you would create a variable of type String. The workflow could then store the name of the employee, such as "John Doe," in
the variable.
Figure: A String variable

SharePoint Designer 2013 has a new variable type called Dictionary. The Dictionary variable type is a container designed to hold a collection of other variables. For example, your
workflow might need to store more than just the name of the employee. It might also need to store his address and birth date. If you do not use the Dictionary variable you will have to
create multiple stand-alone variables. This can quickly become difficult to organize and difficult to work with in the logic of the workflow. A Dictionary variable allows you to store multiple
data points in a single variable.
The figure illustrates the concept.
Figure: A Dictionary variable

Workflow actions that use the Dictionary variable type


A workflow consists of multiple actions that are executed as the workflow is processed. SharePoint Designer 2013 contains many different actions. For example, there is an action to send an
email message, create a list item, and log messages to workflow history.
The following are the three actions specifically designed for the Dictionary variable type.
Build Dictionary
Count Items in a Dictionary
Get an Item from a Dictionary
The workflow actions for the Dictionary variable type can be found on the Action drop-down list, as shown in the figure.
Figure: Dictionary actions
Create variables with the "Build Dictionary" action
You use the Build Dictionary action to create a variable of type Dictionary. You enter the contents of the dictionary and then specify the name of the dictionary in the variable list.
The figure shows the Build a Dictionary dialog box. Notice that three variables have been added to the dictionary: a string, an integer, and a date/time.
Figure: The "Build a Dictionary" dialog box

A Dictionary can contain any type of variable available in the SharePoint Workflow platform. The following list defines the variable types available:
Boolean: A Yes or No value
Date/Time: A date and time
Dictionary: A collection of variables
Guid: A Globally Unique Identifier (GUID)
Integer: A whole number without decimals
Number: A number that can contain decimals
String: A string of characters

Important: The Dictionary variable type is critical when you are using the Call HTTP Web Service action.
Caution: Using the Name field as a lookup is only supported when you are setting a value in a dictionary. Using the Name field as a lookup is not supported when you are building a
dictionary.
NOTE

A Dictionary variable can contain a variable of type Dictionary. The ability to store Dictionary variables within a Dictionary provides a number of benefits. For example, you might create
a Dictionary to store information about employees. Within the Dictionary you might create another Dictionary entry for each employee. As you build the workflow you can use the
Dictionary variable instead of constantly creating new stand-alone variables for each piece of information about each employee. As this example shows, a Dictionary can be used to
organize complex information within the workflow.

Count and store variables with the "Count Items in a Dictionary" action
You use the Count Items in a Dictionary action to count the variables that a Dictionary contains and then store that number in an Integer variable. You can then use the item count to
loop through the Dictionary.
The figure shows the Count Items in a Dictionary workflow action.
Figure: Count items in a Dictionary

Retrieve variables with the "Get an Item from a Dictionary" action


You use the Get an Item from a Dictionary action to retrieve a variable stored in the Dictionary and place it in a variable. This is valuable when you need a value in the dictionary stored
in a stand-alone variable. You can retrieve a value by entering the name of the variable.
The figure shows the Get an Item from a Dictionary workflow action. Notice that Age is the name of the variable in the Dictionary and it is being output to a new Integer variable.
Figure: Get an item from a Dictionary

See also
Workflow in SharePoint
What's new in workflow in SharePoint
Getting started with SharePoint workflow
Understanding Coordination actions in SharePoint Designer 2013
3/26/2018 • 2 minutes to read Edit Online

Coordination Actions in SharePoint Designer 2013 are designed to start a workflow built on the SharePoint 2010 Workflow platform from within a workflow built on the SharePoint
Workflow platform.

Coordination Actions in SharePoint Designer 2013


There are two Coordination Actions available in SharePoint Designer 2013. Both actions are only available for the SharePoint Workflow platform. These actions are:
Start a List Workflow: Used to start a workflow developed for a specific list.
Start a Site Workflow: Used to start a workflow developed for the site.
Coordination Actions appear in the Actions drop-down menu when you build a workflow based on the SharePoint Workflow platform, as shown in the figure.
Figure: Coordination Actions in SharePoint Designer

Both actions are designed to start a workflow built on the SharePoint 2010 Workflow platform from a workflow built on the SharePoint Workflow platform.

Important: The coordination actions only support starting a workflow based on the SharePoint 2010 Workflow platform from a workflow based on the SharePoint Workflow platform.
Starting a workflow built on the SharePoint Workflow platform from within a workflow built on the same platform is not supported.

Using Coordination Actions


There are a number of actions that have been deprecated in the SharePoint Workflow platform. To accommodate legacy workflows you can use Coordination Actions. Coordination Actions
can be used to start a List workflow or a Site workflow that has been built by using the SharePoint 2010 Workflow platform.
A Coordination Action includes three editable regions, as shown in the figure.
Figure: Start a List Workflow coordination action

The three editable regions are:


SharePoint 2010 list workflow Select the 2010 workflow to start.
parameters Parameters to send to the 2010 workflow.
this item The item which the 2010 workflow should be run on.
Click an editable link to enter information. For example, to select the 2010 workflow to start, click the link SharePoint 2010 list workflow. A dialog box appears that can be used to select
the workflow, as shown in the figure.
Figure: Selecting a workflow based on the 2010 platform

The SharePoint 2010 Workflow platform workflow instances that are coordinated from within a SharePoint workflow are listed on the workflow status page in the Subworkflows section, as
shown in the figure.
Figure: The workflow status page lists the subworkflows

See also
What's new in workflow in SharePoint
Getting started with SharePoint workflow
Understanding Dictionary actions in SharePoint Designer 2013
Understanding Task Actions in SharePoint Designer 2013
3/26/2018 • 2 minutes to read Edit Online

Learn to use Task Actions in SharePoint Designer 2013. || |:-----| ||

Overview of Task Actions in SharePoint Designer 2013


A task in SharePoint is used to assign work to a person or group and then track the progress of that work over time. There are two workflow actions in SharePoint Designer 2013 designed
for working with tasks.
These actions are:
Assign a task is used to create a SharePoint task and assign it to a single participant.
Start a task process is used to assign a task to multiple participants.
The Task Actions are accessed in the Action drop-down menu of the SharePoint Designer 2013 ribbon, as shown in the figure.
Figure: Task Actions in SharePoint Designer 2013

Using Task Actions in SharePoint


A business process often consists of tasks that must be performed by people. A workflow orchestrates the steps of a process. A workflow uses Task Actions to assign tasks to people. For
example, when a new employee is hired a number of tasks need to be performed. One such task might be a new employee orientation. The task might need to be performed by a member of
the Human Resources department.
The Assign a task and Start a task process actions are located on the Actions drop-down menu in the SharePoint Designer 2013 ribbon. You can add the actions to your workflow and
then customize them for your particular circumstance. The Assign a task action is used to assign a task to a single participant. The Start a task process action is used to assign a task to
multiple participants.

Assign a task
The Assign a task action is shown in the figure.
Figure: The Assign a task action in SharePoint Designer 2013
The Assign a task action takes three inputs: the user to assign a task, the outcome variable, and the task id variable.
this user: Opens the Assign a Task dialog as shown in the figure. Use the dialog to set the participant, task title, description, due date, task options, email options, and outcome
options.
Variable: Outcome: Assigns the variable that will hold the outcome of the task.
Variable: TaskID: Assigns the variable that will hold the id of the task.
Figure: The Assign a Task dialog box

Start a task process


The Start a task process action is shown in the figure.
Figure: The "Start a task process" action.

The Start a task process action takes two inputs: the users that will participate in the task and the outcome variable.
these users: Opens the Start a Task Process dialog box as shown in the figure. Use the dialog box to set the participants, task title, description, due date, task options, email options,
and outcome options.
Variable: Outcome: Assigns the variable that holds the outcome of the task process.
Figure: The Start a Task Process dialog box
See also
What's new in workflow in SharePoint
Getting started with SharePoint workflow
Workflow development in SharePoint Designer and Visio
Workflow actions quick reference (SharePoint Workflow platform)
Understanding Eventing Actions in SharePoint Designer 2013
3/26/2018 • 3 minutes to read Edit Online

Learn to use Eventing Actions in SharePoint Designer 2013.

Overview of Eventing Actions in SharePoint Designer 2013


A SharePoint workflow can subscribe to be notified when an item is added or changed. When an item is added or changed, it is called an event. A workflow can wait for these events to
happen before proceeding with the workflow. The Eventing actions in SharePoint Designer 2013 are:
Wait for Event in List Item: Used to wait for a new item to be created or an item to be changed.
Wait for Project Event: Used to wait for a project to be checked in, committed, or submitted.
Wait for Field Change in Current Item: Used to wait for a field to be changed in the current item.
The Eventing actions are accessed in the Action drop-down menu of the SharePoint Designer 2013 ribbon as shown in the figures.
NOTE

The Project Web App Actions are only available when working with a Project Web App site.
Eventing Action in SharePoint Designer 2013

Project Web App Eventing Action in SharePoint Designer 2013


Wait for Field Change in Current Item event in SharePoint Designer 2013

Using Eventing Actions in SharePoint


A workflow orchestrates business processes. In a business process it is often important to wait for an item to be added or updated in a SharePoint list. Using the Eventing actions you can
wait for an event to happen and then perform a workflow action.
The Eventing actions are located on the Actions drop-down menu in the SharePoint Designer 2013 ribbon. You can add the action to your workflow and then customize it for your particular
circumstance.

Wait for Event in List Item


The Wait for Event in List Item action contains two editable regions, as shown in the figure.
Wait for Event in List Item
The two editable regions are:
This item event: The list and event that will be monitored.
Output variable: A variable in which to save the GUID of the item from which the event originated. Items have both an ID and a GUID field. The ID is unique to the list and a GUID is
globally unique. For example, the ID of the first item in the list will be the number 1 and the ID of the second item will be the number 2. The GUID is globally unique and in the format
of a 128-bit value consisting of 8 hexadecimal digits, followed by three groups of 4 hexadecimal digits each, followed by one group of 12 hexadecimal digits. An example of a GUID is:
6B29FC40-CA47-1067-B31D-00DD010662DA. The Wait for Event in List Item action retrieves the GUID.
Clicking the this item event link opens the Choose List Item Event dialog box, as shown in the figure.
Choose List Item Event dialog box

The Event drop-down list corresponds to the type of event. The options are to wait for an item to be added to a list or to wait for an item to be changed in a list. The List drop-down
corresponds to the list that is monitored.

Wait for Project Event


The Wait for Project Event action contains one editable region, as shown in the figure.
Wait for Project Event

The editable region is:


This project event: The project event that the workflow should wait for.
The This project event drop-down includes three project events to choose from. These include waiting for the project to be checked in, committed, or submitted.
Once an event has occurred the workflow will continue to process.

Wait for Field Change in Current Item


The Wait for Field Change in Current Item action contains two editable regions, as shown in the figure.
Wait for Field Change in Current Item

The editable regions are:


Field: The field in the item that should be monitored for change.
Value: The value that the field should equal in order for the workflow to proceed.
Once a field has changed the workflow continues.

See also
Workflow in SharePoint
What's new in workflow in SharePoint
Getting started with SharePoint workflow
Workflow development in SharePoint Designer and Visio
Workflow actions quick reference (SharePoint Workflow platform)
Getting familiar with Visual Designer for workflow in SharePoint Designer 2013
3/26/2018 • 2 minutes to read Edit Online

Learn the basic features of the Visual Designer in SharePoint Designer 2013.

Overview of the Visual Designer in SharePoint Designer 2013


SharePoint Designer 2013 includes a new workflow design surface called Visual Designer. You use Visual Designer to develop a workflow by dragging shapes onto the design surface.

Important: In order to work with the Visual Designer, you must have Visio Professional 2013 installed on the same computer as SharePoint Designer 2013. If you do not have Visio
installed you will receive an error, as shown in the figure.

Figure: Visio 2013 Professional is required to work with Visual Designer

The Shapes pane on the left contains workflow shapes that you can drag to the design surface in order to create the workflow. Following are the three categories of shapes available for
building a workflow.
Actions: Specific actions that can be performed by the workflow. Some examples include calling an HTTP web service, adding a comment, and updating a list.
Components: General components that can be added to provide a structured environment for workflow actions. Some examples include a stage container, a loop with conditions, and
a start workflow shape.
Conditions: Conditional logic shapes that can be used to provide a workflow path based on specific criteria. Some examples include checking if one value equals another value,
checking if a person is a valid SharePoint user, and checking if an item is created within a specific date range.

Tip: For a complete list of shapes available in SharePoint Designer 2013, see Shapes in the SharePoint Server workflow template in Visio

The figure shows a workflow in Visual Designer.


Visual Designer in SharePoint Designer 2013

Using the Visual Designer in SharePoint


The Visual Designer in SharePoint Designer 2013 is accessed through the Views drop-down menu of the Workflow tab. There are three different views that can be used for developing a
workflow:
Text-Based Designer: A text-based workflow development environment.
Visual Designer: A visual workflow development environment where shapes can be dragged onto the design surface in order to develop the workflow. (Requires Visio Professional
2013)
Stage View: Provides a high-level view of the visual design surface by showing how stages of the workflow fit together. It is similar to the Visual Designer view but it does not show
the shape-level detail. (Requires Visio Professional 2013)
You can switch between Views in the Manage portion of the Workflow ribbon as shown in the figure.
Switching between design views in SharePoint Designer 2013

A workflow can be developed in either the Text-Based Designer or the Visual Designer or both. For example, if you are developing a workflow by using the Text-Based Designer you can
switch the view to the Visual Designer and continue to develop the same workflow. Likewise, you can also begin developing a workflow by using the Visual Designer and then switch the
view to the Text-Based Designer and continue to develop the same workflow. Moving back and forth between views provides flexibility in workflow development.
See also
Workflow in SharePoint
What's new in workflow in SharePoint
Getting started with SharePoint workflow
Workflow development in SharePoint Designer and Visio
Workflow actions quick reference (SharePoint Workflow platform)
Working with Web Services in SharePoint Workflows using SharePoint Designer 2013
5/10/2018 • 14 minutes to read Edit Online

Demonstrates how to use web services in SharePoint Designer 2013 workflows. Provided by: Andrew Connell, www.AndrewConnell.com
Microsoft has taken a fresh approach to workflows in SharePoint. The workflow team worked with the Microsoft Azure team to create a new product called Workflow Manager. Workflow
Manager serves as the host for the latest version of the Windows Workflow Foundation runtime and provides all of the necessary services as well as leveraging the Microsoft Azure Service
Bus to enhance performance and scalability. Once deployed, it runs the same whether in an on-premises deployment or deployed to the cloud. Importantly, SharePoint hands off all workflow
execution and related tasks to the Workflow Manager farm, which is external to SharePoint. One of the more significant changes to the workflow architecture is that now all workflows are
authored in a declaratively, on a designer surface, including those built using Visual Studio 2012. In previous versions of SharePoint, workflows developed with Visual Studio 2012 were not
exclusively declarative. Instead, they were a mix of declarative XAML and a compiled assembly that contained the workflow business logic.
For those customers who have created workflows using SharePoint Designer in the past, this is nothing new. Workflows authored using SharePoint Designer have always been fully
declarative. This change does benefit customers who create workflows using SharePoint Designer 2013, however, because SharePoint Designer 2013 workflows now support calling and
consuming web services.

Why are web services important for SharePoint workflows


Let's start by understanding scenarios in which using web services makes sense. In the days of SharePoint 2007 or SharePoint 2010, writing custom code was common when using Visual
Studio to author workflows because that was the best way to perform calculations or implement custom business logic. Any time you encountered a situation in which the out-of-the-box
actions and activities didn't meet your needs, you could fall back on custom code in a managed assembly.
For the non-developer users of SharePoint Designer 2013, on the other hand, this was not so easy. When you ran into a use cases that you couldn't handle with existing workflow actions,
you had to call in a developer to write a custom action. Often, this was difficult because they could only create code for the sandbox (when in a hosted environment), or could only use fully-
trusted solutions if in an on-premises deployment. In other cases, the workflow had to be completely handed over to a developer to build as a fully-trusted solution because what was needed
could not be achieved in SharePoint Designer.
Now comes the good news: In the world of SharePoint, when SharePoint Designer 2013 lacks an action that you need, all you need is to create a custom web service. And creating a custom
web service is much easier than creating a custom action. Not only that, but whereas a custom action could only be used by the workflow in which it's installed (or, at best, by only a
SharePoint workflow), a custom web service is portable and can be used by any number of consumers.
Perhaps best of all, in cases where there is an existing web service that you need to access - either a public one, or perhaps a private web service that is hosted by your company - SharePoint
Designer 2013 now provides an action that you can use to call the web service. There is no longer any need to rely on a developer when you need to call an existing web service.
While SharePoint can consume any type of web service, it is easiest (and recommended) that you use web services that accept and return data using the standard OData formats of Atom or
JSON (JavaScript Object Notation).
This recommendation is based on their being support for these OData formats in SharePoint workflow authoring tools (both SharePoint Designer 2013 and Visual Studio 2012). Both tools
support building payloads to submit to the service and for handling the responses returned by the web services. Additionally, the OData formats support communication with anonymous
web services as well as with those protected by various types of authentication. In short, you have full control over the request and response for each service call. This allows you to use a
series of activities within a workflow to first authenticate using one service and obtain an OAuth token, and then include that token in future requests to services secured using the OAuth 2.0
protocol.

Leveraging web services in SharePoint workflows


Invoking web services from workflows using SharePoint takes place in two stages: first is calling the web service, then is exchanging data with the web service.
In SharePoint workflows, you call a web service using a new action introduced in SharePoint named Call HTTP Web Service. This action is flexible and allow you to make simple calls to a
web service easily, or, if needed, you can create more complex calls using HTTP verbs as well as allowing you to add HTTP headers. Figure 1 shows you the Call HTTP Web Service action
on the SharePoint Designer 2013 surface.
Figure 1. SharePoint Designer 2013 stage showing the Call HTTP Web Service action

The Call HTTP Web Service action lets you specify any of several request methods, including GET, PUT, POST, and DELETE. This lets you tell the web services, specifically RESTful
services, what to do on the service that you've specified with the URI property on the activity.
For instance, to get all the properties of a specific item, the service URL would contain the unique address of the item, and you would set the method to GET. To delete the item, the process
is the same, except you set the method to DELETE. The same is true for updating an item, except for setting the method to POST. When you create an item, set the URL to the unique
address of the collection where the item is to be created, and then set the method to POST. When creating or updating items, services generally require the data to use, which you pass along
as content in the request, then indicate using the request property on the Call HTTP Web Service action.
The second stage of working with web services involves submitting data to, and receiving data from, a web service, which you do by using either the request or response properties on the
Call HTTP Web Service action. Note, however, that rather than as a stream, data is passed as a complex structure using the Dynamic Value object. (For more information about dynamic
values, see Understanding Dynamic Value.)
Dynamic value data structures are formatted as JavaScript Object Notation (JSON) strings. However, instead of having a developer create and manipulate strings manually within the
workflow, Microsoft has provided the object type DynamicValue that can be used to store both hierarchal data as well as the response to a web service call.
There is a series of activities associated with the DynamicValue type that can be used to count the number of items in the response, extract values from the response, or build up a new
structure for updating or creating items. Note that SharePoint Designer 2013 does not support working directly with the DynamicValue type and instead, workflow authors will use the
Dictionary type.

Creating web services for SharePoint workflows


So we've learned that SharePoint Designer 2013 supports calling web services, but that it doesn't support invoking custom code from workflows. Consequently, you will need to know how
to create a web service if you wish to extend the functionality of your workflows beyond the default actions.
Fortunately, there are plenty of options for creating custom web services for use in SharePoint workflows. Specifically, the HttpSend activity, along with the DynamicValue data type, are
ideally suited for creating RESTful web services that conform to the OData protocol.
OData is a protocol for creating and consuming data based on the principles of REST services. It was developed to standardize exchanging data using mature, reliable, and robust HTTP
protocols. Once the OData specification was complete, different organizations implemented the protocol on their own technology stacks. Microsoft implemented its own version of OData,
which it branded WCF Data Services.
Following are discussions of two common scenarios in which RESTful web services are useful to workflow developers:
Implementing OData service CRUD-Q operations
Implementing OData service operations

Implementing OData service CRUD-Q operations


A common use for web services is performing simple create, read, update, delete, and query (CRUD-Q) operations on data in a database. It is relatively easy to create an OData web service
for a SharePoint workflow WCF data service an OData service to be used by a workflow by using WCF Data services. You can review the walkthroughs and samples on creating web
services at sites like WCF Data Services, www.OData.org, and others.
Assuming that you already have database that you can operate against, there are four short steps:
1. Create a model of the database using the Microsoft Entity Framework. There is no code required as this is a wizard-based creation in Visual Studio. For additional information, see
Entity Framework 4.0 and WCF Data Services 4.0 in Visual Studio 2010 and Entity Framework Designer Gets Some Love in Visual Studio 2012.
2. Create a new WCF Data Service. Again, no code is required in this Visual Studio wizard. For more information, see Walkthrough: Creating and Accessing a WCF Data Service in
Visual Studio.
3. In the service code file, set the name of the entity model that you created in step one to the source of the service; then, set the accessibility and permission for the entities in the model
(both steps implemented in as little as two lines of code).
4. Publish the service to a location that Workflow Manager can access.

Implementing OData service operations


There's a pretty good chance that your workflow wants to run some business logic that doesn't fit into limited the CRUD-Q model. For example, there may be an OData service that supports
CRUD-Q operations when it creates a new bank loan. This service might also ask for consumers to call the service and provide a credit score so it can then retrieve the current interest rate.
Such a task exceeds the capability of simple CRUD-Q operations, since it calls a method, passes in an integer, and receives a response.
However, you can support this scenario by using OData and WCF Data Services, through which you can implement Service Operations. Service operations are common, and are even used
in the SharePoint services. For example, when SharePoint retrieves a specific list using the address format http://[..]/_api/web/lists/GetByTitle('ListTitle') , the GetByTitle() function in
the address is actually a service operator that was created by the SharePoint team. Typically, developers create their custom service operations in web services they create using WCF Data
Services.

Create a workflow with SharePoint Designer 2013


The following walkthrough demonstrates how to create a custom workflow that calls the OData web service of the Northwind database, which you can find publically hosted at the
www.odata.org site. In this sample, the user enters a customer ID and then starts the workflow, which takes the customer ID and uses it to query the web service to collect additional
information about the customer - specifically, the user's full name and employer. The workflow then takes this information and updates the list item by adding the user's customer name and
employer.

Create a customer list


1. In SharePoint Designer 2013, create a custom list and name it "Customers".
2. Rename the Title field to Customer Id.
3. Add two new fields of type String and name them Full Name and Employer, as shown in Figure 2.
Figure 2. Creating the Customers list in SharePoint Designer 2013

Create the workflow


1. In the SharePoint Designer 2013 navigation pane, select the Workflows option.
2. On the ribbon, click the List Workflows button and select Customers from the resulting drop-down list.
3. Name the workflow "Get Customer Details".
4. Set the Platform Type to SharePoint Workflow, as shown in Figure 3.
Figure 3. Creating a new List Workflow using SharePoint Designer 2013
Query the web service for the customer details
Now that we've created the workflow, we want to enable it to call a web service, which we do by adding a Call HTTP Web Service action to the workflow's default stage.
1. Click on the link labled this.
2. To the right of the Enter the HTTP web service URL text box, click the builder button ( ???) to open the String Builder dialog box.
3. In the String Builder, enter this URL: http://services.odata.org/Northwind/Northwind.svc/Customers('CUSTOMERID')?$format=json&amp;$select=ContactName,CompanyName . Notice the "
$select " portion of the URL is retrieving only the fields that are relevant to this list.

4. In the URL, locate the URL segment CUSTOMERID and remove it. Leave the parentheses and single quotes in place.
5. To then dynamically create the full URL, click the Add or Change Lookup button in the String Builder.
6. In the resulting Lookup for String dialog box, set the Data Source to Current Item and set the Field from Source to CustomerId, as shown in Figure 4.
Figure 4. Dynamically creating the URL for the web service request

1. Click OK, then OK again to accept the new URL.


Now that we've set this up to receive results from the web service, next we need to store the results in another variable.
2. In the Call HTTP Web Service action, click the response link in the action and create a new variable of type Dictionary and name it nwServiceResponse.
The entire Call HTTP Web Service action is not likely visible, since it is a long sentence in the designer. Scroll to the right and notice that the response status code is stored in a
variable called responseCode. This is convenient, and something that can be written to the workflow instance's statistics page using the workflow history list.
3. Add a Log to History List action after the Call HTTP Web Service action and set its message to write the status code for the response to the log, as shown in Figure 5.
Figure 5. Writing the Web Service Response Code to the History List

Extract values from response


Now that we have the web service response stored in the nwServiceResponse variable, the next step is to extract these values and place them in local variables.
To do this, we're going to add two Get item from dictionary actions to the workflow. Note that the path to the item from which we're going to extract a value has to match the structure of
the response and be in a specific format. A good way to figure this out is to enter the URL into the browser to see the response that comes back. Notice that the results are nested within the
object called d. Therefore the path to the field CompanyName in the web service response is d/CompanyName .
1. Add two Get item from dictionary actions to the workflow.
2. On the first of these new actions, set item by name or path to d/ComopanyName .
3. Set the dictionary link to nwServiceResponse.
4. Set the item link to a new String variable named CompanyName.
5. Repeat steps 2, 3, and 4 on the second Get item from dictionary action, except to use ContactName instead of "CompanyName", as shown in Figure 6.
Figure 6. Extracting Values from the Web Service Dictionary Response

Update the list item


The final step is to update the list item using two of the Set field in current item actions. These set the fields in the list item to the values stored in the variables we created, as shown in
Figure 7.
Figure 7. Update the List Item

And finally, we complete the Transition to stage section of the workflow stage.
1. Add a Go To Stage action.
2. Select End of workflow.
3. Save and publish the workflow.

Test the workflow


1. Open a browser and navigate to the Customers list.
2. Add the two customer IDs that are in the Northwind service on two new list items, ALFKI and ANATR.
3. Manually start the workflows by selecting each item, then clicking the Workflows button on the ribbon.
4. Select the Get Customer Details workflow.
At this point the workflow will start and will query the web service.
5. Navigate back to the Customers list and refresh the page. It might take a few refreshes for the workflows to complete, but eventually it should look like the image in Figure 8. You
should see both list items updated with the customer's full name and their employer, which came from the Northwind web service.
Figure 8. List Items Updated by Custom Workflow

Conclusion
SharePointintroduced a new workflow architecture facilitated by a new product, Workflow Manager 1.0. To ensure that all custom workflows worked regardless of the SharePoint
deployment choice, either on-premises or hosted in Office 365, all workflows are now 100 percent declarative. The added support for calling web services from SharePoint Designer 2013-
authored workflows provides a more flexible and powerful workflow authoring process than in previous versions.
Microsoft introduced support for calling web services in Workflow Manager using the new Call HTTP Web Service action in SharePoint Designer 2013. Workflow Manager also
introduced support for creating structures to submit to web services as well as consuming their responses using the Dictionary variable type. When creating workflows, use the Dictionary
type and associated actions in SharePoint workflows that use external web services.

See also
Workflows in SharePoint
OData
Introducing JSON
Get started with the SharePoint REST service
Entity Framework 4.0 and WCF Data Services 4.0 in Visual Studio 2010
Understanding how to package and deploy workflow in SharePoint
3/26/2018 • 3 minutes to read Edit Online

Learn how to package and deploy a workflow in SharePoint with SharePoint Designer 2013.

Overview of the workflow packaging capabilities of SharePoint Designer 2013


SharePoint Designer 2013 provides the capability to save a workflow as a template. Saving a workflow as a template is also known as packaging the workflow. After the workflow is saved as
a template, it can then be imported into other SharePoint environments and used without the need to redevelop the workflow. Not all workflow types can be saved as a template. The
following matrix shows the workflow types that can be saved as a template.
Support, by platform, for saving a workflow as a template

W O R K FLO W T YPE S HAR EPO INT 2 0 1 0 W O R K FLO W PL ATFO R M S HAR EPO INT W O R K FLO W PL ATFO R M

List Workflow No Yes

Site Workflow No Yes

Reusable Workflow Yes Yes


NOTE

SharePoint contains two different workflow platforms: the SharePoint 2010 Workflow platform and the SharePoint Workflow platform. Both platforms are available in SharePoint. For more
information about the two workflow, see Getting started with SharePoint workflow.

Packaging a workflow by using SharePoint Designer 2013


The process for packaging a workflow involves saving the workflow to a template file by using SharePoint Designer 2013. A workflow package is in the form of a Web Solution Package
(WSP) file and has a .wsp extension. To package a workflow follow these steps.

Package a workflow
1. Open an existing workflow, or develop a new workflow, in SharePoint Designer 2013.
2. On the Workflow Settings tab in the ribbon, click the Save as Template button in the Manage section as shown in the figure.
Figure: Save workflow as template

1. An informational dialog box appears to let you know the template has been saved to the Site Assets library.
2. Click the Site Assets library to view the workflow template as shown in the figure.
Figure: A workflow template in Site Assets

Tip: A workflow template automatically saves to the Site Assets library of the site collection in which the workflow resides.

Deploying a workflow package to SharePoint


You can deploy a workflow package to a SharePoint farm or site that is different from the farm or site in which it was developed. In order for a workflow deployment to be successful two
items must be fulfilled:
All workflow dependencies such as lists, libraries, columns, and content types must already exist on the new site.
Each dependency must have the exact name of the source dependency.
If a workflow is deployed and the exact dependencies do not exist then the result will be an error.
Before you can deploy a workflow you must first export the workflow template from the source SharePoint farm. To export a workflow template, follow this procedure.

Export a workflow template


1. Open SharePoint Designer 2013 and navigate to the Site Assets library where the template is located.
2. Select the workflow template you want to export by clicking it.
3. Click the Export File button to save the template file to your local computer or a network drive, as shown in the figure.
Figure: Export workflow template from SharePoint Designer 2013

To deploy a workflow package follow this procedure.

Deploy a workflow solution


1. Open Internet Explorer and navigate to the SharePoint site collection where you want to deploy the workflow.
2. Click Site Actions and select Site Settings.
3. In the Web Design Galleries section click Solutions.
NOTE

You must be on the Site Settings page for the site collection in order to see the Solutions gallery. If you are on the Site Settings page for a sub-site then the Solutions gallery is
not visible.
4. Click the Upload Solution button to upload the solution as shown in the figure.
Figure: Upload Solution button

1. Activate the solution by clicking the Activate button as shown in the figure.
Figure: Activate Solution dialog and button

After a workflow solution has been activated for a site collection, it is available as a feature for all sub-sites. To activate the workflow feature for a sub-site, follow this procedure.

Activate the workflow feature


1. Open Site Settings on the site where you wish to activate the workflow feature.
2. In the Site Actions group, click Manage site features.
3. Click Activate next to the workflow feature as shown in the figure.
Figure: Activate workflow feature for site

See also
Workflow in SharePoint
What's new in workflow in SharePoint
Getting started with SharePoint workflow
Workflow development in SharePoint Designer and Visio
Workflow actions quick reference (SharePoint Workflow platform)
Blog article from the SharePoint Designer team: Workflow package and deploy scenario
Create a workflow with elevated permissions by using the SharePoint Workflow platform
3/26/2018 • 5 minutes to read Edit Online

This article describes how to create SharePoint workflows that access objects in SharePoint that require elevated permissions. These solutions use two features: granting permissions to the
workflow app and wrapping actions with the App Step.
IM P O R T A N T

This article assumes that the SharePoint Workflow platform has been installed and configured and that SharePoint has been configured for add-ins. For more information about SharePoint
Workflows and SharePoint Add-ins, including installation and configuration, see Workflows in SharePoint and Install and manage SharePoint Add-ins.
Imagine that as a SharePoint administrator, you would like to define some processes for managing user requests for purchases of add-ins from the Office Store. In the simplest case, you
want to send an acknowledgment email when a user requests an add-in. In addition, you might also want to add structure to the request approval process.
By default, workflow does not have permissions to access the app catalog. Catalog lists in SharePoint require owner (full control) permissions. Workflows generally run at a permission level
equivalent to write.
To solve this, you have to create a workflow with elevated permissions by doing the following in the Site Collection site:
1. Allow the workflow to use add-in permissions.
2. Grant full control permission to the workflow.
3. Develop the workflow to wrap actions inside an App Step.

Allow a workflow to use add-in permissions on a SharePoint site


The first step is to allow the workflow to use add-in permissions. You configure a workflow to use add-in permissions on the Site settings page of the SharePoint site where the workflow
runs. The following procedure configures the SharePoint site to allow the workflow to use add-in permissions.
IM P O R T A N T

The procedure must be completed by a user that has Site Owner permissions.

To allow workflow to use add-in permissions


1. Select the Settings icon as shown in the figure to open the Site settings page.

2. Go to Site settings.
3. In the Site Actions section, select Manage site features.
4. Locate the feature called Workflows can use app permissions, as shown in the figure, and then select Activate.
W A R N IN G

This feature will not activate unless you have properly configured the SharePoint Workflow platform and SharePoint Add-ins.

Grant full control permission to a workflow


For the workflow to function properly, it must be granted full control on the site. The following procedure grants full control permission to the workflow.
IM P O R T A N T

The procedure must be completed by a user that has Site Owner permissions. The workflow must already be published to the SharePoint site.

To grant full control permission to a workflow


1. Select the Settings icon.
2. Go to Site settings.
3. In the Users and Permissions section, select Site app permissions.
4. Copy the client section of the App Identifier. This is the identifier between the last "|" and the "@" sign, as shown in the figure.

5. Go to the Grant permission to an app page. This must be done by browsing to the appinv.aspx page of the site.
Example: http://{hostname}/{the Site Collection}/_layouts/15/appinv.aspx .
NOTE

The 'app' in this step refers to the workflow add-in in general and not just a specific workflow. Individual workflows cannot be access controlled. When you enable add-in permissions,
you are enabling for all workflows within the Site Collection.
For more information about setting up a workflow, see the Blog article from Sympraxis Consulting: Looping Through Content in a SharePoint Site Workflow
The following figure shows an example.

6. Paste the client ID in the App Id field, and then select Lookup, as shown in the previous figure.
7. Paste the following code in the Permission Request XML field to grant full control permission (note: this code block was updated on 12/29/17 to include the AllowAppOnlyPolicy ).

<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" />
</AppPermissionRequests>

W A R N IN G

There are no placeholders in the Scope value. It is a literal value. Enter it exactly as it appears here.
The following figure shows an example of the completed page (note that the code in the Permission Request XML area does not reflect the recent update to the code in Step 7).
8. Select Create.
9. You are then asked to trust the workflow add-in, as shown in the following figure. Select Trust It.

Wrap actions inside an App Step


Finally, you need to wrap the workflow actions inside an App Step. The following procedure wraps a Send an Email action inside an App Step. The workflow in this example sends an
acknowledgement email message from a custom list.

To wrap actions inside an App Step


1. Open the app catalog site in SharePoint Designer.
2. Create a new Custom List on which to run the workflow. In this example, the list name is App Demo.
3. Select Workflows in the navigation window.
4. Create a new List Workflow for the App Demo list, as shown in the figure.

5. Insert an App Step, as shown in the figure.

6. Insert a Send an Email action in the App Step.


7. Select the Address book button. In the To field, select Workflow Lookup for a User, and then select Add as shown in the figure.
8. Enter the Created By field as the lookup value, as shown in the figure.

9. Enter Email from the App Demo list in the email message body.
10. Select OK to return to the workflow. The completed workflow is shown in the figure.

11. Select the Workflow Settings icon in the ribbon, as shown in the figure.

12. Clear the check box next to Automatically update the workflow status to the current stage name, and then select Publish.
Understand how it works
To understand why elevating permissions for a workflow is required, consider that workflows are fundamentally add-ins for SharePoint, and they follow the same authorization rules of the
add-in model. The default configuration for workflow is that the effective permissions of the workflow are an intersection of user permissions and the add-in permissions, as shown in the
figure.

Two reasons why it is necessary to elevate permissions to create a workflow in the App Request list are:
By default, workflow only has write permission.
The user has no permissions.
The first step to solve this problem is to allow the application to authorize by using only its identity and ignoring that of the user. This is done by enabling the App Step feature. The second
step grants full control permission to the workflow.
The following diagram illustrates the change in permissions.

See also
Blog article from the SharePoint Designer team: Workflow package and deploy scenario
What's new in workflow in SharePoint
Getting started with SharePoint workflow
Workflow actions and activities reference for SharePoint
Workflow development in SharePoint Designer and Visio
Matching the SharePoint Designer version with the farm version
3/26/2018 • 2 minutes to read Edit Online

Learn which version of SharePoint Designer to use.

Using SharePoint Designer with SharePoint


SharePoint Designer is tool used to connect to and work with a SharePoint site. It is important that the version of SharePoint Designer match the version of the SharePoint farm hosting the
SharePoint site to which you are connecting. If your farm is upgraded then you will also need to upgrade your version of SharePoint Designer.
NOTE

The latest version of the product is SharePoint Designer 2013. To learn how to find and install SharePoint Designer 2013, see Creating a workflow by using SharePoint Designer 2013 and
the SharePoint Workflow platform. If you already have an older version of SharePoint Designer installed on your computer we recommend that you uninstall it before installing the new
version.
Trying to use a version of SharePoint Designer that does not match with the SharePoint farm can result in a number of issues. For example, see You have problems with workflows or receive
errors in SharePoint Designer 2010.

See also
What's new in workflow in SharePoint
Getting started with SharePoint workflow
Workflow development in SharePoint Designer and Visio
Transfer a workflow between SharePoint Designer 2013 and Visio Professional 2013 (SharePoint 2010
Workflow platform)
3/26/2018 • 3 minutes to read Edit Online

Use SharePoint Designer to import a workflow from Visio or export a workflow to Visio.

Transferring a workflow between SharePoint Designer 2013 and Visio Professional 2013
Business analysts and process analysts who are already familiar with flowcharting in Visio can use Visio to design a SharePoint workflow. The workflow in Visio represents the business logic.
After the business logic is complete, the workflow can be exported to SharePoint Designer. Once the workflow is in SharePoint Designer, an IT professional can wire it up to the SharePoint
site.

In Microsoft SharePoint Designer 2013, you can import a workflow created in Microsoft Visio Professional 2013 or export a workflow to Visio for viewing.
This article describes transferring a workflow by using the SharePoint 2010 Workflow platform in SharePoint Designer 2013.
To select the SharePoint 2010 Workflow platform when you create a workflow:
1. In the Navigation pane, click Workflows.
2. On the Workflows tab, in the New section, click List Workflow, Reusable Workflow, or Site Workflow.
3. In the Create Workflow dialog box, in the Platform Type box, click SharePoint 2010 Workflow.
You can visualize workflows in SharePoint Designer in two ways:
If Visio Services is installed on the server that is running SharePoint, you can create a workflow visualization on the workflow status page that displays progress and assignments.
You can export the workflow to Visio to create a workflow drawing that can be used for feedback and approval.

Import a workflow from Visio


To import a SharePoint workflow, do the following:
1. In SharePoint Designer 2013, in the Navigation pane, click Workflows.
2. On the Workflows tab, in the Manage group, click Import from Visio.

3. In the Import Workflow from Visio Drawing dialog box, browse to and select the Visio Workflow Interchange (.vwi) file you want to use, and then click Next.
4. Type a name for the workflow, and then select the type of workflow you want it to be once it has been imported. Your choices are:
List workflow A workflow that is attached to a specific list. If you select this option, you must choose the list to which the workflow will be attached.
Reusable workflow A workflow that is attached to a content type, and is therefore portable. It can be used by different lists on a SharePoint site. If you select this option, you must
choose the content type on which the workflow will run.
1. Click Finish.
The imported workflow appears in the SharePoint Designer full-screen workflow editor. All text in the Visio custom shapes is imported into SharePoint Designer as activity labels (the gray
text in the image below) to clarify the intent of the workflow:
After the workflow is imported to SharePoint Designer, it is editable and can be revised to add the necessary conditions, actions, steps, and settings.

Export a workflow to Visio


Once you have created or edited a workflow in SharePoint Designer 2013, you can export the workflow as a Visio drawing that can be opened in Visio Professional 2013. The ability to
export a workflow back to Visio after it has been edited in SharePoint Designer—also known as "round-tripping"—enables deeper collaboration between business users and workflow
designers. When you iterate the workflow design in this way, you can use Visio to define the business requirements and then use round-tripping to coordinate and approve changes.
NOTE

Visio Professional 2013 does not support steps. Step information that has been added in SharePoint Designer may be lost when the workflow is viewed in Visio and then re-imported into
SharePoint Designer.
To export a workflow, do the following:
1. In SharePoint Designer 2013, click Workflows in the Navigation pane.
2. On the Workflow tab, in the Manage group, click Export to Visio.
3. In the Export Workflow to Visio Drawing dialog box, name the file, select a location, and then click Save. The exported file is saved as a .vwi file that can be opened directly in Visio
Professional 2013.

See also
What's new in workflows for SharePoint
Get started with workflows in SharePoint
Workflow development in SharePoint Designer and Visio
Workflow actions and activities reference for SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn about the workflow actions that are available for workflow authoring in SharePoint Designer 2013, and the workflow activity classes that are available to workflow developers using
Visual Studio 2012.

Workflow activities and actions


Workflow activities represent the code-level objects that handle method calls to the various APIs that drive workflow behaviors. You interact with workflow activities in code, using or another
development environment.
For a list of available activities, see Workflow activity classes in SharePoint.
On the other hand, workflow actions are wrapper objects that encapsulate these underlying activities and present them in a user-friendly form in SharePoint Designer. You interact with
workflow actions in SharePoint Designer.
For a list of available workflow actions, see Workflow actions quick reference (SharePoint Workflow platform) and Workflow actions available using the workflow interop bridge.

Windows Workflow Foundation 4.0 activities


Although the SharePoint platform and infrastructure provide you with specially crafted activity classes for creating custom SharePoint workflows, you can also use any of the activities that
are provided by Windows Workflow Foundation (WF) 4.0. These WF 4.0 activity classes are available in the Microsoft .NET Framework 4 in the System.Activities.Statements namespace.
The WF 4.0 activity classes provide some useful features that you may not find in the SharePoint activity class library. For example, WF 4.0 includes the If class, which allows you to create
conditional activities. Additionally, you can use the System.ServiceModel.Activities.Send activity to connect to web services.

In this section
Workflow activity classes in SharePoint
Workflow actions quick reference (SharePoint Workflow platform)
Workflow actions available using the workflow interop bridge

See also
Develop SharePoint workflows using Visual Studio
SharePoint workflow fundamentals
Workflows in SharePoint
Workflow activity classes in SharePoint
3/26/2018 • 3 minutes to read Edit Online

Provides a summary of the SharePoint workflow activity classes that are available in SharePoint. The palette of activity classes has been revised for SharePoint. Table 1 lists the current
catalog of 49 available activities grouped by their respective activity categories.
NOTE

In future releases, the activities listed in this table will provide links to the API reference documentation for their respective managed classes.

Workflow activity classes available in SharePoint


Table 1. Workflow activity classes

Activity Category Description

CreatedBy Condition Returns whether current item was created by specified user.

CreatedInRange Condition Returns whether current item was created in specified date range.

ModifiedBy Condition Returns whether current item was modified by specified user.

ModifiedInRange Condition Returns whether current item was modified in specified date range.

WordsInTitle Condition Returns whether specified keywords are present in the title of the
current item.

WorkflowInterop Coordination Starts a SharePoint 2010 workflow (Windows Workflow Foundation


3.5).

WaitForCustomEvent Event Waits for a custom event to be sent in to the workflow.

WaitForFieldChange Event Waits for specified field to change to specified value on the specified
list item.

WaitForItemEvent Event Waits for specified event to happen on specified list item.

CheckInItem List Checks in the specified list item.

CheckOutItem List Checks out the specified list item.

CopyItem List Copies the specified file item to the specified document library. Does
not apply to non-file-list items.

CreateListItem List Creates a list item.

DeleteListItem List Deletes a list item.

LookupSPList List Returns information about the list that corresponds to the specified
list ID.

LookupSPListItem List Returns properties of the specified list item.

LookupSPListItemBooleanProperty List Returns value of specified list item property as Boolean.

LookupSPListItemDateTimeProperty List Returns value of specified list item property as DateTime.

LookupSPListItemDoubleProperty List Returns value of specified list item property as Double.

LookupSPListItemDynamicValueProperty List Returns value of specified list item property as DynamicValue.

LookupSPListItemGuid List Returns GUID property of the first list item that matches specified
filter criteria of property name and property value.

LookupSPListItemInt32Property List Returns value of specified list item property as Int32.

LookupSPListItemProperty List Returns value of specified list item property as Object.

LookupSPListItemStringProperty List Returns value of specified list item property as String.

LookupSPListProperty List Returns list properties as DynamicValue.

UndoCheckOutItem List Undoes checkout of the specified list item.

UpdateListItem List Updates a list item.

CompositeTask Task Runs a task process - assigns multiple tasks to multiple people in
series or parallel, waits for tasks to complete, and calculates
aggregate outcome.
SingleTask Task Runs a simple task process - assigns a single task to a single person
or a group, waits for the task to complete.

ExpandGroupToUsers User Returns a collection of LoginNames of users who are members of a


specified SharePoint group principal.

IsValidUser User Checks whether specified User Principal ID represents a valid


SharePoint user.

LookupSPGroup User Returns information about an SP group that corresponds to the


specified principal id.

LookupSPGroupMembers User Returns collection of information about each member of a group.

LookupSPPrincipal User Returns information about an SP Principal (Principal represents a


user or a group in SharePoint that can be assigned permissions).

LookupSPPrincipalId User Returns Principal ID that corresponds to a specified user name.

LookupSPPrincipalProperty User Returns value of a specified property of a specified SP Principal.

LookupSPUser User Returns information about a user that corresponds to the specified
principal ID.

LookupSPUserProperty User Returns value of a specified property of the user that corresponds to
specified SP Principal.

Email Utility Sends an email message to SharePoint site users.

GetCurrentItemGuid Utility Returns GUID property of SharePoint List Item on which the
workflow instance is running.

GetCurrentListId Utility Returns ID property of SharePoint list on which the workflow


instance is running.

GetHistoryListId Utility Returns ID of the history list of a workflow instance, if a history list is
specified for the workflow association.

GetTaskListId Utility Returns ID of the task list of a workflow instance, if a history list is
specified for the workflow association.

LookupWorkflowContextProperty Utility Returns value of specified workflow context property.

SetField Utility Sets a field on current item.

SetWorkflowStatus Utility Sets specified text as status on specified field on current list item.
Allows the workflow to set the value of any string field of a list item
as "workflow status."

TranslateDocument Utility Creates a translated copy of specified document in a specified


document library using SharePoint Translation Services.

WebUri Utility Returns absolute URI of the SP web that contains the workflow.

WriteToHistory Utility Writes specified comment to history list.

See also
Workflow actions and activities reference for SharePoint
Develop SharePoint workflows using Visual Studio
Set up and configure SharePoint Workflow Manager
Workflow actions quick reference (SharePoint Workflow platform)
3/26/2018 • 8 minutes to read Edit Online

This reference lists the workflow actions that are supported in the current build of SharePoint Designer 2013, in addition to those that are not available.

Workflow actions in SharePoint Designer 2013


The following is a reference for workflow actions available for the SharePoint Workflow platform. In addition to the SharePoint Workflow platform, SharePoint Designer 2013 also supports
the SharePoint 2010 Workflow platform. To view workflow actions for the 2010 platform, see Workflow actions quick reference (SharePoint 2010 Workflow platform)

Core actions
Core actions are those that are most commonly performed, and they are grouped together for easy access.
Table 1. Core actions reference

ACTIO N D ES CR IPTIO N

Add a Comment Enables you to leave informative comments in the workflow designer for reference purposes. This is
especially helpful when there are other users collaborating on the workflow.

Add Time to Date Adds a specific time in minutes, hours, days, or months to a date (Year is not supported), and stores the
output value as a variable. The date can be a current data, specific date, or a lookup. The 'Current Date'
value returns UTC midnight.

Build Dictionary Builds a Dictionary variable of key/value pairs.


Note: The Dictionary uses JSON notation to store data. For more information on the Dictionary variable,
see Understanding Dictionary actions in SharePoint Designer 2013

Call HTTP Web Service Functions as a method call to an HTTP web service and returns data using the JSON format. Basic
authentication is supported through the RequestHeader.
For more information on the Dictionary variable, see Understanding Dictionary actions in SharePoint
Designer 2013

Count Items in a Dictionary Returns a count of the number of items in a specified dictionary.

Do Calculation Performs an arithmetic calculation and stores the output value in a variable.
Note: For SharePoint, this action supports only the Double numeric type. Integers are not supported.
Use of the "+" operator (concatenation) for strings is not supported.

Get an Item from a Dictionary Returns a particular item from a dictionary variable.

Log to History List Writes a message from a list of predefined message items to the workflow history list.

Pause for Duration Causes a workflow to pause executing for a specified time interval, in days, hours, and minutes.

Pause Until Date Causes a workflow to pause executing until a specified date and time.

Send an Email Automatically sends an email message that contains a predetermined message to a user or group when
a specified workflow event occurs.
Important: If the site is not added to the Trusted Sites list then emails are routed to the Outlook Junk
folder.

Set Time Portion of Date/Time Field Creates a timestamp, and stores the output value in a variable. You can set the time in hours and
minutes and add a current date, specific date, or lookup.

Set Workflow Status Sets the status of the workflow.

Set Workflow Variable Sets a workflow variable to a value. You can also use this action when you want the workflow to assign
data to a variable.

Go to Stage Specifies the next stage to which flow control should be handed.

Coordination actions
Coordination actions are used to invoke a workflow based on the SharePoint 2010 Workflow platform. For more information on Coordination actions, see Understanding Coordination
actions in SharePoint Designer 2013
Table2. Coordination actions reference

ACTIO N D ES CR IPTIO N

Start a List Workflow Starts a List workflow based on the SharePoint 2010 Workflow platform.
Note: The Start a list workflow has the following issues:> The 'Assignments' type field cannot be used as
a parameter when the 2010 workflow has a TaskProcess action in it.> When multiple calls are made to
the same 2010 workflow the result will be multiple data sources in the 2013 workflow lookup
functionality. These data sources are all the same.> Variable names in 2013 cannot contain special
characters such as '?' and '#'. If a 2010 workflow contains special characters then they will be converted
to hexadecimal code in the 2013 workflow.
ACTIO N D ES CR IPTIO N

Start a Site Workflow Starts a Site workflow based on the SharePoint 2010 Workflow platform..
Note: The Start a list workflow has the following issues:> The 'Assignments' type field cannot be used as
a parameter when the 2010 workflow has a TaskProcess action in it.> When multiple calls are made to
the same 2010 workflow the result will be multiple data sources in the 2013 workflow lookup
functionality. These data sources are all the same.> Variable names in 2013 cannot contain special
characters such as '?' and '#'. If a 2010 workflow contains special characters then they will be converted
to hexadecimal code in the 2013 workflow.

List actions
List actions group together actions that are used to manipulate lists and list items.
Table3. List actions reference

ACTIO N D ES CR IPTIO N

Check In Item Checks in an item that is checked out. You can check in items only from a document library.
Caution: The workflow crashes if you try to check in an item that is not checked out.

Check Out Item Checks out an item. The workflow verifies whether the item is checked in before it checks out a
document. You can check out items only from a library in your site.
Caution: The workflow crashes if you try to check out an item that is not checked in.

Copy Document Copies a document from the current list to a different Document Library list.

Create List Item Creates a new list item in the list that you specify. You can supply the fields and values in the new item.
You can use this action whenever you want a new item to be created with specific information.

Delete Item Deletes an item.


Note: This action is terminated on the computer running the Workflow Manager workflow engine and
throws a System.InvalidOperationException exception. There is no workaround.

Discard Check Out Item Discards the changes and checks the item back in if an item is checked out and changes have been made
to it.
Caution: The workflow crashes if you try to check in an item that is not checked out.

Set Field in Current Item Sets a specified field in the current item to a specified value.
Note: If you need the workflow to pause until the value of the field has changed, use the Wait for
Event in List Item action instead of this action.

Translate Document Translates a document into a particular language


Note: Requires a preconfigured Machine Translation Service Application.

Update List Item Updates a list item. You can specify the fields and the new values in those fields.

Wait for Event in List Item [Enhanced version of Office 2010 action.] Pauses the current instance of the workflow to await a specified
list item event. This action listens for two events: ItemUpdated and ItemAdded.

Wait for Field Change in Current Item Waits for a field on the current item to equal a particular value.

Project actions
Project actions support the integration of Microsoft Project. They are used to build Project-based workflows. All of the Project actions are new in SharePoint Designer 2013.
Table4. Project actions reference

ACTIO N D ES CR IPTIO N

Create Project from Current Item Takes the current item and creates a new project in the SharePoint farm PWA site. Using App Steps with
this action is not supported in Project Online.

Set Project Field Sets a value for a particular field on Project Server.
Note: This action requires the project to be checked in first. If the project is not checked in, the workflow
will be terminated and users cannot open that project in Project Web App.

Set Project Stage Status Sets the status of the Project Stage.
Note: An exception occurs when a current project is checked out.

Set status field in idea list Updates the status on the original list item that is associated to the current project.

Wait for Project Event Waits for a particular Project Event.

Task actions
Task actions provide the ability to invoke a workflow based on the SharePoint 2010 Workflow platform from within a workflow based on the SharePoint Workflow platform.
Table 5. Task actions reference

ACTIO N D ES CR IPTIO N

Assign a Task Assigns a workflow task to a user and establishes a due date for completion of the task.

Start a Task Process Creates tasks on multiple users and enables the tasks to be taken through a customized process.

Utility actions
Utility actions are actions that manipulate strings or find the interval between dates.
Table 6. Utility actions reference

ACTIO N D ES CR IPTIO N

Extract Substring from End of String Copies a specified number of characters starting from the end of a string and stores the output in a
variable.

Extract Substring from Index of String Copies a substring starting at a specified index in the string and places the value in a variable.
Note: Be aware that although the index value in Microsoft SharePoint Designer 2013 is zero-based,
values in SharePoint Designer 2010 were indexed starting at 1.

Extract Substring from Start of String Copies a specified number of characters beginning at the start of a string and stores the output in a
variable.

Extract Substring of String from Index with Length Copies out a substring comprising a specified number of characters, starting at a specified index in the
string, and places the value in a variable.
Note: Be aware that although the index value in Microsoft SharePoint Designer 2013 is zero-based,
values in SharePoint Designer 2010 were indexed starting at 1.

Find Interval Between Dates Calculates the time interval in minutes, hours, or days between two dates and stores the output in a
variable.

Trim String Removes white spaces from the beginning and end of a string.

Find Substring in String Finds a particular substring inside of a string and returns the index of the substrings's starting position.

Replace Substring in String Replaces a particular substring with another substring.

Trim String Removes white spaces from the beginning and end of a string.

Workflow actions that are deprecated in SharePoint


For a list of actions from SharePoint 2010 that are deprecated and will not appear in SharePoint, see Workflow actions available using the workflow interop bridge.

See also
Workflow actions and activities reference for SharePoint
SharePoint workflow fundamentals
Get started with workflows in SharePoint
Workflow development in SharePoint Designer and Visio
Workflow actions available using the workflow interop bridge
3/26/2018 • 2 minutes to read Edit Online

Contains a concise list of workflow actions in SharePoint 2010 that are available to SharePoint workflows by using the workflow interop bridge.

Workflow actions for the interop bridge


The SharePoint workflow infrastructure is built on Windows Workflow Foundation (WF) 4 and therefore executes workflows in Microsoft Azure. For this reason, some actions from
SharePoint 2010 workflows are available in SharePoint only when using the SharePoint workflow interop .
The following actions are available only when you use the workflow interop bridge.
Add List Item Permissions
Assign a Form to a Group
Assign a To-do Item
Capture a version of the Document Set
Collect Data from a User
Copy List Item
Declare Record
Inherit List Item Parent Permissions
Lookup Manager of a User
Remove List Item Permissions
Replace List Item Permissions
Send Document Set to Repository
Set Content Approval Status
Set Content Approval Status for the Document Set
Set Workflow Status
Start Approval Process
Start Custom Task Process
Start Document Set Approval Process
Start Feedback Process
Undeclare Record

Conditions and blocks


Conditions
If current item field equals value
Check list item permission levels
Check list item permissions
Blocks
Impersonation block

See also
Workflow actions quick reference (SharePoint Workflow platform)
SharePoint workflow interop
Workflow development in SharePoint Designer and Visio
Set up and configure SharePoint Workflow Manager
Workflow conditions quick reference (SharePoint 2010 Workflow platform)
3/26/2018 • 14 minutes to read Edit Online

Learn about the workflow conditions that are available in the SharePoint 2010 Workflow Platform in Microsoft SharePoint Designer 2013.Use this article only if you are working in
SharePoint Designer 2013, but want to continue to use the SharePoint 2010 Workflow Platform.If instead you want to use the SharePoint Workflow Platform, see Workflow actions and
activities reference for SharePoint, and other articles listed in the "Additional resources" section, which describe new features that are available in the newer platform.To begin creating a
workflow by using the 2010 Workflow Platform, select SharePoint 2010 Workflow in the Platform Type box in the Create Workflow dialog box.

Where to find the workflow conditions


There are two ways to access the menu of available workflow conditions.
While you are editing inside a workflow step, do one of the following:
On the Workflow tab, in the Insert group, click Conditions to open the list of workflow actions.
Double-click inside a workflow step. In the search box that appears, type text that appears in the name of the condition that you want, such as "created", and then press Enter. Actions
and conditions that contain the text you typed appear after the text box.

Which conditions are available to you while you are creating or modifying a workflow depends on the precise context that you are working in. See the following illustration for more
information.

1 General conditions in SharePoint Designer 2013.


2 Check exact list item permissions and Check list item permissions are available only inside an impersonation step.
3 The file size is a specific range kilobytes and The file type is a specific type are available only in a workflow that is associated with the Document content type, a child of the
Document content type, or a library.
4 If any value equals value and Person is a valid SharePoint user are the only conditions available when you create a site workflow.

General conditions
This section describes the conditions that are available in SharePoint Designer 2013 for list and reusable list workflows, no matter what list type or content type the workflow is associated to.

If any value equals value


This condition is initially displayed in a workflow step as If any value equals value. Use this condition when you want to compare one value with another value. Each value can be static
text, a dynamic string, or a lookup to a variable, to context information, or to a SharePoint field.
You can select from a wide range of operators in your condition, such as contains and is greater than. To do so, you must set the first value in the condition and then click equals. The
operators that are available depend on what the first value in the condition is set to. For example, if you used the lookup dialog to set the first value in the condition to a Date and Time data
type, such as Created, the Contains operator is not among the available options.
There are two variations of the equals and contains operators:
The equals and contains operators are both case-sensitive.
The equals (ignoring case) and contains (ignoring case) operators are not case-sensitive.
The option that you choose for the second value in the condition also depends to some extent on what the first value is set to. For example, suppose that you set the first value to Created,
and then you look up the second value by using a variable that is a string, such as Last 10 Characters. You would probably want to return the string As Date/Time, so that the comparison
with Created will return predictable results.
NOTE

You can use logical operators such as||(or) or && (and) in the condition.
Following are examples of what the condition might look like in a workflow step:
If Variable: A week from Modifiedis greater thanToday
If Variable: Specification Namecontains (ignoring case)SharePoint Designer || SPD
The If any value equals value condition is one of only two conditions available when you are working in a site workflow, the other being Person is a valid SharePoint user. For more
information about site workflows, see the Conditions available within a site workflow section of this article.
If current item field equals value
This condition is initially displayed in a workflow step as If field equals value. Use this condition to compare the value in a field in the current item (that is, the item that the list or reusable
list workflow is currently running on) to another value. Values can be static text, dynamic strings, or lookups to variables, to context information, or to other SharePoint fields.
You can click field to see the list of options. The available options for field depend on the content type, list, library, or site that the workflow is associated to. For example, a workflow that is
associated to a default library will have field options such as Title, Created, and Created By.
You can select from a range of operators in your condition, including contains and is greater than. Before you select an operator, you must first select a value for field, and then click
equals. Which operators are available depends on the field setting. For example, if you used the lookup dialog to set field to a Date and Time data type, such as Created, the Contains
operator is not listed as an option.
There are two variations of the equals and contains operators. The equals and contains operators are case-sensitive, while the equals (ignoring case) and contains (ignoring case) are
not case-sensitive. For example, if you set field to Title and then use the contains operator, and if the value in your condition isDocument, then the condition is true only if the title contains
Document, with a capital D, and not if it contains only document, without a capital D. If you use the contains (ignoring case) operator instead, then the condition is true for titles containing
eitherDocument ordocument or both.
The option that you choose for value also depends to some extent on what field is set to. For example, suppose that you set field to Created, and then you look up the value by using a
variable that is a string, such as Last 10 Characters. You would probably want to return the string As Date/Time, so that the comparison with Created will return predictable results.
NOTE

You can use logical operators such as||(or) or && (and) in the condition.
Following are examples of what the condition might look like in a workflow step. (Note that in the first example, is less than is interpreted to mean "earlier than".)
If Current Item:Modifiedis less than1/1/2010 12:00:00 AM
If Current Item:Pathcontains (ignoring case)Marketing || Public Relations

Created by a specific person


This condition is initially displayed in a workflow step as If created by specific person. Use this condition to discover whether an item was created by a specified user. You can specify the
user either by entering their user name or email address manually (for example, Olivier@contoso.com) or by selecting the user from among users already listed in SharePoint, Exchange, or
Active Directory.
NOTE

Because both the user name and the e-mail address are case sensitive, it is recommended that you use the latter method to ensure correct cases. If you must enter a user name or e-mail
address manually, be careful to match the cases precisely. For example, the condition If created by contoso\molly does not evaluate as true if the user account is registered as
Contoso\Molly.
Following is an example of what the condition might look like in a workflow step:
If created by Molly Clark

Created in a specific date span


This condition is initially displayed in a workflow step as If created between date and date. Use this condition to discover whether an item was created between two specified dates. You
can use the current date, a specified date, or the result of a lookup.
Following is an example of what the condition might look like in a workflow step:
If created between 1/1/2009 and1/1/2010 12:00:00 AM

Modified by a specific person


This condition is initially displayed in a workflow step as If modified by specific person. Use this condition to discover whether an item was modified by a specified user. The user can be
specified as an e-mail address, such as olivier@contoso.com, or selected from SharePoint, Exchange, or Active Directory users.
NOTE

The user name and e-mail address are case sensitive. It is recommended that you select a user name or e-mail address to help ensure that you use the correct case. If you type a user name or
e-mail address, you must match the case of the account. For example, If modified by contoso\molly will not evaluate as true if the user account is Contoso\Molly.
Following is an example of what the condition might look like in a workflow step:
If modified by Molly Clark

Modified in a specific date span


This condition is initially displayed in a workflow step as If modified between date and date. Use this condition to discover whether an item was modified between two specified dates.
For each of the date values, you can use the current date, a specified date, or the result of a lookup.
Following is an example of what the condition might look like in a workflow step,
If modified between 1/1/2009 and1/1/2009 12:00:00 AM

Person is a valid SharePoint user


This condition is initially displayed in a workflow step as If person is a valid SharePoint user. Use this condition to discover whether the specified user is a member of the SharePoint site.
In SharePoint Designer 2013, you can include people outside your corporate domain (called external participants) in your workflows. For example, suppose that you have assigned tasks in
your workflow to external participants. You can then use this action to make a site user follow up with the external participants until the tasks are complete.
Following is an example of what the condition might look like in a workflow step,
If Molly Clark is a valid SharePoint user
The Person is a valid SharePoint user condition is one of only two conditions available when you are working in a site workflow, the other being If any value equals value. For more
information about site workflows, see the Conditions available within a site workflow section in this article.

Title field contains keywords


This condition is initially displayed in a workflow step as If title field contains keywords. Use this condition to discover whether the Title field for an item contains specified text. You can
either specify the text in the String Builder (as a static value, as a dynamic string, or as a combination of the two) or insert a lookup to a field or variable.
NOTE

When using the Title field contains keywords condition, you cannot search for more than a single keyword text. To search for multiple, alternative keyword texts, you can use logical
operators such as||( or) and && (and) in either of the following two conditions: If any value equals value and If current item field equals value. (Use the latter condition if you want to
search in the Title field only). For an example, see the following image:>

Conditions available only within an impersonation step


By default, when a workflow is started manually it uses the permissions of the person who starts it. But what if the person who starts it doesn't have adequate rights for one or more of the
operations that the workflow will need to perform? For example: What if the workflow will sometimes need to archive a document to a library for which the person who starts the workflow
might have only the Read permission level, which does not include permission to archive?
In such cases, you can use one or more impersonation steps in the workflow. An impersonation step uses the permissions of the person who most recently saved the workflow template???
typically the author of the template, who would typically have the needed permissions for all of the workflow's operations, including in this case permission to archive the document to the
appropriate library.
NOTE

For both of these conditions, all of the specified users and groups must pass the comparison in order for the condition to evaluate to True.> For both of these conditions, it does not matter
whether the specified permissions have been assigned explicitly to the specified individual users or whether the permissions are held by those individual users only implicitly (as members of
a group to which the permissions have been assigned, for instance).For specified groups , on the other hand, the permissions must have been assigned explicitly and not inherited from a
parent group.

Check list item permissions


This condition is initially displayed in an impersonation step as If permissions for these users are at least these permissions on item in this list.
Use this condition to discover whether, for the specified list or library, the individual permissions that each specified user and group holds include all of the individual permissions that are
included in the specified security level or levels.
Examples
A user or group has only the Read permission level for a list, but the condition specifies the Approve level. The Read level does not include all of the permissions that are included in
the Approve level, so in this case the condition evaluates as False.
Another user or group has the Full Control permission level for the same list. The Full Control level does include all of the permissions that are included in the Approve level (as well
as other permissions), and so this time the condition evaluates as True.
Following is an example of what the condition might look like in a workflow step:
If permissions for Contoso Members are at leastRead on item inCurrent Items

Check list item permission levels


This condition is initially displayed in an impersonation step as If permission levels for these users are at least these permission levels on item in this list.
Use this condition to discover whether, for the specified list or library, each specified user and group has been explicitly assigned the specified permission level or levels . Permissions held
only implicitly (for instance, by a member of a group to which the permissions have been assigned) are not considered by this condition, and neither are the individual permissions held by
the specified users and groups.
Examples
A user has been explicitly assigned only the Full Control permission level for a list, but the condition specifies only the Read level. Even though the user holds all of the individual
permissions that are included in the Read level, the user not been explicitly assigned the Read level, so the condition evaluates as False.
A different user has been explicitly assigned only the Design permission level for a different list, but the condition specifies both the Design level and the Manage Hierarchy level.
Because the user has been assigned only one of the two required levels, the condition evaluates as False.
For a third list, a user is a member of the Members group and inherits permissions from that group. However, no permissions level has been explicitly assigned to the user. The
condition requires explicit assignment of the Contribute level, so because the user holds the permissions of that level only implicitly, the condition again evaluates to False.
Following is an example of what the condition might look like in a workflow step:
If permission levels for Contoso Members are at leastRead on item inCurrent Items

Conditions available only when the workflow is associated to a library or the Document content type
The conditions The file size is a specific range kilobytes and The file type is a specific type are available only when your workflow is associated with a Library or the Document content
type.

The file size in a specific range of kilobytes


This condition is initially displayed in a workflow step as If the file size is between size and size kilobytes. Use this condition to discover whether the file size of a document falls between
two specified sizes measured in kilobytes. The condition does not include the specified sizes in the evaluation. For each instance of size, you can either enter a number or use a lookup.
Following is an example of what the condition might look like in a workflow step,
If the file size is between 1023 and1048577 kilobytes
NOTE

The specified upper and lower limits are not included in the defined range. In the example given here, a file that is 1023 KB would evaluate as false because it is not between 1023 and
1048577.

The file type is a specific type


This condition initially displays in a workflow step as If the file type is specific type. Use this condition to discover whether the file type of the current item is the specified type, (such as
docx. You can either enter the file type as a string or use a lookup.
Following is an example of what the condition might look like in a workflow step:
If the file type is docx
Conditions available within a site workflow
Site workflows operate at the site level and are not associated with a list item. When you are working in a site workflow, only the following conditions are available. (All other conditions in
SharePoint Designer 2013 operate on list items, and therefore none of them function in site workflows.)
If any value equals value
Person is a valid SharePoint user
From within an impersonation step in a site workflow:
Check list item permissions
Check list item permission levels
Person is a valid SharePoint user
For more information about conditions, see the General conditions section of this article.

See also
What's new in workflows for SharePoint
Get started with workflows in SharePoint
Workflow development in SharePoint Designer and Visio
Workflow actions quick reference (SharePoint 2010 Workflow platform)
3/26/2018 • 38 minutes to read Edit Online

Learn about the workflow actions that are available in the SharePoint 2010 Workflow Platform in Microsoft SharePoint Designer 2013.Use this article only if you are working in SharePoint
Designer 2013, but want to continue to use the SharePoint 2010 Workflow Platform.If instead you want to use the SharePoint Workflow Platform, see Workflow actions quick reference
(SharePoint Workflow platform), along with other articles (mentioned in the "Additional resources" section.md) about new features that are available in the newer platform.To begin creating
a workflow by using the 2010 Workflow Platform, select SharePoint 2010 Workflow in the Platform Type box in the Create Workflow dialog box.

Where to find the workflow actions


There are two ways to access the menu of available workflow actions.
While you are editing inside a workflow step, do one of the following:
On the Workflow tab, in the Insert group, click Actions.
Double-click inside the workflow step. In the search box that appears, type text that appears in the name of the action that you want (such as "add"), and then press Enter. Actions and
conditions that contain the text that you typed appear below the text box.

The actions available to you during workflow creation depend on the current context. For example, the Start Approval Process and Start Feedback Process actions are not available for
sites that are based on Microsoft SharePoint Foundation 2013. Some list actions are available only inside an impersonation step, and others are available only when your workflow is
associated with a document library or document content type. List actions that work on the current item, such as Set Content Approval Status and Set Field in Current Item, are not
available in a site workflow.
Actions are organized into categories based on their area of application in a workflow. For example, actions that affect an item's behavior are listed under List Actions, actions pertinent to
Document Sets under Document Set Actions, and custom workflow actions under Custom Actions. The categories for actions are:
Core Actions
Document Set Actions (appear only when your workflow is associated with a document library or a document content type)
List Actions
Relational Actions (appear only when your SharePoint site is running SharePoint)
Task Actions (appear only when your SharePoint site is running SharePoint)
Task Behavior Actions (appear only when you are customizing tasks in pre-built workflow actions, such as Start Approval Process and Start Feedback Process)
Utility Actions
Custom Actions

General actions
General actions are actions that display in the Actions list in all workflow contexts.

ACTIO N D ES CR IPTIO N

Core Actions Actions in this category are the ones most commonly used in workflows.

Add a comment This action is initially displayed in a workflow step as Comment: comment text. Use this action to leave
informative comments in the workflow designer for reference purposes. This is especially helpful when
there are other users co-authoring the workflow. For example, if a variable in the current workflow
doesn't have a user-friendly name, you can use this action to add a comment to indicate what the
variable does in the workflow.
Following is an example of what the action might look like in a workflow step:
- Comment: This variable provides the department of the workflows initiator.
Note: Anyone editing the workflow in Microsoft Visio 2013 will also be able to view the comments.

Add Time to Date This action is initially displayed in a workflow step as Add 0 minutes to date (Output to Variable:
date). Use this action to add a specified number of minutes, hours, days, months, or years to a date
value and to store the output value in a variable. The date value to which the time is added can be the
current date, a specified date, or the result of a lookup.
Following is an example of what the action might look like in a workflow step:
- Add 7 days to Current Item:Modified (Output to: Variable: A week from Modified)

Do Calculation This action is initially displayed in a workflow step as Calculate value plus value (output to Variable:
calc). Use this action to perform a calculation using two values and to store the output value in a
variable. Possible calculations include addition, subtraction, multiplication, and division.
Following are examples of what the action might look like in a workflow step:
- Calculate 36divided by9 (Output to Variable:Number of Widgets/)
- Calculate [fx :: Courses*, Filled Seats] plus 1 (Output to Variable: New Filled Seats)
ACTIO N D ES CR IPTIO N

Log to History List This action is initially displayed in a workflow step as Log this message to the workflow history list
Use this action to log a message in the workflow's history list about the workflow's actions or progress.
The message can be a summary of a workflow event, or anything else that you want to capture about
the current run of the workflow. Such messages can be helpful in troubleshooting workflow issues. For
example, you can log a message that records an event like Copied to list A or Sent email to
reviewers. After the workflow completes successfully, you can go to the Workflow History list and see
the messages displayed in the Description column.
Following is an example of what the action might look like in a workflow step:
- Log A week from Modified variable set to the workflow history list
Note: If you want an action that stops the workflow and then logs a message to the history list, use the
Stop Workflow action instead.

Pause for Duration This action is initially displayed in a workflow step as Pause for 0 days, 0 hours, 5 minutes. Use this
action to pause the workflow for a duration specified as a number of days, hours, and minutes.
Note: The delay time that is initially displayed reflects the timer job interval, which has a default value of
five minutes.

Pause until Date This action is initially displayed in a workflow step as Pause until this time. Use this action to pause the
workflow until a particular date. You can use the current date, a specified date, or the result of a lookup.
Following are examples of what the action might look like in a workflow step:
- Pause until 1/1/2010 12:00:00 AM
- Pause until Variable: A week from Modified

Send an Email This action is initially displayed in a workflow step as Email these users. Use this action to send an email
message to a user or a group. It is commonly used to send a confirmation message to workflow
participants. Email recipients can be a user or a group within the site collection, or anyone inside your
organization. You can now specify a dynamic value, such as a lookup or a string, in your subject.
Important: Outgoing e-mail must be configured in SharePoint Central Administration. Following is an
example of what the action might look like in a workflow step:
- Email Variable: approvers

Set Time Portion of Date/Time Field This action is initially displayed in a workflow step as Set time as 00:00 for date (Output to Variable:
date1). Use this action to create a timestamp and to store the output value in a variable. You can set the
time in hours and minutes and add the current date, a specified date, or the result of a lookup. For
example, suppose you want to add a timestamp to any new customer order that is added to an orders
list. Instead of using the current time when the order was actually received in the timestamp, you want
to add a specific time so that you can have your workflow perform any operation (such as routing orders
to the warehouse) on all new items that have the same timestamp. Another example: Suppose that you
have a presentation scheduled for 9 a.m. on a particular day, and you want to receive an email reminder.
You can use this action to add the time to the date, pause the workflow till the day before the
presentation, and then have the workflow send you the reminder.
Following is an example of what the action might look like in a workflow step:
- Set time as 00: 00 for Current Item:Modified (Output to Modified time variable set to midnight)

Set Workflow Status This action is initially displayed in a workflow step as Set workflow status to Canceled. Use this action
to set the status of the workflow. The default options are Canceled, Approved, and Rejected.
If you type a new status value in the dropdown list in the action, your new status is automatically added
to the dropdown list for subsequent use. For example, you can add a custom status that is more user-
friendly and informative than Completed or Canceled, such as Expense Report Approved.
Note:
- You cannot rename or delete a custom status value once it has been created. However, you do not
ever have to use it.
- A custom status is applicable to the current workflow only, and cannot be used in another workflow.
- A workflow cannot use custom status values that you define in the action if the action is used inside an
impersonation step.
If the Set Workflow Status action is the last step in a workflow where you have also used a custom
value, you can see your custom value in the Status column in the list when the workflow pauses or
completes.
Following is an example of what the action might look like in a workflow step:
- Set workflow status to Specification status: Ready for Design Review

Set Workflow Variable This action is initially displayed in a workflow step as Set workflow variable to value. Use this action to
direct the workflow to assign value data to a workflow variable.
Following is an example of what the action might look like in a workflow step:
- Set Variable: Expense report total to Current Item:Total

List Actions Actions in this category perform operations on list items.


Note: Some actions in this category appear in some but not all workflow contexts. For example, some
list actions only appear when you click inside an impersonation step in your workflow, while some appear
only when your workflow is attached to a document library or document content type. For more
information, see Actions available only within an impersonation step and Actions available when the
workflow is associated to a document library or document content type later in this article.

Check In Item This action is initially displayed in a workflow step as Check in item in this list with comment:
comment. Use this action to check in an item that is currently checked out.
Following is an example of what the action might look like in a workflow step:
- Check in item in Expense Reports with comment: Expense report approved
Note: You can check in items only in document libraries.

Check Out Item This action is initially displayed in a workflow step as Check out item in this list. Use this action to check
out an item that is currently checked in.
Following is an example of what the action might look like in a workflow step:
- Check out item in Current Item
Note:
- You can check out items only from a library in your site.
- Before checking the item out, the workflow first verifies that the item is currently checked in.
ACTIO N D ES CR IPTIO N

Copy List Item This action is initially displayed in a workflow step as Copy item in this list to this list. Use this action to
copy a list item to another list. (If there is a document in the list item, the workflow also copies the
document to the destination list.)
Following is an example of what the action might look like in a workflow step:
- Copy item in Current Item to Archive Requests
Important: There must be at least one column similar in both the source list and the destination list.

Create List Item This action is initially displayed in a workflow step as Create item in this list (Output to Variable:
create). Use this action to create a new list item in the list that you specify. You can supply the fields and
values in the new item.
You can use this action whenever you want a new item to be created containing specified information.
For example, create an announcement whenever an important company-related document (such as a
contract) is approved, or archive documents.
Note:
- The output variable is the ID of the new item created in the list. Following is an example of what the
action might look like in a workflow step:
- Create item in Orders (Output to Variable: New Order ID)

Delete Item This action is initially displayed in a workflow step as Delete item in this list. Use this action to delete an
item from a list.
Following is an example of what the action might look like in a workflow step:
- Delete item in Documents

Discard Check Out Item This action is initially displayed in a workflow step as Discard check out of item in this list. Use this
action to check an item back in without retaining any changes that have been made to it since it was last
checked out.
Following is an example of what the action might look like in a workflow step:
- Discard check out of item in Documents

Set Content Approval Status This action is initially displayed in a workflow step as Set content approval status to this status with
comments. Use this action to set the content approval status field to a value such as Approved,
Rejected, or Pending. (You can also type a custom status in the action.)
Following is an example of what the action might look like in a workflow step:
- Set content approval status to Approved with Looks good
Note: Content approval must be enabled in the list for this action to function. This action works on the
item that the workflow is currently acting upon, and therefore is not available in a site workflow.

Set Field in Current Item This action is initially displayed in a workflow step as Set field to value. Use this action to set a field in
the current item to a value.
Following is an example of what the action might look like in a workflow step:
- Set Content Type ID to Specification
Note:
- If you want to pause the workflow until the value of a field changes use the Wait for Field Change in
Current Item action instead.
- The Set Field in Current Item action is not available when you are working in a site workflow.

Update List Item This action is initially displayed in a workflow step as Update item in this list. Use this action to update
a list item. You can specify the fields and the new values in those fields.
Following is an example of what the action might look like in a workflow step:
- Update item in Documents

Wait for Field Change in Current Item This action is initially displayed in a workflow step as Wait for field to equal value. Use this action to
pause the workflow until the specified field in the current item has changed to a specified value.
Following is an example of what the action might look like in a workflow step:
- Wait for Approval Statusto equal1;#Rejected
Note: If you want the workflow to change the value of the field, rather than having the workflow wait
for the field to change, use the Set Field in Current Item action instead.

Task Actions Actions in this category pertain to task items.

Assign a Form to a Group This action is initially displayed in a workflow step as Assign a custom form to these users. Use this
action to create a custom task form and to assign the form to one or more participants or groups.
Participants provide their responses in the fields of the form and, when they are done, click Complete
Task on the form.
Following is an example of what the action might look like in a workflow step:
- Assign Asset Reporting to Marketing
Note: There is not a return value that identifies the task data.

Assign a To-do Item This action is initially displayed in a workflow step as Assign a to-do item to these users. Use this
action to assign a to-do task to one or more participants or groups, prompting them to perform their
tasks and then, when they are done, to click the Complete Task button on their task form.
Following is an example of what the action might look like in a workflow step:
- Assign Submit expense report to Marketing

Collect Data from a User This action is initially displayed in a workflow step as Collect data from this user (Output to Variable:
collect). Use this action to assign a task to the participant, prompting them to provide the needed
information in a custom task form, and then to click the Complete Task button on the task form.
This action has an output clause???that is, the workflow stores the information returned by the action in
a corresponding variable. The list-item ID of the completed task item from the action is stored in the
collect variable.
Following is an example of what the action might look like in a workflow step:
- Collect Expense report from Marketing (Output to Variable: Marketing Expense Report)
ACTIO N D ES CR IPTIO N

Utility Actions Most actions in this category can be used to extract information from text strings.
You can cut up a text string and use it in several different scenarios in a workflow. For example, suppose
that your company wants to stamp all incoming documents by using a specific name format such as
date_department (for example: 07142009_sales.docx), and you want to run workflows that assign tasks
to a reviewer based on the date in the stamp on that file. You could use a utility action to get the first 8
characters of the document name (07142009) and convert them into a date by using lookup coercions,
so that you can assign tasks that have that due date.
For more information on lookup coercions, see the See Also section.

Extract Substring from End of String This action is initially displayed in a workflow step as Copy 0 characters from end of string (Output to
Variable: substring). Use this action to copy a specified number of characters from the end of a string
and to store the output value in a variable. You specify the number of characters that the workflow
copies from the string.
Following is an example of what the action might look like in a workflow step:
- Copy 15 characters from end of Current Item:Name (Output to Variable:
Copy15CharFromEndOfName)

Extract Substring from Index of String This action is initially displayed in a workflow step as Copy from string, starting at 0 (Output to
Variable: substring. Use this action to copy all characters starting from a specified character in a string
and to store the output in a variable.
Following is an example of what the action might look like in a workflow step:
- Copy from Current Item:Name, starting at 4 (Output to Variable: CopyStringFromChar4)

Extract Substring from Start of String This action is initially displayed in a workflow step as Copy 0 characters from start of string (Output
to Variable: substring). Use this action to copy a specified number of characters from the start of a
string and to store the output in a variable. You specify the number of characters that the workflow
copies from the string.
Following is an example of what the action might look like in a workflow step:
- Copy 15 characters from start of Current Item:Name (Output to Variable:
Copy15CharFromStartOfName)

Extract Substring of String from Index with Length This action is initially displayed in a workflow step as Copy from string, starting at 0 for 0 characters
(Output to Variable: substring). Use this action to copy a specified number of characters starting from
a particular character in a string and to store the output in a variable. You specify the number of
characters that the workflow copies from the string.
Following is an example of what the action might look like in a workflow step:
Copy from Current Item:Name, starting at 4 for 15 characters (Output to Variable:
CopyfromChar4for15CharOfName)

Find Interval Between Dates This action is initially displayed in a workflow step as Find minutes between date and date (Output to
Variable: time). Use this action to calculate the time difference, in terms of minutes, hours, or days,
between two dates and to store the output in a variable.
Following is an example of what the action might look like in a workflow step:
- Find minutes between CurrentItem:Modified and Today (Output to Variable: Last Modified In Minutes

Actions available when your SharePoint site is running SharePoint


Actions such as Start Approval Process, Declare Record, and Lookup Manager of a User are available only when your SharePoint site is running SharePoint.

ACTIO N D ES CR IPTIO N

Document Set Actions Actions in this category pertain to a Document Set. A Document Set is a folder in which documents are
stored. In a workflow, a Document Set is treated as a single item.
Note: To be able to use Document Sets in your library, you must add the Document Set content type
from your Library Settings page in your SharePoint site.

Start Document Set Approval Process This action is initially displayed in workflow steps as Start Approval process for the contents of this
Document Set with the users specified by this column. Use this action to start an approval action on
a Document Set and all of the documents that it contains.
When you use this action, both the status of the Document Set and the status of all of the documents
that it contains it are changed (for example, to Approved or to Rejected).
If, on the other hand, you use the Start Approval Process action on the Document Set, only the status
of the Document Set itself is changed, and not the statuses of the individual documents that it contains.
Following is an example of what the action might look like in a workflow step:
- Start Bill of material approval process for the contents of this Document Set with the users specified by
Variable: Bill of Materials Approvers

Capture a version of the Document Set This action is initially displayed in workflow steps as Capture a version of this Document Set that
includes the type versions of the contents with comment: comment. Use this action to lock the
version of the Document Set that contains the version of documents, major or minor, that you specify in
the action.
Following is an example of what the action might look like in a workflow step:
- Capture a version of this Document Set that includes the last major versions of the contents with
comment: Last major version of the Bill of Material

Send Document Set to Repository This action is initially displayed in workflow steps as Submit Document Set using this action to this
destination content organizer with this explanation (Output to Variable: submit file result). Use
this action to move or copy a Document Set to a document repository. A document repository can be a
library in your SharePoint site, or an entire site (like the Document Center), that routes records to a
specific destination by using rules that you define.
Following is an example of what the action might look like in a workflow step:
- Submit Document Set using Copy to DocumentRepository:GUID with Copy final bill of Material to
repository (Output to Variable: Copy Document Set to repository)
Note: Before you can define rules and route documents, you must enable the Content Organizer site
feature in your SharePoint site. For more information, see the Configure the content organizer to route
records topic in the See Also section.
ACTIO N D ES CR IPTIO N

Set Content Approval Status of the Document Set This action is initially displayed in workflow steps as Set content approval status for the contents of
this Document Set to this status with comments. Use this action to set content approval of a
Document Set to Approved, Rejected, or Pending.
Following is an example of what the action might look like in a workflow step:
- Set content approval status for the contents of this Document Set to Approved with The bill of
materials is approved
Note: Content approval must be enabled in the list before you can use this action.

Task Actions Actions in this category are used in approval scenarios. There are two pre-built workflow actions in this
category: Start Approval Process and Start Feedback Process. Pre-built actions work sort of like
sub-workflows, meaning that the workflow logic is already defined in the actions. All you need to do is
supply the appropriate information.
These actions are used in the globally reusable workflows Approval-SharePoint and Collect
Feedback-SharePoint that are included with SharePoint. For information about when to use these
workflows and when to use the actions, see the When should you use the approval and feedback
actions? section of this article.
Also available is the Start Custom Task Process, which also has built-in logic, but which (unlike the
previous two actions.md) does not come pre-built with what the workflow should be doing at each
phase.
A category of actions called Task Behavior Actions appear in the Actions list only when you customize
the behavior of an approval action such as Assign Item for Approval or Assign Item for Feedback
For more information on Task Behavior Actions, see the Actions available within task actions section of
this article.

Start Approval Process This action is initially displayed in a workflow step as Start Approval process on Current Item with
these users. Use this action to route a document for approval. Approvers can approve or reject the
document, reassign the approval task, or request changes to the document.
The Start Approval Process action behaves like a pre-built workflow: the logic is already defined in the
action. The action has distinct phases built in to define task behaviors, task process behaviors, logging to
the History Log, e-mail notifications, and completion conditions. Although the action comes with this
pre-built logic, it still needs information from you???such as who the reviewers are, whether the approval
tasks are assigned one at a time ("in serial", the default) or all at once ("in parallel"), and the due dates or
permitted durations for task completion.
You can assign tasks to both internal and external participants. An external participant can be either an
employee in your organization who isn't a user in the site collection or anyone outside of your
organization.
Following is an example of what the action might look like in a workflow step:
-Start Specification Approval process on Current Item with Variable: Approvers

Start Feedback Process This action is initially displayed in a workflow step as Start Feedback process on Current Item with
these users. Use this action to route a document for feedback. Reviewers can submit feedback or
reassign the feedback task.
The Start Feedback Process action behaves like a pre-built workflow: the logic is already defined in the
action. The action has distinct phases built in to define task behaviors, task process behaviors, logging to
the History Log, e-mail notifications, and completion conditions. Although the approval action comes
with this pre-built logic, it still needs information from your end???such as who the reviewers are,
whether the approval tasks are assigned one at a time ("in serial", the default) or all at once ("in parallel"),
and the due dates or permitted durations for task completion.
You can assign tasks to both internal and external participants. An external participant can be either an
employee in your organization who isn't a user in the site collection, or anyone outside of your
organization.
Following is an example of what the action might look like in a workflow step:
- Start Specification Feedback process on Current Item with Variable: Reviewers

Start Custom Task Process This action is initially displayed in a workflow step as Start Task process on Current Item with these
users. Use the Start Custom Task Process action (an approval process template) if neither of the two
preceding approval actions meets your needs. The Start Custom Task Process also allows logic to be
built inside of it; but unlike the other two approval actions, it does not come pre-built with every action
that the workflow needs in each of its phases. You can specify your own actions and conditions in task
behaviors or completion conditions.
Following is an example of what the action might look like in a workflow step:
- Start Video Lesson Approval process on Current Item with Variable: Approvers

List Actions Actions in this category perform operations on list items.

Declare Record This action displays in a workflow step as Declare this item as a record. Use this action to identify a
document as a record and to apply the record restrictions settings you may have defined in the Record
Declaration Settings page on your SharePoint site.
There are no variables to set for this action.
You can define record declaration settings at the top-level site in your site collection. Record declaration
settings govern how records are treated, such as whether they can be edited or deleted, what metadata
is applied to them, and what the record-retention policy is. Record declaration settings specify
restrictions that should be applied after an item is declared as a record, as well as which user roles are
allowed to declare records and whether record declaration is available to all site users.

Undeclare Record This action displays in a workflow step as Undeclare the item as a record. Use this action to undo any
record declaration settings that are applied to a record.
There are no variables to set for this action.
You can define record declaration settings at the top-level site in your site collection. Record declaration
settings govern how records are treated, such as whether they can be edited or deleted, what metadata
is applied to the record, and what a record's retention policy is. Record declaration settings specify
restrictions that should apply after an item is declared as a record, user roles allowed to declare records,
and if record declaration is available to all site users.

Relational Actions The action in this category enables you to look up a user's manager and to store that output value in a
variable.

Lookup Manager of a User This action is initially displayed in workflow steps as Find Manager of this user (output to Variable:
manager). Use this action to look up a user's manager and to store that output value in a variable.
Following is an example of what the action might look like in a workflow step:
- Find Manager of Workflow Context:Initiator (output to Variable: manager)
Actions available within task actions
Actions such as Start Approval Process and Start Feedback Process can be used in workflows to assign list items for approval or feedback. While these actions are pre-built (that is, much
of the workflow logic is already defined in the action), you will supply additional information required by the action (for example, by identifying the approvers or reviewers to whom tasks are
to be assigned).

Note: If these actions do not fully meet your needs, you can customize them in the browser, in SharePoint Designer 2013, and in development environments that are compatible with
SharePoint, including Visual Studio. You can also customize the Start Custom Task Process action by using the same tools. This action is a template that you can use to define a new
task process for your organization.

When you customize task behavior inside actions such as Start Approval Process and Start Feedback Process, a new category of actions, titled Task Behavior Actions, are available.

Note: Which actions in this category are available varies depending on where in the workflow you are currently working.

ACTIO N D ES CR IPTIO N

End Task Process This action is initially displayed in a workflow step as End Task Process. Use this action to end the task
process. The main workflow then continues to the next action.

Set Content Approval Status (as author) This action is initially displayed in a workflow step as Set content approval of item that the task
process is running on to this status (run as the workflow author). It allows you to set the approval
status of the list item to Approved, Rejected, or Pending by using the permissions of the workflow
author instead of those of person who starts the workflow. This action is commonly used if the person
who starts an approval workflow might not have the neeecessary permissions to approve a
document.The list item specified in the action is the item that the action is currently running on. This
may or may not be the same item that the workflow overall is running on.
Note: Content approval must be enabled in the list for this action to function.

Wait for Change in Task Process Item This action displays in a workflow step as Wait for change in item that the task process is running
on. Use this action to pause the task process until a value in the item on which the approval process is
running changes.

Wait for Deletion in Task Process Item This action displays in a workflow step as Wait for deletion of item that the task process is running
on. Use this action to pause the task process until a value in the item on which the approval process is
running is deleted.

The following action appears only when, customizing the Start Approval Process action, you click
changing the behavior of a single task, and then click inside the Before a Task is Assigned step.

Set Task Field This action is initially displayed in a workflow step as Set Task field to value. Use this action to set a
specific field in the current task item to a specified value. This action can be used on a task that has not
yet been created.

The following actions appear only when, customizing the Start Approval Process action, you click
changing the behavior of a single task, and then click inside the When a Task is Pending or When
a Task Expires step.

Rescind Task This action is displayed in a workflow step as then Rescind this task. Use this action to complete the
task without an outcome.

Append Task This action is displayed in a workflow step as then Append a new task and assign to this user. Use
this action to assign a new task to the specified user at the end of the current stage in the approval
action. If the current stage was Molly;Diane;Oliver, then appending a task to Diane would change the
stage to Molly;Diane;Oliver;Diane.

Delegate Task This action is initially displayed in a workflow step as then Delegate this task to this user. Use this
action to rescind a task assignment to a current user and then assign the same task to a different user. If
the new assignment is to a group, only a single task will be assigned to the group as a whole and not
one task to each group member. To assign one task to each group member, use the Forward Task
action instead.

Escalate Task This action is initially displayed in a workflow step as then Escalate this task to the current assignee's
manager. Use this action to assign the task to the manager of the user to whom the task is currently
assigned. There are no variables to set for this action.

Forward Task This action is initially displayed in a workflow step as then Forward this task to this user. Use this
action to rescind a task assignment to a current user and assign the same task to a different user. If the
new assignment is to a group, one task will be assigned to each member of the group and not only a
single task to the group as a whole. To assign a single task to the group as a whole, use the Delegate
Task action instead.

Insert Task This action is initially displayed in a workflow step as then Insert a task assigned to this user. Use this
action in the approval process to insert, following the current stage, a new stage in which the specified
user is the only participant.

Reassign Task This action is initially displayed in a workflow step as then Reassign this task to this user. Use this
action to reassign a task to another user.

Request a Change This action is initially displayed in a workflow step as then Request a change of this user. Use this
action to request a change from a different user and then, when the requested change is completed, to
have a new task assigned to the current user.

Send Task Email This action is initially displayed in a workflow step as then Email these users. Use this action to include
the Edit Task button in the email task notification that is sent to the specified users.

When should you use the approval and feedback actions?


In Microsoft Office SharePoint Designer 2007, you used task actions in approval scenarios. With pre-built reusable workflows in SharePoint, such as Approval - SharePoint and Collect
Feedback - SharePoint, you are probably wondering how they differ from the task actions Start Approval Process and Start Feedback Process. Although both the task actions and the
pre-built workflows can be used in both collecting feedback and collecting approval scenarios, the pre-built workflows provide a more sophisticated and complete solution.
If the pre-built reusable workflows do not meet your needs, you customize them by using SharePoint Designer 2013. If customizing a pre-built workflow to meet your needs will be more
work that creating a new workflow, you can leverage the Start Approval Process and Start Feedback Process actions in your new workflow. If you want the structure that these actions
provide, but not the all of their preconfigured functionality, you can use the Start Custom Task Process action.
Note that the various task actions can be used in scenarios that are not strictly approval or feedback processes. For example, you can use a task action to send email messages that remind
employees to complete their timesheets.
The following table presents a comparison between the three task actions on the one hand and the pre-built reusable workflows on the other:

FE ATU R E TAS K ACTIO NS PR E- B U ILD R EU S AB LE W O R K FLO W S

Number of users involved in the process A single user or group per task action. In the pre-built workflows, multiple users and groups can be
specified in multiple assignment stages. Each assignment stage
enables you to make two specifications: whether the tasks are
assigned in serial or in parallel, and to which users, groups, and
other participants the tasks are assigned.

Pre-loaded workflow logic The three task actions do not have built-in logic. You must use other The pre-built workflows are already equipped with all of the built-in
actions and conditions to build out an approval or feedback logic to provide a start-to-finish approval or feedback collection
mechanism. experience. You can use their default logic, or customize them to
meet your needs.

Order in which tasks are assigned In the three task actions, tasks can only be assigned in parallel, both In the pre-built workflows, tasks can be assigned either in a single
for individual users and for each member of a group. That is: all distribution stage or in multiple stages; and within each stage, tasks
tasks assigned by a task action are assigned at the same time, in a can be assigned either in serial or in parallel.
single distribution stage.

Data binding against task information The three task actions do not come equipped with ready-to-use The pre-built workflows take advantage of data sources (including
lookups. Current Item, pre-defined Workflow Variables and Parameters, the
Collect data from a user is an action that has an output clause: context of the current workflow, and Task Results), making it easier
the data generated at a workflow's run time is stored in the variable to customize the workflow to meet your needs.
in the output clause. To build an approval or feedback scenario on For example, to send e-mail to the person to whom the current task
your own, you must then supply this variable in several different is assigned, you can use the Send an Email action and configure
actions in the workflow the action to send email to Current Task: Assigned To.

Special features for task participants The three task actions do not provide special features (such as task In the pre-built workflows, approval actions can allow a task
reassignment and change request options) for task participants. participant to reassign the task to another user or to request a
change from the task process owner with just a single click.

Task completion In the three task actions, the only button available to indicate task In the pre-built workflows, you can add more meaningful buttons,
completion is always labeled Complete Task. such as Approve and Reject to indicate task outcome in the task
completion form.

Actions available when the workflow is associated to a document library or document content type
Some workflow actions (such as Shared Documents) are available only when the workflow is associated to a document library, or to the Document content type or a child of that content
type..

ACTIO N D ES CR IPTIO N

Core Actions

Send Document to Repository This action is initially displayed in a workflow step as Submit File using this action to this destination
router with this explanation (Output to Variable: submit file result). Use this action to move or
copy the document associated to the list item to a document repository. A document repository can be
a library in your SharePoint site, or an entire site (like the Document Center), that routes records to a
specific destination by using rules that you define.
Following is an example of what the action might look like in a workflow step:
- Submit File using Move to Archive:DocumentID Value with The file is ready for archival (Output to
Variable: Submit file for archival)

Document Set Actions Actions in this category pertain to a Document Set. A Document Set is a folder in which documents are
stored. In a workflow, a Document Set and all of the documents that it contains are treated as a single
item.
Note:
- To be able to use Document Sets in your library, you must add the Document Set content type from
your Library Settings page in your SharePoint site.
- Document Sets are a feature of SharePoint.
For more information about Document Sets Actions, see the Actions available when your SharePoint site
is running SharePoint section of this article.

List Actions This category of actions performs operations on list items.

Delete Drafts This action is displayed in a workflow step as Delete all drafts (minor versions) of the item. Use this
action to delete all existing draft or minor versions of the current item. There are no variables to set for
this action.
Note: Versioning with minor versions must be enabled on the SharePoint list for this action to function.

Delete Previous Versions This action is displayed in a workflow step as Delete all previous versions of the item. Use this action
to delete all existing previous versions of the current item. There are no variables to set for this action.
Note: Versioning must be enabled on the SharePoint list for this action to function.

Actions available only within an impersonation step


Some list actions are available only inside an impersonation step in. Impersonation steps direct the workflow to perform actions by impersonating the workflow author instead of the
workflow initiator. Impersonation steps are useful in scenarios such as approval and publishing, in which people submitting content for approval may not have the same permissions that the
people approving the content have. Impersonation steps are also helpful in automating site administrator tasks (for example, in a workflow that automatically assigns permissions to users).

Note: The "workflow author" is the person who last published the workflow.> An impersonation step cannot be nested inside of another step of any kind.

ACTIO N D ES CR IPTIO N

Add List Item Permissions This action is initially displayed in a workflow step as Add these permissions to item in list. Use this
action to grant the specified permission levels for the specified item to the specified user or users.
Following is an example of what the action might look like in a workflow step:
- Add Contribute, Read to item in Images

Inherit List Item Parent Permissions This action is initially displayed in a workflow step as Inherit parent permissions from item in this list
Use this action to force a list item that has unique permissions to inherit the parent permissions from its
list.
Following is an example of what the action might look like in a workflow step:
- Inherit parent permissions from item in Images

Remove List Item Permissions This action is initially displayed in a workflow step as Remove these permissions from item in list. Use
this action to remove specified permission levels for a specified item from a specified user or users.
Following is an example of what the action might look like in a workflow step:
- Remove Contribute from item in Images

Replace List Item Permissions This action is initially displayed in a workflow step as Replace these permissions of item in list. Use
this action to replace, for a specified user or users, their current permission level for a specified item with
a specified new permission level.
Following is an example of what the action might look like in a workflow step:
- Replace Read of item in Images

Actions within a site workflow


A site workflow operates at a site-level and is not attached to any more specific object (such as an individual item or content type). When you are working inside a site workflow, actions that
work on a current item, such as Set Content Approval Status and Set Field in Current Item, are not available to you. For more information about these actions, see the General actions
section of this article.

See also
Workflow actions quick reference (SharePoint Workflow platform)
What's new in workflows for SharePoint
Get started with workflows in SharePoint
Workflow development in SharePoint Designer and Visio
Visio shapes in SharePoint Designer 2013: A quick reference guide (SharePoint 2010 Workflow
platform)
3/26/2018 • 18 minutes to read Edit Online

You can create a workflow in Microsoft Visio Professional 2013 and then export it to Microsoft SharePoint Designer 2013. This guide identifies the Visio shapes that you use to create your
workflow.Use this reference article only if you are working in SharePoint Designer 2013 but want to continue to use the SharePoint 2010 Workflow Platform.The shapes for the SharePoint
2010 Workflow Platform come in three stencils: Actions - SharePoint 2010 Workflow, Conditions - SharePoint 2010 Workflow, and Terminators - SharePoint 2010 Workflow.

Workflow actions
Workflow actions are specific operations that workflow performs. Every workflow must contain at least one action.
The actions in this list are organized in categories based on their area of application in a workflow. For example, actions that affect the behavior of a list item are grouped under List Actions
and actions related to document sets are grouped under Document Set Actions. The categories for actions are:
Core actions These are the most commonly used actions in a workflow.
Document set actions Typically, these actions are used in workflows that are associated with a document library or the document content type.
List actions These actions perform operations on list items.
Relational actions The single action in this category looks up a user's manager and stores that information in a variable.
Task actions These actions are associated with approval, feedback, and form operations.

Important: Most of the action shapes that you can insert into a SharePoint workflow in Visio require additional configuration when the workflow is imported into SharePoint Designer.
In Visio, remember to use the comments feature of each action shape to specify the settings or configuration of the action.

Core actions
These are the most commonly-used actions and can be used in any type of workflow or step.

V IS IO ACTIO N S HAPE CO R R ES PO ND ING ACTIO N IN S HAR EPO INT D ES IG NER ACTIO N D ES CR IPTIO N

This Visio action is the same as the Add a Comment action in Add a comment
SharePoint Designer 2013 and appears as: Use this action to leave informative comments in the workflow
designer for reference purposes. This is especially helpful when there
Note: Comments remain visible when the workflow is exported to are other users co-authoring the workflow. For example, if a variable
Visio. in the current workflow doesn't have a user-friendly name, you use
this action to add a comment to indicate what the variable does in
the workflow.

This Visio action is the same as the Add Time to Date action in Add time to date
SharePoint Designer 2013 and appears as: Use this action to add a specific time in minutes, hours, days,
months, or years to a date, and store the output value as a variable.
The date can be a current date, specific date, or a lookup.

This Visio action is the same as the Do Calculation action in Do calculation


SharePoint Designer 2013 and appears as: Use this action to perform a calculation, such as add, subtract,
multiply, or divide two values, and stores the output value in a
variable.

This Visio action is the same as the Log to History List action in Log to history list
SharePoint Designer 2013 and appears as: Use this action to log a message about the workflow into its history
list. A message can be a summary of a workflow event, or anything
significant about the workflow. The workflow history list can be
helpful in troubleshooting issues with the workflow.

This Visio action is the same as the Pause for Duration action in Pause for duration
SharePoint Designer 2013 and appears as: Use this action to pause the workflow for a specific duration in days,
hours, or minutes.
Note: The delay time is effected by the timer job interval, which has
a default value of five minutes.

This Visio action is the same as the Pause Until Date action in Pause until date
SharePoint Designer 2013 and appears as: Use this action to pause the workflow until a particular date. You
can add a current date, a specific date, or a lookup.

This Visio action is the same as the Set Time Portion of Set time portion of date/time field
Date/Time Field action in SharePoint Designer 2013 and appears Use this action to create a timestamp, and stores the output value
as: in a variable. You can set the time in hours and minutes and add a
current date, specific date or a lookup.

This Visio action is the same as the Set Workflow Status action in Set workflow status
SharePoint Designer 2013 and appears as: Use this action to set the status of the workflow. The default options
You cannot rename or delete a status value are Canceled, Approved, and Rejected.
once it has been created. However, you do not have to use it. You can enter a new status value in the dropdown in the action.
A custom status is applicable to the current workflow only, and Once you enter a status value, the entry is automatically added to
cannot be used in another workflow the dropdown list.
A workflow cannot use custom status values that you define in the If the Set Workflow Status action is the last step in your workflow
action if the action is used inside an impersonation step. where you have also used a custom value, you can see your custom
value in the Status column in the list upon workflow pausing or
completion.
V IS IO ACTIO N S HAPE CO R R ES PO ND ING ACTIO N IN S HAR EPO INT D ES IG NER ACTIO N D ES CR IPTIO N

This Visio action is the same as the Set Workflow Variable action Set workflow variable
in SharePoint Designer 2013 and appears as: Use this action to set a workflow variable to a value. Use this action
when you want the workflow to assign data to a variable.

This Visio action is the same as the Stop workflow action in Stop workflow
SharePoint Designer 2013 and appears as: Use this action to stop the current instance of the workflow and log
a message to the Workflow History list. The message that you
specify in the action will appear in the Description column in the
Workflow History upon workflow completion.

List actions
These actions are used on list items.

V IS IO ACTIO N S HAPE CO R R ES PO ND ING ACTIO N IN S HAR EPO INT D ES IG NER ACTIO N D ES CR IPTIO N

This Visio action is the same as the Add List Item Permissions Add list item permissions
action in SharePoint Designer 2013 and appears as: This action grants specific permission levels for an item to specific
Note: This action is only available within users.
an impersonation step.

This Visio action is the same as the Check In Item action in Check in item
SharePoint Designer 2013 and appears as: This action checks in an item that is checked out.
Note: You can only check in items from a document library.

This Visio action is the same as the Check Out Item action in Check out item
SharePoint Designer 2013 and appears as: Use this action to check out an item. The workflow verifies if the
item is checked in, before it checks out a document.
Note: You can only check out items from a library in your site.

This Visio action is the same as the Copy List Item action in Copy list item
SharePoint Designer 2013 and appears as: Use this action to copy a list item to another list. If there is a
document in the list item, the workflow also copies the document to
the destination list.
Important: You must have at least one column similar in both the
source and destination lists.

This Visio action is the same as the Create List Item action in Create list item
SharePoint Designer 2013 and appears as: Use this action to create a new list item in the list that you specify.
You can supply the fields and values in the new item.
You can use this action whenever you want a new item to be
created with specific information.
Note: The output variable is the ID of the item created in the list.

This Visio action is the same as the Delete Item action in Delete item
SharePoint Designer 2013 and appears as: Use this action to delete an item.

This Visio action is the same as the Discard Check Out Item action Discard check out item
in SharePoint Designer 2013 and appears as: Use this action if an item is checked out, changes have been made
to it, and you want to discard the changes and check the item back
in.

This Visio action is the same as the Inherit List Item Parent Inherit list item permissions
Permissions action in SharePoint Designer 2013 and appears as: If your item has unique permissions, you can use this action to
Note: This action is only available in make the item inherit the parent permissions from the list.
an impersonation step.

This Visio action is the same as the Remove List Item Permissions Remove list item permissions
action in SharePoint Designer 2013 and appears as: This action removes permissions from an item for specific users.
This action is only available in an
Note:
impersonation step.

This Visio action is the same as the Replace List Item Permissions Replace list item permissions
action in SharePoint Designer 2013 and appears as: It replaces an item's current permissions with the new permissions
This action is only available in an that you specify in the action.
Note:
impersonation step.

This Visio action is the same as the Set Content Approval Status Set content approval status
action in SharePoint Designer 2013 and appears as: If you have content approval enabled in your list, use this action to
Note: Content approval must set the content approval status field to a value such as Approved,
be enabled in the list in order to use this action. Rejected, or Pending. You can type a custom status in the action.
Note: The Set Content Approval Status action works on the
current item that the workflow is acting upon, therefore the action is
not available in a site workflow.

This Visio action is the same as the Set Field in Current Item Set field in current item
action in SharePoint Designer 2013 and appears as: Use the action to set a field in the current item to a value.
Note: If you want to pause the workflow until it changes the value
of the field, use the Wait for Field Change in Current Item action
instead. The Set Field in Current Item action should not be used in
a site workflow.
V IS IO ACTIO N S HAPE CO R R ES PO ND ING ACTIO N IN S HAR EPO INT D ES IG NER ACTIO N D ES CR IPTIO N

This Visio action is the same as the Update List Item action in Update list item
SharePoint Designer 2013 and appears as: Use this action to update a list item. You can specify the fields and
the new values in those fields.

This Visio action is the same as the Wait for Field Change in Wait for field change in current item
Current Item action in SharePoint Designer 2013 and appears as: This action pauses the workflow until the field in the current item
has changed to a new value.
Note: If you want the workflow to change the value of the field,
rather than have the workflow wait for the field to change, use the
Set Field in Current Item action instead.

Task actions
Actions in this category pertain to task items. These actions apply only to SharePoint sites running SharePoint.

V IS IO ACTIO N S HAPE CO R R ES PO ND ING ACTIO N IN S HAR EPO INT D ES IG NER ACTIO N D ES CR IPTIO N

This Visio action is the same as the Assign a Form to a Group Assign a form to a group
action in SharePoint Designer 2013 and appears as: Use this action to enable you to create a custom task form with
customized fields.
You can use this action to assign a task to one or more participants
or groups prompting them to perform their tasks. Participants
provide their responses it the fields of the custom task form and,
when they are done with the task, click Complete Task on the
form.

This Visio action is the same as the Assign a To-do Item action in Assign a to-do item
SharePoint Designer 2013 and appears as: Use this action to assign a task to each of the participants,
prompting them to perform their tasks and then, when they are
done, to click the Complete Task button on their task form.

This Visio action is the same as the Collect Data from a User Collect data from a user
action in SharePoint Designer 2013 and appears as: Use this action to assign a task to the participant, prompting them
to provide the needed information in a custom task form, and then
click the Complete Task button on the task form.
This action has an output clause??? meaning, the workflow stores
the information returned by the action in a corresponding variable.
The list item ID of the completed task item from the action is stored
in the collect variable.

This Visio action is the same as the Start Approval Process action Start approval process
in SharePoint Designer 2013 and appears as: Use this action to route a document for approval. Approvers can
approve or reject the document, reassign the approval task, or
request changes.
You can assign tasks to both internal and external participants in the
action. An external participant can be an employee in your
organization who isn't a user in the site collection, or anyone outside
your organization.

This Visio action is the same as the Start Feedback Process action Start feedback process
in SharePoint Designer 2013 and appears as: Use this action to assign task items for feedback to users in a
specific order???serial or parallel. The default is parallel. Users or task
participants can also reassign a task to other users. When the users
are done, they can click the Submit Feedback button to indicate
task completion.
You can assign tasks to both internal and external participants in the
action. An external participant can be an employee in your
organization who isn't a user in the site collection, or anyone outside
your organization.

This Visio action is the same as the Start Custom Task Process Start custom task process
action in SharePoint Designer 2013 and appears as: The Start Custom Task Process action is an approval process
template that you can use if other approval actions do not meet
your needs.

Relational actions
The single action in this category looks up a user's manager and stores that information in a variable. This action applies only to SharePoint sites running SharePoint.

V IS IO ACTIO N S HAPE CO R R ES PO ND ING ACTIO N IN S HAR EPO INT D ES IG NER ACTIO N D ES CR IPTIO N

This Visio action is the same as the Lookup Manager of a User Lookup manager of a user
action in SharePoint Designer 2013 and appears as: Use this action to look up a user's manager. The output value is then
stored in a variable.
Note: For this action to work properly, the User Profile service must
be running in SharePoint.

Document set actions


Some workflow actions are only available when the workflow is associated to a document library, such as Shared Documents, or to the Document content type.

V IS IO ACTIO N S HAPE CO R R ES PO ND ING ACTIO N IN S HAR EPO INT D ES IG NER ACTIO N D ES CR IPTIO N

This Visio action is the same as the Start Document Set Approval Send approval for document set
Process action in SharePoint Designer 2013 and appears as: Use this action to begin the approval process for a document set.
V IS IO ACTIO N S HAPE CO R R ES PO ND ING ACTIO N IN S HAR EPO INT D ES IG NER ACTIO N D ES CR IPTIO N

This Visio action is the same as the Send Document Set to Send document set to repository
Repository action in SharePoint Designer 2013 and appears as: Use this action to allow you to move or copy the document set to a
document repository. A document repository can be a library in
your SharePoint site, or a site on its own like the Document Center,
that routes records to a specific destination based on rules that you
define.

This Visio action is the same as the Send Document to Repository Send document to repository
action in SharePoint Designer 2013 and appears as: Use this action to allow you to move or copy a document to a
document repository. A document repository can be a library in
your SharePoint site, or a site on its own like the Document Center,
that routes records to a specific destination based on rules that you
define.

This Visio action is the same as the Set Content Approval Status Set content approval status for the document set
for the Document Set action in SharePoint Designer 2013 and Use this action to set content approval of a document set to
appears as: Approved, Rejected, or Pending.

Workflow conditions
A workflow condition is a branching point in the workflow. The workflow condition compares the input to a specified value. If they match, the workflow follows one branch; if not, it follows
the other branch.

Important: Most of the condition shapes that you can insert into a SharePoint workflow in Visio require additional configuration when the workflow is imported into SharePoint
Designer. In Visio, remember to use the comments feature of each condition shape to specify the decision criteria of the condition.

General conditions
This section describes the conditions that are available in SharePoint Designer 2013for list and reusable list workflows, no matter which list or content type the workflow is associated with.

V IS IO CO ND ITIO N S HAPE CO R R ES PO ND ING CO ND ITIO N IN S HAR EPO INT D ES IG NER CO ND ITIO N D ES CR IPTIO N

This Visio condition is the same as the If any value equals value Compare data source
condition in SharePoint Designer 2013 and appears as: This condition compares two values. You can specify whether the
values should be equal or not equal.

This Visio condition is the same as the If current item field equals Compare document field
value condition in SharePoint Designer 2013 and appears as: This condition checks a field against a value that you specify. You can
specify whether the values should be equal or not equal.

This Visio condition is the same as the Created by a specific Created by a specified person
person condition in SharePoint Designer 2013 and appears as: This condition checks if an item was created by a specific user. The
user can be specified as an e-mail address, such as
olivier@contoso.com, or selected from SharePoint, Exchange, or
Active Directory users.
Note: The user name and e-mail address are case sensitive. It is
recommended that you select a user name or e-mail address to help
ensure that you use the correct case. If you type a user name or e-
mail address, you must match the case of the account. For example,
If created by contoso\molly will not evaluate as true if the user
account is Contoso\Molly.

This Visio condition is the same as the Created in a specific date Created in specific date span
span condition in SharePoint Designer 2013 and appears as: This condition checks if the item was created between the specified
dates. You can use the current date, a specific date, or a lookup.

This Visio condition is the same as the Modified by a specific Modified by a specific person
person condition in SharePoint Designer 2013 and appears as: Use this condition to check if an item was modified by a specified
user. The user can be specified as an e-mail address, such as
olivier@contoso.com, or selected from SharePoint, Exchange, or
Active Directory users.
Note: The user name and e-mail address are case sensitive. It is
recommended that you select a user name or e-mail address to help
ensure that you use the correct case. If you type a user name or e-
mail address, you must match the case of the account. For example,
If modified by contoso\molly will not evaluate as true if the user
account is Contoso\Molly.

This Visio condition is the same as the Modified in a specific date Modified in a specific date span
span condition in SharePoint Designer 2013 and appears as: This condition checks if an item was modified between the specified
dates. You can use the current date, a specific date, or a lookup.

This Visio condition is the same as the Title field contains Title field contains keywords
keywords condition in SharePoint Designer 2013 and appears as: This condition checks if the Title field for an item contains a specific
word. You can either specify the keyword in the String Builder???
which can be a static value or a dynamic string or a combination ???
or insert a lookup to a field or variable.
Note: You cannot search for more than one keyword in the Title
field contains keywords condition. However, you can use logical
operators such as**

Document set conditions


Some workflow conditions are only available when the workflow is associated to a document library, such as Shared Documents, or to the Document content type.

V IS IO CO ND ITIO N S HAPE CO R R ES PO ND ING CO ND ITIO N IN S HAR EPO INT D ES IG NER CO ND ITIO N D ES CR IPTIO N

This Visio condition is the same as the The file size in a specific File size is in a specific range
range kilobytes condition in SharePoint Designer 2013 and This condition checks if the file size of a document is between the
appears as: specified sizes, in kilobytes. The condition does not include the
specified sizes in the evaluation. You can enter a number or use a
lookup for the first or the second size in the condition.

This Visio condition is the same as the The file type is a specific File is a specific type
type condition in SharePoint Designer 2013 and appears as: This condition checks if the file type of the current item is of the
specified type, such as docx. You can enter the file type as a string or
use a lookup.

List conditions
V IS IO CO ND ITIO N S HAPE CO R R ES PO ND ING CO ND ITIO N IN S HAR EPO INT D ES IG NER CO ND ITIO N D ES CR IPTIO N

This Visio condition is the same as the Check list item permission Check exact user permissions
levels condition in SharePoint Designer 2013 and appears as: This condition checks that the specified user has the minimum
necessary permission level.

This Visio condition is the same as the Check list item permissions Check user permission
condition in SharePoint Designer 2013 and appears as: This condition checks if the specified user has the minimum
necessary permissions.

Workflow terminators
In Visio, each workflow must begin with a Start terminator ( ) and end with a Stop terminator ( ). Only one of each type of terminator can be used in a given workflow. Terminators
are necessary when you create a SharePoint workflow in Visio so that the workflow can pass validation and can be exported. Workflow terminators are not used in SharePoint Designer.

See also
What's new in workflows for SharePoint
Get started with workflows in SharePoint
Workflow development in SharePoint Designer and Visio
Validation issues in Visio (SharePoint 2010 Workflow platform)
3/26/2018 • 6 minutes to read Edit Online

Use this reference to help resolve validation issues when you export a SharePoint workflow from Visio Professional 2013 to SharePoint Designer 2013. This article describes validation
issues that might arise when you use the SharePoint 2010 Workflow platform in SharePoint Designer 2013.

Introduction
When you export a SharePoint workflow from Microsoft Visio Professional 2013 to Microsoft SharePoint Designer 2013, the diagram must first be validated. If the workflow diagram is not
valid, an Issues window appears that includes a list of issues that must be repaired before the workflow can be exported..
This article includes a description, example, and suggested action for each of the workflow validation issues that you can receive in Visio Professional 2013. If you receive notice of an issue
during validation, find the issue name in the list below, use the example to help identify where the problem is, and then follow the suggested action to resolve it.

A custom action cannot be added to a workflow diagram


Message:
A Custom action cannot be added to a workflow diagram. The Custom action can only be generated when importing workflow from SharePoint Designer.
Example:

Suggested action:
If you want to add an action to your workflow and a master shape does not exist for it in the stencil, do not create your own shape or import one from a different stencil. Instead, use an
existing shape, and then use the Add Comment feature of the shape to specify the intended behavior.

A Custom condition cannot be added to a workflow diagram


Message:
A Custom condition cannot be added to a workflow diagram. The custom condition can only be generated when importing workflow from SharePoint Designer.
Example:

Suggested action:
If you want to add a condition to your workflow and a master shape does not exist for it in the stencil, do not create your own shape or import one from a different stencil. Instead, use an
existing shape, and then use the Add Comment feature of the shape to specify the intended behavior.

A Compound condition cannot be manually added to a workflow diagram


Message:
A Compound condition cannot be manually added to a workflow diagram. The compound condition can only be generated when importing workflow from SharePoint Designer.
Example:

Suggested action:
If you want to add a condition to your workflow and a master shape does not exist for it in the stencil, do not create your own shape or import one from a different stencil. Instead, use an
existing shape, and then use the Add a Comment feature of the shape to specify the intended behavior.

Duplicate connections exist between workflow shapes


Message:
Duplicate connections exist between workflow shapes.
Example:
Suggested action:
Remove the redundant connector by selecting and deleting it.

Loop back to parent shape is not allowed


Message:
Loop back to parent shape is not allowed.
Example:

Suggested action:
Neither Visio Professional 2013 nor SharePoint Designer 2013 supports workflows with loops. Check your workflow for loops, and delete the looping connections. If you want to create a
SharePoint workflow that includes a set of looping steps, you must create the workflow in Visual Studio.

Parallel activities that are also sequential are not allowed


Message:
Parallel activities that are also sequential are not allowed.
Example:

Suggested action:
Activities can be either parallel or sequential, but not both simultaneously. For parallel activities, remove the sequential connectors. For sequential activities, remove the parallel connectors.
Sometimes, simultaneously parallel and sequential activities can be difficult to identify. The following examples show other common instances of parallel and sequential arrangement and
offer alternative arrangements.
Example:

Suggested action:
To avoid having connectors point to the same activity from multiple paths, try duplicating the activity:
Example:

Suggested action:
If dealing with parallel blocks in sequential steps (usually found in workflows constructed by using SharePoint Designer), try using the "Add a Comment" shape between the two parallel
blocks so that the steps are separated cleanly.

The condition shape does not have connections labeled with Yes or No
Message:
The condition shape does not have connections labeled with Yes or No.
Example:

Suggested action:
Right-click the connector to assign a "Yes" or "No" label.

The condition shape must have at least one outgoing connection with label Yes or No
Message:
The condition shape must have at least one outgoing connection with label Yes or No.
Example:

Suggested action:
Ensure that the condition shape has at least one outgoing connector attached to another workflow shape.
The connector is not a SharePoint Workflow connector
Message:
The connector is not a SharePoint Workflow connector. Ensure the correct connector is used by using the connector tool or AutoConnect.
Example:

Suggested action:
Avoid reusing connectors from other diagrams, because they are not necessarily designed to be used with SharePoint workflows. Delete the selected connector, and use the connector tool or
AutoConnect to replace it with a new connector.

The connector must be connected to two workflow shapes


Message:
The connector must be connected to two workflow shapes.
Example:

Suggested action:
Remove dead-end connectors or attach them to a second shape.

The diagram must only have one workflow and one Start shape
Message:
The diagram must only have one workflow and one Start shape.
Example:

Suggested action:
All paths must originate from the same Start shape. Remove extra Start shapes, and arrange the connectors so that the path starts in one place.

The shape is not a SharePoint workflow shape. Only SharePoint workflow shapes can be connected in a workflow
Message:
The shape is not a SharePoint workflow shape. Only SharePoint workflow shapes can be connected in a workflow.
Example:
Suggested action:
Only workflow shapes from the SharePoint workflow stencils can be used in the Microsoft SharePoint Workflow template. Other flowchart shapes are not recognized, and they prevent the
workflow from being exported to SharePoint Designer 2013.

The Start shape must not have incoming connections


Message:
The Start shape must not have incoming connections.
Example:

Suggested action:
Remove the incoming connector to the Start shape.

The Terminate shape must not have outgoing connections


Message:
The Terminate shape must not have outgoing connections.
Example:

Suggested action:
Remove the outgoing connector from the Terminate shape.

The workflow must have a Start shape


Message:
The workflow must have a Start shape.
Example:
Suggested action:
Add a Start shape to the beginning of the workflow, and connect it to the first activity.

The workflow shape is not connected to a Terminate shape


Message:
The workflow shape is not connected to a Terminate shape.
Example:

Suggested action:
If the workflow does not have a Terminate shape, add one and connect it to the end of the workflow. If a workflow shape is missing a connection to another workflow shape (see example),
you can remove it or connect it to another workflow shape.

The workflow shape is not connected to the workflow


Message:
The workflow shape is not connected to the workflow.
Example:

Suggested action:
If the workflow shape is necessary, add connectors to attach it to the workflow path. Otherwise, delete the shape.

Workflow nesting levels must not exceed a maximum of 10


Message:
Workflow nesting levels must not exceed a maximum of 10.
Suggested action:
Visio Professional 2013 can recognize a maximum of 10 levels of nested workflow activities. Rearrange the workflow to reduce complexity by eliminating activities or dividing the workflow
path into more than one branch.

See also
What's new in workflows for SharePoint
Get started with workflows in SharePoint
Workflow development in SharePoint Designer and Visio
Social and collaboration features in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn about social and collaboration features in SharePoint and development scenarios for My Sites, team sites, and Community Sites.

Social and collaboration features in SharePoint


The social and collaboration features on My Sites, team sites, and Community Sites in SharePoint make it easy for users to find and connect with the people and content that matter to them
and to share information and ideas.

My Site and team site features in SharePoint


On My Site and team sites, the interactive newsfeed can help users keep current with people and content through real-time microblog messages and status updates. My Site also acts as a
central location where users can track their tasks and access the documents and sites they are following. See Get started developing with social features in SharePoint to learn about
SharePoint APIs that you can use to develop with My Site features.

Community Site features in SharePoint


People can use the rich, forum-like experience in Community Sites to find and share information and ideas, find people with similar interests, and build reputation. You use SharePoint site
and list APIs directly to extend Community Site features because the Community Site feature doesn't expose a specific API. We describe development scenarios for Community Sites in
What's new for developers in social and collaboration features.

In this section
What's new for developers in social and collaboration features in SharePoint
Get started developing with social features in SharePoint
Work with social feeds in SharePoint
Follow people in SharePoint
Follow content in SharePoint
Work with user profiles in SharePoint

See also
Plan for social computing and collaboration in SharePoint
Social client class library
SharePoint Social server class library
What's new for developers in social and collaboration features in SharePoint
7/12/2018 • 8 minutes to read Edit Online

Learn about new and changed social and collaboration features for My Site and Community Site development scenarios in SharePoint. Social and collaboration features in SharePoint make
it easy for users to communicate and to stay engaged and informed. The improved social feed on personal sites and team sites helps users to keep up-to-date with the people and content
that they care about. The new Community Site feature provides a rich community experience that lets users easily find and share information and find people who have similar interests.
For an in-depth overview of the new social and collaboration features in SharePoint, see What's new in social computing in SharePoint on TechNet. For more information about
programming with social and collaboration features, see Social and collaboration features in SharePoint.

New and changed My Site features in SharePoint


The My Site Social API, which includes user profiles and social data, contains many new and changed features. New functionality for My Sites and team sites provides an interactive,
conversational experience within feeds that makes it easier for users to stay connected to the people and content that matter to them.
The Newsfeed page on SharePoint displays several of these improvements, including a text box that enables users to quickly publish microblog posts and an interactive, conversational feed
of posts and updates from the people and content that the user is following.

New Social namespace provides APIs for social feeds and following people and content
The Social namespace contains the primary API for working with feeds and microblog posts and for following people and content. For more information, see
Microsoft.SharePoint.Client.Social for the .NET client object model, SP.Social for the JavaScript object model, and Microsoft.Office.Server.Social for the server object model.
NOTE

The API in the Microsoft.Office.Server.ActivityFeed namespace is deprecated. See Deprecated and removed My Site Social API and features.

New client APIs for social feeds, following people and content, and user properties in SharePoint
SharePoint includes new client APIs that you can use to work with social feeds, follow people and content, and retrieve user properties in online, on-premises, and mobile development.
When possible, you should use client APIs for SharePoint development instead of using the server object model or web services. Client APIs include managed client object models, a
JavaScript object model, and a Representational State Transfer (REST) service. If you are developing an SharePoint Add-in, you must use a client API.
Not all server-side functionality in the Microsoft.Office.Server.UserProfiles assembly is available from client APIs. For example, there's no client-side access to the API in the
Microsoft.Office.Server.Audience namespace, the Microsoft.Office.Server.ReputationModel namespace, or the Microsoft.Office.Server.SocialData namespace. To see which APIs are available,
see the Microsoft.SharePoint.Client.Social namespace and the Microsoft.SharePoint.Client.UserProfiles namespace.
For information about how to access the My Site Social client APIs, see Get started developing with social features in SharePoint. For more information about the API sets in SharePoint and
when to use them, see Choose the right API set in SharePoint.

Use the ProfileLoader.CreatePersonalSiteEnqueueBulk method to provision personal sites and OneDrive for Business for multiple users (My Site Host
administrators on SharePoint Online only)
My Site Host administrators can use the ProfileLoader.CreatePersonalSiteEnqueueBulk method to programmatically provision personal sites for multiple users on SharePoint Online,
which include features such as OneDrive for Business and the Sites page.
The following code example uses the .NET client object model in a console application. Before you run the example, add references to Microsoft.SharePoint.Client.dll,
Microsoft.SharePoint.Client.Runtime.dll and Microsoft.SharePoint.Client.UserProfiles.dll, and change the placeholder values for the userName, passwordStr, and serverUrl variables. The
serverUrl variable must be the URL of the SharePoint Online Administration Center.
NOTE

To get the required client DLLs, download the SharePoint Online Client Components SDK.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.UserProfiles;

namespace CreatePersonalSiteBulkConsole
{
class Program
{
static void Main(string[] args)
{
string userName = "administrator@contoso.onmicrosoft.com";
string passwordStr = "password";
string serverUrl = "https://contoso-admin.sharepoint.com/";

using (var clientContext = new ClientContext(serverUrl))


{
SecureString password = new SecureString();
Array.ForEach(passwordStr.ToCharArray(), c => password.AppendChar(c));

var credentials = new SharePointOnlineCredentials(userName, password);

clientContext.Credentials = credentials;

var web = clientContext.Web;


clientContext.Load(web);
clientContext.ExecuteQuery();
ProfileLoader loader = ProfileLoader.GetProfileLoader(clientContext);

if (loader == null)
{
throw new InvalidOperationException("Failed to get ProfileLoader");
}

string[] userEmails = { "usera@contoso.onmicrosoft.com", "userb@contoso.onmicrosoft.com" };


loader.CreatePersonalSiteEnqueueBulk(userEmails);
loader.Context.ExecuteQuery();
}
}
}
}

To use the CreatePersonalSiteEnqueueBulk method with Windows PowerShell, first change the placeholder values (the URL of the SharePoint Online Administration Center and user
names) in the following commands, and then run the commands in the SharePoint Management Shell.

$webUrl = "https://yoursharepointadmin.sharepoint.com"
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($webUrl)

$web = $ctx.Web
$username = "admin@myadmin.sharepoint.com"
$password = read-host -AsSecureString

$ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username,$password)

$ctx.Load($web)
$ctx.ExecuteQuery()

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles")

$loader =[Microsoft.SharePoint.Client.UserProfiles.ProfileLoader]::GetProfileLoader($ctx)

#To get profile


$profile = $loader.GetUserProfile()
$ctx.Load($profile)
$ctx.ExecuteQuery()
$profile
#To enqueue profile
$loader.CreatePersonalSiteEnqueueBulk(@("user1@domain.com"))
$loader.Context.ExecuteQuery()

For more information, see So you want to programmatically provision Personal Sites (OneDrive for Business) in Office 365? and Use Windows PowerShell to administer SharePoint.

New objects for users and user properties in SharePoint


SharePoint includes new objects that represent users and user properties:
The SocialActor object represents users (and other entities) for feed and following activities.
The PersonProperties object contains general user properties and user profile properties.
NOTE

Server object model versions are the SPSocialActor object and the PersonProperties object.
SharePoint also includes a new client-side UserProfile object that provides methods you can use to create a personal site for the current user. However, it does not contain all the user
properties that the server-side UserProfile object contains. To access all user properties from client-side code, use the PeopleManager.GetMyProperties method or
PeopleManager.GetPropertiesFor method (user profile properties are stored in the PersonProperties.UserProfileProperties property) or use the PeopleManager.GetUserProfilePropertiesFor
method or PeopleManager.GetUserProfilePropertyFor method.

New client-side people picker control


The client-side People Picker control is an HTML and JavaScript control that provides cross-browser support for selecting people, groups, and claims. You can configure the picker with the
same settings as the server-side version of the control, including control-specific properties (like allowing multiple users or users and groups) and web application-level configuration
settings (like Active Directory Domain Services parameters or targeting particular forests). For more information, see Use the client-side People Picker control in SharePoint-hosted
SharePoint Add-ins.

Deprecated and removed My Site Social API and features


The following My Site Social API and features are deprecated in SharePoint:
The API in the Microsoft.Office.Server.ActivityFeed namespace is deprecated. The Social namespace provides the API for programmatically working with social feeds in SharePoint.
For backward compatibility, ActivityEvent items from SharePoint 2010 are displayed in SharePoint feeds as events that cannot be replied to. (Legacy event migration must be
enabled in Central Administration.)
The My Site RSS feed (ActivityFeed.aspx) is replaced with new APIs in the REST service, the client object model, and the JavaScript object model. To migrate custom SharePoint 2010
code that uses this API (preferably a client API), replace all requests to ActivityFeed.aspx with calls to the new API and handle feed data that is returned in JavaScript Object Notation
(JSON) format.
The Recent Activities web part is replaced with a new Newsfeed web part that supports multithreaded conversations and dynamic feed retrieval.
NOTE

We don't support customizations of the Newsfeed web part or other feed web parts (such as the Site Feed web part on team sites). If you do customize these web parts, for example
by using JavaScript overrides, be aware that your customizations may break in updates to SharePoint.
The Social Comments web part is deprecated.
The following activity events no longer automatically inform the feed: profile update, upcoming birthday, upcoming workplace anniversary, new membership, and change of manager.
However, you can create custom event receivers for these activities. No new social events have been added.
The following fields in the Privacy enumeration are deprecated: Contacts, Organization, and Manager. SharePoint offers only Private ( Only Me) and Public ( Everyone) privacy
settings. Existing privacy settings are retained until they are changed by the user. To migrate custom SharePoint 2010 code that uses this API, replace all references to the deprecated
privacy fields.
The Following People API that is accessed from the SocialFollowingManager replaces the Colleagues functionality from SharePoint Server 2010. The Colleagues page is
replaced with the People I'm following page. The Groups feature that enabled users to organize colleagues into groups is no longer available.
Organization profiles are obsolete in SharePoint, and the following types are deprecated: OrganizationProfile, OrganizationProfileManager, OrganizationMembershipType,
OrganizationNotFoundException, OrganizationProfileChange, OrganizationProfileChangeQuery, OrganizationProfileMembershipChange, and
OrganizationProfileValueCollection.
The My Links feature is deprecated in SharePoint.

New Community Site feature in SharePoint


The new Community Site feature includes a new site template and improved discussion experience. Features such as reputation, categories, featured discussions, a question-post type, and
best replies let community members easily find popular discussions, relevant information, and people with similar interests. Members build reputation as they participate in communities.
The Community Site feature does not expose a specific API for development. To extend Community Site features, you use SharePoint site and list APIs directly. For example, you can use
SharePoint APIs to customize the site and list templates, create custom activities from communities for the social feed, integrate reputation information into search results, customize the
reputation model, or create workflows to moderate discussions.
The following list contains information for developing with Community Site features:
Community Sites use the Community site template ( Id = 62). The site template is not available for public websites. The template type of the discussion board list is DiscussionBoard
(value = 108).
Activating the Community Site feature activates the CommunityEventReceiver event receiver.
To customize the client-side rendered list view, you must use JavaScript overrides to replace the view. List views cannot be extended through the SharePoint API. For more
information, see Customize a list view in SharePoint Add-ins using client-side rendering.
Community Sites use asynchronous events to update objects. If asynchronous events run in the background, you may encounter Save conflicts when you attempt to update lists or list
items, and your handle to the object may become stale.
As a workaround, handle exceptions that are returned by Update calls, refresh the instance before you retry the call, and loop for multiple retries, as shown in the following code
example.

int retries = 1;
while (retries <= 10)
{
try
{
spListItem.IconOverlay = urlString;
spListItem.Update();
break;
}
catch (SPException saveConflict)
{
spListItem = web.Lists.GetItemById(spListItem.ID);
retries++;
if (retries > 10) throw;
System.Threading.Thread.Sleep(1000);
}
}

See also
Social and collaboration features in SharePoint
Get started developing with social features in SharePoint
What's new in social computing in SharePoint
Get started developing with social features in SharePoint
3/26/2018 • 8 minutes to read Edit Online

Get started programming with SharePoint social feeds and microblog posts, following people and content (documents, sites, and tags), and working with user profiles.
How can I use social features in apps and solutions?
Setting up the development environment
Development scenarios for social features
How-tos for programming with social features
APIs for programming with social features
App permission requests for accessing social features
Additional resources

How can I use social features in SharePoint apps and solutions?


Social features in SharePoint apps and solutions can help people to connect, communicate, and collaborate with each other and find, track, and share important content and information. You
can add new social features or extend the features that are already available in SharePoint. For example, you can create an app that lets you find and follow people who have a common
interest, create a custom visualization of feed data, or publish custom activities to the feed.
The features described in this article align to the people, feeds, and following functionality that you find on personal sites and team sites. The forum experience and reputation model on
Community Sites don't expose a specific API, so you use SharePoint site and list APIs directly to extend that functionality. For more information, see New Community Site feature.
Before you start developing, you should know where your code will run, what SharePoint environment it will run on, and what functionality it will provide. These factors help you choose the
kind of app to create and which API or APIs to use. See Choose the right API set in SharePoint and SharePoint Add-ins compared with SharePoint solutions for information that can help
you decide.

Setting up your development environment


To get started developing with social features, you'll need:
SharePoint or SharePoint Online
Visual Studio 2012 or Visual Studio 2013, with Office Developer Tools for Visual Studio 2013 - or newer
For more guidance, see Set up a general development environment for SharePoint and Configure social computing features in SharePoint.

Development scenarios for social features in SharePoint


High-level development scenarios for social features include working with social feeds, following people and content (documents, sites, and tags), and working with user properties. Table 1
contains links to articles that describe the primary APIs that you use to access functionality for each scenario and common programming tasks.
The following articles describe the primary APIs and programming tasks for the particular development scenario:
Work with social feeds in SharePoint
Follow people in SharePoint
Follow content in SharePoint
Work with user profiles in SharePoint

How-tos for programming with social features in SharePoint


After you set up your development environment and choose your scenario, you can get started programming with social features. Table 1 contains links to articles that show how to do basic
programming tasks with social features.
Table 1. How-to articles for developing with social features

FE ATU R E AR E A D ES CR IPTIO N

How to: Learn to read and write to the social feed by using the .NET client object model in SharePoint Walk through detailed steps for creating an application that reads and writes to the social feed by using
the .NET client object model.

How to: Learn to read and write to the social feed by using the REST service in SharePoint Walk through detailed steps for creating an application that reads and writes to the social feed by using
the REST service.

How to: Create and delete posts and retrieve the social feed by using the .NET client object model in Learn how to create and delete and microblog posts and retrieve social feeds by using the .NET client
SharePoint object model.

How to: Create and delete posts and retrieve the social feed by using the JavaScript object model in Learn how to create and delete and microblog posts and retrieve social feeds by using the JavaScript
SharePoint object model.

How to: Include mentions, tags, and links to sites and documents in posts in SharePoint Learn how to add SocialDataItem objects to microblog posts, which render as mentions, tags, and links
in social feeds.

How to: Embed images, videos, and documents in posts in SharePoint Learn how to add SocialAttachment objects to microblog posts, which render as embedded pictures,
videos, and documents in social feeds.

How to: Follow people by using the .NET client object model in SharePoint Learn how to work with Following People features by using the .NET client object model.

How to: Follow people by using the JavaScript object model in SharePoint Learn how to work with Following People features by using the JavaScript object model.

How to: Follow documents and sites by using the .NET client object model in SharePoint Learn how to work with Following Content features by using the .NET client object model.
FE ATU R E AR E A D ES CR IPTIO N

How to: Follow documents, sites, and tags by using the REST service in SharePoint Learn how to work with Following Content features by using the REST service.

How to: Retrieve user profile properties by using the .NET client object model in SharePoint Learn how to retrieve user profile properties by using the .NET client object model.

How to: Retrieve user profile properties by using the JavaScript object model in SharePoint Learn how to retrieve user profile properties by using the JavaScript object model.

How to: Work with user profiles and organization profiles by using the server object model in SharePoint Learn how to create, retrieve, and manage user profiles and properties by using the server object model.

APIs for programming with SharePoint social features


Although apps and solutions access SharePoint differently, after you do access SharePoint you use the social APIs in basically the same way. Table 2 shows the APIs for programming with
feed, following, and user profiles features in SharePoint and the paths to the source files on the server.
Table 2. APIs for programming with social features

API NAME S O U R CE AND PATH

.NET client object model Microsoft.SharePoint.Client.UserProfiles.dll


in %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\ISAPI

Silverlight client object model Microsoft.SharePoint.Client.UserProfiles.Silverlight.dll


in %ProgramFiles%\Common Files\Microsoft Shared\web server
extensions\15\TEMPLATE\LAYOUTS\ClientBin

Mobile client object model Microsoft.SharePoint.Client.UserProfiles.Phone.dll


in %ProgramFiles%\Common Files\Microsoft Shared\web server
extensions\15\TEMPLATE\LAYOUTS\ClientBin

JavaScript object model SP.UserProfiles.js


in %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\TEMPLATE\LAYOUTS

Representational State Transfer (REST) service http://<site url>/_api/social.feed


http://<site url>/_api/social.following
http://<site url>/_api/SP.UserProfiles.PeopleManager

Server object model Microsoft.Office.Server.UserProfiles.dll


in %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\ISAPI
NOTE

Not all server-side functionality in the Microsoft.Office.Server.UserProfiles assembly is available from client APIs. To see which APIs are available, see the Microsoft.SharePoint.Client.Social
namespace and the Microsoft.SharePoint.Client.UserProfiles namespace.

App permission requests for accessing social features in SharePoint Add-ins


An SharePoint Add-in must request the permissions that it needs to access SharePoint resources from the user who installs it. For example, an app that posts to the feed should request
Write permission (at minimum) to the feed. You specify the permissions that your app need in the AppManifest.xml file in Visual Studio.
App permission requests are scoped to the SharePoint deployment landscape. Table 3 shows the scope names (with corresponding scope URIs) and the available rights for accessing social
features. For more information, see Add-in permissions in SharePoint, Add-in authorization policy types in SharePoint, and Plan app permissions management in SharePoint.
Table 3. App permission scopes and available rights for social features in SharePoint

S CO PE NAME D ES CR IPTIO N AV AIL AB LE R IG HTS

User Profiles The permission request scope used to access all user profiles. Only Read, Write, Manage, FullControl
http://sharepoint/social/tenant the profile picture can be changed; all other user profile properties
are read-only for SharePoint Add-ins. Must be installed by a tenant
administrator.

Core The permission request scope used to access the user's followed Read, Write, Manage, FullControl
http://sharepoint/social/core content and shared metadata that is used by microblogging
features. This scope applies only to personal sites that support
following content. If the app installs on any other type of site, use
the Tenant scope.

News Feed The permission request scope used to access the user's feed or the Read, Write, Manage, FullControl
http://sharepoint/social/microfeed team feed. This scope applies to personal sites that support
microblogging or to team sites where the Site Feed feature is
activated. If the app installs on any other type of site, use the Tenant
scope.

http://sharepoint/social/trimming This permission request scope used to determine whether to display Read, Write, Manage, FullControl
security-trimmed content in the social feed to apps. If this high-
trust permission is not granted, some content (such as activities
about documents and sites that the app doesn't have permissions
to) is trimmed from the feed data that's returned to the app, even if
the user has sufficient permissions. This permission must be
manually added to the app's manifest file.

What you'll need to consider when requesting app permissions


You should be aware of the following considerations when you specify app permissions for social features:
Apps that specify FullControl rights are not allowed for Office Store apps. Only Read, Write, and Manage rights are allowed for Office Store apps.
You can specify permissions for feed and following features by using the Core, News Feed, and Tenant ( http://sharepoint/content/tenant ) scopes. The Tenant scope represents the
whole tenancy where an app is installed, including the Core and News Feed scopes. So if your app already specifies the rights that it needs at the Tenant scope, then you don't need to
request permissions at the Core or News Feed scope.
During development, use the Tenant scope if you get a "SocialListNotFound : The Social list does not exist in your personal site" or "File Not Found" message. If you want to use the
Core or News Feed scope in your app, you can test the permissions by opening the app from the app catalog.
The Core scope applies to personal sites that support following content. The News Feed scope applies to personal sites that support microblogging or to team sites where the Site
Feed feature is activated. If the app will be installed on any other type of site, you must use the Tenant scope. See Tenancies and deployment scopes for SharePoint Add-ins.
Apps that request rights for the User Profiles scope must be installed by a tenant administrator, and they cannot be installed in Office 365 Small Business Premium version of
SharePoint Online.
If licensing or feature activation requirements for social and microblogging features are not met, users get a message saying that they can't install the app.
Apps that are launched outside of SharePoint can request permission on-the-fly (except Full Control). For more information, see Authorization Code OAuth flow for SharePoint Add-
ins.

See also
Conceptual articles
Social and collaboration features in SharePoint
What's new for developers in social and collaboration features in SharePoint
Plan for social computing and collaboration in SharePoint
Configure social computing features in SharePoint
Social computing terminology and concepts in SharePoint
Reference documentation
Social client class library
SP.UserProfiles.js JavaScript Reference
Social feed REST API reference for SharePoint
Following people and content REST API reference for SharePoint
User profiles REST API reference
SharePoint Social server class library
Read and write to the social feed by using the .NET client object model in SharePoint
3/26/2018 • 5 minutes to read Edit Online

Create a console application that reads and writes to the social feed by using the SharePoint .NET client object model.

Prerequisites for creating a console application that reads and writes to the social feed by using the SharePoint .NET
client object model
The console application that you'll create retrieves a target user's feed and prints the root post from each thread in a numbered list. Then, it publishes a simple text reply to the selected
thread. The same method ( CreatePost ) is used to publish both posts and replies to the feed.
To create the console application, you'll need the following:
SharePoint with My Site configured, with personal sites created for the current user and a target user, and with a few posts written by the target user
Visual Studio 2012
Full Control access permissions to the User Profile service application for the logged-on user
NOTE

If you're not developing on the computer that is running SharePoint, get the SharePoint Client Components download that contains SharePoint client assemblies.

Core concepts to know about working with SharePoint social feeds


Table 1 contains links to articles that describe core concepts you should know before you get started.
Table 1. Core concepts for working with SharePoint social feeds

AR TICLE TITLE D ES CR IPTIO N

Get started developing with social features in SharePoint Find out how to get started programming with social feeds and microblog posts, following people and
content (documents, sites, and tags.md), and working with user profiles.

Work with social feeds in SharePoint Learn about common programming tasks for working with social feeds and the API that you use to
perform the tasks.

Create the console application in Visual Studio 2012 and add references to client assemblies
1. On your development computer, open Visual Studio 2012.
2. On the menu bar, choose File, New, Project.
3. In the New Project dialog box, choose .NET Framework 4.5 from the drop-down list at the top of the dialog box.
4. From the Templates list, choose Windows, and then choose the Console Application template.
5. Name the project ReadWriteMySite, and then choose the OK button.
6. Add references to the client assemblies, as follows:
a. In Solution Explorer, open the shortcut menu for the ReadWriteMySite project, and then choose Add Reference.
b. In the Reference Manager dialog box, choose the following assemblies:
Microsoft.SharePoint.Client
Microsoft.SharePoint.Client.Runtime
Microsoft.SharePoint.Client.UserProfiles
If you are developing on the computer that is running SharePoint, the assemblies are in the Extensions category. Otherwise, browse to the location that has the client assemblies you
downloaded (see SharePoint Client Components).
7. In the Program.cs file, add the following using statements.

using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

Retrieve the social feed for a target user by using the SharePoint .NET client object model
1. Declare variables for the server URL and target user's account credentials.

const string serverUrl = "http://serverName/";


const string targetUser = "domainName\\userName";

NOTE

Remember to replace the http://serverName/ and domainName\\userName placeholder values before you run the code.
2. In the Main method, initialize the SharePoint client context.

ClientContext clientContext = new ClientContext(serverUrl);

3. Create the SocialFeedManager instance.

SocialFeedManager feedManager = new SocialFeedManager(clientContext);


4. Specify the parameters for the feed content that you want to retrieve.

SocialFeedOptions feedOptions = new SocialFeedOptions();


feedOptions.MaxThreadCount = 10;

The default options return the first 20 threads in the feed, sorted by last modified date.
5. Get the target user's feed.

ClientResult<SocialFeed> feed = feedManager.GetFeedFor(targetUser, feedOptions);


clientContext.ExecuteQuery();

GetFeedFor returns a ClientResult object that stores the collection of threads in its Value property.

Iterate through and read from the social feed by using the SharePoint .NET client object model
The following code iterates through the threads in the feed. It checks whether each thread has the CanReply attribute and then gets the thread identifier and the text of the root post. The
code also creates a dictionary to store the thread identifier (which is used to reply to a thread) and writes the text of the root post to the console.

Dictionary<int, string> idDictionary = new Dictionary<int, string>();


for (int i = 0; i < feed.Value.Threads.Length; i++)
{
SocialThread thread = feed.Value.Threads[i];
string postText = thread.RootPost.Text;
if (thread.Attributes.HasFlag(SocialThreadAttributes.CanReply))
{
idDictionary.Add(i, thread.Id);
Console.WriteLine("\\t" + (i + 1) + ". " + postText);
}
}

Post a reply to the social feed by using the SharePoint .NET client object model
1. (UI-related only) Get the thread to reply to and prompt for the user's reply.

Console.Write("Which post number do you want to reply to? ");


string threadToReplyTo = "";
int threadNumber = int.Parse(Console.ReadLine()) - 1;
idDictionary.TryGetValue(threadNumber, out threadToReplyTo);
Console.Write("Type your reply: ");

1. Define the reply. The following code gets the reply's text from the console application.

SocialPostCreationData postCreationData = new SocialPostCreationData();


postCreationData.ContentText = Console.ReadLine();

1. Publish the reply. The threadToReplyTo parameter represents of the thread's Id property.

feedManager.CreatePost(threadToReplyTo, postCreationData);
clientContext.ExecuteQuery();

> [!NOTE]
> The [CreatePost](https://msdn.microsoft.com/library/Microsoft.SharePoint.Client.Social.SocialFeedManager.CreatePost.aspx) method is also used to publish a root post to the current user's feed

1. (UI-related only) Exit the program.

Console.WriteLine("Your reply was published.");


Console.ReadKey(false);

2. To test the console application, on the menu bar, choose Debug, Start Debugging.

Code example: Retrieve a feed and reply to a post by using the SharePoint .NET client object model
The following example is the complete code from the Program.cs file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace ReadWriteMySite
{
class Program
{
static void Main(string[] args)
{

// Replace the following placeholder values with the target server running SharePoint and the
// target thread owner.
const string serverUrl = "http://serverName/";
const string targetUser = "domainName\\userName";

// Connect to the client context.


ClientContext clientContext = new ClientContext(serverUrl);

// Get the SocialFeedManager instance.


SocialFeedManager feedManager = new SocialFeedManager(clientContext);

// Specify the parameters for the feed content that you want to retrieve.
SocialFeedOptions feedOptions = new SocialFeedOptions();
feedOptions.MaxThreadCount = 10;

// Get the target owner's feed (posts and activities) and then run the request on the server.
ClientResult<SocialFeed> feed = feedManager.GetFeedFor(targetUser, feedOptions);
clientContext.ExecuteQuery();

// Create a dictionary to store the Id property of each thread. This code example stores
// the ID so a user can select a thread to reply to from the console application.
Dictionary<int, string> idDictionary = new Dictionary<int, string>();
for (int i = 0; i < feed.Value.Threads.Length; i++)
{
SocialThread thread = feed.Value.Threads[i];

// Keep only the threads that can be replied to.


if (thread.Attributes.HasFlag(SocialThreadAttributes.CanReply))
{
idDictionary.Add(i, thread.Id);

// Write out the text of the post.


Console.WriteLine("\\t" + (i + 1) + ". " + thread.RootPost.Text);
}
}
Console.Write("Which post number do you want to reply to? ");

string threadToReplyTo = "";


int threadNumber = int.Parse(Console.ReadLine()) - 1;
idDictionary.TryGetValue(threadNumber, out threadToReplyTo);

Console.Write("Type your reply: ");

// Define properties for the reply.


SocialPostCreationData postCreationData = new SocialPostCreationData();
postCreationData.ContentText = Console.ReadLine();

// Post the reply and make the changes on the server.


feedManager.CreatePost(threadToReplyTo, postCreationData);
clientContext.ExecuteQuery();

Console.WriteLine("Your reply was published.");


Console.ReadKey(false);

// TODO: Add error handling and input validation.


}
}
}

Next steps
To learn how to do more read tasks and write tasks with the social feed by using the .NET client object model, see the following:
How to: Create and delete posts and retrieve the social feed by using the .NET client object model in SharePoint

See also
Get started developing with social features in SharePoint
Work with social feeds in SharePoint
Read and write to the social feed by using the REST service in SharePoint
3/26/2018 • 6 minutes to read Edit Online

Create a SharePoint-hosted app that uses the REST service to publish a post and get the personal feed for the current user.

Prerequisites for creating a SharePoint-hosted SharePoint Add-in that publishes a post and gets the social feed by
using the SharePoint REST service
This article assumes that you create the SharePoint Add-in by using Napa on an Office 365 Developer Site. If you're using this development environment, you've already met the
prerequisites.
NOTE

Go to Set up a development environment for SharePoint Add-ins on Office 365 to find out how to sign up for a Developer Site and start using Napa.
If you're not using Napa on a Developer Site, you'll need the following:
SharePoint with My Site configured, and with a personal site created for the current user
Visual Studio 2012 and Office Developer Tools for Visual Studio 2013
Full Control access permissions to the User Profile service application for the logged-on user
NOTE

For guidance about how to set up a development environment that fits your needs, see Start building apps for Office and SharePoint.

Core concepts to know about working with SharePoint social feeds


The SharePoint-hosted app that you create in this article uses JavaScript to build and send HTTP requests to Representational State Transfer (REST) endpoints. These requests publish a post
and get the personal feed for the current user. Table 1 contains links to articles that describe general concepts you should understand before you get started.
Table 1. Core concepts for working with SharePoint social feeds

AR TICLE TITLE D ES CR IPTIO N

SharePoint Add-ins Learn about SharePoint Add-ins and fundamental concepts for building them.

Get started developing with social features in SharePoint Find out how to start programming with social feeds and microblog posts, following people and content
(documents, sites, and tags.md), and working with user profiles.

Work with social feeds in SharePoint Learn about common programming tasks for working with social feeds and the API that you use to
perform the tasks.

Create the SharePoint Add-in project


1. On your Developer Site, open Napa, and then choose Add New Project.
2. Choose the App for SharePoint template, name the projectSocialFeedREST, and then choose the Create button.
3. Specify the permissions that your app needs:
a. Choose the Properties button at the bottom of the page.
b. In the Properties window, choose Permissions.
c. In the Content category, set Write permissions for the Tenant scope.
d. In the Social category, set Read permissions for the User Profiles scope.
e. Close the Properties window.
4. Expand the Scripts node, choose the App.js file, and delete the contents of the file.

Post to the social feed by using the SharePoint REST service


1. In the App.js file, declare a global variable for the URL of the SocialFeedManager endpoint.

var feedManagerEndpoint;

1. Add the following code, which gets the SPAppWebUrl parameter from the query string and uses it to build the SocialFeedManager endpoint.

$(document).ready(function () {
var appweburl;
var params = document.URL.split("?")[1].split("&amp;");
for (var i = 0; i < params.length; i = i + 1) {
var param = params[i].split("=");
if (param[0] === "SPAppWebUrl") appweburl = param[1];
}
feedManagerEndpoint = decodeURIComponent(appweburl) + "/_api/social.feed";
postToMyFeed();
});

1. Add the following code, which builds the HTTP POST request for the /my/Feed/Post endpoint, defines the post's creation data, and publishes the post.
The request sends a SocialRestPostCreationData resource in the request body. SocialRestPostCreationData contains the target for the post (in this case, null to specify a root
post for the current user) and a SocialPostCreationData complex type that defines the post's properties.
function postToMyFeed() {
$.ajax( {
url: feedManagerEndpoint + "/my/Feed/Post",
type: "POST",
data: JSON.stringify( {
'restCreationData':{
'__metadata':{
'type':'SP.Social.SocialRestPostCreationData'
},
'ID':null,
'creationData':{
'__metadata':{
'type':'SP.Social.SocialPostCreationData'
},
'ContentText':'This post was published using REST.',
'UpdateStatusText':false
}
}
}),
headers: {
"accept": "application/json;odata=verbose",
"content-type":"application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: getMyFeed,
error: function (xhr, ajaxOptions, thrownError) {
alert("POST error:\\n" + xhr.status + "\\n" + thrownError);
}
});
}

Retrieve the social feed for the current user by using the SharePoint REST service
Add the following code, which gets the Personal feed type for the current user by using the /my/Feed endpoint. The accept header requests that the server return a JavaScript Object
Notation (JSON) representation of the feed in its response.

function getMyFeed() {
$.ajax( {
url: feedManagerEndpoint + "/my/Feed",
headers: {
"accept": "application/json;odata=verbose"
},
success: feedRetrieved,
error: function (xhr, ajaxOptions, thrownError) {
alert("GET error:\\n" + xhr.status + "\\n" + thrownError);
}
});
}

Iterate through the social feed and read from it by using the SharePoint REST service
Add the following code, which prepares the returned data by using the JSON.stringify function and the JSON.parse function, and then iterates through the feed and gets the thread's
owner and the root post's text.

function feedRetrieved(data) {
var stringData = JSON.stringify(data);
var jsonObject = JSON.parse(stringData);

var feed = jsonObject.d.SocialFeed.Threads;


var threads = feed.results;
var feedContent = "";
for (var i = 0; i < threads.length; i++) {
var thread = threads[i];
var participants = thread.Actors;
var owner = participants.results[thread.OwnerIndex].Name;
feedContent += '<p>' + owner +
' said "' + thread.RootPost.Text + '"</p>';
}
$("#message").html(feedContent);
}

Run the app for SharePoint on the Developer Site


1. To run the app, choose the Run Project button at the bottom of the page.
2. In the Do you trust page that opens, choose the Trust It button. The app page opens and displays the owner's name and the text of each root post in the feed.

Code example: Publish a post and get the feed for the current user by using the SharePoint REST service
The following is the complete code example for the App.js file. It publishes a post and gets the personal feed for the current user, which is returned as a JSON object. Then it iterates through
the feed.
var feedManagerEndpoint;

// Get the SPAppWebUrl parameter from the query string and build
// the feed manager endpoint.
$(document).ready(function () {
var appweburl;
var params = document.URL.split("?")[1].split("&amp;");
for (var i = 0; i < params.length; i = i + 1) {
var param = params[i].split("=");
if (param[0] === "SPAppWebUrl") appweburl = param[1];
}
feedManagerEndpoint = decodeURIComponent(appweburl)+ "/_api/social.feed";
postToMyFeed();
});

// Publish a post to the current user's feed by using the


// "<app web URL>/_api/social.feed/my/Feed/Post" endpoint.
function postToMyFeed() {
$.ajax( {
url: feedManagerEndpoint + "/my/Feed/Post",
type: "POST",
data: JSON.stringify( {
'restCreationData':{
'__metadata':{
'type':'SP.Social.SocialRestPostCreationData'
},
'ID':null,
'creationData':{
'__metadata':{
'type':'SP.Social.SocialPostCreationData'
},
'ContentText':'This post was published using REST.',
'UpdateStatusText':false
}
}
}),
headers: {
"accept": "application/json;odata=verbose",
"content-type":"application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: getMyFeed,
error: function (xhr, ajaxOptions, thrownError) {
alert("POST error:\\n" + xhr.status + "\\n" + thrownError);
}
});
}

// Get the current user's feed by using the


// "<app web URL>/_api/social.feed/my/Feed" endpoint.
function getMyFeed() {
$.ajax( {
url: feedManagerEndpoint + "/my/Feed",
headers: {
"accept": "application/json;odata=verbose"
},
success: feedRetrieved,
error: function (xhr, ajaxOptions, thrownError) {
alert("GET error:\\n" + xhr.status + "\\n" + thrownError);
}
});
}

// Parse the JSON data and iterate through the feed.


function feedRetrieved(data) {
var stringData = JSON.stringify(data);
var jsonObject = JSON.parse(stringData);

var feed = jsonObject.d.SocialFeed.Threads;


var threads = feed.results;
var feedContent = "";
for (var i = 0; i < threads.length; i++) {
var thread = threads[i];
var participants = thread.Actors;
var owner = participants.results[thread.OwnerIndex].Name;
feedContent += '<p>' + owner +
' said "' + thread.RootPost.Text + '"</p>';
}
$("#message").html(feedContent);
}

Next steps
See Social feed REST API reference for SharePoint and Following people and content REST API reference for SharePoint for other REST endpoints that you can use to access social features.

See also
Social feed REST API reference for SharePoint
Get started developing with social features in SharePoint
Work with social feeds in SharePoint
Social feed REST API reference for SharePoint
3/26/2018 • 29 minutes to read Edit Online

Find SharePoint REST endpoints for reading and writing to social feeds by using the SocialRestFeedManager resource. You can use the SharePoint Representational State Transfer (REST)
service to do the same things that you can do with the .NET client object models and the JavaScript object model. The REST service exposes resources that correspond to SharePoint objects,
properties, and methods. To use the REST service, you build and send HTTP GET and POST requests to the resource endpoints that represent the tasks you want to do.
The endpoint URIs for most feed tasks begin with the SocialRestFeedManager resource ( social.feed ), followed by the my resource or the post resource:
The my resource represents the current user. When used inline in the endpoint URI, it sets the context of the request to the current user. For example,
http://contoso.com/_api/social.feed/my/news gets the newsfeed for the current user.
The post resource represents a specific thread or post. When used inline in the endpoint URI, it sets the context of the request to the specified thread or post. For example,
http://contoso.com/_api/social.feed/post/lock locks the specified thread.
If the resource endpoint takes a parameter, the parameter metadata is specified in the URI or in the request body. By default, the REST service returns responses formatted in the Atom
protocol, but you can request the JSON format by using HTTP Accept headers. See Example REST requests for feed tasks for examples of complete requests.

Resource endpoints for feed tasks


END PO INT D ES CR IPTIO N

My Gets information about the current user.

My/Feed/Post Creates a root post in the current user's feed.

My/Feed Gets the feed of activity by the current user.

My/News Gets the feed of activity by the current user and by people and content the user is following.

My/TimelineFeed Gets the feed of activity by the current user and by people and content the user is following, sorted by
created date.

My/Likes Gets the feed of posts that the current user likes.

My/MentionFeed Gets the feed of posts that mention the current user.

My/MentionFeed/ClearUnreadMentionCount Gets the feed of posts that mention the current user and clears the unread mention count.

My/UnreadMentionCount Gets the count of unread mentions for the current user.

Actor Gets information about the specified user and the current user.

Actor/Feed Gets the feed of activity by the specified user.

Actor/Feed/Post Creates a root post in the specified site feed.

Post Gets a full thread that contains the specified post.

Post/Reply Posts a reply to the specified post.

Post/Delete Deletes the specified post.

Post/Like Makes the current user a liker of the specified post.

Post/Unlike Removes the current user from the list of likers for the specified post.

Post/Likers Gets the users who like the specified post.

Post/Lock Locks the specified thread.

Post/Unlock Unlocks the specified thread.


NOTE

The following feed-related REST resources use the same pattern as the other SharePoint REST APIs to construct the endpoint URI.> For CreateImageAttachment, send a POST request
to http://<siteCollection>/<site>/_api/SP.Social.SocialFeedManager/CreateImageAttachment > For GetPreview, send a POST request to
http://<siteCollection>/<site>/_api/SP.Social.SocialFeedManager/GetPreview > For SuppressThreadNotifications, send a POST request to
http://<siteCollection>/<site>/_api/SP.Social.SocialFeedManager/SuppressThreadNotifications

My
Gets information about the current user.
The my endpoint sets the current user as the context for any subsequent resource in the URI. For example, http://contoso.com/_api/social.feed/my/news gets the newsfeed for the current
user.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.feed/my

Request parameter
None.
Response
Type: SP.Social.SocialRestActor
Information about the current user.
You can call SocialRestActor properties individually in the URI, for example http://<siteCollection>/<site>/_api/social.feed/my/me gets only the Me property.
The following response example represents information about the current user.

{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/my",
"uri":"http://serverName/sites/dev/_api/social.feed/my",
"type":"SP.Social.SocialRestActor"
},
"FollowableItem":"domain\\username1",
"FollowableItemActor":null,
"Me":{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName/my/personal/username1/",
"Status":0,
"StatusText":"This is post 2",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}
}}

My/Feed/Post
Creates a root post in the current user's feed.
You can post only in the context of the current user. You cannot create a root post in a different user's feed, but you can reply to another user's post. See Post/Reply.
NOTE

Don't confuse this Post resource with the Post resource that represents a specific thread or post.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.feed/my/feed/post

Request parameter
restCreationData
Type: SP.Social.SocialRestPostCreationData
A null ID and the properties of the new post, as shown in the following example.

"restCreationData":{
"__metadata":{
"type":"SP.Social.SocialRestPostCreationData"
},
"ID":null,
"creationData":{
"__metadata":{
"type":"SP.Social.SocialPostCreationData"
},
"ContentText":"This post was published using REST.",
"UpdateStatusText":false
}
}

Response
Type: SP.Social.SocialRestThread
A thread that contains the new root post.
The following response example represents the thread that contains the new root post.
{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c6
"uri":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c
"type":"SP.Social.SocialRestThread"
},
"ID":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-21275
"SocialThread":{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}]
},
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-212
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4
"PostReference":null,
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T19:31:57.204511Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-2
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-17T19:31:57.204511Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Posted with REST."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":0
}
}}

My/Feed
Gets the feed of activity by the current user ( Personal feed type).

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.feed/my/feed

GET http://<siteCollection>/<site>/_api/social.feed/my/feed(MaxThreadCount=10,SortOrder=1,NewerThan=@v)?@v=datetime'2013-01-01T08:00'

Request parameter
feedOptions (optional)
Type: SP.Social.SocialFeedOptions
The maximum number of threads, date-time range, and sort order. You can optionally specify any combination of these properties, for example, you can specify only the MaxThreadCount
property.
You can use an @ alias to pass special characters. For example, <siteUri>/_api/social.feed/my/feed(OlderThan=@v)?@v=datetime'2013-01-01T08:00' uses the @v alias to send a : character.

Response
Type: SP.Social.SocialRestFeed
The current user's personal feed.
The following response example represents the current user's personal feed.

{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/my/feed",
"id":"http://serverName/sites/dev/_api/social.feed/my/feed",
"uri":"http://serverName/sites/dev/_api/social.feed/my/feed",
"type":"SP.Social.SocialRestFeed"
},
"SocialFeed":{
"__metadata":{"type":"SP.Social.SocialFeed"},
"Attributes":1,
"NewestProcessed":"2013-04-15T06:10:11Z",
"OldestProcessed":"2013-04-15T05:33:12Z",
"Threads":{
"results":[{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
},{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username2",
"ActorType":0,
"CanFollow":true,
"ContentUri":null,
"EmailAddress":"username2@somecompany.com",
"FollowedContentUri":null,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":"http://serverName:80/my/User Photos/Profile Pictures/username2_MThumb.jpg",
"IsFollowed":true,
"LibraryUri":null,
"Name":"User2 Name",
"PersonalSiteUri":"http://serverName/my/personal/username2",
"Status":6,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":"SOME TITLE",
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername2"
}]
},
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.c554cbf1934b4c82bb1d43ebf961de92.17.17.S-1-5-21
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac2
"PostReference":null,
"Replies":{
"results":[{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":1,
"CreatedTime":"2013-04-15T06:10:11.3480926Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.59c0273c6c7b41e784b496c9aaa909a8.17.24.S-1-5-
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-15T06:10:11.3480926Z",
"Overlays":{"results":[]},
"PostType":1,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"This is a reply to post 1."
}]
},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-15T05:58:24Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.c554cbf1934b4c82bb1d43ebf961de92.17.17.S-1-5-
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-15T06:10:11Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
},
"Text":"This is post 1."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":1
},{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}]
},
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.82e71ca2381b4657935546e57f1992d5.23.23.S-1-5-21-2
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25a
"PostReference":null,
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-15T06:07:05Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.82e71ca2381b4657935546e57f1992d5.23.23.S-1-5-21
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0},
"ModifiedTime":"2013-04-15T06:07:05Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,"Uri":null},
"Text":"This is post 2."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":0
},{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
},{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username2",
"ActorType":0,
"CanFollow":true,
"ContentUri":null,
"EmailAddress":"username2@somecompany.com",
"FollowedContentUri":null,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":"http://serverName:80/my/User Photos/Profile Pictures/username2_MThumb.jpg",
"IsFollowed":true,
"LibraryUri":null,
"Name":"User2 Name",
"PersonalSiteUri":"http://serverName/my/personal/username2",
"Status":6,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":"SOME TITLE",
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername2"
}]
},
"Attributes":0,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.cecc0de3d7d04520bb87a181b24c105a.16.16.S-1-5-21-2
"OwnerIndex":0,
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25a
"PostReference":{
"__metadata":{"type":"SP.Social.SocialPostReference"},
"Digest":null,
"Post":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":1,
"CreatedTime":"2013-04-15T05:05:13Z",
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.ca83f758aab04065bc303398f2701eb9.10.10.S-1-5-
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":true,
"Indexes":{"results":[]},
"TotalCount":1
},
"ModifiedTime":"2013-04-15T05:05:13Z",
"Overlays":{
"results":[{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[0]},
"Index":1,
"Length":18,
"LinkUri":null,
"OverlayType":1
}]
},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"@User1 Name presented at the conference."},
"ThreadId":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.ca83f758aab04065bc303398f2701eb9.10.10.
"ThreadOwnerIndex":1
},
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":14,
"AuthorIndex":0,
"CreatedTime":"2013-04-15T05:33:12Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.cecc0de3d7d04520bb87a181b24c105a.16.16.S-1-5-
"LikerInfo":null,
"ModifiedTime":"2013-04-15T05:33:12Z",
"Overlays":{
"results":[{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[0]},
"Index":0,
"Length":18,
"LinkUri":null,
"OverlayType":1
},{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[1]},
"Index":35,
"Length":10,
"LinkUri":null,
"OverlayType":1
}]
},
"PostType":0,
"PreferredImageUri":"http://serverName:80/_layouts/15/Images/Like.11x11x32.png",
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,"Uri":null
},
"Text":"User1 Name liked a post by User2 Name."
},
"Status":0,
"ThreadType":1,
"TotalReplyCount":0
}]
},
"UnreadMentionCount":1
}
}}

My/News
Gets the feed of activity by the current user and by people and content the user is following, sorted by last modified date ( News feed type).

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.feed/my/news

GET http://<siteCollection>/<site>/_api/social.feed/my/news(MaxThreadCount=10,NewerThan=@v)?@v=datetime'2013-01-01T08:00'

Request parameter
feedOptions (optional)
Type: SP.Social.SocialFeedOptions
The maximum number of threads, date-time range, and sort order. You can optionally specify any combination of these properties, for example, you can specify only the MaxThreadCount
property.
You can use an @ alias to pass special characters. For example, <siteUri>/_api/social.feed/my/News(OlderThan=@v)?@v=datetime'2013-01-01T08:00' uses the @v alias to send a : character.

Response
Type: SP.Social.SocialRestFeed
The current user's newsfeed.
The following response example represents the current user's newsfeed.

{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/my/news",
"uri":"http://serverName/sites/dev/_api/social.feed/my/news",
"type":"SP.Social.SocialRestFeed"
},
"SocialFeed":{
"__metadata":{"type":"SP.Social.SocialFeed"},
"Attributes":1,
"NewestProcessed":"2013-04-15T06:10:11.4730902Z",
"OldestProcessed":"2013-04-12T20:51:51Z",
"Threads":{
"results":[{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":"http://serverName:80/my/_layouts/15/MySite.aspx?MySiteRedirect=FollowedDocuments",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
},{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username2",
"ActorType":0,
"CanFollow":true,
"ContentUri":null,
"EmailAddress":"username2@somecompany.com",
"FollowedContentUri":null,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":"http://serverName:80/my/User Photos/Profile Pictures/username2_MThumb.jpg",
"IsFollowed":true,
"LibraryUri":null,
"Name":"User2 Name",
"PersonalSiteUri":"http://serverName/my/personal/username2",
"Status":0,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":"SOME TITLE",
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername2"
}]
},
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.c554cbf1934b4c82bb1d43ebf961de92.17.17.S-1-5-21
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac2
"PostReference":null,
"Replies":{
"results":[{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":1,
"CreatedTime":"2013-04-15T06:10:11.3480926Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.59c0273c6c7b41e784b496c9aaa909a8.17.24.S-1-
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-15T06:10:11.3480926Z",
"Overlays":{"results":[]},
"PostType":1,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"This is a reply to post 1."
}]
},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-15T05:58:24Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.c554cbf1934b4c82bb1d43ebf961de92.17.17.S-1-5-
"LikerInfo":{
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0},
"ModifiedTime":"2013-04-15T06:10:11.4730902Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"This is post 1."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":1
},{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":"http://serverName:80/my/_layouts/15/MySite.aspx?MySiteRedirect=FollowedDocuments",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}]
},
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.82e71ca2381b4657935546e57f1992d5.23.23.S-1-5-21
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac2
"PostReference":null,
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-15T06:07:05.4804434Z","Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-15T06:07:05.4804434Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"This is post 2."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":0
}]
},
"UnreadMentionCount":1
}
}}

My/TimelineFeed
Gets the feed of activity by the current user and by people and content the user is following, sorted by created date ( Timeline feed type).

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.feed/my/timelinefeed

GET http://<siteCollection>/<site>/_api/social.feed/my/timelinefeed(MaxThreadCount=10,NewerThan=@v)?@v=datetime'2013-01-01T08:00'

Request parameter
feedOptions (optional)
Type: SP.Social.SocialFeedOptions
The maximum number of threads, date-time range, and sort order. You can optionally specify any combination of these properties, for example, you can specify only the MaxThreadCount
property.
You can use an @ alias to pass special characters. For example, <siteUri>/_api/social.feed/my/timelinefeed(OlderThan=@v)?@v=datetime'2013-01-01T08:00' uses the @v alias to send a :
character.

Response
Type: SP.Social.SocialRestFeed
The current user's timeline feed.
The following response example represents the current user's timeline feed, which is sorted by created date.

{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/my/timelinefeed",
"uri":"http://serverName/sites/dev/_api/social.feed/my/timelinefeed",
"type":"SP.Social.SocialRestFeed"
},
"SocialFeed":{
"__metadata":{"type":"SP.Social.SocialFeed"},
"Attributes":1,
"NewestProcessed":"2013-04-15T06:07:05.4804434Z",
"OldestProcessed":"2013-04-12T20:51:51Z",
"Threads":{
"results":[{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":"http://serverName:80/my/_layouts/15/MySite.aspx?MySiteRedirect=FollowedDocuments",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"This is post 2.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}]
},
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.82e71ca2381b4657935546e57f1992d5.23.23.S-1-5-21
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac2
"PostReference":null,
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-15T06:07:05.4804434Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.82e71ca2381b4657935546e57f1992d5.23.23.S-1-5-
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-15T06:07:05.4804434Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"This is post 2."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":0
},{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":"http://serverName:80/my/_layouts/15/MySite.aspx?MySiteRedirect=FollowedDocuments",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"This is post 2.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}]
},
"Attributes":6,
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.c554cbf1934b4c82bb1d43ebf961de92.17.17.S-1-5-21
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac2
"PostReference":null,
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-15T05:58:24Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.c554cbf1934b4c82bb1d43ebf961de92.17.17.S-1-5-
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-15T06:04:49Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"This is post 1."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":0
}]
},
"UnreadMentionCount":1
}
}}

My/Likes
Gets the feed of microblog posts that the current user likes, represented by LikeReference thread types. See Reference threads and digest threads in SharePoint social feeds.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.feed/my/likes

GET http://<siteCollection>/<site>/_api/social.feed/my/likes(MaxThreadCount=10,SortOrder=1,NewerThan=@v)?@v=datetime'2013-01-01T08:00'

Request parameter
feedOptions (optional)
Type: SP.Social.SocialFeedOptions
The maximum number of threads, date-time range, and sort order. You can optionally specify any combination of these properties, for example, you can specify only the MaxThreadCount
property.
You can optionally specify retrieval options in the query string. You can use an @ alias to pass special characters. For example,
<siteUri>/_api/social.feed/my/likes(OlderThan=@v)?@v=datetime'2013-01-01T08:00' uses the @v alias to send a : character.

Response
Type: SP.Social.SocialRestFeed
A feed that contains posts that the current user likes.
The following response example represents a reference to a post that the current user likes. The thread is a LikeReference thread type (value = 1) whose PostReference property
references the actual post.

{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/my/likes",
"uri":"http://serverName/sites/dev/_api/social.feed/my/likes",
"type":"SP.Social.SocialRestFeed"
},
"SocialFeed":{
"__metadata":{"type":"SP.Social.SocialFeed"}.
"Attributes":1,
"NewestProcessed":"2013-04-15T05:33:12Z",
"OldestProcessed":"2013-04-15T05:33:12Z",
"Threads":{
"results":[{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"Status":0,
"StatusText":"This is post 2",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
},{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username2",
"ActorType":0,
"CanFollow":true,
"ContentUri":null,
"EmailAddress":"username2@somecompany.com",
"FollowedContentUri":null,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":"http://serverName:80/my/User Photos/Profile Pictures/username2_MThumb.jpg",
"IsFollowed":true,
"LibraryUri":null,
"Name":"User2 Name",
"PersonalSiteUri":"http://serverName/my/personal/username2",
"Status":6,
"StatusText":"@User1 Name presented at the conference.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":"SOME TITLE",
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername2"}]
},
"Attributes":0,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.cecc0de3d7d04520bb87a181b24c105a.16.16.S-1-5-
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62a
"PostReference":{
"__metadata":{"type":"SP.Social.SocialPostReference"},
"Digest":null,
"Post":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":1,
"CreatedTime":"2013-04-15T05:05:13Z",
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.ca83f758aab04065bc303398f2701eb9.10.10.S-
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":true,
"Indexes":{"results":[]},
"TotalCount":1
},
"ModifiedTime":"2013-04-15T05:05:13Z",
"Overlays":{
"results":[{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[0]},
"Index":1,
"Length":18,
"LinkUri":null,
"OverlayType":1
}]
},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"@User1 Name presented at the conference."
},
"ThreadId":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.ca83f758aab04065bc303398f2701eb9.10.1
"ThreadOwnerIndex":1
},
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":14,
"AuthorIndex":0,
"CreatedTime":"2013-04-15T05:33:12Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.cecc0de3d7d04520bb87a181b24c105a.16.16.S-1-
"LikerInfo":null,
"ModifiedTime":"2013-04-15T05:33:12Z",
"Overlays":{
"results":[{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[0]},
"Index":0,
"Length":18,
"LinkUri":null,
"OverlayType":1
},{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[1]},
"Index":35,
"Length":10,
"LinkUri":null,
"OverlayType":1
}]
},
"PostType":0,
"PreferredImageUri":"http://serverName:80/_layouts/15/Images/Like.11x11x32.png",
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"User1 Name liked a post by User2 Name."
},
"Status":0,
"ThreadType":1,
"TotalReplyCount":0
}]
},
"UnreadMentionCount":1
}
}}

My/MentionFeed
Gets the feed of microblog posts that mention the current user, represented by MentionReference thread types. See Reference threads and digest threads in SharePoint social feeds.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.feed/my/mentionfeed

GET http://<siteCollection>/<site>/_api/social.feed/my/mentionfeed(MaxThreadCount=10,SortOrder=1,NewerThan=@v)?@v=datetime'2013-01-01T08:00'

Request parameter
feedOptions (optional)
Type: SP.Social.SocialFeedOptions
The maximum number of threads, date-time range, and sort order. You can optionally specify any combination of these properties, for example, you can specify only the MaxThreadCount
property.
You can use an @ alias to pass special characters. For example, <siteUri>/_api/social.feed/my/likes(OlderThan=@v)?@v=datetime'2013-01-01T08:00' uses the @v alias to send a : character.

Response
Type: SP.Social.SocialRestFeed
A feed that contains posts that mention the current user.
The following response example represents one thread that mentions the current user. The thread is a MentionReference thread type (value = 3) whose PostReference property
references the actual post.

{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/my/mentionfeed",
"uri":"http://serverName/sites/dev/_api/social.feed/my/mentionfeed",
"type":"SP.Social.SocialRestFeed"
},
"SocialFeed":{
"__metadata":{"type":"SP.Social.SocialFeed"},
"Attributes":1,
"NewestProcessed":"2013-04-15T05:05:19Z",
"OldestProcessed":"2013-04-15T05:05:19Z",
"Threads":{
"results":[{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"This is post 2",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
},{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username2",
"ActorType":0,
"CanFollow":true,
"ContentUri":null,
"EmailAddress":"username2@somecompany.com",
"FollowedContentUri":null,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":"http://serverName:80/my/User Photos/Profile Pictures/username2_MThumb.jpg",
"IsFollowed":true,
"LibraryUri":null,
"Name":"User2 Name",
"PersonalSiteUri":"http://serverName/my/personal/username2",
"Status":6,
"StatusText":"@User1 Name presented at the conference.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":"SOME TITLE",
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername2"
}]
},
"Attributes":0,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.ec5198399300401fb44f0f5c9d8dea80.15.15.S-1-5-21
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac2
"PostReference":{
"__metadata":{"type":"SP.Social.SocialPostReference"},
"Digest":null,
"Post":{
"Post":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":1,
"CreatedTime":"2013-04-15T05:05:12.0102795Z",
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.ca83f758aab04065bc303398f2701eb9.10.10.S-1-
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-15T05:05:12.0102795Z",
"Overlays":{
"results":[{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[0]},
"Index":1,
"Length":18,
"LinkUri":null,
"OverlayType":1
}]
},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"@User1 Name presented at the conference."
},
"ThreadId":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.ca83f758aab04065bc303398f2701eb9.10.10.
"ThreadOwnerIndex":1
},
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":14,
"AuthorIndex":1,
"CreatedTime":"2013-04-15T05:05:19Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.ec5198399300401fb44f0f5c9d8dea80.15.15.S-1-5-
"LikerInfo":null,
"ModifiedTime":"2013-04-15T05:05:19Z",
"Overlays":{
"results":[{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[1]},
"Index":13,
"Length":10,
"LinkUri":null,
"OverlayType":1
}]
},
"PostType":0,
"PreferredImageUri":"http://serverName:80/_layouts/15/Images/mention.11x11x32.png",
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Mentioned by User2 Name."},
"Status":0,
"ThreadType":3,
"TotalReplyCount":0
}]
},
"UnreadMentionCount":1
}
}}

My/MentionFeed/ClearUnreadMentionCount
Gets the feed of microblog posts that mention the current user, represented by MentionReference thread types, and sets the user's unread mention count to 0. See Reference threads and
digest threads in SharePoint social feeds.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.feed/my/mentionfeed/clearunreadmentioncount

Request parameter
feedOptions
Type: SP.Social.SocialFeedOptions
This parameter must be sent as an empty string in the data attribute of the request body, as shown in the following example.

'feedOptions': {
'__metadata': {
'type': 'SP.Social.SocialFeedOptions'
},
}

Response
Type: SP.Social.SocialRestFeed
The current user's mention feed.
The following response example represents the current user's mention feed. The thread is a MentionReference thread type (value = 3) whose PostReference property references the
actual post. The unread mention count is cleared after the feed is retrieved.

{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/my/mentionfeed",
"uri":"http://serverName/sites/dev/_api/social.feed/my/mentionfeed",
"type":"SP.Social.SocialRestFeed"
},
"SocialFeed":{
"__metadata":{"type":"SP.Social.SocialFeed"},
"Attributes":1,
"NewestProcessed":"2013-04-15T05:05:19Z",
"OldestProcessed":"2013-04-15T05:05:19Z",
"Threads":{
"results":[{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"Posted with REST.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
},{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username2",
"ActorType":0,
"CanFollow":true,
"ContentUri":null,
"EmailAddress":"username2@somecompany.com",
"FollowedContentUri":null,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":"http://serverName:80/my/User Photos/Profile Pictures/username2_MThumb.jpg",
"IsFollowed":true,
"LibraryUri":null,
"Name":"User2 Name",
"PersonalSiteUri":"http://serverName/my/personal/username2",
"Status":6,
"StatusText":"This is post 1 from the specified user.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":"SOME TITLE",
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername2"
}]
},
"Attributes":0,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.ec5198399300401fb44f0f5c9d8dea80.15.15.S-1-5-21-2
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25a
"PostReference":{
"__metadata":{"type":"SP.Social.SocialPostReference"},
"Digest":null,
"Post":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":1,
"CreatedTime":"2013-04-15T05:05:12.0102795Z",
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.ca83f758aab04065bc303398f2701eb9.10.10.S-1-5-
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-15T05:05:12.0102795Z",
"Overlays":{
"results":[{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[0]},
"Index":1,
"Length":18,
"LinkUri":null,
"OverlayType":1
}]
},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"@User1 Name presented at the conference."},
"ThreadId":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.ca83f758aab04065bc303398f2701eb9.10.10.
"ThreadOwnerIndex":1
},
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":14,
"AuthorIndex":1,
"CreatedTime":"2013-04-15T05:05:19Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.ec5198399300401fb44f0f5c9d8dea80.15.15.S-1-5-
"LikerInfo":null,
"ModifiedTime":"2013-04-15T05:05:19Z",
"Overlays":{
"results":[{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[1]},
"Index":13,
"Length":10,
"LinkUri":null,
"OverlayType":1
}]
},
"PostType":0,
"PreferredImageUri":"http://serverName:80/_layouts/15/Images/mention.11x11x32.png",
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Mentioned by User2 Name."
},
"Status":0,
"ThreadType":3,
"TotalReplyCount":0
}]
},
"UnreadMentionCount":1
}
}}

My/UnreadMentionCount
Gets the count of unread mentions for the current user.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.feed/my/unreadmentioncount

Request parameter
None.

Response
Type: Int32
The count of unread mentions for the current user.
The following response example represents an unread mention count of 1.

{"d":{"UnreadMentionCount":1}}

Actor
Gets information about the specified user and the current user.
NOTE

The endpoint sets the specified user or site feed as the context for any subsequent resource in the URI. For example,
actor
http://contoso.com/_api/social.feed/actor(item='domain\\user')/feed gets the personal feed for the specified user and
http://contoso.com/_api/social.feed/actor(item=@v)/feed?@v='http://<server>/<teamSite>/newsfeed.aspx' gets the site feed for the specified team site.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.feed/actor(item='domain\\user')

GET http://<siteCollection>/<site>/_api/social.feed/actor(item=@v)?@v='i:0"%23".f|membership|user@domain.com'

Request parameter
item
Type: String
The account name of the specified user.
You send the item parameter in the query string. You can use an @ alias to pass special characters. For example,
<siteUri>/_api/social.feed/actor(item=@v)?@v='i:0"%23".f|membership|user@domain.com' uses the @v alias and the "%23" encoding to send a # character.

Response
Type: SP.Social.SocialRestActor
Information about the specified user and the current user.
You can call SocialRestActor properties individually in the URI, for example http://<siteCollection>/<site>/_api/social.feed/actor(item='domain\\user')/followableitem gets only the
FollowableItem property for the specified actor.
The following response example represents information about the specified user and the current user.
{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/actor(Item=@ai)/?@ai='domain\\username2'",
"uri":"http://serverName/sites/dev/_api/social.feed/actor(Item=@ai)/?@ai='domain%5cusername2'",
"type":"SP.Social.SocialRestActor"
},
"FollowableItem":"domain\\username2",
"FollowableItemActor":{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username2",
"ActorType":0,
"CanFollow":true,
"ContentUri":null,
"EmailAddress":"username2@somecompany.com",
"FollowedContentUri":null,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":"http://serverName:80/my/User Photos/Profile Pictures/username2_MThumb.jpg",
"IsFollowed":true,
"LibraryUri":null,
"Name":"User2 Name",
"PersonalSiteUri":"http://serverName/my/personal/username2",
"Status":0,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":"SOME TITLE",
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername2"
},
"Me":{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName/my/personal/username1/",
"Status":0,
"StatusText":"This is post 2",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}
}}

Actor/Feed
Gets the feed of activity by the specified user ( Personal feed type) or gets the specified site feed.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.feed/actor(item='domain\\user')/feed

GET http://<siteCollection>/<site>/_api/social.feed/actor(item=@v)/feed?@v='i:0"%23".f|membership|user@domain.com'

GET http://<siteCollection>/<site>/_api/social.feed/actor(item='domain\\user')/feed(MaxThreadCount=10,SortOrder=1,NewerThan=@v)?@v=datetime'2013-01-01T08:00'

GET http://<siteCollection>/<site>/_api/social.feed/actor(item=@v)/feed?@v='http://<teamSiteUri>/newsfeed.aspx'

Request parameter
feedOptions (optional)
Type: SP.Social.SocialFeedOptions
The maximum number of threads, date-time range, and sort order. You can optionally specify any combination of these properties, for example, you can specify only the MaxThreadCount
property.
You can use an @ alias to pass special characters. For example,
<siteUri>/_api/social.feed/actor(item=@v)/feed(NewerThan=@x)?@v='i:0"%23".f|membership|user@domain.com'&amp;@x=datetime'2013-01-01T08:00' uses the @v alias and the "%23" encoding to
send a # character, and the @x alias to send a : character.

Response
Type: SP.Social.SocialRestFeed
The personal feed of the specified user or the site feed at the specified URI.
The following response example represents personal feed of the specified user.

{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/actor(Item=@ai)/feed/?@ai='domain\\username2'",
"uri":"http://serverName/sites/dev/_api/social.feed/actor(Item=@ai)/feed/?@ai='domain%5cusername2'",
"type":"SP.Social.SocialRestFeed"
},
"SocialFeed":{
"__metadata":{"type":"SP.Social.SocialFeed"},
"Attributes":1,
"NewestProcessed":"2013-04-16T22:40:55Z",
"OldestProcessed":"2013-04-16T22:40:07Z",
"Threads":{
"results":[{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username2",
"ActorType":0,
"CanFollow":true,
"ContentUri":null,
"EmailAddress":"username2@somecompany.com",
"FollowedContentUri":null,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":"http://serverName:80/my/User%20Photos/Profile%20Pictures/username2_MThumb.jpg",
"IsFollowed":true,
"LibraryUri":null,
"Name":"User2 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username2",
"Status":0,
"StatusText":"This is post 1 from the specified user.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":"SOME TITLE",
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername2"
},{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName/my/personal/username1/",
"Status":0,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}]
},
"Attributes":0,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.4cb7a5d36cb14d62b0fb68ef98f9765e.15.15.S-1-5-21
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac2
"PostReference":{
"__metadata":{"type":"SP.Social.SocialPostReference"},
"Digest":null,
"Post":null,
"ThreadId":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.c554cbf1934b4c82bb1d43ebf961de92.17.17.
"ThreadOwnerIndex":1
},
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":14,
"AuthorIndex":0,
"CreatedTime":"2013-04-16T22:40:55Z",
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.4cb7a5d36cb14d62b0fb68ef98f9765e.15.15.S-1-5-
"LikerInfo":null,
"ModifiedTime":"2013-04-16T22:40:55Z",
"Overlays":{
"results":[{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[0]},
"Index":0,
"Length":10,
"LinkUri":null,
"OverlayType":1
},{
"__metadata":{"type":"SP.Social.SocialDataOverlay"},
"ActorIndexes":{"results":[1]},
"Index":32,
"Length":18,
"LinkUri":null,
"OverlayType":1
}]
},
"PostType":0,
"PreferredImageUri":"http://serverName:80/_layouts/15/Images/RepliedTo.11x11x32.png",
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"User2 Name replied to a post by User1 Name."
},
"Status":0,
"ThreadType":2,
"TotalReplyCount":0
},{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username2",
"ActorType":0,
"CanFollow":true,
"ContentUri":null,
"EmailAddress":"username2@somecompany.com",
"FollowedContentUri":null,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":"http://serverName:80/my/User%20Photos/Profile%20Pictures/username2_MThumb.jpg",
"IsFollowed":true,
"LibraryUri":null,
"LibraryUri":null,
"Name":"User2 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username2",
"Status":0,
"StatusText":"This is post 1 from the specified user.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":"SOME TITLE",
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername2"
}]
},
"Attributes":6,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.b83675d28e264e69823205ad4e76df9f.14.14.S-1-5-21
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac2
"PostReference":null,
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-16T22:40:07Z",
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b.b83675d28e264e69823205ad4e76df9f.14.14.S-1-5-
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-16T22:40:07Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"This is post 1 from the specified user."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":0
}]
},
"UnreadMentionCount":0
}
}}

Actor/Feed/Post
Creates a root post in the specified site feed.
You can post only in the context of the current user. You cannot create a root post in a different user's feed, but you can reply to another user's post. See Post/Reply.
NOTE

Don't confuse this Post resource with the Post resource that represents a specific thread or post.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.feed/actor(item=@v)/feed/post?@v='http://<siteCollection>/<teamSite>/newsfeed.aspx'

Request parameter
restCreationData
Type: SP.Social.SocialRestPostCreationData
A null ID and the properties of the new post, as shown in the following example.

'restCreationData':{
'__metadata':{
'type':'SP.Social.SocialRestPostCreationData'
},
'ID':null,
'creationData':{
'__metadata':{
'type':'SP.Social.SocialPostCreationData'
},
'ContentText':'This post was published using REST.',
'UpdateStatusText':false
}
}

Response
Type: SP.Social.SocialRestThread
A thread that contains the new root post.
The following response example represents the thread that contains the new root post.
{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='8.c4bb19b167a448a3be9b597522152420.c305b669c2b649e9b820e7feabe3c095.c4bb19b167a448a3be9b597522152420.0c37852b34d0418e91c6
"uri":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='8.c4bb19b167a448a3be9b597522152420.c305b669c2b649e9b820e7feabe3c095.c4bb19b167a448a3be9b597522152420.0c37852b34d0418e91c
"type":"SP.Social.SocialRestThread"
},
"ID":"8.c4bb19b167a448a3be9b597522152420.c305b669c2b649e9b820e7feabe3c095.c4bb19b167a448a3be9b597522152420.0c37852b34d0418e91c62ac25af4be5b.866d920d78d949a394f26073b767cb19.3.3.1",
"SocialThread":{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":null,
"ActorType":2,
"CanFollow":true,
"ContentUri":"http://serverName:80/sites/teamSite",
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"8.c4bb19b167a448a3be9b597522152420.c305b669c2b649e9b820e7feabe3c095.c4bb19b167a448a3be9b597522152420.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":true,
"LibraryUri":null,
"Name":"Team Site",
"PersonalSiteUri":null,
"Status":0,
"StatusText":null,
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/sites/teamSite"
},{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"Posted with REST.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}]
},
"Attributes":6,
"Id":"8.c4bb19b167a448a3be9b597522152420.c305b669c2b649e9b820e7feabe3c095.c4bb19b167a448a3be9b597522152420.0c37852b34d0418e91c62ac25af4be5b.866d920d78d949a394f26073b767cb19.3.3.1",
"OwnerIndex":0,
"Permalink":"http://serverName/sites/teamSite/newsfeed.aspx?ThreadID=8.c4bb19b167a448a3be9b597522152420.c305b669c2b649e9b820e7feabe3c095.c4bb19b167a448a3be9b597522152420.0c37852b34d0418e91c62
"PostReference":null,
"Replies":{"results":[]},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":1,
"CreatedTime":"2013-04-18T22:44:11.8485085Z",
"Id":"8.c4bb19b167a448a3be9b597522152420.c305b669c2b649e9b820e7feabe3c095.c4bb19b167a448a3be9b597522152420.0c37852b34d0418e91c62ac25af4be5b.866d920d78d949a394f26073b767cb19.3.3.1",
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-18T22:44:11.8485085Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Posted with REST."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":0
}
}}

Post
Gets a full thread that contains the specified microblog post.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.feed/post

Request parameter
ID
Type: String
The unique identifier of the post, as shown in the following example.

'ID':'1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.644240140e0b43379883ebcb859deaab.27.32.S-1-5-21-2127521

Response
Type: SP.Social.SocialRestThread
A full thread that contains the specified post.
The following response example represents the full thread that contains the specified post. Unlike digest threads (which contain only the two most recent replies), a full thread contains all
replies.

{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c6
"uri":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c
"type":"SP.Social.SocialRestThread"
},
"ID":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.62bff48184bd433b8f7b04f6ea76268b.27.27.S-1-5-21-21275
"SocialThread":{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"Posted with REST.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
},{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username2",
"ActorType":0,
"CanFollow":true,
"ContentUri":null,
"EmailAddress":"username2@somecompany.com",
"FollowedContentUri":null,
"Id":"1.ed418efb7f984ee49ce276c9c5441938.de1675d4929d431894c18908ac53516a.65da910de21f4e40abb318ba33520931.0c37852b34d0418e91c62ac25af4be5b","ImageUri":"http://serverName:80/my/User Photo
"IsFollowed":true,
"LibraryUri":null,"Name":"User2 Name","PersonalSiteUri":"http://serverName/my/personal/username2","Status":6,"StatusText":"This is post 1 from the specified user.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":"SOME TITLE",
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername2"
}]
},
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.62bff48184bd433b8f7b04f6ea76268b.27.27.S-1-5-21-212
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4
"PostReference":null,
"Replies":{
"results":[{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":1,
"CreatedTime":"2013-04-23T23:02:40Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.644240140e0b43379883ebcb859deaab.27.32.S-1-5-21
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-23T23:02:40Z",
"Overlays":{"results":[]},
"PostType":1,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"This is a reply."
}]
},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T19:45:45Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.62bff48184bd433b8f7b04f6ea76268b.27.27.S-1-5-21-2
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[1]},
"TotalCount":1
"TotalCount":1
},
"ModifiedTime":"2013-04-23T23:02:41Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Posted with REST."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":1
}
}}

Post/Reply
Posts a reply to the specified post.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.feed/post/reply

Request parameter
restCreationData
Type: SP.Social.SocialRestPostCreationData
The ID of the post to reply to and the properties of the reply, as shown in the following example.

'restCreationData':{
'__metadata':{
'type': 'SP.Social.SocialRestPostCreationData'
},
'ID':'1.4975bef1e1bc42608c1dfae9f320c751.35c9fd7b79904800aaa5f74684bf0f75.623664921f034e8d814c000267d3e5e4.0c37852b34d0418e91c62ac25af4be5b.230d3c5272fc499f88ac0b74b2f4512f.119.119.S-1-5-21-124
'creationData':{
'__metadata':{
'type':'SP.Social.SocialPostCreationData'
},
'ContentText':'Posted with REST.',
'UpdateStatusText':false
}
}

Response
Type: SP.Social.SocialRestThread
A digest of the modified thread that includes the specified post.
The following response example represents the thread that contains the specified post and reply.
{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c6
"uri":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c
"type":"SP.Social.SocialRestThread"
},
"ID":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-21275
"SocialThread":{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{
"type":"SP.Social.SocialActor"
},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"Posted with REST.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"}
]},
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-212
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4
"PostReference":null,
"Replies":{
"results":[{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T20:52:51.0650454Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.ce3ac812293c4903b5c406efe01b9432.26.29.S-1-5-21
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-17T20:52:51.0650454Z",
"Overlays":{"results":[]},
"PostType":1,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Replied with REST."
}]
},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T19:33:17Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-2
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-17T20:52:51.6900774Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Posted with REST."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":1
}
}}

Post/Delete
Deletes the specified microblog post. If the post is the root post, the whole thread is deleted.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.feed/post/delete
Request parameter
ID
Type: String
The ID of the post to delete, as shown in the following example.

'ID':'1.94fdcc5fc39b4a2c99ae4570caf02321.d0a03fb1761a404a9a8e7f9f5ec58e17.5a1067e8af65410b9e2ba6a74a4b718a.0c37852b34d0418e91c62ac25af4be5b.9dbfb5598e2248d7b57eee57abf2e7c1.31.31.S-1-5-21-1245250

Response
None.

{"d":{"Delete":null}}

Post/Like
Makes the current user a liker of the specified microblog post.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.feed/post/like

Request parameter
ID
Type: String
The ID of the post to like, as shown in the following example.

'ID':'1.94fdcc5fc39b4a2c99ae4570caf02321.d0a03fb1761a404a9a8e7f9f5ec58e17.5a1067e8af65410b9e2ba6a74a4b718a.0c37852b34d0418e91c62ac25af4be5b.9dbfb5598e2248d7b57eee57abf2e7c1.31.31.S-1-5-21-1245250

Response
Type: SP.Social.SocialRestThread
A digest thread that contains the specified post.
The following response example represents the thread that contains the liked post.
{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c6
"uri":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c
"type":"SP.Social.SocialRestThread"
},
"ID":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-21275
"SocialThread":{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"Posted with REST.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}]
},
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-212
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4
"PostReference":null,
"Replies":{
"results":[{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T20:52:51.0650454Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.ce3ac812293c4903b5c406efe01b9432.26.29.S-1-5-21
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-17T20:52:51.0650454Z",
"Overlays":{"results":[]},
"PostType":1,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Replied with REST."
}]
},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T19:33:17Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-2
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":true,
"Indexes":{"results":[]},
"TotalCount":1
},
"ModifiedTime":"2013-04-17T20:52:51Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Posted with REST."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":1
}
}}

Post/Unlike
Removes the current user from the list of likers for the specified microblog post. If the current user is not a liker of the post, this request is ignored.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.feed/post/unlike

Request parameter
ID
Type: String
The ID of the post to stop liking, as shown in the following example.

'ID':'1.94fdcc5fc39b4a2c99ae4570caf02321.d0a03fb1761a404a9a8e7f9f5ec58e17.5a1067e8af65410b9e2ba6a74a4b718a.0c37852b34d0418e91c62ac25af4be5b.9dbfb5598e2248d7b57eee57abf2e7c1.31.31.S-1-5-21-1245250

Response
Type: SP.Social.SocialRestThread
A digest of the modified thread that includes the specified post.
The following response example represents the thread that contains the post that the user stopped liking.
{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c6
"uri":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c
"type":"SP.Social.SocialRestThread"
},
"ID":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-21275
"SocialThread":{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"Posted with REST.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}]
},
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-212
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4
"PostReference":null,
"Replies":{
"results":[{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T20:52:51.0650454Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.ce3ac812293c4903b5c406efe01b9432.26.29.S-1-5-21
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-17T20:52:51.0650454Z",
"Overlays":{"results":[]},
"PostType":1,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Replied with REST."
}]
},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T19:33:17Z","Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-17T20:52:51Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Posted with REST."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":1
}
}}

Post/Likers
Gets the users who like the specified microblog post.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.feed/post/likers

Request parameter
ID
Type: String
The ID of the post to get the likers for, as shown in the following example.

'ID':'1.94fdcc5fc39b4a2c99ae4570caf02321.d0a03fb1761a404a9a8e7f9f5ec58e17.5a1067e8af65410b9e2ba6a74a4b718a.0c37852b34d0418e91c62ac25af4be5b.9dbfb5598e2248d7b57eee57abf2e7c1.31.31.S-1-5-21-1245250

Response
Likers
Type: SP.Social.SocialActor[]
The users who like the specified post.
The following response example represents the users that like the specified post.

{"d":{
"Likers":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName/my/personal/username1/",
"Status":0,
"StatusText":"Posted with REST.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}]
}
}}

Post/Lock
Locks the specified thread. If a thread is locked, no reply posts can be added to the thread until it is unlocked.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.feed/post/lock

Request parameter
ID
Type: String
The ID of the thread to lock, as shown in the following example.

'ID':'1.94fdcc5fc39b4a2c99ae4570caf02321.d0a03fb1761a404a9a8e7f9f5ec58e17.5a1067e8af65410b9e2ba6a74a4b718a.0c37852b34d0418e91c62ac25af4be5b.9dbfb5598e2248d7b57eee57abf2e7c1.31.31.S-1-5-21-1245250

Response
Type: SP.Social.SocialRestThread
A digest of the locked thread.
The following response example represents a locked thread. The Attributes property of the thread contains a bitwise value from the SP.Social.SocialThreadAttributes enumeration, which
indicates whether the thread is locked.
{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c6
uri":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c6
"type":"SP.Social.SocialRestThread"
},
"ID":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-21275
"SocialThread":{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"Posted with REST.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}]
},
"Attributes":12,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-21275
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be
"PostReference":null,
"Replies":{
"results":[{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":22,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T20:52:51.0650454Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.ce3ac812293c4903b5c406efe01b9432.26.29.S-1-5-21-2
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-17T20:52:51.0650454Z",
"Overlays":{"results":[]},
"PostType":1,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Replied with REST."
}]
},
"RootPost":{
"__metadata":{
"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":22,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T19:33:17Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-2
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-17T20:52:51Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Posted with REST."
},
"Status":0,
"ThreadType":0,
"TotalReplyCount":1
}
}}

Post/Unlock
Unlocks the specified thread.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.feed/post/unlock
Request parameter
ID
Type: String
The ID of the thread to unlock, as shown in the following example.

'ID':'1.94fdcc5fc39b4a2c99ae4570caf02321.d0a03fb1761a404a9a8e7f9f5ec58e17.5a1067e8af65410b9e2ba6a74a4b718a.0c37852b34d0418e91c62ac25af4be5b.9dbfb5598e2248d7b57eee57abf2e7c1.31.31.S-1-5-21-1245250

Response
Type: SP.Social.SocialRestThread
A digest of the unlocked thread.
The following response example represents the unlocked thread. The Attributes property of the thread contains a bitwise value from the SP.Social.SocialThreadAttributes enumeration,
which indicates whether the thread is locked.
{"d":{
"__metadata":{
"id":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c6
"uri":"http://serverName/sites/dev/_api/social.feed/post(ID=@ai)/?@ai='1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c
"type":"SP.Social.SocialRestThread"
},
"ID":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-21275
"SocialThread":{
"__metadata":{"type":"SP.Social.SocialThread"},
"Actors":{
"results":[{
"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\username1",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":null,
"FollowedContentUri":null,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":false,
"LibraryUri":null,
"Name":"User1 Name",
"PersonalSiteUri":"http://serverName:80/my/personal/username1/",
"Status":0,
"StatusText":"Posted with REST.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"http://serverName:80/my/Person.aspx?accountname=domain%5Cusername1"
}
]},
"Attributes":6,
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-212
"OwnerIndex":0,
"Permalink":"http://serverName:80/my/ThreadView.aspx?ThreadID=1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4
"PostReference":null,
"Replies":{
"results":[{
"__metadata":{"type":"SP.Social.SocialPost"},
"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T20:52:51.0650454Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.ce3ac812293c4903b5c406efe01b9432.26.29.S-1-5-21
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-17T20:52:51.0650454Z",
"Overlays":{"results":[]},
"PostType":1,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Replied with REST."
}]
},
"RootPost":{
"__metadata":{"type":"SP.Social.SocialPost"},

"Attachment":null,
"Attributes":23,
"AuthorIndex":0,
"CreatedTime":"2013-04-17T19:33:17Z",
"Id":"1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21-2
"LikerInfo":{
"__metadata":{"type":"SP.Social.SocialPostActorInfo"},
"IncludesCurrentUser":false,
"Indexes":{"results":[]},
"TotalCount":0
},
"ModifiedTime":"2013-04-17T20:52:51Z",
"Overlays":{"results":[]},
"PostType":0,
"PreferredImageUri":null,
"Source":{
"__metadata":{"type":"SP.Social.SocialLink"},
"Text":null,
"Uri":null
},
"Text":"Posted with REST."
},
"Status":5,
"ThreadType":0,
"TotalReplyCount":1
}
}}

Example REST requests for feed tasks


GET requests for feed tasks specify parameters in the URI or in the url attribute of the request. POST requests specify parameters in the data attribute of the request body in XML or
JavaScript Object Notation (JSON) format. You can make HTTP requests in any language, including JavaScript and C#. The following example requests show how to make requests by using
JavaScript and how to pass entity information in JSON format.
Example: How to specify the ID parameter in the request body (in the data attribute).
NOTE

The values of thread and post Id properties are too long to send in a URL, so you have to send them in the request body. As a result, even read-only operations that are logically GET
requests must be sent as POST requests. For example, to get a thread, you have to send a POST request and pass the thread Id as an entity in the request body.

var endpoint = siteUrl + '/_api/social.feed/post';


var postId = '1.655c70c348374d48839daabc24a360f0.82baa3bdfa2f481a8185802eb9c6c6cd.5d227a6fa3894f0c9dde26876b71d619.0c37852b34d0418e91c62ac25af4be5b.4316bdaa94bf4984be5dfea1ba96954e.26.26.S-1-5-21

$.ajax({
url: endpoint,
type: 'POST',
data: JSON.stringify({
'ID': postId
}),
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: function(data) {
var stringData = JSON.stringify(data);
alert(stringData);

// Converts the response data into an object that you can work with.
var jsonObject = JSON.parse(stringData);
},
error: function(xhr, ajaxOptions, thrownError) {
alert("Error: " + xhr.status + " " + thrownError + "\\nResponseText: " + xhr.responseText);
}
});

Example: How to publish a root post and specify the restCreationData parameter in the data attribute.

var endpoint = <site url> + '/_api/social.feed/my/feed/post';


var postContent = 'Posted with REST.';

$.ajax({
url: endpoint,
type: 'POST',
data: JSON.stringify({
'restCreationData': {
'__metadata': {
'type': 'SP.Social.SocialRestPostCreationData'
},
'ID': null,
'creationData': {
'__metadata': {
'type': 'SP.Social.SocialPostCreationData'
},
'ContentText': postContent
}
}
}),
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: function(data) {
var stringData = JSON.stringify(data);
alert(stringData);

// Converts the response data into an object that you can work with.
var jsonObject = JSON.parse(stringData);
},
error: function(xhr, ajaxOptions, thrownError) {
alert("Error: " + xhr.status + " " + thrownError + "\\nResponseText: " + xhr.responseText);
}
});

To publish a reply to a specified thread, send a POST request to the Reply resource ( <site url>/_api/social.feed/Post/Reply ) and pass restCreationData information that includes the
target post ID.

{ 'restCreationData': {
'__metadata': { 'type': 'SP.Social.SocialRestPostCreationData' },
'ID':'1.4975bef1e1bc42608c1dfae9f320c751.35c9fd7b79904800aaa5f74684bf0f75.623664921f034e8d814c000267d3e5e4.0c37852b34d0418e91c62ac25af4be5b.230d3c5272fc499f88ac0b74b2f4512f.119.119.S-1-5-21-1
'creationData':{
'__metadata':{ 'type':'SP.Social.SocialPostCreationData' },
'ContentText':'This is a reply to the specified post.',
'UpdateStatusText':false
}
} }

Resources used in feed-related REST requests and responses


The following REST resources are used as parameters in client-side requests or are returned in server responses.

SP.Social.SocialFeedOptions
Represents options that you can specify when retrieving a feed.
Client-side GET requests for feeds can optionally specify SocialFeedOptions properties as parameters. These properties are specified in the query string.
O PTIO N T YPE D ES CR IPTIO N

MaxThreadCount Int32 The maximum number of threads to retrieve. The default number is
20.

NewerThan String The "newer than" boundary of the time span to retrieve, as a string
representation of a DateTime object. The default is no specified
boundary.

OlderThan String The "older than" boundary of the time span to retrieve, as a string
representation of a DateTime object. The default is no specified
boundary.

SortOrder Int32 The sort order of the threads in the feed. The default sort order is
by modified date, except for the timeline feed, which is sorted by
created date.
0 sorts threads by modified time, according to the most recent
modification times of their posts.
1 sorts threads by created time, according to the creation times of
their root posts.

SP.Social.SocialRestActor
Represents a user, document, site, or tag.
The server returns a SocialRestActor resource in the response to a client-side request for actor information.
SocialRestActor has the following properties.

PR O PER T Y T YPE D ES CR IPTIO N

FollowableItem String The unique identifier of the specified actor. Returns the account
name for a user or the URI for a document, site, or tag.

FollowableItemActor SP.Social.SocialActor The specified user. Returns null if the user is the current user or if
the resource is not a user-type actor.

Me SP.Social.SocialActor The current user.

SP.Social.SocialRestFeed
Represents a social feed.
The server returns a SocialRestFeed resource in the response to a client-side request for feed content.
SocialRestFeed contains a wrapped SP.Social.SocialFeed object, which has the following properties.

PR O PER T Y T YPE D ES CR IPTIO N

Attributes SP.Social.SocialFeedAttributes A bitwise set of attributes that apply to the feed.

NewestProcessed DateTime The date and time of the newest retrieved post.

OldestProcessed DateTime The date and time of the oldest retrieved post.

Threads SP.Social.SocialThread[] The threads that make up the feed.

UnreadMentionCount Int32 The count of unread mentions for the current user.

SP.Social.SocialRestPostCreationData
Represents content and related information for a new post.
Clients specify SocialRestPostCreationData properties as parameters in a request to publish a root post or a reply. These properties are specified in the data attribute of the request body.
SocialRestPostCreationData contains an ID property and a wrapped SP.Social.SocialPostCreationData object. ID is required but the SocialPostCreationData properties are optional.

PR O PER T Y T YPE D ES CR IPTIO N

ID (required) null or String The target destination for the post. The value can be one of the
following:
null to publish a root post to the current user's feed
The ID of a post to reply to
The URL of a site feed to post to (for example:
http://<teamSiteURL>/newsfeed.aspx )

The following properties belong to the SocialPostCreationData object.

PR O PER T Y T YPE D ES CR IPTIO N

Attachment SP.Social.SocialAttachment An image, video, or document attachment for the post.

ContentItems SP.Social.SocialDataItem[] The items to replace the corresponding tokens in the post's content
text

ContentText String The plain text of the post, which can include positional insertion
tokens (for example, "Today is {0}'s birthday!").
PR O PER T Y T YPE D ES CR IPTIO N

SecurityUris String[] String representations of the URIs to SharePoint objects that define
access permissions for the post.

Source SP.Social.SocialLink The source of the post.

UpdateStatusText Boolean A value that controls whether the post's plain-text content should
replace the current user's status text.

SP.Social.SocialRestThread
Represents a thread that contains a root post and a set of replies.
The server returns a SocialRestThread resource in the response to a client-side request to create a post or to get a full thread.
SocialRestThread contains an ID property and a wrapped SP.Social.SocialThread object.

PR O PER T Y T YPE D ES CR IPTIO N

ID String The unique identifier of the thread.

The following properties belong to the SocialThread object.

PR O PER T Y T YPE D ES CR IPTIO N

Actors SP.Social.SocialActor[] The merged array of participating actors.

Attributes Int32 The bitwise value that represents the set of attributes for the thread.
See SP.Social.SocialThreadAttributes.

Id String The unique identifier of the thread.

OwnerIndex Int32 The index of the thread's owner within the thread's actors.

Permalink String The string representation of the stable URI for navigating directly to
the thread, if one is available.

PostReference SP.Social.SocialPostReference The referenced post.

Replies SP.Social.SocialPost[] The replies to the thread.

RootPost SP.Social.SocialPost The root post of the thread.

Status Int32 The code that identifies recoverable errors that occurred during
thread retrieval. See SP.Social.SocialStatusCode.

ThreadType SP.Social.SocialThreadType The thread type.

TotalReplyCount Int32 The count of the total number of replies for the thread.

See also
Get started developing with social features in SharePoint
How to: Learn to read and write to the social feed by using the REST service in SharePoint
Work with social feeds in SharePoint
Following people and content REST API reference for SharePoint
To see the members in the SP.Social OData schema used by the SharePoint REST service, browse to http://<siteUri>/_api/$metadata .
Following people and content REST API reference for SharePoint
3/26/2018 • 10 minutes to read Edit Online

Find SharePoint REST endpoints for following people and content by using the SocialRestFollowingManager resource and the PeopleManager resource. You can use the SharePoint
Representational State Transfer (REST) service to do the same tasks you can do when you use the .NET client object models and the JavaScript object model. To use the REST service, you
build and send HTTP GET and POST requests to the resource endpoints that represent the tasks you want to do. These resource endpoints correspond to SharePoint objects, properties, and
methods.
The endpoint URI for most Following tasks begins with the SocialRestFollowingManager resource ( social.following ) and ends with the resource that performs the specific task. For
example, you use the URI http://www.contoso.com/_api/social.following/follow to make the current user start following people or content, and the URI
https://www.contoso.com/sites/devSite/_api/social.following/followed to get the people or content the current user is following.

NOTE

This article shows the endpoint URI and parameter components of HTTP requests. For examples of complete requests, see How to: Follow documents, sites, and tags by using the REST
service in SharePoint.
We recommend that you use the SocialRestFollowingManager API for Following People and Following Content tasks, but you can use the PeopleManager resource for some Following
People tasks that SocialRestFollowingManager doesn't support. For example, you can find out whether someone is following the current user or get another user's followers. For these
tasks, you send HTTP GET requests to endpoint URIs that begin with the PeopleManager resource ( sp.userprofiles.peoplemanager ) and end with the resource that performs the specific
task.If the endpoint takes a parameter, the parameter metadata is sent in the URI or in the request body in XML or JavaScript Object Notation (JSON) format. You can make HTTP requests
in any language, including JavaScript and C#. By default, the REST service returns responses that are formatted by using the Atom protocol, but you can request the JSON format by using
HTTP Accept headers. See Use OData query operations in SharePoint REST requests.

Resource endpoints for Following People and Following Content tasks


Follow
StopFollowing
IsFollowed
My
My/FollowedDocumentsUri
My/FollowedSitesUri
My/Followed
My/FollowedCount
My/Followers
My/Suggestions
GetMySuggestions
IsMyPeopleListPublic
AmIFollowedBy
GetPeopleFollowedBy
GetFollowersFor

Follow
Makes the current user start following a user, document, site, or tag.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.following/follow

Request parameter
actor
Type: SP.Social.SocialActorInfo
The actor to start following.
User actor in the URI

http://<siteCollection>/<site>/_api/social.following/follow(ActorType=0,AccountName=@v,Id=null)?@v='domain\\user'

User actor in the request body

"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":0,
"AccountName":"domain\\user",
"Id":null
}

If you're using a claims-based identity model, you can pass the account name by using the format @v='i:0"%23".f|membership|user@domain.com' in the query string or
"i:0#.f|membership|user@domain.com" in the request body.

Document actor in the URI

http://<siteCollection>/<site>/_api/social.following/follow(ActorType=1,ContentUri=@v,Id=null)?@v='http://server/Shared%20Documents/fileName.docx'

Document actor in the request body


"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":1,
"ContentUri":"http://server/Shared%20Documents/fileName.docx",
"Id":null
}

Site actor in the URI

http://<siteCollection>/<site>/_api/social.following/follow(ActorType=2,ContentUri=@v,Id=null)?@v='http://server/site'

Site actor in the request body

"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":2,
"ContentUri":"http://siteCollection/site",
"Id":null
}

Tag actor in the URI

http://<siteCollection>/<site>/_api/social.following/follow(ActorType=3,TagGuid='19a4a484-c1dc-4bc5-8c93-bb96245ce928',Id=null)

Tag actor in the request body

"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":3,
"TagGuid":"19a4a484-c1dc-4bc5-8c93-bb96245ce928",
"Id":null
}

You need the tag GUID to start following a tag. You can't get the GUID by using the REST service, but you can use the .NET client object model or the JavaScript object model. See How to
get a tag's GUID based on the tag's name by using the JavaScript object model.

Response
Follow
Type: SP.Social.SocialFollowResult
The status of the request: 0 = OK; 1 = AlreadyFollowing; 2 = LimitReached; or 3 = InternalError.
The following response indicates that the request succeeded.

{"d":{"Follow":0}}

StopFollowing
Makes the current user stop following a user, document, site, or tag.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.following/stopfollowing

Request parameter
actor
Type: SP.Social.SocialActorInfo
The actor to stop following.
User actor in the URI

http://<siteCollection>/<site>/_api/social.following/stopfollowing(ActorType=0,AccountName=@v,Id=null)?@v='domain\\user'

User actor in the request body

"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":0,
"AccountName":"domain\\user",
"Id":null
}

If you're using a claims-based identity model, you can pass the account name by using the format @v='i:0"%23".f|membership|user@domain.com' in the query string or
"i:0#.f|membership|user@domain.com" in the request body.

Document actor in the URI

http://<siteCollection>/<site>/_api/social.following/stopfollowing(ActorType=1,ContentUri=@v,Id=null)?@v='http://server/Shared%20Documents/fileName.docx'
Document actor in the request body

"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":1,
"ContentUri":"http://server/Shared%20Documents/fileName.docx",
"Id":null
}

Site actor in the URI

http://<siteCollection>/<site>/_api/social.following/stopfollowing(ActorType=2,ContentUri=@v,Id=null)?@v='http://server/site'

Site actor in the request body

"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":2,
"ContentUri":"http://siteCollection/site",
"Id":null
}

Tag actor in the URI

http://<siteCollection>/<site>/_api/social.following/stopfollowing(ActorType=3,TagGuid='19a4a484-c1dc-4bc5-8c93-bb96245ce928',Id=null)

Tag actor in the request body

"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":3,
"TagGuid":"19a4a484-c1dc-4bc5-8c93-bb96245ce928",
"Id":null
}

You need the tag GUID to start following a tag. You can't get the GUID by using the REST service, but you can use the .NET client object model or the JavaScript object model. See How to
get a tag's GUID based on the tag's name by using the JavaScript object model.

Response
None.

{"d":{"StopFollowing":null}}

IsFollowed
Indicates whether the current user is following a specified user, document, site, or tag.

Endpoint URI structure


POST http://<siteCollection>/<site>/_api/social.following/isfollowed

Request parameter
actor
Type: SP.Social.SocialActorInfo
The actor to find the following status for.
User actor in the URI

http://<siteCollection>/<site>/_api/social.following/isfollowed(ActorType=0,AccountName=@v,Id=null)?@v='domain\\user'

User actor in the request body

"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":0,
"AccountName":"domain\\user",
"Id":null
}

If you're using a claims-based identity model, you can pass the account name by using the format @v='i:0"%23".f|membership|user@domain.com' in the query string or
"i:0#.f|membership|user@domain.com" in the request body.

Document actor in the URI

http://<siteCollection>/<site>/_api/social.following/isfollowed(ActorType=1,ContentUri=@v,Id=null)?@v='https://domain.sharepoint.com/Shared%20Documents/fileName.docx'

Document actor in the request body


"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":1,
"ContentUri":"http://server/Shared%20Documents/fileName.docx",
"Id":null
}

Site actor in the URI

http://<siteCollection>/<site>/_api/social.following/isfollowed(ActorType=2,ContentUri=@v,Id=null)?@v='http://domain.sharepoint.com'

Site actor in the request body

"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":2,
"ContentUri":"http://siteCollection/site",
"Id":null
}

Tag actor in the URI

http://<siteCollection>/<site>/_api/social.following/isfollowed(ActorType=3,TagGuid='19a4a484-c1dc-4bc5-8c93-bb96245ce928',Id=null)

Tag actor in the request body

"actor":{
"__metadata":{"type":"SP.Social.SocialActorInfo"},
"ActorType":3,
"TagGuid":"19a4a484-c1dc-4bc5-8c93-bb96245ce928",
"Id":null
}

You need the tag GUID to start following a tag. You can't get the GUID by using the REST service, but you can use the .NET client object model or the JavaScript object model. See How to
get a tag's GUID based on the tag's name by using the JavaScript object model.

Response
IsFollowed
Type: bool
true if the current user is following the actor; otherwise false.
The following response indicates that the user is not following the specified actor.

{"d":{"IsFollowed":false}}

My
Gets information about the SocialRestFollowingManager instance and information about the current user.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.following/my

Request parameter
None.

Response
Type: SP.Social.SocialRestFollowingManager
Information about the SocialRestFollowingManager instance, and the MyFollowedDocumentsUri, MyFollowedSitesUri, and SocialActor properties for the current user.
The following response represents the SocialRestFollowingManager instance for the current user.
{"d":{
"__metadata":{
"id":"https://somecompany-a2ef5dfc05b1da.sharepoint.com/appInstance/_api/social.following/my/following",
"uri":"https://somecompany-a2ef5dfc05b1da.sharepoint.com/appInstance/_api/social.following/my/following",
"type":"SP.Social.SocialRestFollowingManager"
},
"MyFollowedDocumentsUri":"https://somecompany-my.sharepoint.com/personal/someone_somecompany_onmicrosoft_com/Social/FollowedContent.aspx",
"MyFollowedSitesUri":"https://somecompany-my.sharepoint.com/personal/someone_somecompany_onmicrosoft_com/Social/Sites.aspx",
"SocialActor":
{"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"i:0#.f|membership|someone@somecompany.onmicrosoft.com",
"ActorType":0,
"CanFollow":false,
"ContentUri":null,
"EmailAddress":"someone@somecompany.onmicrosoft.com",
"FollowedContentUri":null,
"Id":"1.0f435d74164149cfa76e19ad21dc7c2e.8a7874906a9348189f2fb83295b598d5.06ff4087162c48dcb43828e4ddf82c38.98b9fc73d5224265b039586688b15b98",
"ImageUri":"https://somecompany-my.sharepoint.com/User%20Photos/Profile%20Pictures/someone_somecompany_onmicrosoft_com_MThumb.jpg",
"IsFollowed":false,
"LibraryUri":null,
"Name":"User Name",
"PersonalSiteUri":"https://somecompany-my.sharepoint.com/personal/someone_somecompany_onmicrosoft_com/",
"Status":0,
"StatusText":"I like rabbits.",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":null,
"Uri":"https://somecompany-my.sharepoint.com:443/Person.aspx?accountname=i%3A0%23%2Ef%7Cmembership%7Csomeone%40somecompany%2Eonmicrosoft%2Ecom"
}
}}

My/FollowedDocumentsUri
Gets the URI to the Docs I'm following page for the current user.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.following/my/followeddocumentsuri

Request parameter
None.

Response
FollowedDocumentsUri
Type: String
The URI to the Docs I'm following page for the current user.
The following response represents the FollowedDocumentsUri for the current user.

{"d":{"FollowedDocumentsUri":"https://somecompany-my.sharepoint.com/personal/someone_somecompany_onmicrosoft_com/Social/FollowedContent.aspx"}}

My/FollowedSitesUri
Gets the URI to the Sites I'm following page for the current user.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.following/my/followedsitesuri

Request parameter
None.

Response
FollowedSitesUri
Type: String
The URI to the Sites I'm following page for the current user.
The following response represents the FollowedSitesUri for the current user.

{"d":{"FollowedSitesUri":"https://somecompany-my.sharepoint.com/personal/someone_somecompany_onmicrosoft_com/Social/Sites.aspx"}}

My/Followed
Gets users, documents, sites, and tags that the current user is following.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.following/my/followed(types=15)

Request parameter
types
Type: Int32
The actor types to include. Users = 1, Documents = 2, Sites = 4, Tags = 8. Bitwise combinations are allowed.
Response
Followed
Type: Array of SP.Social.SocialActor
The users, documents, sites, and tags that the current user is following.
The following response represents a document, a site, and a tag. The types parameter in the request specifies the types of actors to include.

{"d":{"Followed":{"results":[
{"__metadata":{"type":"SP.Social.SocialActor"}
"AccountName":null
"ActorType":1
"CanFollow":true
"ContentUri":"https://domain.sharepoint.com:443/Shared%20Documents/fileName.docx"
"EmailAddress":null
"FollowedContentUri":null
"Id":"2.089f4944a6374a64b52b7af5ba140392.9340a4837688405daa6b83f2b58f973d.51bbb5d8e214457ba794669345d23040.98b9fc73d5224265b039586688b15b98"
"ImageUri":null
"IsFollowed":true
"LibraryUri":null
"Name":"snippets.txt"
"PersonalSiteUri":null
"Status":0
"StatusText":null
"TagGuid":"00000000-0000-0000-0000-000000000000"
"Title":null
"Uri":"https://domain.sharepoint.com:443/Shared%20Documents/fileName.docx"}
{"__metadata":{"type":"SP.Social.SocialActor"}
"AccountName":null
"ActorType":2
"CanFollow":true
"ContentUri":"https://domain.sharepoint.com:443/"
"EmailAddress":null
"FollowedContentUri":null
"Id":"8.089f4944a6374a64b52b7af5ba140392.9340a4837688405daa6b83f2b58f973d.089f4944a6374a64b52b7af5ba140392.98b9fc73d5224265b039586688b15b98"
"ImageUri":null
"IsFollowed":true
"LibraryUri":null
"Name":"Developer Site"
"PersonalSiteUri":null
"Status":0
"StatusText":null
"TagGuid":"00000000-0000-0000-0000-000000000000"
"Title":null
"Uri":"https://domain.sharepoint.com:443/"}
{"__metadata":{"type":"SP.Social.SocialActor"}
"AccountName":null
"ActorType":3
"CanFollow":true
"ContentUri":null
"EmailAddress":null
"FollowedContentUri":null
"Id":"16.00000000000000000000000000000000.00000000000000000000000000000000.19a4a484c1dc4bc58c93bb96245ce928.98b9fc73d5224265b039586688b15b98"
"ImageUri":null
"IsFollowed":true
"LibraryUri":null
"Name":"#someTag"
"PersonalSiteUri":null
"Status":0
"StatusText":null
"TagGuid":"19a4a484-c1dc-4bc5-8c93-bb96245ce928"
"Title":null
"Uri":"https://somecompany-my.sharepoint.com:443/_layouts/15/HashTagProfile.aspx?
TermID=19a4a484-c1dc-4bc5-8c93-bb96245ce928"}
]}}}

My/FollowedCount
Gets the count of users, documents, sites, and tags that the current user is following.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.following/my/followedcount(types=15)

Request parameter
types
Type: Int32
The types of actors to include. Users = 1, Documents = 2, Sites = 4, Tags = 8. Bitwise combinations are allowed.

Response
FollowedCount
Type: Int32
The count of users, documents, sites, and tags that the current user is following.
The following response indicates that the current user is following 3 actors of the specified type. The types parameter in the request specifies the types of actors to include.

{"d":{"FollowedCount":3}}

My/Followers
Gets the users who are following the current user.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.following/my/followers

Request parameter
None.

Response
Followers
Type: Array of SP.Social.SocialActor
The following response represents one user who is following the current user.

{"d":{"Followers":{"results":[
{"__metadata":{"type":"SP.Social.SocialActor"},
"AccountName":"domain\\user",
"ActorType":0,
"CanFollow":true,
"ContentUri":null,
"EmailAddress":"user@domain.com",
"FollowedContentUri":null,
"Id":"1.60a6bd2d1537446880bb4a5a5b07fd63.3a6c6893e6b549cebffefcfa97412dcf.00093edb336e47ac8791bab0a0b77c5d.0c37852b34d0418e91c62ac25af4be5b",
"ImageUri":null,
"IsFollowed":true,
"LibraryUri":null,
"Name":"User Name",
"PersonalSiteUri":"http://server/my/personal/user/",
"Status":0,
"StatusText":"",
"TagGuid":"00000000-0000-0000-0000-000000000000",
"Title":"SALES DIRECTOR",
"Uri":"http://server:80/my/Person.aspx?accountname=domain%5Cuser"}
]}}}

My/Suggestions
Gets users who the current user might want to follow.
NOTE

People Suggestions functionality depends on users' following activities, search crawls, and search analytics. See How People Suggestions works on SharePoint Online.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/social.following/my/suggestions

Request parameter
None.

Response
Suggestions
Type: Array of SP.Social.SocialActor
Users who the current user might want to follow.

GetMySuggestions
Gets users who the current user might want to follow.
NOTE

People Suggestions functionality depends on users' following activities, search crawls, and search analytics. See How People Suggestions works on SharePoint Online.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/sp.userprofiles.peoplemanager/getmysuggestions

Request parameter
None.

Response
Suggestions
Type: List of SP.UserProfiles.PersonProperties
Users who the current user might want to follow.

IsMyPeopleListPublic
Finds out whether the People I'm Following list for the current user is public.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/sp.userprofiles.peoplemanager/ismypeoplelistpublic

Request parameter
None.
Response
IsMyPeopleListPublic
Type: bool
true if the current user's people list is public; otherwise false.
The following response indicates that the current user's people list is public.

{"d":{"IsMyPeopleListPublic":true}}

AmIFollowedBy
Finds out whether a specified user is following the current user.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/sp.userprofiles.peoplemanager/amifollowedby(accountName=@v)?@v='domain\\user'

GET http://<siteCollection>/<site>/_api/sp.userprofiles.peoplemanager/amifollowedby(accountName=@v)?@v='i:0"%23".f|membership|user@domain.com'

Request parameter
accountName
Type: String
The account name of the target user.

Response
AmIFollowedBy
Type: bool
true if the specified user is following the current user; otherwise false.
The following response indicates that the specified user is not following the current user.

{"d":{"AmIFollowedBy":false}}

GetPeopleFollowedBy
Gets the users followed by a specified user.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/sp.userprofiles.peoplemanager/getpeoplefollowedby(accountName=@v)?@v='domain\\user'

GET http://<siteCollection>/<site>/_api/sp.userprofiles.peoplemanager/getpeoplefollowedby(accountName=@v)?@v='i:0"%23".f|membership|user@domain.com'

Request parameter
accountName
Type: String
The account name of the target user.

Response
GetPeopleFollowedBy
Type: List of SP.UserProfiles.PersonProperties
The users followed by the specified user.
The following response represents two users followed by the specified user.

{"d":{"results":[
{"__metadata":{
"id":"http://server/sites/dev/_api/SP.UserProfiles.PersonPropertiesa776ccd0-5566-47d2-9d59-3422cf1fb362",
"uri":"http://server/sites/dev/_api/SP.UserProfiles.PersonPropertiesa776ccd0-5566-47d2-9d59-3422cf1fb362",
"type":"SP.UserProfiles.PersonProperties"
},
"AccountName":"domain\\user1",
"DirectReports":{"results":[]},
"DisplayName":"User Name",
"Email":"user@domain.com",
"ExtendedManagers":{"results":[]},
"ExtendedReports":{"results":["domain\\user1"]},
"IsFollowed":true,
"LatestPost":null,
"Peers":{"results":[]},
"PersonalUrl":"http://server/my/personal/user1/",
"PictureUrl":null,
"Title":null,
"UserProfileProperties":{"results":[
{"__metadata":{"type":"SP.KeyValue"},"Key":"UserProfile_GUID","Value":"00093edb-336e-47ac-8791-bab0a0b77c5d","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SID","Value":"S-1-5-09-4830882673-197582990-1037597527-29477","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"ADGuid","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"AccountName","Value":"domain\\user1","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"FirstName","Value":"User","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PhoneticFirstName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"LastName","Value":"Name","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PhoneticLastName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PreferredName","Value":"User Name","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PreferredName","Value":"User Name","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PhoneticDisplayName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"WorkPhone","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Department","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Title","Value":"SALES DIRECTOR","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-JobTitle","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Department","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Manager","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"AboutMe","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PersonalSpace","Value":"/my/personal/user1/","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PictureURL","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"UserName","Value":"user1","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"QuickLinks","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"WebSite","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PublicSiteRedirect","Value":"http://cox64-096/my/personal/user1/","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Dotted-line","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Peers","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Responsibility","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SipAddress","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-MySiteUpgrade","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ProxyAddresses","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-HireDate","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-DisplayOrder","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ClaimID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ClaimProviderID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ClaimProviderType","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SavedAccountName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SavedSID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ResourceSID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ResourceAccountName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ObjectExists","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-MasterAccountName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-UserPrincipalName","Value":"user1@company.com","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PersonalSiteCapabilities","Value":"14","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-O15FirstRunExperience","Value":"15","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PersonalSiteInstantiationState","Value":"2","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-DistinguishedName","Value":"CN=user1 (User Name),OU=UserAccounts,DC=domain,DC=corp,DC=company,DC=com","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SourceObjectDN","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-FeedIdentifier","Value":"http://server/my/personal/user1;1.60a6bd2d1537446880bb4a5a5b07fd63.3a6c6893e6b549cebffefcfa97412dcf.50dcee8186ae4dd690
{"__metadata":{"type":"SP.KeyValue"},"Key":"WorkEmail","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"CellPhone","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Fax","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"HomePhone","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Office","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Location","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Assistant","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PastProjects","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Skills","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-School","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Birthday","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-StatusNotes","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Interests","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-HashTags","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-EmailOptin","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PrivacyPeople","Value":"True","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PrivacyActivity","Value":"4095","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-TimeZone","Value":"","ValueType":"Edm.String"}]
},
"UserUrl":"http://server:80/my/Person.aspx?accountname=domain%5Cuser1"},
{"__metadata":{
"id":"http://server/sites/dev/_api/SP.UserProfiles.PersonPropertiesf0ddf6e4-e69c-453f-9a7f-44e0e47d89d4",
"uri":"http://server/sites/dev/_api/SP.UserProfiles.PersonPropertiesf0ddf6e4-e69c-453f-9a7f-44e0e47d89d4",
"type":"SP.UserProfiles.PersonProperties"},
"AccountName":"domain\\user2",
"DirectReports":{"results":[]},
"DisplayName":"User Name",
"Email":"user2@company.com",
"ExtendedManagers":{"results":[]},
"ExtendedReports":{"results":["domain\\user2"]},
"IsFollowed":true,"LatestPost":null,
"Peers":{"results":[]},
"PersonalUrl":"http://server/my/Person.aspx?accountname=domain%5Cuser2",
"PictureUrl":null,
"Title":null,
"UserProfileProperties":{"results":[
{"__metadata":{"type":"SP.KeyValue"},"Key":"UserProfile_GUID","Value":"40deca2e-6231-43f9-9559-9a51b0135067","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SID","Value":" S-1-5-09-4830882673-197582990-1037597527-0688328","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"ADGuid","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"AccountName","Value":"domain\\user2","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"FirstName","Value":"User","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PhoneticFirstName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"LastName","Value":"Name","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PhoneticLastName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PreferredName","Value":"User2","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PhoneticDisplayName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"WorkPhone","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Department","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Title","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-JobTitle","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Department","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Manager","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"AboutMe","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PersonalSpace","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PictureURL","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"UserName","Value":"user2","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"QuickLinks","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"WebSite","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PublicSiteRedirect","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Dotted-line","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Peers","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Responsibility","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SipAddress","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-MySiteUpgrade","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ProxyAddresses","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-HireDate","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-DisplayOrder","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-DisplayOrder","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ClaimID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ClaimProviderID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ClaimProviderType","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SavedAccountName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SavedSID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ResourceSID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ResourceAccountName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ObjectExists","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-MasterAccountName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-UserPrincipalName","Value":"user2@company.com","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PersonalSiteCapabilities","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-O15FirstRunExperience","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PersonalSiteInstantiationState","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-DistinguishedName","Value":"CN=User2,OU=UserAccounts,DC=domain,DC=corp,DC=company,DC=com","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SourceObjectDN","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-FeedIdentifier","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"WorkEmail","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"CellPhone","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Fax","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"HomePhone","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Office","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Location","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Assistant","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PastProjects","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Skills","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-School","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Birthday","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-StatusNotes","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Interests","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-HashTags","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-EmailOptin","Value":"0","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PrivacyPeople","Value":"True","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PrivacyActivity","Value":"4095","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-TimeZone","Value":"","ValueType":"Edm.String"}]
},
"UserUrl":"http://server:80/my/Person.aspx?accountname=domain%5Cuser2"}
]}}

GetFollowersFor
Gets the users who are following a specified user.

Endpoint URI structure


GET http://<siteCollection>/<site>/_api/sp.userprofiles.peoplemanager/getfollowersfor(accountName=@v)?@v='domain\\user'

GET http://<siteCollection>/<site>/_api/sp.userprofiles.peoplemanager/getfollowersfor(accountName=@v)?@v='i:0"%23".f|membership|user@domain.com'

Request parameter
accountName
Type: String
The account name of the target user.

Response
GetFollowersFor
Type: List of SP.UserProfiles.PersonProperties
The users who are following the specified user.
The following response represents a user who is following the specified user.

{"d":{"results":[
{"__metadata":{
"id":"http://server/sites/dev/_api/SP.UserProfiles.PersonPropertiesabe0c40e-ce77-4631-9fc9-ec20b859061c",
"uri":"http://server/sites/dev/_api/SP.UserProfiles.PersonPropertiesabe0c40e-ce77-4631-9fc9-ec20b859061c",
"type":"SP.UserProfiles.PersonProperties"
},
"AccountName":"domain\\user",
"DirectReports":{"results":[]},
"DisplayName":"User Name",
"Email":"user@domain.com",
"ExtendedManagers":{"results":[]},
"ExtendedReports":{"results":["domain\\user"]},
"IsFollowed":false,
"LatestPost":"#tally",
"Peers":{"results":[]},
"PersonalUrl":"http://server/my/personal/user/",
"PictureUrl":null,
"Title":"MARKETING DIRECTOR",
"UserProfileProperties":{"results":[
{"__metadata":{"type":"SP.KeyValue"},"Key":"UserProfile_GUID","Value":"fa59ba73-edd4-4dc9-97d1-8ada702aae7f","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SID","Value":" S-1-5-09-4830882673-197582990-1037597527-002428","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"ADGuid","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"AccountName","Value":"domain\\user","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"FirstName","Value":"User","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PhoneticFirstName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"LastName","Value":"Name","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PhoneticLastName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PreferredName","Value":"User Name","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PhoneticDisplayName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"WorkPhone","Value":"+1 (208) 3192190 X2190","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Department","Value":"Marketing","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Title","Value":"MARKETING DIRECTOR","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-JobTitle","Value":"MARKETING DIRECTOR","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Department","Value":"Marketing","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Manager","Value":"DOMAIN\\randalli","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Manager","Value":"DOMAIN\\randalli","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"AboutMe","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PersonalSpace","Value":"/my/personal/user/","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PictureURL","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"UserName","Value":"user","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"QuickLinks","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"WebSite","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"PublicSiteRedirect","Value":"http://my/sites/user/","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-DataSource","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-MemberOf","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Dotted-line","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Peers","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Responsibility","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SipAddress","Value":"user@domain.com","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-MySiteUpgrade","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-DontSuggestList","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ProxyAddresses","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-HireDate","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-DisplayOrder","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ClaimID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ClaimProviderID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ClaimProviderType","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-LastColleagueAdded","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-OWAUrl","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SavedAccountName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SavedSID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ResourceSID","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ResourceAccountName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ObjectExists","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-MasterAccountName","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-UserPrincipalName","Value":"user@domain.com","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PersonalSiteCapabilities","Value":"14","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-O15FirstRunExperience","Value":"15","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PersonalSiteInstantiationState","Value":"2","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-DistinguishedName","Value":"CN=User Name,OU=UserAccounts,DC=domain,DC=corp,DC=company,DC=com","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-SourceObjectDN","Value":"CN=User Name,OU=UserAccounts,DC=domain,DC=corp,DC=company,DC=com","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-LastKeywordAdded","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-FeedIdentifier","Value":"http://server/my/personal/user;1.64769ec247734e699a5616f1701f7d94.ab42c829ec534daa99fc5909ef940213.3fb2a502be274948a66
{"__metadata":{"type":"SP.KeyValue"},"Key":"WorkEmail","Value":"user@domain.com","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"CellPhone","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Fax","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"HomePhone","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Office","Value":"2253","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Location","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"Assistant","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PastProjects","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Skills","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-School","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Birthday","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-StatusNotes","Value":"#tally","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Interests","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-HashTags","Value":"#tally","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-EmailOptin","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PrivacyPeople","Value":"True","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-PrivacyActivity","Value":"4095","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-MUILanguages","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ContentLanguages","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-TimeZone","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-RegionalSettings-FollowWeb","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Locale","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-CalendarType","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-AltCalendarType","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-AdjustHijriDays","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-ShowWeeks","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-WorkDays","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-WorkDayStartHour","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-WorkDayEndHour","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-Time24","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-FirstDayOfWeek","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-FirstWeekOfYear","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SPS-RegionalSettings-Initialized","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"EduUserRole","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"EduPersonalSiteState","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"EduOAuthTokenProviders","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"SISUserId","Value":"","ValueType":"Edm.String"},
{"__metadata":{"type":"SP.KeyValue"},"Key":"EduExternalSyncState","Value":"","ValueType":"Edm.String"}]
},
"UserUrl":"http://server:80/my/Person.aspx?accountname=domain%5Cuser"}
]}}

See also
How to: Follow documents, sites, and tags by using the REST service in SharePoint
Social feed REST API reference for SharePoint
SharePoint User Profiles JavaScript Reference (sp.userprofiles.js)
Get started developing with social features in SharePoint
Work with social feeds in SharePoint
3/26/2018 • 8 minutes to read Edit Online

Learn about common programming tasks for working with social feeds and microblog posts in SharePoint.

APIs for working with social feeds in SharePoint


In SharePoint on-premises farms, interactive social feeds are designed to encourage people to share information and to stay connected with people and content. You can see many of the
feed features on the Newsfeed page on a user's personal site. Feeds contain collections of threads that represent microblog posts, conversations, status updates, and other notifications.
SharePoint provides the following APIs that you can use to programmatically work with social feeds:
Client object models for managed code
.NET client object model
Silverlight client object model
Mobile client object model
JavaScript object model
Representational State Transfer (REST) service
Server object model
As a best practice in SharePoint development, use client APIs when you can. Client APIs include the client object models, the JavaScript object model, and the REST service. For more
information about the APIs in SharePoint and when to use them, see Choose the right API set in SharePoint.
Each API includes a manager object that you use to perform core feed-related tasks. Table 1 shows the manager and other key objects (or REST resources) in the APIs and the class library
(or endpoint URI) where you can find them.
NOTE

The Silverlight and mobile client object models are not explicitly mentioned in Table 1 or Table 2 because they provide the same core functionality as the .NET client object model and use the
same signatures. The Silverlight client object model is defined in Microsoft.SharePoint.Client.UserProfiles.Silverlight.dll, and the mobile client object model is defined in
Microsoft.SharePoint.Client.UserProfiles.Phone.dll.
Table 1. SharePoint APIs used for working with social feeds programmatically

API K EY O B JECTS

.NET client object model Manager object: SocialFeedManager


See: How to: Create and delete posts and retrieve the social feed by using the .NET client object model in Primary namespace: Microsoft.SharePoint.Client.Social
SharePoint Other key objects: SocialFeed , SocialThread , SocialPost , SocialPostCreationData , SocialFeedOptions ,
SocialActor
Class library: Microsoft.SharePoint.Client.UserProfiles.dll

JavaScript object model Manager object: SocialFeedManager


See How to: Create and delete posts and retrieve the social feed by using the JavaScript object model in Primary namespace: SP.Social
SharePoint Other key objects: SocialFeed, SocialThread, SocialPost, SocialPostCreationData, SocialFeedOptions,
SocialActor
Class library: SP.UserProfiles.js

REST service Manager resource: social.feed (SocialRestFeedManager)


See How to: Learn to read and write to the social feed by using the REST service in SharePoint Primary namespace (OData): SP.Social
Other key resources: SocialFeed, SocialRestFeed, SocialThread, SocialRestThread, SocialPost,
SocialPostCreationData, SocialRestPostCreationData, SocialFeedOptions, SocialActor, SociaRestActor
Access point: <siteUri>/_api/social.feed

Server object model Manager object: SPSocialFeedManager


Note: Code that uses the server object model to access feed data and runs remotely must use an Primary namespace: Microsoft.Office.Server.Social
SPServiceContextScope object. Other key objects: SPSocialFeed , SPSocialThread , SPSocialPost , SPSocialFeedOptions , SPSocialActor
Class library: Microsoft.Office.Server.UserProfiles.dll

If you're using the server object model to access feed content and your code isn't running in a SharePoint instance (in other words, if your extension is not installed in the L AYOUTS folder on
the application server), use an SPServiceContextScope object in your code. The following code example shows one way to incorporate the SPServiceContextScope object into your code.

using (SPSite site = new SPSite(<siteURL>))


{
using (new Microsoft.SharePoint.SPServiceContextScope(SPServiceContext.GetContext(site)))
{
// code
}
}

Common programming tasks for working with social feeds in SharePoint


Table 2 shows common programming tasks for working with social feeds and the members that you use to perform them. Members are from the .NET client object model (CSOM),
JavaScript object model (JSOM), REST service, and server object model (SSOM).
Table 2. API for common programming tasks for working with social feeds in SharePoint

TAS K MEMB ER S

Create an instance of the manager object in the context of the current user CSOM: SocialFeedManager
JSOM: SocialFeedManager
REST: GET <siteUri>/_api/social.feed
SSOM: SPSocialFeedManager
TAS K MEMB ER S

Create an instance of the manager object in the context of a particular user CSOM: not implemented
JSOM: not implemented
REST: not implemented
SSOM: SPSocialFeedManager

Get the user for the current context CSOM: Owner


JSOM: owner
REST: GET <siteUri>/_api/social.feed/my
SSOM: Owner

Get the feed for the current user CSOM: GetFeed


(specify the feed type) JSOM: getFeed
REST: GET <siteUri>/_api/social.feed/my/Feed (personal feed.md),
<siteUri>/_api/social.feed/my/News , <siteUri>/_api/social.feed/my/TimelineFeed , or
<siteUri>/_api/social.feed/my/Likes
SSOM: GetFeed

Get the personal feed for a particular user CSOM: GetFeedFor


JSOM: getFeedFor
REST: GET <siteUri>/_api/social.feed/actor(item='domain\\user')/Feed
SSOM: GetFeedFor

Get the site feed for a team site CSOM: GetFeedFor


(specify the URL of the site feed as the actor (example: http:////newsfeed.aspx)) JSOM: getFeedFor
REST: GET
<siteUri>/_api/social.feed/actor(item=@v)/Feed?
@v='http://<siteCollection>/<teamSite>/newsfeed.aspx'
SSOM: GetFeedFor

Publish a root post to the current user's feed CSOM: CreatePost


(specify null for the target) JSOM: createPost
REST: POST <siteUri>/_api/social.feed/my/Feed/Post and pass the restCreationData parameter in
the request body
SSOM: CreatePost

Publish a post to a site feed CSOM: CreatePost


(specify the URL of the site feed as the target (example: http:///teamSite>/newsfeed.aspx)) JSOM: createPost
REST: POST
<siteUri>/_api/social.feed/actor(item=@av)/feed/post/?@av='<teamSiteUri>/newsfeed.aspx'
and pass the restCreationData parameter in the request body (specify null for the ID parameter)
SSOM: CreatePost

Publish a reply to a post CSOM: CreatePost


(specify the ID of the target thread) JSOM: createPost
REST: POST <siteUri>/_api/social.feed/Post/Reply and pass the restCreationData parameter in
the request body
SSOM: CreatePost

Delete a post, reply, or thread in the current user's feed (deleting a root post deletes the whole thread) CSOM: DeletePost
JSOM: deletePost
REST: POST <siteUri>/_api/social.feed/Post/Delete and pass the ID parameter in the request
body
SSOM: DeletePost

Get a thread (a root post and all its replies) from the user's feed CSOM: GetFullThread
JSOM: getFullThread
REST: POST <siteUri>/_api/social.feed/Post and pass the ID parameter in the request body
SSOM: GetFullThread

Have the user like (unlike) a post or reply CSOM: LikePost ( UnlikePost )
JSOM: likePost ( unlikePost)
REST: POST <siteUri>/_api/social.feed/Post/Like ( <siteUri>/_api/social.feed/Post/Unlike
and pass the ID parameter in the request body
SSOM: LikePost ( UnlikePost )

Get all likers for a post CSOM: GetAllLikers


JSOM: getAllLikers
REST: POST <siteUri>/_api/social.feed/Post/Likers and pass the ID parameter in the request
body
SSOM: GetAllLikers

Get the posts that mention a user CSOM: GetMentions


JSOM: getMentions
REST: GET <siteUri>/_api/social.feed/my/MentionFeed
SSOM: GetMentions

Get the number of unread mentions for the current user CSOM: GetUnreadMentionCount
JSOM: getUnreadMentionCount
REST: GET <siteUri>/_api/social.feed/my/UnreadMentionCount
SSOM: GetUnreadMentionCount

Lock (unlock) a thread in the current user's feed CSOM: LockThread ( UnlockThread )
JSOM: lockThread ( unlockThread)
REST: POST <siteUri>/_api/social.feed/Post/Lock ( <siteUri>/_api/social.feed/Post/Unlock
and pass the ID parameter in the request body
SSOM: LockThread ( UnlockThread .md)
NOTE

The domain\user placeholder value in the REST example should be replaced with the account name of an actual user. To see how to pass a REST parameter in a request body, see the
examples in the Social feed REST API reference.
SharePoint does not provide an API to customize the layout or rendering of microblog posts directly. SharePoint only provides the data and allows cross-platform and cross-device client
applications to define layouts that are appropriate for their form factors and needs. In SharePoint development, you can use JavaScript overrides in client-side rendering, as described in
Customize a list view in SharePoint Add-ins using client-side rendering.

Overview of feed types in the My Site Social API


Feed types represent slices of feed data. When you retrieve a feed for the current user, you can specify one of the following feed types:
Personal contains the posts and updates that are generated from a user. On My Site, this feed is shown on a user's About me page.
News contains the posts and updates that are generated from the current user and from the people and the content that the user is following. When you retrieve the News feed type,
use the ByModifiedTime sort order option to get the most recent (cached) activities from the people who the user is following. On My Site, this feed is shown on a user's Newsfeed
page.
Timeline contains the posts and updates that are generated from the current user and from the people and the content that the user is following. Timeline is particularly useful when
you want feed data from a specific time range or when you want to sort with the ByCreatedTime option (which includes the largest sampling of people).
Likes contains reference threads with a PostReference property that represents a post that the current user has flagged with the Like attribute.
Everyone contains the threads from the current user's whole organization.
The server, client, and JavaScript object models provide the GetFeed method that you can use to retrieve any feed type for the current user and the GetFeedFor method that you can use to
retrieve the Personal feed type (only) for a specified user. Both methods take a SocialFeedOptions object as a parameter, which you use to specify the time-based sort order, date range,
and maximum number of threads to return.
NOTE

The REST service provides separate resources to retrieve each feed type, as shown in Table 2.
If a thread contains more than two replies, the server returns a digest of the thread that contains only the two most recent replies. (Thread digests have the IsDigest thread attribute applied.)
If you want to get all the replies in a thread, call the GetFullThread method from the feed manager object and pass in the thread identifier.

See also
Conceptual and how-to articles
Social and collaboration features in SharePoint
Get started developing with social features in SharePoint
How to: Create and delete posts and retrieve the social feed by using the .NET client object model in SharePoint
How to: Create and delete posts and retrieve the social feed by using the JavaScript object model in SharePoint
How to: Learn to read and write to the social feed by using the REST service in SharePoint
How to: Include mentions, tags, and links to sites and documents in posts in SharePoint
How to: Embed images, videos, and documents in posts in SharePoint
Reference threads and digest threads in SharePoint social feeds
API reference documentation
Microsoft.SharePoint.Client.Social (client object model)
SP.Social namespace (JavaScript object model)
Social feed REST API reference for SharePoint
Microsoft.Office.Server.Social (server object model)
Create and delete posts and retrieve the social feed by using the .NET client object model in
SharePoint
3/26/2018 • 10 minutes to read Edit Online

Learn how to create and delete microblog posts and retrieve social feeds by using the SharePoint .NET client object model.

What are social feeds in SharePoint?


In SharePoint, a social feed is a collection of threads that represent conversations, single microblog posts, or notifications. Threads contain a root post and a collection of reply posts, and they
represent conversations, single microblog posts, or notifications. In the .NET client object model, feeds are represented by SocialFeed objects, threads are represented by SocialThread
objects, and posts and replies are represented by SocialPost objects. To perform core feed-related tasks in the .NET client object model, you use the SocialFeedManager object. In this article,
we'll show you how to create a console application that uses the .NET client object model to work with social feeds.
For more information about working with SocialFeedManager or for information about using other APIs to work with social feeds, see Work with social feeds in SharePoint.

Prerequisites for setting up your development environment to work with social feeds by using the SharePoint .NET
client object model
To create a console application that uses the .NET client object model to work with social feeds, you'll need:
SharePoint with My Site configured, with personal sites created for the current user and a target user, with the current user following the target user, and with a few posts written by
the target user
Visual Studio 2012
Full Control access permissions to the User Profile service application for the logged-on user
NOTE

If you are not developing on the computer that is running SharePoint, get the SharePoint Client Components download that contains SharePoint client assemblies.

Create a console application that works with social feeds by using the SharePoint .NET client object model
1. Open Visual Studio and choose File, New, Project.
2. In the New Project dialog box, choose .NET Framework 4.5 from the drop-down list at the top of the dialog box.
3. In the Templates list, choose Windows, and then choose the Console Application template.
4. Name the project SocialFeedCSOM, and then choose the OK button.
5. Add references to the following assemblies:
Microsoft.SharePoint.Client
Microsoft.SharePoint.ClientRuntime
Microsoft.SharePoint.Client.UserProfiles
6. Replace the contents of the Program class with the code example from one of the following scenarios:
Publish posts and replies to the social feed
Retrieve social feeds
Delete posts and replies from the social feed
7. To test the console application, on the menu bar, choose Debug, Start Debugging.

Code example: Publish posts and replies to the social feed by using the SharePoint .NET client object model
The following code example publishes a post and a reply from the current user. It shows how to:
Define post content. This example includes a link in the post.
Publish a post to the current user's feed by using the CreatePost method and passing null as the targetId parameter.
Get the News feed type for the current user by using the GetFeed method.
Iterate through the feed to find all threads that can be replied to and to get information about threads and posts.
Reply to a post by using the CreatePost method and passing the thread identifier as the targetId parameter.
NOTE

Change the placeholder value for the serverUrl variable before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace SocialFeedCSOM
{
class Program
{
static void Main(string[] args)
{
// Replace the following placeholder value with the target server URL.
const string serverUrl = "http://serverName/";

Console.Write("Type your post text: ");

// Create a link to include in the post.


SocialDataItem linkDataItem = new SocialDataItem();
linkDataItem.ItemType = SocialDataItemType.Link;
linkDataItem.Text = "link";
linkDataItem.Uri = "http://bing.com";

// Define properties for the post.


SocialPostCreationData postCreationData = new SocialPostCreationData();
postCreationData.ContentText = Console.ReadLine() + " Plus a {0}.";
postCreationData.ContentItems = new SocialDataItem[1] { linkDataItem };

// Get the client context.


ClientContext clientContext = new ClientContext(serverUrl);

// Get the SocialFeedManager instance.


SocialFeedManager feedManager = new SocialFeedManager(clientContext);

// Publish the post. This is a root post, so specify null for the
// targetId parameter.
feedManager.CreatePost(null, postCreationData);
clientContext.ExecuteQuery();

Console.WriteLine("\\nCurrent user's newsfeed:");

// Set parameters for the feed content that you want to retrieve.
SocialFeedOptions feedOptions = new SocialFeedOptions();

// Get the target owner's feed and then run the request on the server.
ClientResult<SocialFeed> feed = feedManager.GetFeed(SocialFeedType.News, feedOptions);
clientContext.ExecuteQuery();

// Create a dictionary to store the Id property of each thread. This


// code example stores the Id so you can select a thread to reply to.
Dictionary<int, string> idDictionary = new Dictionary<int, string>();

// Iterate through each thread in the feed.


for (int i = 0; i < feed.Value.Threads.Length; i++)
{
SocialThread thread = feed.Value.Threads[i];

// Keep only the threads that can be replied to.


if (thread.Attributes.HasFlag(SocialThreadAttributes.CanReply))
{
idDictionary.Add(i, thread.Id);

// Get properties from the root post and thread.


// If a thread contains more than two replies, the server returns
// a thread digest that contains only the two most recent replies.
// To get all replies, call SocialFeedManager.GetFullThread.
SocialPost rootPost = thread.RootPost;
SocialActor author = thread.Actors[rootPost.AuthorIndex];
Console.WriteLine(string.Format("{0}. {1} said \\"{2}\\" ({3} replies)",
(i + 1), author.Name, rootPost.Text, thread.TotalReplyCount));
}
}
Console.Write("\\nWhich thread number do you want to reply to? ");

string threadToReplyTo = "";


int threadNumber = int.Parse(Console.ReadLine()) - 1;
idDictionary.TryGetValue(threadNumber, out threadToReplyTo);

Console.Write("Type your reply: ");

// Define properties for the reply. This example reuses the


// SocialPostCreationData object that was used to create a post.
postCreationData.ContentText = Console.ReadLine();

// Publish the reply and make the changes on the server.


ClientResult<SocialThread> result = feedManager.CreatePost(threadToReplyTo, postCreationData);
clientContext.ExecuteQuery();

Console.WriteLine("\\nThe reply was published. The thread now has {0} replies.", result.Value.TotalReplyCount);
Console.ReadLine();
}
}
}

Code example: Retrieve social feeds by using the SharePoint .NET client object model
The following code example retrieves feeds for the current user and a target user. It shows how to:
Get the Personal, News, and Timelinefeed types for the current user by using the GetFeed method.
Get the Personal feed type for a target user by using the GetFeedFor method.
Iterate through the feeds to find all non-reference threads and to get information about threads and posts. Reference threads represent notifications that contain information about
another thread. For example, if a user mentions someone in a post, the server generates a MentionReference-type thread that contains the link to the original post and other
metadata about the post.
For more information about feed types, see Overview of feed types. For more information about reference threads, see Reference threads and digest threads in SharePoint social feeds.
NOTE

Change the placeholder values for the serverUrl and targetUser variables before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace SocialFeedCSOM
{
class Program
{
static string owner;
static void Main(string[] args)
{

// Replace the following placeholder values with the target


// server URL and target thread owner.
const string serverUrl = "http://serverName/";
const string targetUser = "domainName\\\\userName";

// Get the client context.


ClientContext clientContext = new ClientContext(serverUrl);

// Get the SocialFeedManager instance.


// Load the instance to get the Owner property.
SocialFeedManager feedManager = new SocialFeedManager(clientContext);
clientContext.Load(feedManager, f => f.Owner);

// Set parameters for the feed content that you want to retrieve.
SocialFeedOptions feedOptions = new SocialFeedOptions();
feedOptions.MaxThreadCount = 10; // default is 20

// Get all feed types for current user and get the Personal feed
// for the target user.
ClientResult<SocialFeed> personalFeed = feedManager.GetFeed(SocialFeedType.Personal, feedOptions);
ClientResult<SocialFeed> newsFeed = feedManager.GetFeed(SocialFeedType.News, feedOptions);
ClientResult<SocialFeed> targetUserFeed = feedManager.GetFeedFor(targetUser, feedOptions);

// Change the sort order to optimize the Timeline feed results.


feedOptions.SortOrder = SocialFeedSortOrder.ByCreatedTime;
ClientResult<SocialFeed> timelineFeed = feedManager.GetFeed(SocialFeedType.Timeline, feedOptions);

// Run the request on the server.


clientContext.ExecuteQuery();

// Get the name of the current user within this instance.


owner = feedManager.Owner.Name;

// Iterate through the feeds and write the content.


IterateThroughFeed(personalFeed.Value, SocialFeedType.Personal, true);
IterateThroughFeed(newsFeed.Value, SocialFeedType.News, true);
IterateThroughFeed(timelineFeed.Value, SocialFeedType.Timeline, true);
IterateThroughFeed(targetUserFeed.Value, SocialFeedType.Personal, false);

Console.ReadKey(false);
}

// Iterate through the feed and write to the console window.


static void IterateThroughFeed(SocialFeed feed, SocialFeedType feedType, bool isCurrentUserOwner)
{
SocialThread[] threads = feed.Threads;

// If this is the target user's feed, get the user's name.


// A user is the owner of all threads in his or her Personal feed.
if (!isCurrentUserOwner)
{
SocialThread firstThread = threads[0];
owner = firstThread.Actors[firstThread.OwnerIndex].Name;
}
Console.WriteLine(string.Format("\\n{0} feed type for {1}:", feedType.ToString(), owner));

// Iterate through each thread in the feed.


foreach (SocialThread thread in threads)
{

// Ignore reference thread types.


if (thread.ThreadType == SocialThreadType.Normal)
{

// Get properties from the root post and thread.


// If a thread contains more than two replies, the server returns
// a thread digest that contains only the two most recent replies.
// To get all replies, call SocialFeedManager.GetFullThread.
SocialPost rootPost = thread.RootPost;
SocialActor author = thread.Actors[rootPost.AuthorIndex];
Console.WriteLine(string.Format(" - {0} posted \\"{1}\\" on {2}. This thread has {3} replies.",
author.Name, rootPost.Text, rootPost.CreatedTime.ToShortDateString(), thread.TotalReplyCount));
}
}
}
}
}

Code example: Delete posts and replies from the social feed by using the SharePoint .NET client object model
The following code example deletes a post or a reply from the current user's personal feed. It shows how to:
Get the Personal feed type for the current user by using the GetFeed method.
Iterate through the threads in the feed to get information about the root post and replies.
Delete a root post, reply, or thread by using the DeletePost method (deleting a root post deletes the whole thread).
NOTE

Change the placeholder value for the serverUrl variable before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace SocialFeedCSOM
{
class Program
{
static void Main(string[] args)
{

// Replace the following placeholder value with the target SharePoint server.
const string serverUrl = "http://serverName/";

// Get the client context.


ClientContext clientContext = new ClientContext(serverUrl);

// Get the SocialFeedManager instance.


SocialFeedManager feedManager = new SocialFeedManager(clientContext);

Console.WriteLine("\\nCurrent user's personal feed:");

// Set the parameters for the feed content that you want to retrieve.
SocialFeedOptions feedOptions = new SocialFeedOptions();

// Get the target owner's feed (posts and activities) and


// then run the request on the server.
ClientResult<SocialFeed> feed = feedManager.GetFeed(SocialFeedType.Personal, feedOptions);
clientContext.ExecuteQuery();

// Create a dictionary to store the Id property of each post and


// reply. This code example stores the Id so you can select a post
// or a reply to delete.
Dictionary<int, string> idDictionary = new Dictionary<int, string>();

// Iterate through each thread in the feed.


for (int i = 0; i < feed.Value.Threads.Length; i++)
{
SocialThread thread = feed.Value.Threads[i];
SocialPost rootPost = thread.RootPost;

// Only keep posts that can be deleted.


if (rootPost.Attributes.HasFlag(SocialPostAttributes.CanDelete))
{
idDictionary.Add(i, rootPost.Id);

Console.WriteLine(string.Format("{0}. \\"{1}\\" has {2} replies.",


(i + 1), rootPost.Text, thread.TotalReplyCount));

// Get the replies.


// If a thread contains more than two replies, the server returns
// a thread digest that contains only the two most recent replies.
// To get all replies, call SocialFeedManager.GetFullThread.
if (thread.TotalReplyCount > 0)
{
foreach (SocialPost reply in thread.Replies)
{

// Only keep replies that can be deleted.


if (reply.Attributes.HasFlag(SocialPostAttributes.CanDelete))
{
i++;
idDictionary.Add(i, reply.Id);

SocialActor author = thread.Actors[reply.AuthorIndex];


Console.WriteLine(string.Format("\\t{0}. {1} replied \\"{2}\\"",
(i + 1), author.Name, reply.Text));
}
}
}
}
}
Console.Write("\\nEnter the number of the post or reply to delete. "
+ "(If you choose a root post, the whole thread is deleted.)");
string postToDelete = "";
int postNumber = int.Parse(Console.ReadLine()) - 1;
idDictionary.TryGetValue(postNumber, out postToDelete);

// Delete the reply and make the changes on the server.


ClientResult<SocialThread> result = feedManager.DeletePost(postToDelete);
clientContext.ExecuteQuery();

// DeletePost returns digest thread if the deleted post is not the


// root post. If it is the root post, the whole thread is deleted
// and DeletePost returns null.
if (result.Value != null)
{
SocialThread threadResult = result.Value;
Console.WriteLine("\\nThe reply was deleted. The thread now has {0} replies.", threadResult.TotalReplyCount);
}
else
{
Console.WriteLine("\\nThe post and thread were deleted.");
}
Console.ReadKey(false);
}
}
}
Next steps
How to: Include mentions, tags, and links to sites and documents in posts in SharePoint

See also
Work with social feeds in SharePoint
How to: Create and delete posts and retrieve the social feed by using the JavaScript object model in SharePoint
How to: Learn to read and write to the social feed by using the REST service in SharePoint
Reference threads and digest threads in SharePoint social feeds
Create and delete posts and retrieve the social feed by using the JavaScript object model in
SharePoint
3/26/2018 • 10 minutes to read Edit Online

Learn how to create and delete microblog posts and retrieve social feeds by using the SharePoint JavaScript object model.

What are social feeds in SharePoint?


In SharePoint, a social feed is a collection of threads that represent conversations, single microblog posts, or notifications. Threads contain a root post and a collection of reply posts. In the
JavaScript object model, feeds are represented by SocialFeed objects, threads are represented by SocialThread objects, and post and replies are represented by SocialPost objects. To
perform core feed-related tasks, you use the SocialFeedManager object. In this article, we'll show you how to create an application page that uses the JavaScript object model to work with
social feeds.
For more information about working with SocialFeedManager or for information about using other APIs to work with social feeds, see Work with social feeds in SharePoint.

Prerequisites for setting up your development environment to work with social feeds in the SharePoint JavaScript
object model
To create an application page that uses the JavaScript object model to work with social feeds, you'll need:
SharePoint with My Site configured as public, with personal sites created for the current user and a target user, with the current user following the target user, and with a few posts
written by the target user
Visual Studio 2012 or Visual Studio 2013 with Office Developer Tools for Visual Studio 2013
Full Control access permissions to the User Profile service application and permissions to deploy a farm solution for the logged-on user
Sufficient permissions for the application pool account to access the content database of the My Sites web application

Create an application page that works with social feeds by using the SharePoint JavaScript object model
1. Open Visual Studio and choose File, New, Project.
2. In the New Project dialog box, choose .NET Framework 4.5 from the drop-down list at the top of the dialog box.
3. In the Templates list, expand Office SharePoint, choose the SharePoint Solutions category, and then choose the SharePoint Project template.
4. Name the project SocialFeedJSOM, and then choose the OK button.
5. In the SharePoint Customization Wizard dialog box, choose Deploy as a farm solution, and then choose the Finish button.
6. In Solution Explorer, open the shortcut menu for the SocialFeedJSOM project, and then add a SharePoint "Layouts" mapped folder.
7. In the Layouts folder, open the shortcut menu for theSocialFeedJSOM folder, and then add a new SharePoint application page namedSocialFeed.aspx.

Note: The code examples in this article define custom code in the page markup but do not use the code-behind class that Visual Studio creates for the page.

8. Open the shortcut menu for the SocialFeed.aspx page, and then choose Set as Startup Item.
9. In the markup for the SocialFeed.aspx page, define controls inside the "Main" asp:Content tags, as shown in the following code.

<table width="100%" id="tblPosts"></table><br/>


<button id="btnDelete" type="button"></button><br />
<span id="spanMessage" style="color: #FF0000;"></span>

Note: These controls may not be used in every scenario. For example, the "Publish posts and replies" scenario only uses the span control.

1. After the closing span tag, add SharePoint:ScriptLink controls, a SharePoint:FormDigest control, and script tags, as shown in the following code. The SharePoint:ScriptLink tags
reference the class library files that define the JavaScript object model that you can use for My Site Social development. The SharePoint:FormDigest tag generates a message digest for
security validation when required by operations that update server content.

<SharePoint:ScriptLink ID="ScriptLink1" name="SP.js" runat="server" ondemand="false" localizable="false" loadafterui="true" />


<SharePoint:ScriptLink ID="ScriptLink2" name="SP.UserProfiles.js" runat="server" ondemand="false" localizable="false" loadafterui="true" />
<SharePoint:FormDigest id="FormDigest" runat="server"/>
<script type="text/javascript">
// Replace this comment with the code for your scenario.
</script>

1. To add the logic to work with feeds, replace the comment between the script tags with the code example from one of the following scenarios:
Publish posts and replies to the social feed
Retrieve social feeds
Delete posts and replies from the social feed
2. To test the application page, on the menu bar, choose Debug, Start Debugging. If you are prompted to modify the web.config file, choose the OK button.
If the response calls the failure callback method, set a breakpoint in the method and add a watch on the args object or check the ULS logs and the event viewer for more information.

Code example: Publish posts and replies to the social feed by using the SharePoint JavaScript object model
The following code example publishes a post and a reply. It shows how to:
Define post content. This example includes a link in the post.
Publish a post to the current user's feed by using the createPost method and passing null as the targetId parameter.
Reply to a post by using the createPost method and passing the thread identifier as the targetId parameter.
NOTE

Paste the following code between the script tags that you added in the Create the application page procedure.

// Ensure that the SP.UserProfiles.js file is loaded before the custom code runs.
SP.SOD.executeOrDelayUntilScriptLoaded(PublishPost, 'SP.UserProfiles.js');

// Declare global variables.


var clientContext;
var feedManager;
var resultThread;

function PublishPost() {

// Initialize the current client context and the SocialFeedManager instance.


clientContext = SP.ClientContext.get_current();
feedManager = new SP.Social.SocialFeedManager(clientContext);

// Create a link to include in the post.


var linkDataItem = new SP.Social.SocialDataItem();
linkDataItem.set_itemType(SP.Social.SocialDataItemType.link);
linkDataItem.set_text('link');
linkDataItem.set_uri('http://bing.com');
var socialDataItems = [ linkDataItem ];

// Create the post content.


var postCreationData = new SP.Social.SocialPostCreationData();
postCreationData.set_contentText('The text for the post, which contains a {0}.');
postCreationData.set_contentItems(socialDataItems);

// Publish the post. Pass null for the "targetId" parameter because this is a root post.
resultThread = feedManager.createPost(null, postCreationData);
clientContext.executeQueryAsync(PublishReply, PostFailed);
}
function PublishReply(sender, args) {

// Create the reply content.


var postCreationData = new SP.Social.SocialPostCreationData();
postCreationData.set_contentText('The text for the reply.');

// Publish the reply.


resultThread = feedManager.createPost(resultThread.get_id(), postCreationData);
clientContext.executeQueryAsync(PostSucceeded, PostFailed);
}
function PostSucceeded(sender, args) {
$get("spanMessage").innerText = 'The post and reply were published.';
}
function PostFailed(sender, args) {
$get("spanMessage").innerText = 'Request failed: ' + args.get_message();
}

Code example: Retrieve social feeds by using the SharePoint JavaScript object model
The following code example retrieves feeds for the current user and a target user. It shows how to:
Get the Personal, News, and Timeline feed types for the current user by using the getFeed method.
Get the Personal feed type for a target user by using the getFeedFor method.
Iterate through the feeds to find all non-reference threads and to get information about threads and posts. Reference threads represent notifications that contain information about
another thread. For example, if a user mentions someone in a post, the server generates a MentionReference-type thread that contains the link to the original post and other
metadata about the post.
For more information about feed types, see Overview of feed types in the My Site Social API. For more information about reference threads, see Reference threads and digest threads in
SharePoint social feeds.
NOTE

Paste the following code between the script tags that you added in the Create the application page procedure. Then, change the placeholder value for the targetUser variable before you run
the code.
// Replace the placeholder value with the account name of the target user.
var targetUser = 'domainName\\\\userName';

// Ensure that the SP.UserProfiles.js file is loaded before the custom code runs.
SP.SOD.executeOrDelayUntilScriptLoaded(GetFeeds, 'SP.UserProfiles.js');

// Declare global variables.


var clientContext;
var feedManager;
var personalFeed;
var newsFeed;
var timelineFeed;
var targetUserFeed;

function GetFeeds() {

// Initialize the current client context and the SocialFeedManager instance.


clientContext = SP.ClientContext.get_current();
feedManager = new SP.Social.SocialFeedManager(clientContext);

// Set parameters for the feed content that you want to retrieve.
var feedOptions = new SP.Social.SocialFeedOptions();
feedOptions.set_maxThreadCount(10); // default is 20

// Get all feed types for current user and get the Personal feed
// for the target user.
personalFeed = feedManager.getFeed(SP.Social.SocialFeedType.personal, feedOptions);
newsFeed = feedManager.getFeed(SP.Social.SocialFeedType.news, feedOptions);
targetUserFeed = feedManager.getFeedFor(targetUser, feedOptions);

// Change the sort order to optimize the Timeline feed results.


feedOptions.set_sortOrder(SP.Social.SocialFeedSortOrder.byCreatedTime);
timelineFeed = feedManager.getFeed(SP.Social.SocialFeedType.timeline, feedOptions);

clientContext.load(feedManager);
clientContext.executeQueryAsync(CallIterateFunctionForFeeds, RequestFailed);
}
function CallIterateFunctionForFeeds() {
IterateThroughFeed(personalFeed, "Personal", true);
IterateThroughFeed(newsFeed, "News", true);
IterateThroughFeed(timelineFeed, "Timeline", true);
IterateThroughFeed(targetUserFeed, "Personal", false);
}
function IterateThroughFeed(feed, feedType, isCurrentUser) {
tblPosts.insertRow().insertCell();
var feedHeaderRow = tblPosts.insertRow();
var feedOwner = feedManager.get_owner().get_name();

// Iterate through the array of threads in the feed.


var threads = feed.get_threads();
for (var i = 0; i < threads.length ; i++) {
var thread = threads[i];
var actors = thread.get_actors();

if (i == 0) {

// Get the name of the target user for the feed header row. Users are
// owners of all threads in their Personal feed.
if (!isCurrentUser) {
feedOwner = actors[thread.get_ownerIndex()].get_name();
}
feedHeaderRow.insertCell().innerText = feedType.toUpperCase() + ' FEED FOR '
+ feedOwner.toUpperCase();
}

// Use only Normal-type threads and ignore reference-type threads. (SocialThreadType.Normal = 0)


if (thread.get_threadType() == 0) {

// Get the root post's author, content, and number of replies.


var post = thread.get_rootPost();
var authorName = actors[post.get_authorIndex()].get_name();
var postContent = post.get_text();
var totalReplies = thread.get_totalReplyCount();

var postRow = tblPosts.insertRow();


postRow.insertCell().innerText = authorName + ' posted \\"' + postContent
+ '\\" (' + totalReplies + ' replies)';

// If there are any replies, iterate through the array and


// get the author and content.
// If a thread contains more than two replies, the server
// returns a thread digest that contains only the two most
// recent replies. To get all replies, call the
// SocialFeedManager.getFullThread method.
if (totalReplies > 0) {
var replies = thread.get_replies();

for (var j = 0; j < replies.length; j++) {


var replyRow = tblPosts.insertRow();

var reply = replies[j];


replyRow.insertCell().innerText = ' - ' + actors[reply.get_authorIndex()].get_name()
+ ' replied \\"' + reply.get_text() + '\\"';
}
}
}
}
}
function RequestFailed(sender, args) {
$get("spanMessage").innerText = 'Request failed: ' + args.get_message();
}
Code example: Delete posts and replies from the social feed by using the SharePoint JavaScript object model
The following code example deletes a post or a reply. It shows how to:
Get the News feed type for the current user by using the getFeed method.
Iterate through the posts and replies in the feed to get the id property that you use to delete the post or reply.
Delete a root post or reply by using the deletePost method (deleting a root post deletes the whole thread).
NOTE

Paste the following code between the script tags that you added in the Create the application page procedure. This example assumes that the current user's newsfeed contains at least one
post.

// Ensure that the SP.UserProfiles.js file is loaded before the custom code runs.
SP.SOD.executeOrDelayUntilScriptLoaded(GetFeeds, 'SP.UserProfiles.js');

// Declare global variables.


var clientContext;
var feedManager;
var feed;
var postOrReplyToDelete;

function GetFeeds() {

// Initialize the current client context and the SocialFeedManager instance.


clientContext = SP.ClientContext.get_current();
feedManager = new SP.Social.SocialFeedManager(clientContext);

// Set parameters for the feed content that you want to retrieve.
var feedOptions = new SP.Social.SocialFeedOptions();
feedOptions.set_maxThreadCount(10); // default is 20

// Get all the News feed type for current user.


feed = feedManager.getFeed(SP.Social.SocialFeedType.news, feedOptions);
clientContext.executeQueryAsync(IterateThroughFeed, RequestFailed);
}
function IterateThroughFeed() {

// Iterate through the array of threads in the feed.


var threads = feed.get_threads();
for (var i = 0; i < threads.length ; i++) {
var thread = threads[i];
var actors = thread.get_actors();

// Get the root post's author, content, and number of replies.


var post = thread.get_rootPost();

var authorName = actors[post.get_authorIndex()].get_name();


var postContent = post.get_text();
var totalReplies = thread.get_totalReplyCount();

var postRow = tblPosts.insertRow();


postRow.insertCell().innerText = authorName + ' posted \\"' + postContent
+ '\\" (' + totalReplies + ' replies)';
postOrReplyToDelete = post.get_id();

// If there are any replies, iterate through the array and


// get the author and content.
// If a thread contains more than two replies, the server
// returns a thread digest that contains only the two most
// recent replies. To get all replies, call the
// SocialFeedManager.getFullThread method.
if (totalReplies > 0) {
var replies = thread.get_replies();
for (var j = 0; j < replies.length; j++) {
var replyRow = tblPosts.insertRow();

var reply = replies[j];


replyRow.insertCell().innerText = ' - ' + actors[reply.get_authorIndex()].get_name()
+ ' replied \\"' + reply.get_text() + '\\"';
postOrReplyToDelete = reply.get_id();
}
}

// Initialize button properties.


$get("btnDelete").onclick = function () { DeletePostOrReply(); };
$get("btnDelete").innerText = 'Click to delete the last post or reply';
}
}

// Delete the last post or reply listed on the page.


function DeletePostOrReply() {
feedManager.deletePost(postOrReplyToDelete);
clientContext.executeQueryAsync(DeleteSucceeded, RequestFailed);
}
function DeleteSucceeded(sender, args) {
$get("spanMessage").innerText = 'The post or reply was deleted. Refresh the page to see your changes.';
}
function RequestFailed(sender, args) {
$get("spanMessage").innerText = 'Request failed: ' + args.get_message();
}

See also
Work with social feeds in SharePoint
SP.Social namespace (sp.userprofiles)
How to: Create and delete posts and retrieve the social feed by using the .NET client object model in SharePoint
How to: Learn to read and write to the social feed by using the REST service in SharePoint
Reference threads and digest threads in SharePoint social feeds
Include mentions, tags, and links to sites and documents in posts in SharePoint
3/26/2018 • 6 minutes to read Edit Online

Learn how to add SocialDataItem objects to microblog posts, which render as mentions, tags, or links in SharePoint social feeds. In a social feed, the simplest form of post content contains
only text, but you can also add links that render as mentions, tags, or links to websites, SharePoint sites, and documents. To do this, you add SocialDataItem objects to the ContentItems
property of the SocialPostCreationData object that defines the post. Posts can contain multiple links.
NOTE

To add embedded pictures, videos, or documents to a post's content, you add a SocialAttachment object to the SocialPostCreationData.Attachment property. For more information, see How
to: Embed images, videos, and documents in posts in SharePoint.
The API described in this article is from the .NET client object model. However, if you're using another API, such as the JavaScript object model, the object names or corresponding API might
be different. See Additional resources for links to documentation for related APIs.

Prerequisites for using the code examples to add links to a post in SharePoint
The code examples in this article show how to add links to microblog posts. These examples are from console applications that use the following SharePoint assemblies:
Microsoft.SharePoint.Client
Microsoft.SharePoint.Client.Runtime
Microsoft.SharePoint.Client.UserProfilies
For instructions about how to set up your development environment and create a console application, see How to: Create and delete posts and retrieve the social feed by using the .NET
client object model in SharePoint.

Example: Include links to websites, SharePoint sites, and documents in a post in SharePoint
The following code example publishes a post that contains links to a website, a SharePoint site, and a document. It shows how to:
Create SocialDataItem objects that represent the links. Each instance sets the SocialDataItemType field for the link type, the display text for the link, and the link URI.
Add placeholders to the post text to indicate where the link's display text should appear.
Add the link objects to the ContentItems property of the SocialPostCreationData object that's used to create the post.
NOTE

Currently, SharePoint handles links to websites, SharePoint sites, and documents in the same way, but as a best practice, choose the Site type and the Document type for SharePoint sites and
documents.
In the social feed, clicking a link to a website, SharePoint site, or document opens the item in a separate browser window.
NOTE

Change the placeholder values for the URL variables before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace IncludeLinksInPost
{
class Program
{
static void Main(string[] args)
{

// Replace the following placeholder values with the actual values.


const string serverUrl = "http://serverName/siteName/";
const string websiteLinkUrl = "http://bing.com";
const string siteLinkUrl = "http://serverName/siteName/";
const string docLinkUrl = "http://serverName/Shared%20Documents/docName.txt";

// Define the link to a website that you want to include in the post.
SocialDataItem websiteLink = new SocialDataItem
{
ItemType = SocialDataItemType.Link,
Text = "link to a website",
Uri = websiteLinkUrl
};

// Define the link to a SharePoint site that you want to include in the post.
SocialDataItem siteLink = new SocialDataItem
{
ItemType = SocialDataItemType.Site,
Text = "link to a SharePoint site",
Uri = siteLinkUrl
};

// Define the link to a document that you want to include in the post.
SocialDataItem docLink = new SocialDataItem
{
ItemType = SocialDataItemType.Document,
Text = "link to a document",
Uri = docLinkUrl
};

// Add the links to the post's creation data.


// Put placeholders ({n}) where you want the links to appear in the post text,
// and then add the links to the post's content items.
SocialPostCreationData postCreationData = new SocialPostCreationData();
postCreationData.ContentText = "Check out this {0}, {1}, and {2}.";
postCreationData.ContentItems = new SocialDataItem[3] {
websiteLink,
siteLink,
docLink
};
try
{

// Get the context and the SocialFeedManager instance.


ClientContext clientContext = new ClientContext(serverUrl);
SocialFeedManager feedManager = new SocialFeedManager(clientContext);

// Publish the post. This is a root post to the user's feed, so specify
// null for the targetId parameter.
feedManager.CreatePost(null, postCreationData);
clientContext.ExecuteQuery();
Console.Write("The post was published.");
Console.ReadLine();
}
catch (Exception ex)
{
Console.Write("Error publishing the post: " + ex.Message);
Console.ReadLine();
}
}
}
}

Example: Mention someone in a post in SharePoint


The following code example publishes a post that mentions a user. It shows how to:
Create a SocialDataItem object to represent a mention, which is a link to a user. The SocialDataItem specifies the SocialDataItemType.User field and the mentioned person's account
name. You can set the account name by using either the person's login or email address.
Add a placeholder to the post text to indicate where the mentioned person's display name should appear.
Add the SocialDataItem to the ContentItems property of the SocialPostCreationData object that's used to create the post.
In the social feed, clicking a mention redirects to the mentioned person's About page.
NOTE

Change the placeholder values for the serverURL and accountName variables before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace IncludeMentionInPost
{
class Program
{
static void Main(string[] args)
{

// Replace the following placeholder values with the actual values.


const string serverUrl = "http://serverName/siteName/";
const string accountName = @"domain\\name or email address";

// Define the mention link that you want to include in the post.
SocialDataItem userMentionLink = new SocialDataItem
{
ItemType = SocialDataItemType.User,
AccountName = accountName
};

// Add the mention to the post's creation data.


// Put a placeholder ({0}) where you want the mention to appear in the post text,
// and then add the mention to the post's content items.
SocialPostCreationData postCreationData = new SocialPostCreationData();
postCreationData.ContentText = "{0} does great work!";
postCreationData.ContentItems = new SocialDataItem[1] { userMentionLink, };

try
{

// Get the context and the SocialFeedManager instance.


ClientContext clientContext = new ClientContext(serverUrl);
SocialFeedManager feedManager = new SocialFeedManager(clientContext);

// Publish the post. This is a root post to the user's feed, so specify
// null for the targetId parameter.
feedManager.CreatePost(null, postCreationData);
clientContext.ExecuteQuery();
Console.Write("The post was published.");
Console.ReadLine();
}
catch (Exception ex)
{
Console.Write("Error publishing the post: " + ex.Message);
Console.ReadLine();
}
}
}
}

Example: Include a tag in a post in SharePoint


The following code example publishes a post that includes a tag. It shows how to:
Create a SocialDataItem object to represent the tag. The SocialDataItem specifies the SocialDataItemType.Tag field and the tag name, which must include a # character.
Add a placeholder to the post text to indicate where the tag should appear.
Add the SocialDataItem to the ContentItems property of the SocialPostCreationData object that's used to create the post.
In the social feed, clicking a tag redirects to the tag's About page. If the tag doesn't already exist, the server creates it.
NOTE

Change the placeholder values for the serverURL and tagName variables before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace IncludeTagInPost
{
class Program
{
static void Main(string[] args)
{

// Replace the following placeholder values with the actual values.


const string serverUrl = "http://serverName/siteName/";
const string tagName = "#" + "tagName";

// Define the link to a tag that you want to include in the post. If the tag is new, the
// server adds it to the tags collection.
SocialDataItem tagLink = new SocialDataItem
{
ItemType = SocialDataItemType.Tag,
Text = tagName
};

// Add the tag to the post's creation data.


// Put a placeholder ({0}) where you want the tag to appear in the post text,
// and then add the tag to the post's content items.
SocialPostCreationData postCreationData = new SocialPostCreationData();
postCreationData.ContentText = "I like {0}.";
postCreationData.ContentItems = new SocialDataItem[1] { tagLink };

try
{

// Get the context and the SocialFeedManager instance.


ClientContext clientContext = new ClientContext(serverUrl);
SocialFeedManager feedManager = new SocialFeedManager(clientContext);

// Publish the post. This is a root post to the user's feed, so specify
// null for the targetId parameter.
feedManager.CreatePost(null, postCreationData);
clientContext.ExecuteQuery();
Console.Write("The post was published.");
Console.ReadLine();
}
catch (Exception ex)
{
Console.Write("Error publishing the post: " + ex.Message);
Console.ReadLine();
}
}
}
}

See also
Work with social feeds in SharePoint
SocialPostCreationData and SocialDataItem in the client object models
SocialPostCreationData and SocialDataItem in the JavaScript object model
Social feed REST API reference for SharePoint
SPSocialPostCreationData and SPSocialDataItem in the server object model
Embed images, videos, and documents in posts in SharePoint
3/26/2018 • 5 minutes to read Edit Online

Learn how to add SocialAttachment objects to microblog posts, which render as embedded pictures, videos, and documents in SharePoint social feeds. In a social feed, the simplest form of
post content contains only text, but you can also add embedded pictures, videos, and documents. To do this, you use the Attachment property on the SocialPostCreationData object that
defines the post. Posts can contain one attachment, which is represented by a SocialAttachment object.
NOTE

To add a mention, tag, or link to a post's content, you add a SocialDataItem object to the SocialPostCreationData.ContentItems property. For more information, see How to: Include mentions,
tags, and links to sites and documents in posts in SharePoint.
The API described in this article is from the .NET client object model. If you're using another API, such as the JavaScript object model, the object names or corresponding API might be
different. See Additional resources for links to documentation for related APIs.

Prerequisites for using the code examples to add attachments to a post


The code examples in this article show how to add image, video, and document attachments to microblog posts. These examples are from a console application that uses the following
SharePoint assemblies:
Microsoft.SharePoint.Client
Microsoft.SharePoint.Client.Runtime
Microsoft.SharePoint.Client.UserProfilies
To use the examples in this article, you'll need to upload an image, a video, and a document. To use the video example, the video feature must be enabled on the server and the video file must
be stored in an asset library. To use the document example in an on-premises environment, Office Online must be configured in the environment. For more information, see Plan digital asset
libraries in SharePoint and Configure SharePoint to use Office Online.
For instructions about how to set up your development environment and create a console application, see How to: Create and delete posts and retrieve the social feed by using the .NET
client object model in SharePoint.

Example: Embed an image in a post in SharePoint


The following code example publishes a post that contains an embedded image. It shows how to:
Create a SocialAttachment object that represents the image. The SocialAttachment specifies the SocialAttachmentKind.Image field and the URI of the image file.
Add the image object to the Attachment property of the SocialPostCreationData object that's used to create the post.
Change the placeholder values for the URL variables before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace EmbedImageInPost
{
class Program
{
static void Main(string[] args)
{

// Replace the following placeholder values with the actual values.


const string serverUrl = "http://serverName/siteName/";
const string imageUrl = "http://serverName/Shared%20Documents/imageName.jpg";

// Define the image attachment that you want to embed in the post.
SocialAttachment attachment = new SocialAttachment()
{
AttachmentKind = SocialAttachmentKind.Image,
Uri = imageUrl
};

// Define properties for the post and add the attachment.


SocialPostCreationData postCreationData = new SocialPostCreationData();
postCreationData.ContentText = "Look at this!";
postCreationData.Attachment = attachment;

try
{

// Get the context and the SocialFeedManager instance.


ClientContext clientContext = new ClientContext(serverUrl);
SocialFeedManager feedManager = new SocialFeedManager(clientContext);

// Publish the post. This is a root post to the user's feed, so specify
// null for the targetId parameter.
feedManager.CreatePost(null, postCreationData);
clientContext.ExecuteQuery();
Console.Write("The post was published.");
Console.ReadLine();
}
catch (Exception ex)
{
Console.Write("Error publishing the post: " + ex.Message);
Console.ReadLine();
}
}
}
}

Embed a video in a post in SharePoint


The following code example publishes a post that contains an embedded video. It shows how to:
Get the SocialAttachment object that represents the video attachment by using the SocialFeedManager.GetPreview method.
Add the video attachment to the Attachment property of the SocialPostCreationData object that's used to create the post.
This example requires the video features to be enabled on the server and the video file to be uploaded to an asset library. See the prerequisites for using the code examples for more
information.
Change the placeholder values for the URL variables before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace EmbedVideoInPost
{
class Program
{
static void Main(string[] args)
{
// Replace the following placeholder values with the actual values.
const string serverUrl = "http://serverName/siteName/";
const string videoUrl = "http://serverName/Asset%20Library/fileName?Web=1";

try
{

// Get the context and the SocialFeedManager instance.


ClientContext clientContext = new ClientContext(serverUrl);
SocialFeedManager feedManager = new SocialFeedManager(clientContext);

// Get the video attachment from the server.


ClientResult<SocialAttachment> attachment = feedManager.GetPreview(videoUrl);
clientContext.ExecuteQuery();

// Define properties for the post and add the attachment.


SocialPostCreationData postCreationData = new SocialPostCreationData();
postCreationData.ContentText = "Look at this!";
postCreationData.Attachment = attachment.Value;

// Publish the post. This is a root post to the user's feed, so specify
// null for the targetId parameter.
feedManager.CreatePost(null, postCreationData);
clientContext.ExecuteQuery();

Console.Write("The post was published.");


Console.ReadLine();
}
catch (Exception ex)
{
Console.Write("Error publishing the post: " + ex.Message);
Console.ReadLine();
}
}
}
}

Example: Embed a document in a post in SharePoint


The following code example publishes a post that contains an embedded document. It shows how to:
Get the SocialAttachment object that represents the document attachment by using the SocialFeedManager.GetPreview method.
Add the document attachment to the Attachment property of the SocialPostCreationData object that's used to create the post.
To use this example in an on-premises environment, your environment must be configured to use Office Online. See the prerequisites for using the code examples for more information.
Otherwise, you can post a link to the document as described in How to: Include mentions, tags, and links to sites and documents in posts in SharePoint.
Change the placeholder values for the URL variables before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace EmbedDocumentInPost
{
class Program
{
static void Main(string[] args)
{
// Replace the following placeholder values with the actual values.
const string serverUrl = "http://serverName";
const string documentUrl = "http://serverName/Shared%20Documents/fileName.docx";

try
{

// Get the context and the SocialFeedManager instance.


ClientContext clientContext = new ClientContext(serverUrl);
SocialFeedManager feedManager = new SocialFeedManager(clientContext);

// Get the document attachment from the server.


ClientResult<SocialAttachment> attachment = feedManager.GetPreview(documentUrl);
clientContext.ExecuteQuery();

// Define properties for the post and add the attachment.


SocialPostCreationData postCreationData = new SocialPostCreationData();
postCreationData.ContentText = "Post with a document.";
postCreationData.Attachment = attachment.Value;

// Publish the post. This is a root post to the user's feed, so specify
// null for the targetId parameter.
feedManager.CreatePost(null, postCreationData);
clientContext.ExecuteQuery();
Console.Write("The post was published.");
Console.ReadLine();
}
catch (Exception ex)
{
Console.Write("Error publishing the post: " + ex.Message);
Console.ReadLine();
}
}
}
}

See also
Work with social feeds in SharePoint
How to: Include mentions, tags, and links to sites and documents in posts in SharePoint
SocialPostCreationData and SocialAttachment in the client object models
SocialPostCreationData and SocialAttachment in the JavaScript object model
Social feed REST API reference for SharePoint
SPSocialPostCreationData and SPSocialAttachment in the server object model
Reference threads and digest threads in SharePoint social feeds
3/26/2018 • 2 minutes to read Edit Online

Learn about reference threads and digest threads, which are thread types that may be included in the collection of threads that make up a social feed in SharePoint. When you retrieve a
social feed, SharePoint returns a SocialFeed object that contains the collection of SocialThread objects that make up the feed. These threads can represent conversations, single microblog
posts, and notifications, which include events and reference threads. Threads that represent conversations may be returned by the server as digest threads.
NOTE

The API referenced in this article is from the .NET client object model. However, corresponding objects in other APIs might be different. See Additional resources for links to other related
APIs.

What are reference threads in SharePoint social feeds?


When a user likes a post, mentions someone in a post, replies to a post, or includes a tag in a post, SharePoint generates a reference thread. Reference threads have two properties that you
use to get information about the referenced thread or post: ThreadType and PostReference .
You can identify a reference thread by its ThreadType property, which can return one of the values shown in Table 1.
Table 1. Types of reference thread

R EFER ENCE T YPE D ES CR IPTIO N

LikeReference **** A reference to a post that a user likes.

MentionReference A reference to a post that mentions a user.

ReplyReference A reference to a reply.

TagReference A reference to a post that contains a tag.

Normal Not a reference thread.

The PostReference property returns a SocialPostReference object that contains information about the thread that triggered the event. At a minimum, it contains the ID of the source thread,
which you can then use with the SocialFeedManager.GetFullThread method to retrieve the thread if it still exists.
SocialPostReference might also contain a copy of the source post or thread. This availability depends on the feed type, thread type, and security trimming. If the reference does contain a post
or thread, these objects represent snapshots of the post or thread at the time the event occurred.
Not all feed-related activities are posted to the feed as reference threads. For example, Following notifications (such as when someone starts following a site) are not reference threads.
NOTE

SharePoint automatically security trims for content in autogenerated posts and for site access in all posts that are directed to a site feed. However, you can use the SecurityUris attribute to
security trim any post by specifying a URL. Users who do not have access to the URL do not receive the post.
Reply, like, and mention references are stored indefinitely in the user's personal feed. Tag references are stored in the Distributed Cache, so they are stored temporarily. For more information
about caching, see Overview of microblog features, feeds, and the Distributed Cache service in SharePoint.

What are digest threads in SharePoint social feeds?


A digest thread represents a compact version of a conversation—it contains the thread's root post and two most recent replies. You can identify a digest thread by checking whether the
thread has the IsDigest attribute applied in its Attributes property. To see whether a thread has more than two threads, check the TotalReplyCount property.
To optimize performance, when a thread contains more than two replies, the server returns a digest thread. If you want to get all the replies for a thread, call the
SocialFeedManager.GetFullThread method and pass in the thread ID.

See also
Work with social feeds in SharePoint
SocialThread in the .NET client object model
SocialThread in the JavaScript object model
SPSocialThread in the server object model
Follow people in SharePoint
3/26/2018 • 5 minutes to read Edit Online

Learn about common programming tasks for following people in SharePoint.

APIs for following people in SharePoint


When a user follows people in SharePoint, microblog posts that the people publish and notifications about their activities show up in the user's newsfeed. The features related to following
people can be seen on the Newsfeed and People I'm following pages.
SharePoint provides the following APIs that you can use to programmatically follow people:
Client object models for managed code
.NET client object model
Silverlight client object model
Mobile client object model
JavaScript object model
Representational State Transfer (REST) service
Server object model
As a best practice in SharePoint development, use client APIs when you can. Client APIs include the client object models, a JavaScript object model, and a REST service. For more
information about the APIs in SharePoint and when to use them, see Choose the right API set in SharePoint.
Each API includes a manager object that you use to perform core tasks for following people.
NOTE

The same APIs are used to follow content. See Follow content in SharePoint for an overview of Following Content tasks.
Table 1 shows the manager and other key objects (or REST resources) in the APIs and the class library (or access point) where you can find them.
NOTE

The Silverlight and mobile client object models are not explicitly included in Table 1 or Table 2 because they provide the same core functionality as the .NET client object model and use the
same signatures. The Silverlight client object model is defined in Microsoft.SharePoint.Client.UserProfiles.Silverlight.dll, and the mobile client object model is defined in
Microsoft.SharePoint.Client.UserProfiles.Phone.dll.
Table 1. SharePoint APIs used for following people programmatically

API K EY O B JECTS

.NET client object model Manager object: SocialFollowingManager


See: How to: Follow people by using the .NET client object model in SharePoint Primary namespace: Microsoft.SharePoint.Client.Social
Other key objects: SocialActor , SocialActorInfo , SocialActorType , SocialActorTypes
Class library: Microsoft.SharePoint.Client.UserProfiles.dll

JavaScript object model Manager object: SocialFollowingManager


See: How to: Follow people by using the JavaScript object model in SharePoint Primary namespace: SP.Social
Other key objects: SocialActor, SocialActorInfo, SocialActorType, SocialActorTypes
Class library: SP.UserProfiles.js

REST service Manager resource: social.following


See: Following people and content REST API reference for SharePoint Endpoint URI: <siteUri>/_api/social.following
Primary namespace (OData.md): sp.social.SocialRestFollowingManager
Other key resources: SocialActor, SocialActorInfo, SocialActorType, SocialActorTypes

Server object model Manager object: SPSocialFollowingManager


Primary namespace: Microsoft.Office.Server.Social
Other key objects: SPSocialActor , SPSocialActorInfo , SPSocialActorType , SPSocialActorTypes
Class library: Microsoft.Office.Server.UserProfiles.dll

Common programming tasks for following people in SharePoint


Table 2 shows common programming tasks for following people and the members that you use to perform them. Members are from the .NET client object model (CSOM), JavaScript object
model (JSOM), REST service, and server object model (SSOM).
NOTE

The same APIs are used to follow content. See Follow content in SharePoint for an overview of Following Content tasks.
The SocialFollowingManager object consolidates the core Following People and Following Content functionality for the current user. However, the PeopleManager object (see Table 3)
provides some functionality that SocialFollowingManager does not provide, including methods to obtain the Following People status of other users.
Table 2. API for common tasks for following people by using the SocialFollowingManager object

TAS K MEMB ER S

Create an instance of a manager object in the context of the current user CSOM: SocialFollowingManager
JSOM: SocialFollowingManager
REST: <siteUri>/_api/social.following
SSOM: SPSocialFollowingManager

Create an instance of a manager object in the context of a particular user CSOM: not implemented
JSOM: not implemented
REST: not implemented
SSOM: SPSocialFollowingManager (overloaded)
TAS K MEMB ER S

Have the current user start following (stop following) someone CSOM: Follow ( StopFollowing )
JSOM: follow ( stopFollowing)
REST: POST <siteUri>/_api/social.following/Follow (
<siteUri>/_api/social.following/StopFollowing ) and pass the actor parameter in the request body
SSOM: Follow ( StopFollowing )

Find out whether the current user is following a particular user CSOM: IsFollowed
JSOM: isFollowed
REST: POST <siteUri>/_api/social.following/my/IsFollowed and pass the actor parameter in the
request body
SSOM: IsFollowed

Get the people who are following the current user CSOM: GetFollowers
JSOM: getFollowers
REST: GET <siteUri>/_api/social.following/my/Followers
SSOM: GetFollowers

Get the people who the current user is following CSOM: GetFollowed
JSOM: getFollowed
REST: GET <siteUri>/_api/social.following/my/Followed(types=1)
SSOM: GetFollowed

Get the count of people who the current user is following CSOM: GetFollowedCount
JSOM: getFollowedCount
REST: GET <siteUri>/_api/social.following/my/FollowedCount(types=1)
SSOM: GetFollowedCount

Get the people who the current user might want to follow CSOM: GetSuggestions
JSOM: getSuggestions
REST: GET <siteUri>/_api/social.following/my/Suggestions
SSOM: GetSuggestions

Table 3 shows the PeopleManager members that you can use for additional Following People functionality.
Table 3. API for common tasks for following people by using the PeopleManager object

TAS K MEMB ER S

Find out whether the People I'm Following list for the current user is public CSOM: IsMyPeopleListPublic
JSOM: isMyPeopleListPublic
REST: IsMyPeopleListPublic
Example: GET <siteUri>/_api/SP.UserProfiles.PeopleManager/IsMyPeopleListPublic
SSOM: IsMyPeopleListPublic

Find out whether someone is following the current user CSOM: AmIFollowedBy
JSOM: amIFollowedBy
REST: AmIFollowedBy
Example: GET
<siteUri>/_api/SP.UserProfiles.PeopleManager/AmIFollowedBy(accountName=@v)?
@v='domain\\user'
SSOM: AmIFollowedBy

Get the people who a particular user is following CSOM: GetPeopleFollowedBy


JSOM: getPeopleFollowedBy
REST: GetPeopleFollowedBy
Example: GET
<siteUri>/_api/SP.UserProfiles.PeopleManager/GetPeopleFollowedBy(accountName=@v)?
@v='domain\\user'
SSOM: GetPeopleFollowedBy

Get the people who are following a particular user CSOM: GetFollowersFor
JSOM: getFollowersFor
REST: GetFollowersFor
Example: GET
<siteUri>/_api/SP.UserProfiles.PeopleManager/GetFollowersFor(accountName=@v)?
@v='domain\\user'
SSOM: GetFollowersFor

Find out whether a particular user is following another user CSOM: IsFollowing
JSOM: isFollowing
REST: IsFollowing (static)
Example: GET
<siteUri>/_api/SP_UserProfiles_PeopleManager_IsFollowing(possibleFollowerAccountName=@v,possibleFo
@v='domain\\user'&amp;@y='domain\\user'
SSOM: IsFollowing

How People Suggestions works on SharePoint Online


Results for People Suggestions are based on established Following People activity. Suggestions are offered when a user is following someone who has a mutual following with someone else
who the user is not already following.
Following-related information is indexed during search crawls. After a crawl is complete, search analytics must then analyze the crawled Following information and output user suggestions.
By default, search analytics runs once per day.
When a user opens the People I'm following page, the PeopleManager.GetMySuggestions() method is called. GetMySuggestions searches for new suggestions for the current user,
updates the user's suggestions in the database, and presents the suggestions on the page.

See also
Social and collaboration features in SharePoint
Get started developing with social features in SharePoint
Follow content in SharePoint
User profiles REST API reference
How to: Follow people by using the .NET client object model in SharePoint
How to: Follow people by using the JavaScript object model in SharePoint
Following people and content REST API reference for SharePoint
Follow people by using the .NET client object model in SharePoint
3/26/2018 • 5 minutes to read Edit Online

Learn how to work with Following People features by using the SharePoint .NET client object model.

Why use Following People features in SharePoint?


In SharePoint, when a user follows people, the posts and activities of the followed people show up in the user's newsfeed. By using Following People features to focus on the people who
users care about, you can improve the relevance of your app or solution. In the .NET client object model, people that you follow are represented by SocialActor objects. To perform core
Following People tasks in the .NET client object model, you use the SocialFollowingManager object. This article shows how to use the .NET client object model to work with Following People
features.
NOTE

We focus on SocialFollowingManager because it consolidates the core functionality for following people and content. However, the PeopleManager object contains additional functionality
for following people, such as the AmIFollowedBy(String) method and methods that obtain the following status of other users.

Prerequisites for setting up your development environment to work with Following People features by using the
SharePoint .NET client object model
To create a console application that uses the .NET client object model to work with Following People features, you'll need the following:
SharePoint with My Site configured, and with user profiles and personal sites created for the current user and a target user
Visual Studio 2012
Full Control access permissions to the User Profile service application for the logged-on user
NOTE

If you're not developing on the computer that is running SharePoint, get the SharePoint Client Components download that contains SharePoint client assemblies.

Create a console application in Visual Studio 2012


1. Open Visual Studio, and choose File, New, Project.
2. In the New Project dialog box, choose .NET Framework 4.5 from the drop-down list at the top of the dialog box.
3. In the Templates list, choose Windows, and then choose the Console Application template.
4. Name the project FollowPeopleCSOM, and then choose the OK button.
5. Add references to the following assemblies:
Microsoft.SharePoint.Client
Microsoft.SharePoint.ClientRuntime
Microsoft.SharePoint.Client.UserProfiles
6. Replace the contents of the Program class with the code example from one of the following scenarios:
Start and stop following people
Get followers and followed people
7. To test the console application, on the menu bar, choose Debug, Start Debugging.

Code example: Start or stop following people by using the SharePoint .NET client object model
The following code example makes the current user start following or stop following a target user. It shows how to:
Check whether the current user is following a target user by using the IsFollowed method.
Get the count of people who the current user is following by using the GetFollowedCount method.
Start following the target user by using the Follow method.
Stop following the target user by using the StopFollowing method.
This code example uses the SocialFollowResult object that is returned by the Follow method to determine whether to start or stop following the target user.
NOTE

Change the placeholder values for the serverUrl and targetUser variables before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace FollowPeopleCSOM
{
class Program
{
static ClientContext clientContext;
static SocialFollowingManager followingManager;
static void Main(string[] args)
{

// Replace the following placeholder values with the target


// server URL and target user.
const string serverUrl = "http://serverName";
const string targetUser = "domainName\\\\userName";

// Get the client context.


clientContext = new ClientContext(serverUrl);

// Get the SocialFeedManager instance.


followingManager = new SocialFollowingManager(clientContext);

// Create a SocialActorInfo object to represent the target user.


SocialActorInfo actorInfo = new SocialActorInfo();
actorInfo.AccountName = targetUser;

// Find out whether the current user is following the target user.
ClientResult<bool> isFollowed = followingManager.IsFollowed(actorInfo);

// Get the information from the server.


clientContext.ExecuteQuery();

Console.WriteLine("Was the current user following the target user? {0}\\n", isFollowed.Value);
Console.Write("Initial count: ");

// Get the current count of followed people.


WriteFollowedCount();

// Try to follow the target user. If the result is OK, then


// the request succeeded.
ClientResult<SocialFollowResult> result = followingManager.Follow(actorInfo);
clientContext.ExecuteQuery();

// If the result is AlreadyFollowing, then stop following


// the target user.
if (result.Value == SocialFollowResult.AlreadyFollowing)
{
followingManager.StopFollowing(actorInfo);
clientContext.ExecuteQuery();
}

// Handle other SocialFollowResult return values.


else if (result.Value == SocialFollowResult.LimitReached
|| result.Value == SocialFollowResult.InternalError)
{
Console.WriteLine(result.Value);
}

// Get the updated count of followed people.


Console.Write("Updated count: ");
WriteFollowedCount();
Console.ReadKey();
}

// Get the count of the people who the current user is following.
static void WriteFollowedCount()
{
ClientResult<int> followedCount = followingManager.GetFollowedCount(SocialActorTypes.Users);
clientContext.ExecuteQuery();
Console.WriteLine("The current user is following {0} people.", followedCount.Value);
}
}
}

Code example: Get followers and followed people by using the SharePoint .NET client object model
The following code example gets the people who the current user is following, gets the people who are followed by the current user, and gets information about the current user's Following
People status. It shows how to:
Check whether the current user is following a target user by using the IsFollowed method.
Get the count of people who the current user is following by using the GetFollowedCount method.
Get the people who the current user is following by using the GetFollowed method.
Get the people who are following the current user by using the GetFollowers method.
Iterate through the groups of people and get each person's display name, personal URI, and picture URI.
NOTE

Change the placeholder values for the serverUrl and targetUser variables before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace FollowPeopleCSOM
{
class Program
{
static void Main(string[] args)
{

// Replace the following placeholder values with the target


// server URL and target user.
const string serverUrl = "http://serverName";
const string targetUser = "domainName\\\\userName";

// Get the client context.


ClientContext clientContext = new ClientContext(serverUrl);

// Get the SocialFeedManager instance.


SocialFollowingManager followingManager = new SocialFollowingManager(clientContext);

// Create a SocialActorInfo object to represent the target user.


SocialActorInfo actorInfo = new SocialActorInfo();
actorInfo.AccountName = targetUser;

// Find out whether the current user is following the target user.
ClientResult<bool> isFollowed = followingManager.IsFollowed(actorInfo);

// Get the count of people who the current user is following.


ClientResult<int> followedCount = followingManager.GetFollowedCount(SocialActorTypes.Users);

// Get the people who the current user is following.


ClientResult<SocialActor[]> followedResult = followingManager.GetFollowed(SocialActorTypes.Users);

// Get the people who are following the current user.


ClientResult<SocialActor[]> followersResult = followingManager.GetFollowers();

// Get the information from the server.


clientContext.ExecuteQuery();

// Write the results to the console window.


Console.WriteLine("Is the current user following the target user? {0}\\n", isFollowed.Value);
Console.WriteLine("People who the current user is following: ({0} count)", followedCount.Value);
IterateThroughPeople(followedResult.Value);
Console.WriteLine("\\nPeople who are following the current user:");
IterateThroughPeople(followersResult.Value);
Console.ReadKey();
}

// Iterate through the people and get each person's display


// name, personal URI, and picture URI.
static void IterateThroughPeople(SocialActor[] actors)
{
foreach (SocialActor actor in actors)
{
Console.WriteLine(" - {0}", actor.Name);
Console.WriteLine("\\tPersonal URI: {0}", actor.PersonalSiteUri);
Console.WriteLine("\\tPicture URI: {0}", actor.ImageUri);
}
}
}
}

See also
Follow people in SharePoint
How to: Follow people by using the JavaScript object model in SharePoint
How to: Follow documents and sites by using the .NET client object model in SharePoint
Follow people by using the JavaScript object model in SharePoint
3/26/2018 • 6 minutes to read Edit Online

Learn how to work with Following People features by using the SharePoint JavaScript object model.

Why use Following People features in SharePoint?


In SharePoint, Following People features help users to stay connected with each other. For example, when a user follows someone, that person's posts and activities show up in the user's
newsfeed. By using Following People features to focus on the people who users care about, you can improve the relevance of your app or solution. In the JavaScript object model, people that
you follow are represented by SocialActor objects. To perform core Following People tasks in the JavaScript object model, you use the SocialFollowingManager object. This article shows
how to use the JavaScript object model to work with Following People features.
NOTE

SocialFollowingManager is the recommended API to use for following people and content. However, the PeopleManager object contains additional functionality for following people, such as
the amIFollowedBy method and methods that obtain the following status of other users.

Prerequisites for setting up your development environment to work with Following People features by using the
SharePoint JavaScript object model
To create the farm solution that uses the JavaScript object model to work with Following People features, you'll need:
SharePoint with My Site configured, and with user profiles and personal sites created for the current user and a target user
Visual Studio 2012
Office Developer Tools for Visual Studio 2012
Full Control access permissions to the User Profile service application for the logged-on user
Local administrator permissions for the logged-on user

Create a farm solution and application page in Visual Studio 2012


1. Run Visual Studio as administrator, and choose File, New, Project.
2. In the New Project dialog box, choose .NET Framework 4.5 from the drop-down list at the top of the dialog box.
3. In the Templates list, expand Office/SharePoint, choose SharePoint Solutions, and then choose the SharePoint - Empty Project template.
4. Name the project FollowPeopleJSOM, and then choose the OK button.
5. In the SharePoint Customization Wizard dialog box, choose Deploy as a farm solution, and then choose the Finish button.
6. In Solution Explorer, open the shortcut menu for the FollowPeopleJSOM project, and then add a SharePoint "Layouts" mapped folder.
7. In the Layouts folder, open the shortcut menu for the FollowPeopleJSOM folder, and then add a new SharePoint application page namedFollowPeople.aspx.
NOTE

The code examples in this article define custom code in the page markup but do not use the code-behind class that Visual Studio creates for the page.
8. Open the shortcut menu for the FollowPeople.aspx page, and then choose Set as Startup Item.
9. In the markup of the FollowPeople.aspx file, paste the following code between the "Main" asp:Content tags. This code defines controls and script references.

<span id="followResults"></span><br/><br />


<button id="sendRequest" type="button"></button><br/>
<span id="message" style="color: #FF0000;"></span>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.min.js" type="text/javascript"></script>
<SharePoint:ScriptLink name="SP.js" runat="server" ondemand="false" localizable="false" loadafterui="true" />
<SharePoint:ScriptLink name="SP.UserProfiles.js" runat="server" ondemand="false" localizable="false" loadafterui="true" />
<SharePoint:FormDigest id="FormDigest" runat="server"/>
<script type="text/javascript">
// Replace this comment with the code for your scenario.
</script>

> [!NOTE]
> The "Get followers and followed people" example doesn't use the button control or the form digest control, which is only required for operations that update server content. A form digest genera

1. Replace the comment between the script tags with the code example from one of the following scenarios:
Start or stop following people
Get followers and followed people
2. To test the solution, on the menu bar, choose Debug, Start Debugging.

Code example: Start or stop following people by using the SharePoint JavaScript object model
The following code example makes the current user start following or stop following a target user. It shows how to:
Check whether the current user is following a target user by using the isFollowed method.
Get the count of people who the current user is following by using the getFollowedCount method.
Start following the target user by using the follow method.
Stop following the target user by using the stopFollowing method.
NOTE

Paste the following code between the script tags that you added in the Create a farm solution and application page procedure. Then, change the placeholder value for the targetUser
variable before you run the code.

// Replace the placeholder value with the account name of the target user.
var targetUser = 'domain\\userName';

var clientContext;
var followingManager;
var actorInfo;
var isFollowed;
var followedCount;

// Ensure that the SP.UserProfiles.js file is loaded before running your code.
$(document).ready(function () {
SP.SOD.executeOrDelayUntilScriptLoaded(getFollowingStatus, 'SP.UserProfiles.js');
});

// Get the Following status of the current user.


function getFollowingStatus() {

// Get the current client context.


clientContext = SP.ClientContext.get_current();

// Get the SocialFeedManager instance.


followingManager = new SP.Social.SocialFollowingManager(clientContext);

// Create a SocialActorInfo object to represent the target user.


actorInfo = new SP.Social.SocialActorInfo();
actorInfo.set_accountName(targetUser);

// Find out whether the current user is following the target user.
isFollowed = followingManager.isFollowed(actorInfo);
followedCount = followingManager.getFollowedCount(1);

// Get the information from the server.


clientContext.executeQueryAsync(showFollowingStatus, requestFailed)
}

// Show the Following status of the current user.


function showFollowingStatus() {
var results = '';
results += 'Is the current user following the target user? ' + isFollowed.get_value();
results += '<br/>Total count of followed people: ' + followedCount.get_value();
$('#followResults').html(results);

// Initialize the button for this example.


$('#sendRequest').click(
function () {
$('#message').empty();
toggleFollowingStatus();
});
$('#sendRequest').text('Toggle following status');
}

// Follow or stop following the target user.


function toggleFollowingStatus() {
if (isFollowed.get_value() === false) {
followingManager.follow(actorInfo);
}
else if (isFollowed.get_value() === true) {
followingManager.stopFollowing(actorInfo);
}
clientContext.executeQueryAsync(getFollowingStatus, requestFailed);
}

// Failure callback.
function requestFailed(sender, args) {
$('#message').html('Error: ' + args.get_message());
}

Code example: Get followers and followed people by using the SharePoint JavaScript object model
The following code example gets the people who the current user is following and gets the people who are followed by the current user. It shows how to:
Get the people who the current user is following by using the getFollowed method.
Get the people who are following the current user by using the getFollowers method and passing 1 to represent User actor types.
Iterate through the groups of people and get each person's display name, personal site URI, and picture URI.
NOTE

Paste the following code between the script tags that you added in the Create a farm solution and application page procedure.
var followed;
var followers;

// Ensure that the SP.UserProfiles.js file is loaded before running your code.
$(document).ready(function () {
SP.SOD.executeOrDelayUntilScriptLoaded(getFollowedAndFollowers, 'SP.UserProfiles.js');

// Hide the button for this example.


$('#sendRequest').hide();
});

// Get the Following status of the current user.


function getFollowedAndFollowers() {

// Get the current client context.


var clientContext = SP.ClientContext.get_current();

// Get the SocialFeedManager instance.


var followingManager = new SP.Social.SocialFollowingManager(clientContext);

// Get followed people and followers.


followers = followingManager.getFollowers();
followed = followingManager.getFollowed(1);

// Send the request to the server.


clientContext.executeQueryAsync(showFollowedAndFollowers, requestFailed)
}

// Show the Following status of the current user.


function showFollowedAndFollowers() {
var results = 'The current user is following ' + followed.length + ' people: <br/>';

for (var i = 0; i < followed.length; i++) {


var user = followed[i];
var name = user.get_name();
var personalSiteUri = user.get_personalSiteUri();
var pictureUri = user.get_imageUri();

results += '<br/>' + name + '<br/>' + personalSiteUri + '<br/>' + pictureUri + '<br/>';


}

results += '<br/>The current user is followed by ' + followers.length + ' people: <br/>';

for (var i = 0; i < followers.length; i++) {


var user = followers[i];
var name = user.get_name();
var personalSiteUri = user.get_personalSiteUri();
var pictureUri = user.get_imageUri();

results += '<br/>' + name + '<br/>' + personalSiteUri + '<br/>' + pictureUri + '<br/>';


}
$('#followResults').html(results);
}

// Failure callback.
function requestFailed(sender, args) {
$('#message').html('Error: ' + args.get_message());
}

See also
Follow people in SharePoint
How to: Follow people by using the .NET client object model in SharePoint
Follow content in SharePoint
3/26/2018 • 4 minutes to read Edit Online

Learn about common programming tasks for following content (documents, sites, and tags) in SharePoint.

APIs for following content in SharePoint


When users follow documents, sites, or tags, status updates from documents, conversations on sites, and notifications of tag use show up in their newsfeed. The features related to following
content can be seen on the Newsfeed and the Following content pages.
SharePoint provides the following APIs that you can use to programmatically follow content:
Client object models for managed code
.NET client object model
Silverlight client object model
Mobile client object model
JavaScript object model
Representational State Transfer (REST) service
Server object model
As a best practice in SharePoint development, use client APIs when you can. Client APIs include the client object models, a JavaScript object model, and a REST service. For more
information about the APIs in SharePoint and when to use them, see Choose the right API set in SharePoint.
Each API includes a manager object that you use to perform core tasks for following content.
NOTE

The same APIs are used to follow people. See Follow people in SharePoint for an overview of Following People tasks.
Table 1 shows the manager and other key objects (or REST resources) in the APIs and the class library (or access point) where you can find them.
NOTE

The Silverlight and mobile client object models are not included in Table 1 or Table 2 because they provide the same core functionality as the .NET client object model and use the same
signatures. The Silverlight client object model is defined in Microsoft.SharePoint.Client.UserProfiles.Silverlight.dll, and the mobile client object model is defined in
Microsoft.SharePoint.Client.UserProfiles.Phone.dll.
Table 1. SharePoint APIs used for following content programmatically

API K EY O B JECTS

.NET client object model Manager object: SocialFollowingManager


See: How to: Follow documents and sites by using the .NET client object model in SharePoint Primary namespace: Microsoft.SharePoint.Client.Social
Other key objects: SocialActor , SocialActorInfo , SocialActorType , SocialActorTypes
Class library: Microsoft.SharePoint.Client.UserProfiles.dll

JavaScript object model Manager object: SocialFollowingManager


Primary namespace: SP.Social
Other key objects: SocialActor, SocialActorInfo, SocialActorType, SocialActorTypes
Class library: SP.UserProfiles.js

REST service Manager resource: social.following


See How to: Follow documents, sites, and tags by using the REST service in SharePoint Primary namespace (OData): sp.social.SocialRestFollowingManager
Other key resources: SocialActor, SocialActorInfo, SocialActorType, SocialActorTypes
Access point: <siteUri>/_api/social.following

Server object model Manager object: SPSocialFollowingManager


Primary namespace: Microsoft.Office.Server.Social
Other key objects: SPSocialActor , SPSocialActorInfo , SPSocialActorType , SPSocialActorTypes
Class library: Microsoft.Office.Server.UserProfiles.dll

Common programming tasks for following content in SharePoint


Table 2 shows common programming tasks for following content and the members that you use to perform them. Members are from the .NET client object model (CSOM), JavaScript object
model (JSOM), REST service, and server object model (SSOM).
NOTE

The same APIs are used to follow people. See Follow people in SharePoint for an overview of Following People tasks.
Table 2. API for common tasks for following content in SharePoint

TAS K MEMB ER S

Create an instance of a manager object in the context of the current user CSOM: SocialFollowingManager
JSOM: SocialFollowingManager
REST: <siteUri>/_api/social.following
SSOM: SPSocialFollowingManager

Create an instance of a manager object in the context of a specified user CSOM: not implemented
JSOM: not implemented
REST: not implemented
SSOM: SPSocialFollowingManager (overloaded)
TAS K MEMB ER S

Have the current user start following (stop following) an item CSOM: Follow ( StopFollowing )
JSOM: follow ( stopFollowing)
REST: POST <siteUri>/_api/social.following/Follow (
<siteUri>/_api/social.following/StopFollowing ) and pass the actor parameter in the request body
SSOM: Follow ( StopFollowing )

Find out whether the current user is following a particular item CSOM: IsFollowed
JSOM: isFollowed
REST: POST <siteUri>/_api/social.following/IsFollowed and pass the actor parameter in the
request body
SSOM: IsFollowed

Get the documents, sites, and/or tags that the current user is following CSOM: GetFollowed
JSOM: getFollowed
REST: GET <siteUri>/_api/social.following/my/Followed(types=2) (documents = 2, sites = 4, tags
= 8.md)
SSOM: GetFollowed

Get the count of documents, sites, and/or tags that the user is following CSOM: GetFollowedCount
JSOM: getFollowedCount
REST: GET <siteUri>/_api/social.following/my/FollowedCount(types=2) (documents = 2, sites =
4, tags = 8.md)
SSOM: GetFollowedCount

Get the URI of the site that lists the current user's followed documents CSOM: FollowedDocumentsUri
JSOM: followedDocumentsUri
REST: GET <siteUri>/_api/social.following/my/FollowedDocumentsUri
SSOM: FollowedDocumentsUri

Get the URI of the site that lists the current user's followed sites CSOM: FollowedSitesUri
JSOM: followedSitesUri
REST: GET <siteUri>/_api/social.following/my/FollowedSitesUri
SSOM: FollowedSitesUri
NOTE

For examples that show how to use the REST service to follow content, see How to: Follow documents, sites, and tags by using the REST service in SharePoint.

How to get a tag's GUID based on the tag's name by using the JavaScript object model
To start and stop following a tag or to find out whether the current user is following it, you need to use the tag's GUID. The following code shows how to get the GUID based on the tag
name.
Before you run the code, you need to add a reference to sp.taxonomy.js and change the placeholder tag name with the name of an existing tag.

function getTagGuid() {
var tagName = '#tally';
var clientContext = new SP.ClientContext.get_current();
var label = SP.Taxonomy.LabelMatchInformation.newObject(clientContext);
label.set_termLabel(tagName);
label.set_trimUnavailable(false);
var taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(clientContext);
var termStore = taxSession.getDefaultKeywordsTermStore();
var termSet = termStore.get_hashTagsTermSet();
terms = termSet.getTerms(label);
clientContext.load(terms);
clientContext.executeQueryAsync(
function () {
var tag = terms.get_item(0);
if (tag !== null) {
var tagGuid = tag.get_id().toString();
if (!SP.ScriptUtility.isNullOrEmptyString(tagGuid)) {
alert(tagGuid);
}
}
},
function (sender, args) {
alert(args.get_message());
}
);
}

See also
How to: Follow documents and sites by using the .NET client object model in SharePoint
How to: Follow documents, sites, and tags by using the REST service in SharePoint
Following people and content REST API reference for SharePoint
Social and collaboration features in SharePoint
Get started developing with social features in SharePoint
Follow people in SharePoint
Follow documents and sites by using the .NET client object model in SharePoint
3/26/2018 • 6 minutes to read Edit Online

Learn how to work with Following Content features by using the SharePoint .NET client object model.

How do I use the .NET client object model to follow content?


SharePoint users can follow documents, sites, and tags can follow documents, sites, and tags to get updates about the items in their newsfeeds and to quickly open followed documents and
sites. You can use the .NET client object model in your app or solution to start following content, stop following content, and get followed content on behalf of the current user. This article
shows you how to create a console application that uses the .NET client object model to work with Following Content features for documents and sites.
The following objects are the primary APIs for Following Content tasks:
SocialFollowingManager provides methods for managing a user's list of followed actors.
SocialActor represents a document, site, or tag that the server returns in response to a client-side request.
SocialActorInfo specifies a document, site, or tag in client-side requests to the server.
Microsoft.SharePoint.Client.Social.SocialActorType and Microsoft.SharePoint.Client.Social.SocialActorTypes specify content types in client-side requests to the server.
NOTE

You also use these APIs for Following People tasks, but the GetSuggestions and GetFollowers methods available from SocialFollowingManager only support following people, not
content. For more information about how you can use SocialFollowingManager , see Follow content in SharePoint and Follow people in SharePoint. For code examples that show how to
follow people, see How to: Follow people by using the .NET client object model in SharePoint.

Prerequisites for setting up your development environment to work with Following Content features by using the
SharePoint .NET client object model
To create a console application that uses the .NET client object model to work with Following Content features for documents and sites, you'll need the following:
SharePoint with My Site configured, with the My Site site created for the current user, and with a document uploaded to a SharePoint document library
Visual Studio 2012
Full Control access permissions to the User Profile service application for the logged-on user
NOTE

If you are not developing on the computer that is running SharePoint, get the SharePoint Client Components download that contains SharePoint client assemblies.

Create a console application to work with Following Content features by using the SharePoint .NET client object
model
1. In Visual Studio, choose File, New, Project.
2. In the New Project dialog box, choose .NET Framework 4.5 from the drop-down list at the top of the dialog box.
3. In the Templates list, choose Windows, and then choose the Console Application template.
4. Name the project FollowContentCSOM, and then choose the OK button.
5. Add references to the following assemblies:
Microsoft.SharePoint.Client
Microsoft.SharePoint.ClientRuntime
Microsoft.SharePoint.Client.UserProfiles
6. Replace the contents of the Program class with the code example from one of the following scenarios:
Start and stop following content
Get followed content for the current user
7. To test the console application, on the menu bar, choose Debug, Start Debugging.

Code example: Start and stop following content by using the SharePoint .NET client object model
The following code example makes the current user start following or stop following a target item. It shows how to:
Check whether the current user is following a particular document or site by using the IsFollowed method.
Start following a document or site by using the Follow method.
Stop following a document or site by using the StopFollowing method.
Get the count of documents or sites that the current user is following by using the GetFollowedCount method.
This code example uses the SocialFollowResult object that is returned by the Follow method to determine whether to start or stop following the target item.
NOTE

Change the placeholder values for the serverUrl and contentUrl variables before you run the code. To use a site instead of a document, use the variables that are commented out.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace FollowContentCSOM
{
class Program
{
static ClientContext clientContext;
static SocialFollowingManager followingManager;
static void Main(string[] args)
{

// Replace the following placeholder values with the URL of the target
// server and target document (or site).
const string serverUrl = "http://serverName";
const string contentUrl = @"http://serverName/libraryName/fileName";
const SocialActorType contentType = SocialActorType.Document;
// Do not use a trailing '/' for a subsite.
//const string contentUrl = @"http://serverName/subsiteName";
//const SocialActorType contentType = SocialActorType.Site;

// Get the client context.


clientContext = new ClientContext(serverUrl);

// Get the SocialFeedManager instance.


followingManager = new SocialFollowingManager(clientContext);

// Create a SocialActorInfo object to represent the target item.


SocialActorInfo actorInfo = new SocialActorInfo();
actorInfo.ContentUri = contentUrl;
actorInfo.ActorType = contentType;

// Find out whether the current user is following the target item.
ClientResult<bool> isFollowed = followingManager.IsFollowed(actorInfo);

// Get the information from the server.


clientContext.ExecuteQuery();

Console.WriteLine("Was the current user following the target {0}? {1}\\n",


actorInfo.ActorType.ToString().ToLower(), isFollowed.Value);
Console.Write("Initial count: ");

// Get the current count of followed items.


WriteFollowedCount(actorInfo.ActorType);

// Try to follow the target item. If the result is OK, then


// the request succeeded.
ClientResult<SocialFollowResult> result = followingManager.Follow(actorInfo);
clientContext.ExecuteQuery();

// If the result is AlreadyFollowing, then stop following


// the target item.
if (result.Value == SocialFollowResult.AlreadyFollowing)
{
followingManager.StopFollowing(actorInfo);
clientContext.ExecuteQuery();
}

// Handle other SocialFollowResult return values.


else if (result.Value == SocialFollowResult.LimitReached
|| result.Value == SocialFollowResult.InternalError)
{
Console.WriteLine(result.Value);
}

// Get the updated count of followed items.


Console.Write("Updated count: ");
WriteFollowedCount(actorInfo.ActorType);
Console.ReadKey();
}

// Get the count of the items that the current user is following.
static void WriteFollowedCount(SocialActorType type)
{

// Set the parameter for the GetFollowedCount method, and


// handle the case where the item is a site.
SocialActorTypes types = SocialActorTypes.Documents;
if (type != SocialActorType.Document)
{
types = SocialActorTypes.Sites;
}

ClientResult<int> followedCount = followingManager.GetFollowedCount(types);


clientContext.ExecuteQuery();
Console.WriteLine("{0} followed {1}", followedCount.Value, types.ToString().ToLower());
}
}
}

Code example: Get followed content by using the SharePoint .NET client object model
The following code example gets the documents and sites that the current user is following and gets information about the user's Following Content status. It shows how to:
Check whether the current user is following the target document and site by using the IsFollowed method.
Get the count of documents and sites that the current user is following by using the GetFollowedCount method.
Get the documents and sites that the current user is following by using the GetFollowed method.
Iterate through the groups of content and get each item's name, content URI, and URI.
NOTE

Change the placeholder value for the serverUrl, docContentUrl, and siteContentUrl variables before you run the code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Social;

namespace FollowContentCSOM
{
class Program
{
static void Main(string[] args)
{

// Replace the following placeholder values with the URLs of


// the target server, document, and site.
const string serverUrl = "http://serverName";
const string docContentUrl = @"http://serverName/libraryName/fileName";
const string siteContentUrl = @"http://serverName/subsiteName"; // do not use a trailing '/' for a subsite

// Get the client context.


ClientContext clientContext = new ClientContext(serverUrl);

// Get the SocialFollowingManager instance.


SocialFollowingManager followingManager = new SocialFollowingManager(clientContext);

// Create SocialActorInfo objects to represent the target


// document and site.
SocialActorInfo docActorInfo = new SocialActorInfo();
docActorInfo.ContentUri = docContentUrl;
docActorInfo.ActorType = SocialActorType.Document;
SocialActorInfo siteActorInfo = new SocialActorInfo();
siteActorInfo.ContentUri = siteContentUrl;
siteActorInfo.ActorType = SocialActorType.Site;

// Find out whether the current user is following the target


// document and site.
ClientResult<bool> isDocFollowed = followingManager.IsFollowed(docActorInfo);
ClientResult<bool> isSiteFollowed = followingManager.IsFollowed(siteActorInfo);

// Get the count of documents and sites that the current


// user is following.
ClientResult<int> followedDocCount = followingManager.GetFollowedCount(SocialActorTypes.Documents);
ClientResult<int> followedSiteCount = followingManager.GetFollowedCount(SocialActorTypes.Sites);

// Get the documents and the sites that the current user
// is following.
ClientResult<SocialActor[]> followedDocResult = followingManager.GetFollowed(SocialActorTypes.Documents);
ClientResult<SocialActor[]> followedSiteResult = followingManager.GetFollowed(SocialActorTypes.Sites);

// Get the information from the server.


clientContext.ExecuteQuery();

// Write the results to the console window.


Console.WriteLine("Is the current user following the target document? {0}", isDocFollowed.Value);
Console.WriteLine("Is the current user following the target site? {0}", isSiteFollowed.Value);
if (followedDocCount.Value > 0)
{
IterateThroughContent(followedDocCount.Value, followedDocResult.Value);
} if (followedSiteCount.Value > 0)
{
IterateThroughContent(followedSiteCount.Value, followedSiteResult.Value);
}
Console.ReadKey();
}

// Iterate through the items and get each item's display


// name, content URI, and absolute URI.
static void IterateThroughContent(int count, SocialActor[] actors)
{
SocialActorType actorType = actors[0].ActorType;
Console.WriteLine("\\nThe current user is following {0} {1}s:", count, actorType.ToString().ToLower());
foreach (SocialActor actor in actors)
{
Console.WriteLine(" - {0}", actor.Name);
Console.WriteLine("\\tContent URI: {0}", actor.ContentUri);
Console.WriteLine("\\tURI: {0}", actor.Uri);
}
}
}
}

See also
Follow content in SharePoint
How to: Follow documents, sites, and tags by using the REST service in SharePoint
How to: Follow people by using the .NET client object model in SharePoint
Follow documents, sites, and tags by using the REST service in SharePoint
5/3/2018 • 16 minutes to read Edit Online

Create SharePoint-hosted apps that use the REST service to follow content (documents, sites, and tags) and to get followed content.

How do I use the SharePoint REST service to follow content?


SharePoint users can follow documents, sites, and tags to get updates about the items in their newsfeeds and to quickly open followed documents and sites. You can use the SharePoint
REST API in your app or solution to start following content, stop following content, and get followed content on behalf of the current user.
The following REST resources are the primary API for Following Content tasks:
SocialRestFollowingManager provides methods for managing a user's list of followed actors.
SocialActor represents a document, site, or tag that the server returns in response to a client-side request.
SocialActorInfo specifies a document, site, or tag in client-side requests to the server.
SocialActorType and SocialActorTypes specify content types in client-side requests to the server.
To perform Following Content tasks by using the REST API, you send HTTP GET and HTTP POST requests to the REST service. REST endpoint URIs for Following Content tasks begin with
the SocialRestFollowingManager resource ( <siteUri>/_api/social.following ) and end with one of the following resources:
follow to start following a document, site, or tag
stopfollowing to stop following a document, site, or tag
isfollowed to find out whether the user is following a specific document, site, or tag
my/followed to get followed documents, sites, and tags
my/followedcount to get the count of followed documents, sites, and tags
NOTE

You also use these endpoints for Following People tasks, but the followers and suggestions resources available from SocialRestFollowingManager only support following people, not
content. For more information about how you can use SocialRestFollowingManager, see Follow content in SharePoint and Follow people in SharePoint.

Prerequisites for creating a SharePoint-hosted app that manages followed content by using the SharePoint REST
service
This article assumes that you create the SharePoint Add-in by using Napa on an Office 365 Developer Site. If you're using this development environment, you've already met the
prerequisites.
NOTE

Go to Set up a development environment for SharePoint Add-ins on Office 365 to sign up for a Developer Site and start using Napa.
If you're not using Napa on an Office 365 Developer Site, you'll need to meet the following prerequisites before you can deploy the SharePoint Add-in:
A SharePoint development environment that is configured for app isolation. If you're developing remotely, the server must support sideloading of apps or you must install the app on
a Developer Site.
The My Site host configured, with a personal site created for the current user.
Visual Studio 2012 or Visual Studio 2013 with Office Developer Tools for Visual Studio 2013.
Sufficient permissions for the logged-on user:
Local administrator permissions on the development computer.
Manage website and Create Subsites user permissions to the SharePoint site where you're installing the app. By default, these permissions are available only to users who have
the Full Control permission level or who are in the site Owners group.
You must be logged on as someone other than the system account. The system account does not have permission to install the app.
NOTE

See Set up an on-premises development environment for SharePoint Add-ins for guidance about on-premises setup (including how to disable the loopback check, if necessary).

Create the SharePoint Add-in project


1. On your Developer Site, open Napa, and then choose Add New Project.
2. Choose the App for SharePoint template, name the project, and then choose the Create button.
3. Set the permissions for your app:
a. Choose the Properties button at the bottom of the page.
b. In the Properties window, choose Permissions.
c. In the Content category, set Write permissions for the Tenant scope.
d. In the Social category, set Read permissions for the User Profiles scope.
e. Close the Properties window.
4. Expand the Scripts node, choose the App.js file and replace its contents with the code from one of the following scenarios:
Start following and stop following a document
Start following and stop following a site
Start following and stop following a tag
Get followed content
5. To run the app, choose the Run Project button at the bottom of the page.
6. In the Do you trust page that opens, choose the Trust It button. The app page opens and runs the code. To debug the page, choose the F12 key and then choose App.js on the Script
tab.

Code example: Start following and stop following a document by using the SharePoint REST service
The following code example represents the contents of the App.js file and shows how to:
Get the app web URI from the query string and construct the <siteUri>/_api/social.following endpoint URI.
Build and send a POST request to the isfollowed endpoint to find out whether the current user is already following a specified document.
Build and send a POST request to the follow endpoint to start following the document.
Build and send a POST request to the stopfollowing endpoint to stop following the document.
Read the JSON response returned by the isfollowed request and the follow request. (The stopfollowing request doesn't return anything in the response.) See Example JSON
responses.
Before you run the code, you'll need to upload a document and change the placeholder value for the documentUrl variable to the document's URL.

// Replace the documentUrl placeholder value before you run the code.
var documentUrl = "https://domain.sharepoint.com/Shared%20Documents/fileName.docx";
var followingManagerEndpoint;

// Get the SPAppWebUrl parameter from the query string and build
// the Following manager endpoint.
$(document).ready(function () {
var appweburl;
var params = document.URL.split("?")[1].split("&amp;");
for (var i = 0; i < params.length; i = i + 1) {
var param = params[i].split("=");
if (param[0] === "SPAppWebUrl") appweburl = param[1];
}
followingManagerEndpoint = decodeURIComponent(appweburl) + "/_api/social.following";
isFollowed();
});

// Check whether the current user is already following the document.


// The request body includes a SocialActorInfo object that represents
// the specified item.
// The success function reads the response from the REST service and then
// toggles the user's following status by calling the appropriate method.
function isFollowed() {
$.ajax( {
url: followingManagerEndpoint + "/isfollowed",
type: "POST",
data: JSON.stringify( {
"actor": {
"__metadata": {
"type":"SP.Social.SocialActorInfo"
},
"ActorType":1,
"ContentUri":documentUrl,
"Id":null
}
}),
headers: {
"accept":"application/json;odata=verbose",
"content-type":"application/json;odata=verbose",
"X-RequestDigest":$("#__REQUESTDIGEST").val()
},
success: function (responseData) {
stringData = JSON.stringify(responseData);
jsonObject = JSON.parse(stringData);
if (jsonObject.d.IsFollowed === true ) {
alert('The user is currently following the document.');
stopFollowDocument();
}
else {
alert('The user is currently NOT following the document.');
followDocument();
}
},
error: requestFailed
});
}

// Make the current user start following a document.


// The request body includes a SocialActorInfo object that represents
// the document to follow.
// The success function reads the response from the REST service.
function followDocument() {
$.ajax( {
url: followingManagerEndpoint + "/follow",
type: "POST",
data: JSON.stringify( {
"actor": {
"__metadata": {
"type":"SP.Social.SocialActorInfo"
},
"ActorType":1,
"ContentUri":documentUrl,
"Id":null
}
} ),
headers: {
"accept":"application/json;odata=verbose",
"content-type":"application/json;odata=verbose",
"X-RequestDigest":$("#__REQUESTDIGEST").val()
},
success: function (responseData) {
stringData = JSON.stringify(responseData);
jsonObject = JSON.parse(stringData);
var statusMessage = {
0 : 'The user has started following the document. ',
1 : 'The user is already following the document. ',
2 : 'An internal limit was reached. ',
3 : 'An internal error occurred. '
}
alert(statusMessage[jsonObject.d.Follow] + 'Status code = ' + jsonObject.d.Follow);
},
error: requestFailed
} );
}

// Make the current user stop following a document.


// The request body includes a SocialActorInfo object that represents
// the document to stop following.
function stopFollowDocument() {
$.ajax( {
url: followingManagerEndpoint + "/stopfollowing",
type: "POST",
data: JSON.stringify( {
"actor": {
"__metadata": {
"type":"SP.Social.SocialActorInfo"
},
"ActorType":1,
"ContentUri":documentUrl,
"Id":null
}
} ),
headers: {
"accept":"application/json;odata=verbose",
"content-type":"application/json;odata=verbose",
"X-RequestDigest":$("#__REQUESTDIGEST").val()
},
success: function () {
alert('The user has stopped following the document.');
},
error: requestFailed
} );
}

function requestFailed(xhr, ajaxOptions, thrownError) {


alert('Error:\\n' + xhr.status + '\\n' + thrownError + '\\n' + xhr.responseText);
}

Code example: Start following and stop following a site by using the SharePoint REST service
The following code example represents the contents of the App.js file and shows how to:
Get the app web URI from the query string and construct the <siteUri>/_api/social.following endpoint URI.
Build and send a POST request to the isfollowed endpoint to find out whether the current user is already following a specified site.
Build and send a POST request to the follow endpoint to start following the site.
Build and send a POST request to the stopfollowing endpoint to stop following the site.
Read the JSON response returned by the isfollowed request and the follow request. (The stopfollowing request doesn't return anything in the response.) See Example JSON
responses.
Before you run the code, change the placeholder value for the siteUrl variable to match the site that you want to follow. Use the format http://server/siteCollection/site for a site in a site
collection. You can follow a site from any page or library in that site. If the site uses a template that doesn't support following (like the My Site host or a personal site), you'll get an
UnsupportedSite error (error code 10).

// Replace the siteUrl placeholder value before you run the code.
var siteUrl = "https://domain.sharepoint.com";
var followingManagerEndpoint;

// Get the SPAppWebUrl parameter from the query string and build
// the Following manager endpoint.
$(document).ready(function () {
var appweburl;
var params = document.URL.split("?")[1].split("&amp;");
for (var i = 0; i < params.length; i = i + 1) {
var param = params[i].split("=");
if (param[0] === "SPAppWebUrl") appweburl = param[1];
}
followingManagerEndpoint = decodeURIComponent(appweburl) + "/_api/social.following";
isFollowed();
});

// Check whether the current user is already following the site.


// The request body includes a SocialActorInfo object that represents
// the specified item.
// The success function reads the response from the REST service and then
// toggles the user's following status by calling the appropriate method.
function isFollowed() {
$.ajax( {
url: followingManagerEndpoint + "/isfollowed",
type: "POST",
data: JSON.stringify( {
"actor": {
"__metadata": {
"type":"SP.Social.SocialActorInfo"
},
"ActorType":2,
"ContentUri":siteUrl,
"ContentUri":siteUrl,
"Id":null
}
}),
headers: {
"accept":"application/json;odata=verbose",
"content-type":"application/json;odata=verbose",
"X-RequestDigest":$("#__REQUESTDIGEST").val()
},
success: function (responseData) {
stringData = JSON.stringify(responseData);
jsonObject = JSON.parse(stringData);
if (jsonObject.d.IsFollowed === true ) {
alert('The user is currently following the site.');
stopFollowSite();
}
else {
alert('The user is currently NOT following the site.');
followSite();
}
},
error: requestFailed
});
}

// Make the current user start following a site.


// The request body includes a SocialActorInfo object that represents
// the site to follow.
// The success function reads the response from the REST service.
function followSite() {
$.ajax( {
url: followingManagerEndpoint + "/follow",
type: "POST",
data: JSON.stringify( {
"actor": {
"__metadata": {
"type":"SP.Social.SocialActorInfo"
},
"ActorType":2,
"ContentUri":siteUrl,
"Id":null
}
} ),
headers: {
"accept":"application/json;odata=verbose",
"content-type":"application/json;odata=verbose",
"X-RequestDigest":$("#__REQUESTDIGEST").val()
},
success: function (responseData) {
stringData = JSON.stringify(responseData);
jsonObject = JSON.parse(stringData);
var statusMessage = {
0 : 'The user has started following the site. ',
1 : 'The user is already following the site. ',
2 : 'An internal limit was reached. ',
3 : 'An internal error occurred. '
}
alert(statusMessage[jsonObject.d.Follow] + 'Status code = ' + jsonObject.d.Follow);
},
error: requestFailed
} );
}

// Make the current user stop following a site.


// The request body includes a SocialActorInfo object that represents
// the site to stop following.
function stopFollowSite() {
$.ajax( {
url: followingManagerEndpoint + "/stopfollowing",
type: "POST",
data: JSON.stringify( {
"actor": {
"__metadata": {
"type":"SP.Social.SocialActorInfo"
},
"ActorType":2,
"ContentUri":siteUrl,
"Id":null
}
} ),
headers: {
"accept":"application/json;odata=verbose",
"content-type":"application/json;odata=verbose",
"X-RequestDigest":$("#__REQUESTDIGEST").val()
},
success: function () {
alert('The user has stopped following the site.');
},
error: requestFailed
} );
}

function requestFailed(xhr, ajaxOptions, thrownError) {


alert('Error:\\n' + xhr.status + '\\n' + thrownError + '\\n' + xhr.responseText);
}

Code example: Start following and stop following a tag by using the SharePoint REST service
The following code example represents the contents of the App.js file and shows how to:
Get the app web URI from the query string and construct the <siteUri>/_api/social.following endpoint URI.
Build and send a POST request to the isfollowed endpoint to find out whether the current user is already following a specified tag.
Build and send a POST request to the follow endpoint to start following the tag.
Build and send a POST request to the stopfollowing endpoint to stop following the tag.
Read the JSON response returned by the isfollowed request and the follow request. (The stopfollowing request doesn't return anything in the response.) For more information,
see Example JSON responses.
Before you run the code, change the placeholder value for the tagGuid variable to the GUID of an existing tag. The taxonomy API that you use to retrieve a tag from the HashTagsTermSet
doesn't have a REST interface, so you have to use the .NET client object model or the JavaScript object model. See How to get a tag's GUID based on the tag's name by using the JavaScript
object model for an example.

// Replace the tagGuid placeholder value before you run the code.
var tagGuid = "19a4a484-c1dc-4bc5-8c93-bb96245ce928";
var followingManagerEndpoint;

// Get the SPAppWebUrl parameter from the query string and build
// the Following manager endpoint.
$(document).ready(function () {
var appweburl;
var params = document.URL.split("?")[1].split("&amp;");
for (var i = 0; i < params.length; i = i + 1) {
var param = params[i].split("=");
if (param[0] === "SPAppWebUrl") appweburl = param[1];
}
followingManagerEndpoint = decodeURIComponent(appweburl) + "/_api/social.following";
isFollowed();
});

// Check whether the current user is already following the tag.


// The request body includes a SocialActorInfo object that represents
// the specified item.
// The success function reads the response from the REST service and then
// toggles the user's following status by calling the appropriate method.
function isFollowed() {
$.ajax( {
url: followingManagerEndpoint + "/isfollowed",
type: "POST",
data: JSON.stringify( {
"actor": {
"__metadata": {
"type":"SP.Social.SocialActorInfo"
},
"ActorType":3,
"TagGuid":tagGuid,
"Id":null
}
}),
headers: {
"accept":"application/json;odata=verbose",
"content-type":"application/json;odata=verbose",
"X-RequestDigest":$("#__REQUESTDIGEST").val()
},
success: function (responseData) {
stringData = JSON.stringify(responseData);
jsonObject = JSON.parse(stringData);
if (jsonObject.d.IsFollowed === true ) {
alert('The user is currently following the tag.');
stopFollowTag();
}
else {
alert('The user is currently NOT following the tag.');
followTag();
}
},
error: requestFailed
});
}

// Make the current user start following a tag.


// The request body includes a SocialActorInfo object that represents
// the tag to follow.
// The success function reads the response from the REST service.
function followTag() {
$.ajax( {
url: followingManagerEndpoint + "/follow",
type: "POST",
data: JSON.stringify( {
"actor": {
"__metadata": {
"type":"SP.Social.SocialActorInfo"
},
"ActorType":3,
"TagGuid":tagGuid,
"Id":null
}
} ),
headers: {
"accept":"application/json;odata=verbose",
"content-type":"application/json;odata=verbose",
"X-RequestDigest":$("#__REQUESTDIGEST").val()
},
success: function (responseData) {
stringData = JSON.stringify(responseData);
jsonObject = JSON.parse(stringData);
var statusMessage = {
0 : 'The user has started following the tag. ',
1 : 'The user is already following the tag. ',
2 : 'An internal limit was reached. ',
3 : 'An internal error occurred. '
}
alert(statusMessage[jsonObject.d.Follow] + 'Status code = ' + jsonObject.d.Follow);
},
error: requestFailed
} );
}

// Make the current user stop following a tag.


// The request body includes a SocialActorInfo object that represents
// the tag to stop following.
function stopFollowTag() {
$.ajax( {
url: followingManagerEndpoint + "/stopfollowing",
type: "POST",
data: JSON.stringify( {
"actor": {
"__metadata": {
"type":"SP.Social.SocialActorInfo"
},
"ActorType":3,
"TagGuid":tagGuid,
"Id":null
}
} ),
headers: {
"accept":"application/json;odata=verbose",
"content-type":"application/json;odata=verbose",
"X-RequestDigest":$("#__REQUESTDIGEST").val()
},
success: function () {
alert('The user has stopped following the tag.');
},
error: requestFailed
} );
}

function requestFailed(xhr, ajaxOptions, thrownError) {


alert('Error:\\n' + xhr.status + '\\n' + thrownError + '\\n' + xhr.responseText);
}

Code example: Get followed content by using the SharePoint REST service
The following code example represents the contents of the App.js file and shows how to:
Get the app web URI from the query string and construct the <siteUri>/_api/social.following endpoint URI.
Build and send a GET request to the my/followedcount endpoint to get the count of content that the current user is following.
Build and send a GET request to the my/followed endpoint to get the content that the current user is following.
Read the JSON response returned by the requests. See Example JSON responses.
var followingManagerEndpoint;
var followedCount;

// Get the SPAppWebUrl parameter from the query string and build
// the following manager endpoint.
$(document).ready(function () {
var appweburl;
var params = document.URL.split("?")[1].split("&amp;");
for (var i = 0; i < params.length; i = i + 1) {
var param = params[i].split("=");
if (param[0] === "SPAppWebUrl") appweburl = param[1];
}
followingManagerEndpoint = decodeURIComponent(appweburl)+ "/_api/social.following";
getMyFollowedCount();
} );

// Get the count of content that the current user is following.


// The "types=14" parameter specifies all content types
// (documents = 2 + sites = 4 + tags = 8).
function getMyFollowedCount() {
$.ajax( {
url: followingManagerEndpoint + "/my/followedcount(types=14)",
headers: {
"accept": "application/json;odata=verbose"
},
success: function (data) {
followedCount = data.d.FollowedCount;
getMyFollowedContent();
},
error: requestFailed
} );
}

// Get the content that the current user is following.


// The "types=14" parameter specifies all content types
// (documents = 2 + sites = 4 + tags = 8).
function getMyFollowedContent() {
$.ajax( {
url: followingManagerEndpoint + "/my/followed(types=14)",
headers: {
"accept": "application/json;odata=verbose"
},
success: followedContentRetrieved,
error: requestFailed
});
}

// Parse the JSON data and iterate through the collection.


function followedContentRetrieved(data) {
var stringData = JSON.stringify(data);
var jsonObject = JSON.parse(stringData);
var types = {
1: "document",
2: "site",
3: "tag"
};

var followedActors = jsonObject.d.Followed.results;


var followedList = "You're following " + followedCount + " items:";
for (var i = 0; i < followedActors.length; i++) {
var actor = followedActors[i];
followedList += "<p>The " + types[actor.ActorType] + ": \\"" +
actor.Name + "\\"</p>";
}
$("#message").html(followedList);
}

function requestFailed(xhr, ajaxOptions, thrownError) {


alert('Error:\\n' + xhr.status + '\\n' + thrownError + '\\n' + xhr.responseText);
}

Example JSON responses for Following Content requests


By default, the REST service returns responses that are formatted by using the Atom protocol, but you can request the JSON format by using an HTTP Accept header (for example:
"accept":"application/json;odata=verbose" ). The response data is returned as a string, and you can use the JSON.stringify function and JSON.parse function to convert the string into an
object, as shown in the previous code examples.
To troubleshoot an error returned by the REST service, in debug mode, look at the responseText property, as shown in the requestFailed callback functions in the previous examples. You
can also get the correlation ID for the ULS server log from a network sniffer or HTTP debugger, such as Fiddler. The correlation ID is the same as the request ID in the HTTP response.

Example response for the Follow endpoint


In response to client-side requests to the follow endpoint, the REST service returns a SocialFollowResult value that represents whether the Follow request succeeded.
The following response represents the AlreadyFollowing status.

{"d":{"Follow":1}}

Table 1 shows SocialFollowResult status codes and their values.


Table 1. SocialFollowResult codes and values

S TATU S CO D E V ALU E

0 OK. The current user is now following the actor.


S TATU S CO D E V ALU E

1 AlreadyFollowing. The current user is already following the actor.

2 LimitReached. The request failed because an internal limit was reached.

3 InternalError. The request failed due to an internal error.


NOTE

The REST service doesn't return a response for the StopFollowing request. It returns {"d":{"StopFollowing":null}} .

Example response for the IsFollowed endpoint


In response to client-side requests to the isfollowed endpoint, the REST service returns a bool value that represents whether the current user is following the specified actor.
The following response indicates that the current user is not following the specified document, site, or tag.

{"d":{"IsFollowed":false}}

Example response for the My/Followed endpoint


In response to client-side requests to the my/followed endpoint, the REST service returns an array of SP.Social.SocialActor objects that represent documents, sites, and tags that the
current user is following.
The following response represents a followed document, site, and tag. The request specifies the types of content to include.

{"d":{"Followed":{"results":[
{"__metadata":{"type":"SP.Social.SocialActor"}
"AccountName":null
"ActorType":1
"CanFollow":true
"ContentUri":"https://domain.sharepoint.com:443/Shared%20Documents/fileName.docx"
"EmailAddress":null
"FollowedContentUri":null
"Id":"2.089f4944a6374a64b52b7af5ba140392.9340a4837688405daa6b83f2b58f973d.
51bbb5d8e214457ba794669345d23040.98b9fc73d5224265b039586688b15b98"
"ImageUri":null
"IsFollowed":true
"LibraryUri":null
"Name":"snippets.txt"
"PersonalSiteUri":null
"Status":0
"StatusText":null
"TagGuid":"00000000-0000-0000-0000-000000000000"
"Title":null
"Uri":"https://domain.sharepoint.com:443/Shared%20Documents/fileName.docx"
}
{"__metadata":{"type":"SP.Social.SocialActor"}
"AccountName":null
"ActorType":2
"CanFollow":true
"ContentUri":"https://domain.sharepoint.com:443/"
"EmailAddress":null
"FollowedContentUri":null
"Id":"8.089f4944a6374a64b52b7af5ba140392.9340a4837688405daa6b83f2b58f973d.
089f4944a6374a64b52b7af5ba140392.98b9fc73d5224265b039586688b15b98"
"ImageUri":null
"IsFollowed":true
"LibraryUri":null
"Name":"Developer Site"
"PersonalSiteUri":null
"Status":0
"StatusText":null
"TagGuid":"00000000-0000-0000-0000-000000000000"
"Title":null
"Uri":"https://domain.sharepoint.com:443/"
}
{"__metadata":{"type":"SP.Social.SocialActor"}
"AccountName":null
"ActorType":3
"CanFollow":true
"ContentUri":null
"EmailAddress":null
"FollowedContentUri":null
"Id":"16.00000000000000000000000000000000.00000000000000000000000000000000.
19a4a484c1dc4bc58c93bb96245ce928.98b9fc73d5224265b039586688b15b98"
"ImageUri":null
"IsFollowed":true
"LibraryUri":null
"Name":"#someTag"
"PersonalSiteUri":null
"Status":0
"StatusText":null
"TagGuid":"19a4a484-c1dc-4bc5-8c93-bb96245ce928"
"Title":null
"Uri":"https://domain-my.sharepoint.com:443/_layouts/15/HashTagProfile.aspx?
TermID=19a4a484-c1dc-4bc5-8c93-bb96245ce928"
}
]}}}

Example response for the My/FollowedCount endpoint


In response to client-side requests to the my/followedcount endpoint, the REST service returns an Int32 value that represents the total count of specified actor types that the current user is
following.
The following response represents a count of three followed documents, sites, and/or tags. The request specifies the types of content to include.
{"d":{"FollowedCount":3}}

See also
Follow content in SharePoint
Following people and content REST API reference for SharePoint
How to: Follow documents and sites by using the .NET client object model in SharePoint
Work with user profiles in SharePoint
3/26/2018 • 5 minutes to read Edit Online

Learn about common programming tasks for working with user profiles in SharePoint.

APIs for working with user profiles in SharePoint


User profiles and user profile properties provide information about SharePoint users. SharePoint provides the following APIs that you can use to programmatically work with user profiles:
Client object models for managed code
.NET client object model
Silverlight client object model
Mobile client object model
JavaScript object model
Representational State Transfer (REST) service
Server object model
As a best practice in SharePoint development, use client APIs when you can. Client APIs include the .NET client object model, the JavaScript object model, and the REST service. For more
information about the APIs in SharePoint and when to use them, see Choose the right API set in SharePoint.
NOTE

Not all functionality that you find in the Microsoft.Office.Server.UserProfiles assembly is available from client APIs. For example, you have to use the server object model to create or
change user profiles because they're read-only from client APIs (except the user profile picture). Also, there's no client-side access to some namespaces, such as
Microsoft.Office.Server.Audience , Microsoft.Office.Server.ReputationModel , or Microsoft.Office.Server.SocialData . To see what's supported functionality for the client APIs, see
Microsoft.SharePoint.Client.Social and Microsoft.SharePoint.Client.UserProfiles .
Each API includes a manager object that you use to perform core profile-related tasks. Table 1 shows the manager and other key objects (or REST resources) in the APIs and the class library
(or access point) where you can find them.
NOTE

The Silverlight and mobile client object models are not included in Table 1 or Table 2 because they provide the same core functionality as the .NET client object model and use the same
signatures. The Silverlight client object model is defined in Microsoft.SharePoint.Client.UserProfiles.Silverlight.dll, and the mobile client object model is defined in
Microsoft.SharePoint.Client.UserProfiles.Phone.dll.
Table 1. SharePoint APIs used for working with user profiles programmatically

API K EY O B JECT

.NET client object model Manager object: PeopleManager


See: How to: Retrieve user profile properties by using the .NET client object model in SharePoint Primary namespace: Microsoft.SharePoint.Client.UserProfiles
Other key objects: PersonProperties , ProfileLoader , UserProfile
Class library: Microsoft.SharePoint.Client.UserProfiles.dll

JavaScript object model Manager object: PeopleManager


See: How to: Retrieve user profile properties by using the JavaScript object model in SharePoint Primary namespace: SP.UserProfiles
Other key objects: PersonProperties, ProfileLoader, UserProfile
Class library: SP.UserProfiles.js

REST service Manager resource: PeopleManager


See: User profiles REST API reference Endpoint URI: http://<siteUri>/_api/SP.UserProfiles.PeopleManager
Primary namespace: SP.UserProfiles
Other key resources: PersonProperties, ProfileLoader, UserProfile

Server object model Manager objects: UserProfileManager , PeopleManager


See: How to: Work with user profiles and organization profiles by using the server object model in Primary namespace: Microsoft.Office.Server.UserProfiles
SharePoint Other key objects: UserProfile , CorePropertyManager , ProfilePropertyManager ,
ProfileSubtypeManager , ProfileSubtypePropertyManager , ProfileTypePropertyManager
Class library: Microsoft.Office.Server.UserProfiles.dll

Common programming tasks for working with user profiles in SharePoint


Table 2 shows common programming tasks for working with user profiles and the members that you use to perform them. Members are from the .NET client object model (CSOM),
JavaScript object model (JSOM), REST service, and server object model (SSOM).
Table 2. API for common programming tasks for working with user profiles

TAS K MEMB ER S

Create an instance of a manager object in the context of the current user CSOM: PeopleManager
JSOM: PeopleManager
REST: GET http://<siteUri>/_api/SP.UserProfiles.PeopleManager
SSOM: UserProfileManager (overloaded) or PeopleManager

Change the current user's profile picture CSOM: SetMyProfilePicture


JSOM: setMyProfilePicture
REST: POST http://<siteUri>/_api/SP.UserProfiles.PeopleManager/SetMyProfilePicture and
pass the picture parameter in the request body
SSOM: UserProfile [PropertyConstants.PictureUrl].Value or SetMyProfilePicture
TAS K MEMB ER S

Get the current user's properties CSOM: GetMyProperties


JSOM: getMyProperties
REST: GET http://<siteUri>/_api/SP.UserProfiles.PeopleManager/GetMyProperties (or get some
basic user properties from /_api/social.feed/my or /_api/social.following/my )
SSOM: GetUserProfile

Get a particular user's properties CSOM: GetPropertiesFor


JSOM: getPropertiesFor
REST: GET
http://<siteUri>/_api/SP.UserProfiles.PeopleManager/GetPropertiesFor(accountName=@v)?
@v='domain\\user'
SSOM: GetUserProfile (overloaded) or GetPropertiesFor

Get the user profile properties for a particular user CSOM: GetUserProfilePropertiesFor
JSOM: getUserProfilePropertiesFor
REST: not implemented. Call GetPropertiesFor and then get the user profile properties from the
UserProfileProperties property of the returned PersonProperties object.
SSOM: GetEnumerator

Get a specific user profile property for a user CSOM: GetUserProfilePropertyFor


JSOM: getUserProfilePropertyFor
REST: GET
http://<siteUri>/_api/SP.UserProfiles.PeopleManager/GetUserProfilePropertyFor(accountName=@v,prope
@v='domain\\user'
SSOM: UserProfile (overloaded) and specify the property name in the indexer

Get a user profile CSOM: GetUserProfile (returns the client-side user profile for the current user only)
JSOM: getUserProfile (returns the client-side user profile for the current user only)
REST: POST
http://<siteUri>/_api/SP.UserProfiles.ProfileLoader.GetProfileLoader/GetUserProfile
(returns the client-side user profile for the current user only)
SSOM: GetUserProfile (overloaded)

Find out whether a user account exists CSOM: not implemented


JSOM: not implemented
REST: not implemented
SSOM: UserExists

Create or change user profiles and user profile properties and attributes CSOM: not implemented
(Client APIs can change the profile picture. See the "Change the user's profile picture" task in this table.) JSOM: not implemented
REST: not implemented
SSOM: multiple???see How to: Work with user profiles and organization profiles by using the server
object model in SharePoint

Delete a user profile CSOM: not implemented


JSOM: not implemented
REST: not implemented
SSOM: RemoveProfile or RemoveUserProfile (overloaded)

Provision a user's personal site CSOM: CreatePersonalSiteEnque (overloaded)


JSOM: createPersonalSiteEnque (overloaded)
REST: POST
http://<siteUri>/_api/SP.UserProfiles.ProfileLoader.GetProfileLoader/GetUserProfile/CreatePersonal
SSOM: CreatePersonalSite() (overloaded)

Provision one or more users' personal sites CSOM: CreatePersonalSiteEnqueueBulk


Available for My Site Host administrators on SharePoint Online only JSOM: createPersonalSiteEnqueueBulk
REST: POST
https://<domain>-
admin.sharepoint.com/_api/SP.UserProfiles.ProfileLoader.GetProfileLoader/CreatePersonalSiteEnqueue
and pass a string array of email addresses for the emailIDs parameter (200 characters maximum) in the
request body (example:
{'emailIDs':['usera@contoso.onmicrosoft.com','userb@contoso.onmicrosoft.com']} ).
SSOM: CreatePersonalSiteEnqueueBulk

New objects for users and user properties in SharePoint


SharePoint includes the following new objects that represent users and user properties:
The SocialActor object and the SocialActorInfo object represent users (and documents, sites, and tasks) for feed and following activities.
A new client-side UserProfile object that provides methods you can use to create a personal site for the current user. However, it does not contain all the user properties that the
server-side UserProfile object contains.
The PersonProperties object contains general user properties and its UserProfileProperties property contains user profile properties. PersonProperties is the primary API for
accessing user properties from client-side code.
NOTE

Server object model versions are the SPSocialActor object and the PersonProperties object.

See also
Social and collaboration features in SharePoint
Get started developing with social features in SharePoint
How to: Retrieve user profile properties by using the .NET client object model in SharePoint
How to: Retrieve user profile properties by using the JavaScript object model in SharePoint
User profiles REST API reference
How to: Work with user profiles and organization profiles by using the server object model in SharePoint
Follow people in SharePoint
Retrieve user profile properties by using the .NET client object model in SharePoint
5/10/2018 • 6 minutes to read Edit Online

Learn how to retrieve user profile properties programmatically by using the SharePoint .NET client object model.

What are user profile properties in SharePoint?


User properties and user profile properties provide information about SharePoint users, such as display name, email, title, and other business and personal information. In client-side APIs,
you access these properties from the PersonProperties object and its UserProfileProperties property. The UserProfileProperties property contains all user profile properties, but the
PersonProperties object contains commonly used properties (such as AccountName , DisplayName , and Email ) that are easier to access.
The PeopleManager object includes the following methods that you can use to retrieve user properties and user profile properties by using the .NET client object model:
The GetMyProperties method and the GetPropertiesFor method return a PersonProperties object.
The GetUserProfilePropertiesFor method and the GetUserProfilePropertyFor method return the values of the user profile properties that you specify.
User profile properties from client APIs are read-only (except the profile picture, which you can change by using the PeopleManager.SetMyProfilePicture method). If you want to change
other user profile properties, you must use the server object model.
NOTE

The client version of the UserProfile object doesn't contain all of the user properties as the server-side version. However, the client-side version does provide the methods for creating a
personal site for the current user. To retrieve the client-side UserProfile for the current user, use the ProfileLoader.GetUserProfile method.
For more information about working with profiles, see Work with user profiles in SharePoint.

Prerequisites for setting up your development environment to retrieve user profile properties by using the
SharePoint .NET client object model
To create a console application that uses the .NET client object model to retrieve user profile properties, you'll need the following:
SharePoint with profiles created for the current user and a target user
Visual Studio 2012
Full Control connection permissions to access the User Profile service application for the current user.
NOTE

If you're not developing on the computer that is running SharePoint, get the SharePoint Client Components download that contains SharePoint client assemblies.

Create the console application that retrieves user profile properties by using the SharePoint .NET client object model
1. On your development computer, open Visual Studio and choose File, New, Project.
2. In the New Project dialog box, choose .NET Framework 4.5 from the drop-down list at the top of the dialog box.
3. From the project templates, choose Windows, and then choose Console Application.
4. Name the project UserProfilesCSOM, and then choose the OK button.
5. Add references to the following assemblies:
Microsoft.SharePoint.Client
Microsoft.SharePoint.ClientRuntime
Microsoft.SharePoint.Client.UserProfiles
6. In the Main method, define variables for the server URL and the target user name, as shown in the following code.

const string serverUrl = "http://serverName/";


const string targetUser = "domainName\\userName";

Note: Remember to replace the http://serverName/ and domainName\\\\userName placeholder values before you run the code.

1. Initialize the SharePoint client context, as shown in the following code.

ClientContext clientContext = new ClientContext(serverUrl);

1. Get the target user's properties from the PeopleManager object, as shown in the following code.

PeopleManager peopleManager = new PeopleManager(clientContext);


PersonProperties personProperties = peopleManager.GetPropertiesFor(targetUser);

The personProperties object is a client object. Some client objects contain no data until they are initialized. For example, you cannot access the property values of the personProperties
object until you initialize it. If you try to access a property before it is initialized, you receive a PropertyOrFieldNotInitializedException exception.
1. To initialize the personProperties object, register the request that you want to run, and then run the request on the server, as shown in the following code.

clientContext.Load(personProperties, p => p.AccountName, p => p.UserProfileProperties);


clientContext.ExecuteQuery();

When you call the Load method (or the LoadQuery method), you pass in the object that you want to retrieve or change. In this example, the call to the Load method passes in optional
parameters to filter the request. The parameters are lambda expressions that request only the AccountName property and UserProfileProperties property of the personProperties
object.

Tip: To reduce network traffic, request only the properties that you want to work with when you call the Load method. In addition, if you're working with multiple objects, group multiple
calls to the Load method when possible before you call the ExecuteQuery method.

1. Iterate through the user profile properties and read the name and value of each property, as shown in the following code.

foreach (var property in personProperties.UserProfileProperties)


{
Console.WriteLine(string.Format("{0}: {1}",
property.Key.ToString(), property.Value.ToString()));
}

Code example: Retrieving all user profile properties by using the SharePoint .NET client object model
The following code example shows how to retrieve and iterate through all the user profile properties of a target user, as described in the previous procedure.
NOTE

Replace the http://serverName/ and domainName\\\\userName placeholder values before you run the code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.UserProfiles;

namespace UserProfilesCSOM
{
class Program
{
static void Main(string[] args)
{

// Replace the following placeholder values with the target SharePoint site and
// target user.
const string serverUrl = "http://serverName/";
const string targetUser = "domainName\\\\userName";

// Connect to the client context.


ClientContext clientContext = new ClientContext(serverUrl);

// Get the PeopleManager object and then get the target user's properties.
PeopleManager peopleManager = new PeopleManager(clientContext);
PersonProperties personProperties = peopleManager.GetPropertiesFor(targetUser);

// Load the request and run it on the server.


// This example requests only the AccountName and UserProfileProperties
// properties of the personProperties object.
clientContext.Load(personProperties, p => p.AccountName, p => p.UserProfileProperties);
clientContext.ExecuteQuery();

foreach (var property in personProperties.UserProfileProperties)


{
Console.WriteLine(string.Format("{0}: {1}",
property.Key.ToString(), property.Value.ToString()));
}
Console.ReadKey(false);

// TODO: Add error handling and input validation.


}
}
}

Code example: Retrieving user profile properties of people who are following me by using the SharePoint .NET client
object model
The following code example shows how to get, in a SharePoint Add-in, the user profile properties of people who are following you.

string contextTokenString = TokenHelper.GetContextTokenFromRequest(Request);

if (contextTokenString != null)
{
Uri sharepointUrl = new Uri(Request.QueryString["SP.Url"]);

ClientContext clientContext = TokenHelper.GetClientContextWithContextToken(sharepointUrl.ToString(), contextTokenString, Request.Url.Authority);

PeopleManager peopleManager = new PeopleManager(clientContext);


ClientObjectList<PersonProperties> peopleFollowedBy = peopleManager.GetMyFollowers();
clientContext.Load(peopleFollowedBy, people => people.Include(person => person.PictureUrl, person => person.DisplayName));
clientContext.ExecuteQuery();

foreach (PersonProperties personFollowedBy in peopleFollowedBy)


{
if (!string.IsNullOrEmpty(personFollowedBy.PictureUrl))
{
Response.Write("<img src=\\"" + personFollowedBy.PictureUrl + "\\" alt=\\"" + personFollowedBy.DisplayName + "\\"/>");
}
}
clientContext.Dispose();
}

Code example: Retrieving a set of user profile properties by using the SharePoint .NET client object model
The following code example shows how to retrieve a specific set of user profile properties for a target user.
NOTE

To retrieve the value for only one user profile property, use the GetUserProfilePropertyFor method.
Unlike the previous code example that retrieves a PersonProperties object for the target user, this example calls the PeopleManager.GetUserProfilePropertiesFor method and passes in a
UserProfilePropertiesForUser object that specifies the target user and the user profile properties to retrieve. GetUserProfilePropertiesFor returns an IEnumerable collection that contains
the values of the properties that you specify.
NOTE

Replace the http://serverName/ and domainName\\\\userName placeholder values before you run the code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.UserProfiles;

namespace UserProfilesCSOM
{
class Program
{
static void Main(string[] args)
{

// Replace the following placeholder values with the target SharePoint site and the
// target user.
const string serverUrl = "http://serverName/";
const string targetUser = "domainName\\\\userName";

// Connect to the client context.


ClientContext clientContext = new ClientContext(serverUrl);

// Get the PeopleManager object.


PeopleManager peopleManager = new PeopleManager(clientContext);

// Retrieve specific properties by using the GetUserProfilePropertiesFor method.


// The returned collection contains only property values.
string[] profilePropertyNames = new string[] { "PreferredName", "Department", "Title" };
UserProfilePropertiesForUser profilePropertiesForUser = new UserProfilePropertiesForUser(
clientContext, targetUser, profilePropertyNames);
IEnumerable<string> profilePropertyValues = peopleManager.GetUserProfilePropertiesFor(profilePropertiesForUser);

// Load the request and run it on the server.


clientContext.Load(profilePropertiesForUser);
clientContext.ExecuteQuery();

// Iterate through the property values.


foreach (var value in profilePropertyValues)
{
Console.Write(value + "\\n");
}
Console.ReadKey(false);

// TO DO: Add error handling and input validation.


}
}
}

See also
Work with user profiles in SharePoint
How to: Retrieve user profile properties by using the JavaScript object model in SharePoint
How to: Work with user profiles and organization profiles by using the server object model in SharePoint
Microsoft.SharePoint.Client.UserProfiles
Retrieve user profile properties by using the JavaScript object model in SharePoint
3/26/2018 • 6 minutes to read Edit Online

Learn how to retrieve user properties and user profile properties programmatically by using the SharePoint JavaScript object model.

What are user properties and user profile properties in SharePoint?


User properties and user profile properties provide information about SharePoint users, such as display name, email, title, and other business and personal information. In client-side APIs,
you access these properties from the PersonProperties object and its userProfileProperties property. The userProfileProperties property contains all user profile properties, but the
PersonProperties object contains commonly used properties (such as accountName, displayName, and email) that are easier to access.
The PeopleManager object includes the following methods that you can use to retrieve user properties and user profile properties by using the JavaScript object model:
The getMyProperties method and the getPropertiesFor method return a PersonProperties object.
The getUserProfilePropertiesFor method and the getUserProfilePropertyFor method return the values of the user profile properties that you specify.
User profile properties from client APIs are read-only (except the profile picture, which you can change by using the PeopleManager.setMyProfilePicture method). If you want to change
other user profile properties, you must use the server object model. For more information about working with user profiles, see Work with user profiles in SharePoint.
NOTE

The client-side UserProfile object doesn't contain all of the user properties as the server-side version. However, the client-side version does provide the methods for creating a personal site
for the current user. To retrieve it, use the ProfileLoader.getUserProfile method.

Prerequisites for setting up your development environment to retrieve user properties by using the SharePoint
JavaScript object model
To create an application page that uses the JavaScript object model to retrieve user properties, you'll need:
SharePoint with profiles created for the current user and a target user
Visual Studio 2012
Office Developer Tools for Visual Studio 2013
Full Control connection permissions to access the User Profile service application for the current user

Create the application page in Visual Studio 2012


1. On the server running SharePoint, open Visual Studio and choose File, New, Project.
2. In the New Project dialog box, choose .NET Framework 4.5 from the drop-down list at the top of the dialog box.
3. In the Templates list, expand Office/SharePoint, choose the SharePoint Solutions category, and then choose the SharePoint Project template.
4. Name the project UserProfilesJSOM, and then choose the OK button.
5. In the SharePoint Customization Wizard dialog box, enter the URL to your target SharePoint site, choose Deploy as a farm solution, and then choose the Finish button.
6. In Solution Explorer, open the shortcut menu for the UserProfilesJSOM project, and then add a SharePoint "Layouts" mapped folder.
7. In the Layouts folder, open the shortcut menu for theUserProfilesJSOM folder, and then add a new SharePoint application page namedUserProfiles.aspx.

Note: The code examples in this article define custom code in the page markup but do not use the code-behind class file that Visual Studio creates for the page.

8. Open the shortcut menu for the UserProfiles.aspx page, and then choose Set as Startup Item.
9. In the markup for the UserProfiles.aspx page, paste the following code inside the "Main" asp:Content tags. This code adds a span control that displays the results of the query,
SharePoint:ScriptLink controls that reference SharePoint JavaScript class library files, and script tags to contain your custom logic.

<span id="results"></span><br />


<SharePoint:ScriptLink ID="ScriptLink1" name="SP.js" runat="server"
ondemand="false" localizable="false" loadafterui="true" />
<SharePoint:ScriptLink ID="ScriptLink2" name="SP.UserProfiles.js" runat="server"
ondemand="false" localizable="false" loadafterui="true" />
<script type="text/javascript">
// Replace this comment with the code for your scenario.
</script>

1. To add logic to retrieve user profile properties, replace the comment between the script tags with the code example from one of the following scenarios:
Retrieve user profile properties from the PersonProperties object and its userProfileProperties property
Retrieve a set of user profile properties by using the getUserProfilePropertiesFor method
2. To test the application page, on the menu bar, choose Debug, Start Debugging. If you're prompted to modify the web.config file, choose the OK button.

Code example: Retrieving user profile properties from the PersonProperties object and its userProfileProperties
property in the SharePoint JavaScript object model
The following code example shows how to get user profile properties for a target user by querying the PersonProperties object and its userProfileProperties property. It shows how to:
Get the PersonProperties object that represents the target user by using the getPropertiesFor method. (To get the PersonProperties object for the current user, use the
getMyProperties method.)
Get a property directly from the PersonProperties object. This example gets the displayName property.
Get a property from the userProfileProperties property of the PersonProperties object. This example gets the Department property.
NOTE
Paste the following code between the script tags that you added to the UserProfiles.aspx file in the Create the application page procedure. Replace the domainName\\userName placeholder
value before you run the code. (This code example does not use the code-behind class file.)

var personProperties;

// Ensure that the SP.UserProfiles.js file is loaded before the custom code runs.
SP.SOD.executeOrDelayUntilScriptLoaded(getUserProperties, 'SP.UserProfiles.js');

function getUserProperties() {

// Replace the placeholder value with the target user's credentials.


var targetUser = "domainName\\userName";

// Get the current client context and PeopleManager instance.


var clientContext = new SP.ClientContext.get_current();
var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);

// Get user properties for the target user.


// To get the PersonProperties object for the current user, use the
// getMyProperties method.
personProperties = peopleManager.getPropertiesFor(targetUser);

// Load the PersonProperties object and send the request.


clientContext.load(personProperties);
clientContext.executeQueryAsync(onRequestSuccess, onRequestFail);
}

// This function runs if the executeQueryAsync call succeeds.


function onRequestSuccess() {

// Get a property directly from the PersonProperties object.


var messageText = " \\"DisplayName\\" property is "
+ personProperties.get_displayName();

// Get a property from the UserProfileProperties property.


messageText += "<br />\\"Department\\" property is "
+ personProperties.get_userProfileProperties()['Department'];
$get("results").innerHTML = messageText;
}

// This function runs if the executeQueryAsync call fails.


function onRequestFail(sender, args) {
$get("results").innerHTML = "Error: " + args.get_message();
}

Code example: Retrieving a set of user profile properties by using the getUserProfilePropertiesFor method in the
SharePoint JavaScript object model
The following code example retrieves the values for a specified set of user profile properties for a target user by using the getUserProfilePropertiesFor method. It shows how to:
Create a UserProfilePropertiesForUser object that specifies the target user and the user profile properties to retrieve. This example gets the PreferredName property and the
Department property.
Get the values of the specified properties by using the getUserProfilePropertiesFor method and passing in the UserProfilePropertiesForUser object. (To retrieve the value for only one
user profile property, use the getUserProfilePropertyFor method.)
Get the values from the returned array of property values.
NOTE

Paste the following code between the script tags that you added to the UserProfiles.aspx file in the Create the application page procedure. Replace the domainName\\\\userName placeholder
value before you run the code. (This code example does not use the code-behind class file.)
var userProfileProperties;

// Ensure that the SP.UserProfiles.js file is loaded before the custom code runs.
SP.SOD.executeOrDelayUntilScriptLoaded(getUserProperties, 'SP.UserProfiles.js');

function getUserProperties() {

// Replace the placeholder value with the target user's credentials.


var targetUser = "domainName\\\\userName";

// Get the current client context and PeopleManager instance.


var clientContext = new SP.ClientContext.get_current();
var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);

// Specify the properties to retrieve and target user for the


// UserProfilePropertiesForUser object.
var profilePropertyNames = ["PreferredName", "Department"];
var userProfilePropertiesForUser =
new SP.UserProfiles.UserProfilePropertiesForUser(
clientContext,
targetUser,
profilePropertyNames);

// Get user profile properties for the target user.


// To get the value for only one user profile property, use the
// getUserProfilePropertyFor method.
userProfileProperties = peopleManager.getUserProfilePropertiesFor(
userProfilePropertiesForUser);

// Load the UserProfilePropertiesForUser object and send the request.


clientContext.load(userProfilePropertiesForUser);
clientContext.executeQueryAsync(onRequestSuccess, onRequestFail);
}

// This function runs if the executeQueryAsync call succeeds.


function onRequestSuccess() {
var messageText = "\\"PreferredName\\" property is "
+ userProfileProperties[0];
messageText += "<br />\\"Department\\" property is "
+ userProfileProperties[1];
$get("results").innerHTML = messageText;
}

// This function runs if the executeQueryAsync call fails.


function onRequestFail(sender, args) {
$get("results").innerHTML = "Error: " + args.get_message();
}

See also
Work with user profiles in SharePoint
How to: Retrieve user profile properties by using the .NET client object model in SharePoint
How to: Work with user profiles and organization profiles by using the server object model in SharePoint
SP.UserProfiles namespace (sp.userprofiles)
Work with user profiles and organization profiles by using the server object model in SharePoint
5/11/2018 • 8 minutes to read Edit Online

Learn how to create, retrieve, and change SharePoint user profiles and user profile properties programmatically by using the SharePoint server object model.

What are user profiles in SharePoint?


In SharePoint, user profiles represent SharePoint users. User profile properties represent information about the users and also about the properties themselves. For example, properties
include the account name or email address of a user and the data type of a property. You can use the server object model to programmatically create, retrieve, and change user profiles,
profile subtypes, and profile properties.
NOTE

For more information about common programming tasks for working with user profiles and the API that you use to perform the tasks, see Work with user profiles in SharePoint.

Prerequisites for setting up your development environment to work with user profiles by using the SharePoint server
object model
To create a console application that uses the server object model to work with user profiles and user profile properties, you'll need:
SharePoint with the profile created for the current user.
Visual Studio 2012.
Permissions to create, retrieve, and change user profile objects. (Creating and modifying profiles requires the Modify User Profiles permission.)

Create a console application that works with user profiles by using the SharePoint server object model
1. Open Visual Studio and choose File, New, Project.
2. In the New Project dialog box, choose .NET Framework 4.5 from the drop-down list at the top of the dialog box.
3. In the Templates list, choose Windows, and then choose Console Application.
4. Name the project UserProfilesSSOM, and then choose the OK button.

Note: Make sure the Prefer 32-bit setting is not selected in the project's Build properties.

5. Add references to the following assemblies:


Microsoft.Office.Server
Microsoft.Office.Server.UserProfiles
Microsoft.SharePoint
System.Web
6. Replace the contents of the Program class with the code example from one of the following scenarios:
Create a user profile
Create a user profile property
Retrieve and change user profiles
Retrieve and change attributes for user profile properties
Retrieve and change values for user properties
7. To test the console application, on the menu bar, choose Debug, Start Debugging. You can check your changes from the Manage Profile Service page for the user profile service
application in Central Administration.

Code example: Create user profiles by using the SharePoint server object model
In SharePoint, user profiles represent SharePoint users. Profile types and subtypes help categorize profiles into groups, such as employees or customers. Profile types and subtypes are used
to set common profile properties and attributes at the subtype level. SharePoint Server includes a default user profile subtype.
The following code example creates a UserProfile object that is associated with the default user profile subtype. Some user profile properties are automatically populated with information
that is imported from the directory that contains user accounts, such as Active Directory Domain Services. For a code example that creates a custom subtype, see ProfileSubtype .
NOTE

Change the domain\username andservername placeholder values before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint;
using System.Web;
namespace UserProfilesSSOM
{
class Program
{
static void Main(string[] args)
{

// Replace "domain\\username" and "servername" with actual values.


string newAccountName = "domain\\username";
using (SPSite site = new SPSite("http://servername"))
{
SPServiceContext serviceContext = SPServiceContext.GetContext(site);
try
{

// Create a user profile that uses the default user profile


// subtype.
UserProfileManager userProfileMgr = new UserProfileManager(serviceContext);
UserProfile userProfile = userProfileMgr.CreateUserProfile(newAccountName);

Console.WriteLine("A profile was created for " + userProfile.DisplayName);


Console.Read();
}

catch (System.Exception e)
{
Console.WriteLine(e.GetType().ToString() + ": " + e.Message);
Console.Read();
}
}
}
}
}

Code example: Create user profile properties by using the SharePoint server object model
User profile properties describe personal and organizational information about users. You can create and add a custom profile property to the default set of SharePoint profile properties.
A profile property and its attributes are represented by a set of linked objects: a CoreProperty object, a ProfileTypeProperty object, and a ProfileSubtypeProperty object.
The following code example creates a CoreProperty that has a URL data type (or optionally a CoreProperty that has a multivalue string data type). In addition, it creates a
ProfileTypeProperty and a ProfileTypeProperty that define availability, privacy, and other settings for the property. The ProfileSubtypeProperty.DefaultPrivacy property controls the visibility
of properties and other My Site content. For a complete list of the possible data types for profile property values, see PropertyDataType .
NOTE

Change the servername placeholder value before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Server;
using Microsoft.Office.Server.Administration;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint;
using System.Web;
namespace UserProfilesSSOM
{
class Program
{
static void Main(string[] args)
{

// Replace "servername" with an actual value.


using (SPSite site = new SPSite("http://servername"))
{
SPServiceContext serviceContext = SPServiceContext.GetContext(site);
try
{
ProfilePropertyManager profilePropMgr = new UserProfileConfigManager(serviceContext).ProfilePropertyManager;
CorePropertyManager corePropMgr = profilePropMgr.GetCoreProperties();

// Create a URL property.


CoreProperty coreProp = corePropMgr.Create(false);
coreProp.Name = "AppsWebsite";
coreProp.DisplayName = "Apps site";
coreProp.Type = PropertyDataType.URL;
coreProp.Length = 100;
corePropMgr.Add(coreProp);

//// Create a multivalue property.


//// To create this property, comment out the previous
//// block of code and uncomment this block of code.
//CoreProperty coreProp = corePropMgr.Create(false);
//coreProp.Name = "PublishedAppsList";
//coreProp.DisplayName = "Published apps";
//coreProp.Type = PropertyDataType.StringMultiValue;
//coreProp.IsMultivalued = true;
//coreProp.Length = 100;
//corePropMgr.Add(coreProp);

// Create a profile type property and make the core property


// visible in the Details section page.
ProfileTypePropertyManager typePropMgr = profilePropMgr.GetProfileTypeProperties(ProfileType.User);
ProfileTypeProperty typeProp = typePropMgr.Create(coreProp);
typeProp.IsVisibleOnViewer = true;
typePropMgr.Add(typeProp);

// Create a profile subtype property.


ProfileSubtypeManager subtypeMgr = ProfileSubtypeManager.Get(serviceContext);
ProfileSubtype subtype = subtypeMgr.GetProfileSubtype(ProfileSubtypeManager.GetDefaultProfileName(ProfileType.User));
ProfileSubtypePropertyManager subtypePropMgr = profilePropMgr.GetProfileSubtypeProperties(subtype.Name);
ProfileSubtypeProperty subtypeProp = subtypePropMgr.Create(typeProp);
subtypeProp.IsUserEditable = true;
subtypeProp.DefaultPrivacy = Privacy.Public;
subtypeProp.UserOverridePrivacy = true;
subtypePropMgr.Add(subtypeProp);

Console.WriteLine("The properties were created.");


Console.Read();
}

catch (System.Exception e)
{
Console.WriteLine(e.GetType().ToString() + ": " + e.Message);
Console.Read();
}
}
}
}
}

Code example: Retrieve and change user profiles by using the SharePoint server object model
The following code example retrieves all user profiles within the context and changes the value of a user's DisplayName property. Most profile properties are accessed by using the
UserProfile.Item accessor.
NOTE

Change the domain\username andservername placeholder values before you run the code.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint;
using System.Web;
namespace UserProfilesSSOM
{
class Program
{
static void Main(string[] args)
{

// Replace "domain\\username" and "servername" with actual values.


string targetAccountName = "domain\\username";
using (SPSite site = new SPSite("http://servername"))
{
SPServiceContext serviceContext = SPServiceContext.GetContext(site);
try
{

// Retrieve and iterate through all of the user profiles in this context.
Console.WriteLine("Retrieving user profiles:");
UserProfileManager userProfileMgr = new UserProfileManager(serviceContext);
IEnumerator userProfiles = userProfileMgr.GetEnumerator();
while (userProfiles.MoveNext())
{
UserProfile userProfile = (UserProfile)userProfiles.Current;
Console.WriteLine(userProfile.AccountName);
}

// Retrieve a specific user profile. Change the value of a user profile property
// and save (commit) the change on the server.
UserProfile user = userProfileMgr.GetUserProfile(targetAccountName);
Console.WriteLine("\\nRetrieving user profile for " + user.DisplayName + ".");
user.DisplayName = "Pat";
user.Commit();
Console.WriteLine("\\nThe user\\'s display name has been changed.");
Console.Read();
}

catch (System.Exception e)
{
Console.WriteLine(e.GetType().ToString() + ": " + e.Message);
Console.Read();
}
}
}
}
}

Code example: Retrieve and change attributes for user profile properties by using the SharePoint server object
model
The following code example retrieves the set of properties that represent a specific user property and its attributes, and then it changes the CoreProperty.DisplayName attribute,
ProfileTypeProperty.IsVisibleOnViewer attribute, and ProfileSubtypeProperty.PrivacyPolicy attribute. These changes apply globally to the property set. ProfileSubtypeProperty.PrivacyPolicy
specifies whether users are required to provide a value for the property. PrivacyPolicy applies to user profile properties only.
NOTE

Change the servername placeholder value before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint;
using System.Web;
namespace UserProfilesSSOM
{
class Program
{
static void Main(string[] args)
{

// Replace "servername" with an actual value.


using (SPSite site = new SPSite("http://servername"))
{
SPServiceContext serviceContext = SPServiceContext.GetContext(site);
try
{
ProfilePropertyManager profilePropMgr = new UserProfileConfigManager(serviceContext).ProfilePropertyManager;
ProfileSubtypePropertyManager subtypePropMgr = profilePropMgr.GetProfileSubtypeProperties("UserProfile");

// Retrieve a specific property set (a profile subtype property and


// its associated core and profile type properties).
// Changing these properties affects all instances of this property set.
ProfileSubtypeProperty subtypeProp = subtypePropMgr.GetPropertyByName(PropertyConstants.Title);
CoreProperty coreProp = subtypeProp.CoreProperty;
ProfileTypeProperty typeProp = subtypeProp.TypeProperty;

Console.WriteLine("Property name: " + coreProp.DisplayName);


Console.WriteLine("IsVisibleOnViewer = " + typeProp.IsVisibleOnViewer);
Console.WriteLine("PrivacyPolicy = " + subtypeProp.PrivacyPolicy);
Console.WriteLine("Press Enter to change the values.");
Console.Read();

// Change attributes on the properties and save (commit) the changes


// on the server.
coreProp.DisplayName = "Position";
coreProp.Commit();
typeProp.IsVisibleOnViewer = true;
typeProp.Commit();
subtypeProp.PrivacyPolicy = PrivacyPolicy.OptOut;
subtypeProp.Commit();
Console.WriteLine("The property attributes have been changed.");
Console.Read();
}

catch (System.Exception e)
{
Console.WriteLine(e.GetType().ToString() + ": " + e.Message);
Console.Read();
}
}
}
}
}

Code example: Retrieve and change values for user properties by using the SharePoint server object model
The following code example retrieves all UserProfile type properties and retrieves the property values for a specific user. Then, it changes the single-value PictureUrl property and the
multivalue PastProjects property. For the complete list of profile property name constants, see PropertyConstants .
NOTE

Change the domain\username, http://servername/docLib/pic.jpg, and servername placeholder values before you run the code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint;
using System.Web;
namespace UserProfilesSSOM
{
class Program
{
static void Main(string[] args)
{

// Replace "domain\\username," "http://servername/docLib/pic.jpg," and "servername" with actual values.


string accountName = "domain\\username";
string newPictureUrl = "http://servername/docLib/pic.jpg";
using (SPSite site = new SPSite("http://servername"))
{
SPServiceContext serviceContext = SPServiceContext.GetContext(site);

try
{
UserProfileManager userProfileMgr = new UserProfileManager(serviceContext);
ProfilePropertyManager profilePropMgr = new UserProfileConfigManager(serviceContext).ProfilePropertyManager;

// Retrieve all properties for the "UserProfile" profile subtype,


// and retrieve the property values for a specific user.
ProfileSubtypePropertyManager subtypePropMgr = profilePropMgr.GetProfileSubtypeProperties("UserProfile");
UserProfile userProfile = userProfileMgr.GetUserProfile(accountName);
IEnumerator<ProfileSubtypeProperty> userProfileSubtypeProperties = subtypePropMgr.GetEnumerator();
while (userProfileSubtypeProperties.MoveNext())
{
string propName = userProfileSubtypeProperties.Current.Name;
ProfileValueCollectionBase values = userProfile.GetProfileValueCollection(propName);
if (values.Count > 0)
{

// Handle multivalue properties.


foreach (var value in values)
{
Console.WriteLine(propName + ": " + value.ToString());
}
}
else
{
Console.WriteLine(propName + ": ");
}
}
Console.WriteLine("Press Enter to change the values.");
Console.Read();

// Change the value of a single-value user property.


userProfile[PropertyConstants.PictureUrl].Value = newPictureUrl;

// Add a value to a multivalue user property.


userProfile[PropertyConstants.PastProjects].Add((object)"Team Feed App");
userProfile[PropertyConstants.PastProjects].Add((object)"Social Ratings View web part");

// Save the changes to the server.


userProfile.Commit();
Console.WriteLine("The property values for the user have been changed.");
Console.Read();
}

catch (System.Exception e)
{
Console.WriteLine(e.GetType().ToString() + ": " + e.Message);
Console.Read();
}
}
}
}
}

See also
Work with user profiles in SharePoint
How to: Retrieve user profile properties by using the .NET client object model in SharePoint
How to: Retrieve user profile properties by using the JavaScript object model in SharePoint
Microsoft.Office.Server.UserProfiles
Integrating location and map functionality in SharePoint
3/26/2018 • 3 minutes to read Edit Online

Learn how to integrate location information and maps in SharePoint lists and location-based web and mobile apps for SharePoint, by using the new Geolocation field, and by creating your
own Geolocation-based field types based on Geolocation.

What are the location and map features in SharePoint?


SharePoint introduces a new field type named Geolocation that enables you to annotate SharePoint lists with location information. In columns of type Geolocation, you can enter location
information as a pair of latitude and longitude coordinates in decimal degrees or retrieve the coordinates of the user's current location from the browser if it implements the W3C
Geolocation API. In the list, SharePoint displays the location on a map powered by Bing Maps. In addition, a new view named Map View displays the list items as pushpins on a Bing Maps
Ajax control V7 with the list items as cards on the left pane. Figure 1 summarizes the default location and map features in SharePoint. Together, the Geolocation field and the Map View
enable you to give a spatial context to any information by integrating data from SharePoint into a mapping experience, and let your users engage in new ways in your web and mobile apps
and solutions.
NOTE

An MSI package named SQLSysClrTypes.msi must be installed on every SharePoint front-end web server to view the geolocation field value or data in a list. This package installs
components that implement the new geometry, geography, and hierarchy ID types in SQL Server 2008. By default, this file is installed for SharePoint Online. However, it is not for an on-
premises deployment of SharePoint. You must be a member of the Farm Administrators group to perform this operation. To download SQLSysClrTypes.msi, see Microsoft SQL Server 2008
R2 SP1 Feature Pack for SQL Server 2008, or Microsoft SQL Server 2012 Feature Packfor SQL Server 2012 in the Microsoft Download Center.
Figure 1.Summarized view of the default location and map features

What can you do with the location and map features?


The location and map features in SharePoint provide unique opportunities for developers to incorporate location, maps, and proximity search features into their web and mobile apps and
solutions. Table 1 contains some basic tasks that help you integrate location and map features in your apps and solutions.
Table 1. Basic tasks for integrating location and maps functionality

TAS K D ES CR IPTIO N

How to: Set the Bing Maps key at the web and farm level in SharePoint SharePoint uses Bings Maps to render the map of the location. To be able to use the Bing Maps feature,
you need to create a Bing Maps key and set the key at the web or farm level. The article shows the
various ways you can set the key in SharePoint and when to choose which option. You see an error
message on the map if you do not use a valid Bing Maps key or if a key is not set at the web that
contains the list or at the farm level.

How to: Add a Geolocation column to a list programmatically in SharePoint The Geolocation column is not available in SharePoint lists for users, by default. To add the column to a
SharePoint list, you need to write code. In this topic, learn how to add the Geolocation field to a list
programmatically.

How to: Extend the Geolocation field type using client-side rendering You can provide your own rendering to default user interface (UI.md), logic, and behavior of the
Geolocation field by creating custom field types that derive from the Geolocation field. SharePoint
simplifies the creation of custom field types by enabling you to run JavaScript by providing a new JSLink
property in the Geolocation field class, which points to a custom .js file that renders the field.

Note: The JSLink property is not supported on Survey or Events lists. A SharePoint calendar is an Events
list.

See also
How to: Add a Geolocation column to a list programmatically in SharePoint
How to: Set the Bing Maps key at the web and farm level in SharePoint
How to: Extend the Geolocation field type using client-side rendering
How to: Integrate maps with Windows Phone apps and SharePoint lists
Use the SharePoint location field type in mobile applications
Add a Geolocation column to a list programmatically in SharePoint
3/26/2018 • 4 minutes to read Edit Online

Learn how to programmatically add a Geolocation column to a list in SharePoint. Integrate location information and maps in SharePoint lists and location-based websites by using the new
Geolocation field creating your own Geolocation-based field type. SharePoint introduces a new field type named Geolocation that enables you to annotate SharePoint lists with location
information. In columns of type Geolocation, you can enter location information as a pair of latitude and longitude coordinates in decimal degrees or retrieve the coordinates of the user's
current location from the browser if it implements the W3C Geolocation API. For more information about the Geolocation column, see Integrating location and map functionality in
SharePoint. The Geolocation column is not available by default in SharePoint lists. To add the column to a SharePoint list, you have to write code. In this article, learn how to add the
Geolocation field to a list programmatically by using the SharePoint client object model.
An MSI package named SQLSysClrTypes.msi must be installed on every SharePoint front-end web server to view the geolocation field value or data in a list. This package installs
components that implement the new geometry, geography, and hierarchy ID types in SQL Server 2008. By default, this file is installed for SharePoint Online. However, it is not for an on-
premises deployment of SharePoint. You must be a member of the Farm Administrators group to perform this operation. To download SQLSysClrTypes.msi, see Microsoft SQL Server 2008
R2 SP1 Feature Pack for SQL Server 2008, or Microsoft SQL Server 2012 Feature Packfor SQL Server 2012 in the Microsoft Download Center.

Prerequisites for adding a Geolocation column


Access to a SharePoint list, with sufficient privileges to add a column.
A valid Bing Maps key set at the farm or web level, which can be obtained from the Bing Maps Account Center.

Important: Please note that you are responsible for compliance with terms and conditions applicable to your use of the Bing Maps key, and any necessary disclosures to users of
your application regarding data passed to the Bing Maps service.

Visual Studio 2010.

Code example: Add a Geolocation column to a list programmatically


Follow these steps to add the Geolocation column to a list using the SharePoint client object model.

To add the Geolocation column to a list using the client object model
1. Start Visual Studio.
2. On the menu bar, choose File, New Project. The New Project dialog box opens.
3. In the New Project dialog box, choose C# in the Installed Templates box, and then choose the Console Application template.
4. Give the project a name, and then choose the OK button.
5. Visual Studio creates the project. Add a reference to the following assemblies, and choose OK.
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Runtime.dll
6. In the default .cs file, add a using directive as follows.
using Microsoft.SharePoint.Client;

7. Add the following code to the Main method in the .cs file.

class Program
{
static void Main(string[] args)
{
AddGeolocationField();
Console.WriteLine("Location field added successfully");
}
private static void AddGeolocationField()
{
// Replace site URL and List Title with Valid values.
ClientContext context = new ClientContext("<Site Url>");
List oList = context.Web.Lists.GetByTitle("<List Title>");
oList.Fields.AddFieldAsXml("<Field Type='Geolocation' DisplayName='Location'/>",true, AddFieldOptions.AddToAllContentTypes);
oList.Update();
context.ExecuteQuery();
}
}

1. Replace <Site Url> and <List Title> with valid values.


2. Set the target framework in Project Properties as .NET Framework 4.0 or 3.5, and run the example.
3. Navigate to the list. You should be able to see a column named Location of type Geolocation in the list. You can now enter some values and see it in action. Figure 1 shows the default
location and map features that you can expect to see in your list.
Figure 1. Summarized view of the default location and map features
Add a list item with the Geolocation field value to a SharePoint list programmatically
After the Geolocation field is added to a SharePoint list, the developer can add the list item to the list programmatically. There are two ways to add the list item programmatically: by passing
the FieldGeolocationValue object to the Geolocation field, and by passing Raw Value to the Geolocation field.

Method A: Pass the FieldGeolocationValue object to the Geolocation field


The following method adds a list item by passing the Geolocation value as an object.

private void AddListItem()


{ // Replace site URL and List Title with Valid values.
ClientContext context = new ClientContext("<Site Url>");
List oList = context.Web.Lists.GetByTitle("<List Name>");

ListItemCreationInformation itemCreationInfo = new ListItemCreationInformation();


ListItem oListItem = oList.AddItem(itemCreationInfo);

oListItem["Title"] = "New Title";

FieldGeolocationValue oGeolocationValue = new FieldGeolocationValue();


oGeolocationValue.Latitude = (double)17.4;
oGeolocationValue.Longitude = (double)78.4;
oListItem["location"] = oGeolocationValue;

oListItem.Update();
context.ExecuteQuery();
}

Method B: Pass a raw value to the Geolocation field


The following method adds a list item to the SharePoint list by passing raw values to the Geolocation field.

private void AddListItem()


{ // Replace site URL and List Title with Valid values.
ClientContext context = new ClientContext("<Site Url>");
List oList = context.Web.Lists.GetByTitle("<List Name>");

ListItemCreationInformation itemCreationInfo = new ListItemCreationInformation();


ListItem oListItem = oList.AddItem(itemCreationInfo);

oListItem["Title"] = "New Title";


// Data in WKT (World Known Text) format.
oListItem["location"] = "POINT (78.4 17.4)" ;

oListItem.Update();
context.ExecuteQuery();
}

See also
Integrating location and map functionality in SharePoint
How to: Set the Bing Maps key at the web and farm level in SharePoint
How to: Extend the Geolocation field type using client-side rendering
Create a map view for the Geolocation field in SharePoint
How to: Integrate maps with Windows Phone apps and SharePoint lists
Use the SharePoint location field type in mobile applications
Create a map view for the Geolocation field in SharePoint
3/26/2018 • 5 minutes to read Edit Online

Learn how to display location information by using a map view in SharePoint lists. You can create a map view manually via the SharePoint user interface (UI) or programmatically by using
the new Geolocation field type. SharePoint introduces a new field type named Geolocation that enables you to annotate SharePoint lists with location information. For example, you can
now make lists "location-aware" and display latitude and longitude coordinates through Bing Maps. An entry is typically seen as a pushpin on a map view.
To display a map view in a SharePoint list, you must use the Bing Maps services. The Geolocation field is not available when you create a list by using the UI. Instead, this field must be
inserted programmatically. For information about how to render and work with this data type programmatically, see Integrating location and map functionality in SharePoint. The
Geolocation field and the map view enable you to give spatial context to any information by integrating data from SharePoint into a mapping experience in web and mobile apps. This
article does not explain how to render the Geolocation field or provide developer guidance for creating a location-based mobile application; it does provide instruction for creating map
views programmatically and from the SharePoint UI by using Bing Maps.
An MSI package named SQLSysClrTypes.msi must be installed on every SharePoint front-end web server to view the Geolocation field value or data in a list. This package installs
components that implement the new geometry, geography, and hierarchy ID types in SQL Server 2008. By default, this file is installed for SharePoint Online. However, it is not installed for
an on-premises deployment of SharePoint. You must be a member of the Farm Administrators group to perform this operation. To download SQLSysClrTypes.msi, see Microsoft SQL
Server 2008 R2 SP1 Feature Pack for SQL Server 2008, or Microsoft SQL Server 2012 Feature Pack for SQL Server 2012 in the Microsoft Download Center.

Prerequisites for creating a map view


Access to a SharePoint list, with sufficient privileges to create a view.
A SharePoint list that contains a Geolocation column
A valid Bing Maps key set at the farm or web level, which can be obtained from the Bing Maps Account Center

Important: You are responsible for compliance with terms and conditions applicable to your use of the Bing Maps key, and any necessary disclosures to users of your application
regarding data passed to the Bing Maps service.

Visual Studio 2012 or Visual Studio 2010

What is a map view?


A map view is a SharePoint view that displays a map (with data obtained from the Bing Maps service), using longitude and latitude entries from the Geolocation field type. When the
Geolocation field type is available on the SharePoint list, a map view can be created either programmatically or from the SharePoint UI. In the list, SharePoint displays the location on a map
powered by Bing Maps. In addition, a new view type named Map View displays the list items as pushpins on a Bing Maps Ajax control V7 with the list items as cards on the left pane.
NOTE

Any SharePoint list can have maximum of two Geolocation columns in it; you won't be able to add a third Geolocation column in the same list. A map view can have only one
Geolocation column. You can create multiple map views with different Geolocation columns.

Create a map view from the SharePoint UI


The following steps demonstrate how to create a map view from the SharePoint UI.
1. Open the SharePoint list with Geolocation column.
2. Choose Create view from the ECB (Edit Control Block) menu, as shown in Figure 1.
Figure 1.Creating a view from the ECB menu

1. On the Choose a view type page, choose Map View, as shown in Figure 2.
Figure 2. Choosing a view type

1. After you choose a view type, you can select various fields to display in the map view, as shown in Figure 3.
Figure 3. Choosing fields for a map view
> [!NOTE]
> At least one **Geolocation** field is required to create a map view. You cannot select multiple **Geolocation** fields for a map view, although you can create two different map views that use t

1. After you add the required Geolocation field and any other field you need, choose OK. A map view is created, as shown in Figure 4.
Figure 4. Completed map view

Create a map view programmatically


Follow these steps to create a map view for a SharePoint list programmatically.
1. Start Visual Studio.
2. On the menu bar, choose File, New Project. The New Project dialog box opens.
3. In the New Project dialog box, choose C# in the Installed Templates box, and then choose the Console Application template.
4. Give the project a name, and then choose the OK button.
5. Visual Studio creates the project. Add a reference to the following assemblies, and choose OK.
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Runtime.dll
1. In the default .cs file, add a using directive as follows.
using Microsoft.SharePoint.Client;

2. Add the following code to the Main method in the .cs file.
NOTE

The JSLink property is not supported on Survey or Events lists. A SharePoint calendar is an Events list.
class Program
{
static void Main(string[] args)
{
CreateMapView ();
Console.WriteLine("A map view is created successfully");
}
private static void CreateMapView()
{
// Replace <Site URL> and <List Title> with valid values.
ClientContext context = new ClientContext("<Site Url>");
List oList = context.Web.Lists.GetByTitle("<List Title>");
ViewCreationInformation viewCreationinfo = new ViewCreationInformation();
// Replace <View Name> with the name you want for your map view.
viewCreationinfo.Title = "<View Name>";
viewCreationinfo.ViewTypeKind = ViewType.Html;
View oView = oList.Views.Add(viewCreationinfo);
oView.JSLink = "mapviewtemplate.js";
oView.Update();
context.ExecuteQuery();
}
}

1. Replace and with valid values.


2. Navigate to the list. You should be able to see a newly created view that has the name you specified in the preceding code.

Understand color-coded pushpins in a map view


A map view providesthree colors of pushpins (as shown in Figure 5), each of which provides a difference user experience. A pushpin on the map has the same color as the pushpin of the
matching item in the left pane.
Orange Indicates that the Geolocation field for the item is mapped with the Bing Maps services.
Grey Indicates that the Geolocation field for the item is empty. The item cannot be mapped with Bing Maps services, so no pushpin for this item appears on the map.
Blue When a user hovers over a list item, the pushpin color changes from orange to blue. Both the pushpin in the left pane and the matching pushpin on the map change color
Figure 5. A map view with different pushpin colors

After you create a map view, all items appear as pushpins. The user can get more information about an item by hovering over a pushpin, as shown in Figure 6.
Figure 6. User experience of pushpins in a map view

See also
Integrating location and map functionality in SharePoint
How to: Add a Geolocation column to a list programmatically in SharePoint
How to: Set the Bing Maps key at the web and farm level in SharePoint
How to: Integrate maps with Windows Phone apps and SharePoint lists
Use the SharePoint location field type in mobile applications
Set the Bing Maps key at the web and farm level in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn how to set the Bing Maps key programmatically at the web and farm level by using the SharePoint client object model and Windows PowerShell, to enable the Bing Maps functionality
in SharePoint lists and location-based web and mobile apps.

Prerequisites for setting the Bing Maps key


To follow the steps in this example, you should have the following:
SharePoint, with administrative privileges.
A valid Bing Maps key, which you can obtain from the Bing Maps Account Center.

Important: Please note that you are responsible for compliance with terms and conditions applicable to your use of the Bing Maps key, and any necessary disclosures to users of
your application regarding data passed to the Bing Maps service.

Code example: Set the Bing Maps key at the farm or web level
The Bing Maps key can be set at the farm or web level. To set the Bing Maps key at the farm level, you need administrator rights on the server; you can then add the key by using the
SharePoint Management Shell. To set the Bing Maps key at the web level, write a console application that uses the SharePoint client object model.

Tip: The Bing Maps key set at web level has higher precedence order than the Bing Maps key set at farm level.

To set the Bing Maps key at the farm level using Windows PowerShell
1. Log on to the SharePoint server as an administrator, and open the SharePoint Management Shell.
2. Execute the following command:
Set-SPBingMapsKey -BingKey "<Enter a valid Bing Maps key>"

The Bing Maps key is now set at the farm level in SharePoint.
NOTE

When you use Windows PowerShell, the Bing Maps key can be set only at the farm level. If you want to set the Bing Maps key at the web level, you can set the key programmatically,
as shown in the following section.

To set the Bing Maps key at the farm or web level using the client object model
1. Start Visual Studio.
2. On the menu bar, choose File, New Project. The New Project dialog box opens.
3. In the New Project dialog box, choose C# in the Installed Templates box, and then choose the Console Application template.
4. Give the project a name, and then choose the OK button.
5. Visual Studio creates the project. Add a reference to the following assemblies, and choose OK.
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Runtime.dll
1. In the default .cs file, add a using directive as follows.
using Microsoft.SharePoint.Client;

2. Add the following code to the Main method in the .cs file.

class Program
{
static void Main(string[] args)
{
SetBingMapsKey();
Console.WriteLine("Bing Maps set successfully");
}
static private void SetBingMapsKey()
{

ClientContext context = new ClientContext("<Site Url>");


Web web = context.Web;
web.AllProperties["BING_MAPS_KEY"] = "<Valid Bing Maps Key>"
web.Update();
context.ExecuteQuery();
}
}

1. Replace the and with valid values.


2. Set the target framework in Project Properties as .NET Framework 4.0, and run the example.
3. The key should now be set at the web level.

Next steps
To learn more about working with location and map functionality in SharePoint, see the following:
How to: Add a Geolocation column to a list programmatically in SharePoint
How to: Extend the Geolocation field type using client-side rendering
Extend the Geolocation field type by using client-side rendering
3/26/2018 • 11 minutes to read Edit Online

Learn how to customize the SharePoint Geolocation field type programmatically using client-side rendering.
SharePoint introduces a new field type named Geolocation that enables you to annotate SharePoint lists with location information. In columns of type Geolocation, you can enter location
information as a pair of latitude and longitude coordinates in decimal degrees, or retrieve the coordinates of the user's current location from the browser if it implements the W3C
Geolocation API. For more information about the Geolocation field, see Integrating location and map functionality in SharePoint. The Geolocation field type is not available in the default
content type of any list or document library in SharePoint. The Geolocation field type is included in SharePoint but isn't visible on the create column page for the list; you must add the
Geolocation field type programmatically. For more information, see How to: Add a Geolocation column to a list programmatically in SharePoint.
After you add the Geolocation field type to SharePoint, you can use it to render maps by using Bing Maps. The built-in Geolocation field can render only with Bing Maps. However, you can
create a custom field by using the Geolocation field as a parent field type. Custom rendering can be provided through the JSLink property in the client-side rendering framework. The client-
side rendering framework is introduced in SharePoint. For more information, see How to: Customize a field type using client-side rendering.
NOTE

The JSLink property is not supported on Survey or Events lists. A SharePoint calendar is an Events list.
In the procedure of this section, you create a custom field derived from Geolocation field type using client-side rendering..

Prerequisites for creating a custom Geolocation field


You must have the following:
A server running SharePoint
Microsoft Visual Studio 2012
Office Developer Tools for Visual Studio 2012
Access to a SharePoint list, with sufficient privileges to add a column

Core concepts to know for customizing the Geolocation field


Table 1. Core concepts for extending the Geolocation field type

AR TICLE TITLE D ES CR IPTIO N

Integrating location and map functionality in SharePoint Learn how to integrate location information and maps in SharePoint lists and location-based web and
mobile apps by using the new Geolocation field, and by creating your own Geolocation-based field
types.

How to: Customize a field type using client-side rendering Learn more about the new client-side rendering introduced in SharePoint.

How to: Add a Geolocation column to a list programmatically in SharePoint Learn how to add a Geolocation column to a list programmatically in SharePoint.

Step 1: Set up the Visual Studio project


To set up the custom field project
1. Start Visual Studio 2012 on the same computer where SharePoint is installed.
2. In the New Project dialog box, under Installed templates, choose Visual C#, Office SharePoint, SharePoint Solutions. Choose the SharePoint project type. Figure 1 shows the
location of the SharePoint Project template in Visual Studio 2012. Make it a farm solution, not a sandboxed solution.
Figure 1. SharePoint project template in Visual Studio

1. Specify a name for the project. We are using CustomGeolocationField in this example. Then choose the OK button.
2. In the SharePoint Customization Wizard, enter the URL for the SharePoint site where you want to deploy your new custom field type.
3. In Solution Explorer, open the shortcut menu for the project name (in our example, it is CustomGeolocationField), and choose Add, New Item.
4. In the Add New Item dialog box, under the Code templates, choose Class, and specify the name for the class ( CustomGeolocationField.cs in this example).
5. In Solution Explorer, open the shortcut menu for the project name, and choose Add, SharePoint mapped folder.
6. In the Add SharePoint Mapped Folder dialog box, use the tree control to map the folder to TEMPLATE\LAYOUTS, and choose the OK button.
7. In Solution Explorer, open the shortcut menu for the new LAYOUTS folder (not the project name), and choose Add, New Item.
8. In the Add New Item dialog box, choose Visual C#, Web, and then choose Javascript File under Templates.
9. In the Name box, specify the name for the file (CustomGeolocationField in our example), and choose Add.
10. Repeat step 8 to create another SharePoint mapped folder, and map it to TEMPLATE\XML. Then choose the OK button.
11. In Solution Explorer, open the shortcut menu for the new XML folder (not the project name), and choose Add, New Item.
12. In the Add New Item dialog box, choose Visual C#, Data, and then choose XML File under Templates.
13. In the Name box, specify the name for the file (this example usesfldtypes_CustomGeolocationControl.xml), and choose the Add button.

Step 2: Create a custom field class


A field class is a class whose instances can represent particular fields that are based on your custom field type. This class must inherit from SPField or one of the classes in SharePoint
Foundation that derive from it. To enable you to extend or customize the Geolocation field type, this class must inherit from SPFieldGeolocation. For more information about creating field
types, see Walkthrough: Creating a Custom Field Type.
NOTE

In this example, the class and solution are named CustomGeolocationField; you can specify the name of the class and project that you want as you create your Visual Studio project.

To create a custom field class


1. Open the CustomGeolocationField.cs file, and add a using directive as follows.

using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;

1. Ensure that the namespace is CustomGeolocationField.


2. Be sure that the class is named CustomGeolocationField, and change its declaration to specify that it inherits from SPFieldGeolocation. Add the following required constructors
for the class.

public class CustomGeolocationField : SPFieldGeolocation


{
/// <summary>
/// Create an instance of CustomGeolocationField object.
/// </summary>
/// <param name="fields">Field collection</param>
/// <param name="fieldName">Name of the field</param>
///
public CustomGeolocationField(SPFieldCollection fields, string fieldName)
: base(fields, fieldName)
{
}

/// <summary>
/// Create an instance of CustomGeolocationField object.
/// </summary>
/// <param name="fields">Field collection</param>
/// <param name="typeName">type name of the field</param>
/// <param name="displayName">display name of the field</param>

public CustomGeolocationField(SPFieldCollection fields, string typeName, string displayName)


: base(fields, typeName, displayName)
{
}

1. Add the following override of the JSLink method to the class. CustomGeolocationControl.js is a JavaScript file that you create in the following step. By providing your own JavaScript file,
you are overriding the default rendering of Bing Maps. If you do not override this method, the default rendering will be from Bing Maps. The JSLink property is introduced in SharePoint.
For more information about the JSLink property, see How to: Customize a field type using client-side rendering.

/// <summary>
/// Override JSLink property.
/// </summary>

public override string JSLink


{
get
{
return "CustomGeolocationControl.js";
}
set
{
base.JSLink = value;
}
}

1. The GetFieldValue method converts the specified value into a field type value. For more information about the GetFieldValue method, see GetFieldValue(String) . Add the following
override of the GetFieldValue method to the CustomGeolocationField class.

/// <summary>
/// get the field values
/// </summary>
/// <param name="value"></param>
/// <returns></returns>

public override object GetFieldValue(string value)


{
return base.GetFieldValue(value);
}

1. Add the following override of the GetValidatedString method to the CustomGeolocationField class:
/// <summary>
/// get validated string
/// </summary>
/// <param name="value"></param>
/// <returns></returns>

public override string GetValidatedString(object value)


{
return base.GetValidatedString(value);
}

Step 3: Create rendering for the new custom field


Next, you should create the JavaScript file that the JSLink method of the field class points to. This file should define the rendering of the custom field type using the new client-side rendering
framework. For more information, see How to: Customize a field type using client-side rendering.
The following example shows the registration logic for registering with the client side rendering framework introduced in SharePoint.

function _registerCustomGeolocationFieldTemplate() {

var geolocationFieldContext = {};


geolocationFieldContext.Templates = {};
geolocationFieldContext.Templates.Fields = {

'CustomGeolocationField': {
'View': CustomGeolocationFieldTemplate.RenderGeolocationField,
'DisplayForm': CustomGeolocationFieldTemplate.SPFieldGeolocation_Display,
'EditForm': CustomGeolocationFieldTemplate.SPFieldGeolocation_Edit,
'NewForm': CustomGeolocationFieldTemplate.SPFieldGeolocation_Edit
}
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(geolocationFieldContext);
}

In the registration process there are four variables and their respective methods. The client-side rendering framework calls these methods for rendering CustomGeolocationControl.
The following code example creates new rendering for a new custom field for new custom field that is derived from Geolocation.

To create the JavaScript file


1. Create a text file and specify a name, such as x, give it a .js extension, and save it to the SharePoint-mapped TEMPL ATE\L AYOUTS folder. This example uses the name
CustomGeolocationControl.js.
2. Copy the following code into the .js file.

(function () {
if (typeof CustomGeolocationFieldTemplate == "object") {
return;
}
window.CustomGeolocationFieldTemplate = (function () {
return {
SPFieldGeolocation_Display: function (rCtx) {
if (rCtx == null || rCtx.CurrentFieldValue == null || rCtx.CurrentFieldValue == '')
return '';
var listItem = rCtx['CurrentItem'];
var fldvalue = CustomGeolocationFieldTemplate.ParseGeolocationValue(listItem[rCtx.CurrentFieldSchema.Name]);
var _myData = SPClientTemplates.Utility.GetFormContextForCurrentField(rCtx);

if (_myData == null || _myData.fieldSchema == null)


return '';
var _latitude = 0;
var _longitude = 0;

if (fldvalue != null) {
_latitude = fldvalue.latitude;
_longitude = fldvalue.longitude;
}

var result = '<div>';


result += '<span>Latitude:</span><span>' + _latitude + '</span><span>Longitude:</span><span>' + _longitude + '</span>';
result += '</div>';
return result;
},
ParseGeolocationValue: function (fieldValue) {

if (fieldValue == null || fieldValue == '')


return null;

var point = new Object();


point.longitude = null;
point.latitude = null;
point.altitude = null;
point.measure = null;

var matches = fieldValue.match(/POINT\\s*\\((\\d+(\\.\\d+)?)\\s+(\\d+(\\.\\d+)?)\\s+(\\d+(\\.\\d+)?)\\s+(\\d+(\\.\\d+)?)\\)/i);


if (matches != null) {

point.longitude = parseFloat(matches[1]);
point.latitude = parseFloat(matches[3]);
point.altitude = parseFloat(matches[5]);
point.measure = parseFloat(matches[7]);
}
else
{
matches = fieldValue.match(/POINT\\s*\\((\\d+(\\.\\d+)?)\\s+(\\d+(\\.\\d+)?)\\)/i);
if (matches != null) {
point.longitude = parseFloat(matches[1]);
point.latitude = parseFloat(matches[3]);
}
}
return point;
},
SPFieldGeolocation_Edit: function (rCtx) {
if (rCtx == null)
return '';
var _myData = SPClientTemplates.Utility.GetFormContextForCurrentField(rCtx);

if (_myData == null || _myData.fieldSchema == null)


return '';
var _latitude = null;
var _longitude = null;
var _inputId_Latitude = _myData.fieldName + '_' + _myData.fieldSchema.Id + '_$geolocationField_Latitude';
var _inputId_Longitude = _myData.fieldName + '_' + _myData.fieldSchema.Id + '_$geolocationField_Longitude';
var _inputId_Div = _myData.fieldName + '_' + _myData.fieldSchema.Id + '_$geolocationField_Div';
var _latitudeBox = null;
var _longitudeBox = null;

var _value = _myData.fieldValue != null ? _myData.fieldValue : '';


var listItem = rCtx['CurrentItem'];
var fldvalue = CustomGeolocationFieldTemplate.ParseGeolocationValue(listItem[rCtx.CurrentFieldSchema.Name]);

if (fldvalue != null) {
_latitude = fldvalue.latitude;
_longitude = fldvalue.longitude;
}

var validators = new SPClientForms.ClientValidation.ValidatorSet();

if (_myData.fieldSchema.Required)
validators.RegisterValidator(new SPClientForms.ClientValidation.RequiredValidator());

_myData.registerClientValidator(_myData.fieldName, validators);

// Post DOM initialization callback.


_myData.registerInitCallback(_myData.fieldName, function () {

// Initialize the input control references.


_latitudeBox = document.getElementById(_inputId_Latitude);
_longitudeBox = document.getElementById(_inputId_Longitude);

// Set the initial values.


if ((_latitudeBox != null &amp;&amp; _longitudeBox != null) &amp;&amp;
(_latitude != null &amp;&amp; _longitude != null)) {
_latitudeBox.value = _latitude;
_longitudeBox.value = _longitude;
}
});
// On focus call back.
_myData.registerFocusCallback(_myData.fieldName, function () {
if (_latitudeBox != null)
_latitudeBox.focus();
});
// Validation failure handler.
_myData.registerValidationErrorCallback(_myData.fieldName, function (errorResult) {
SPFormControl_AppendValidationErrorMessage(_inputId_Div, "invalid Geolocation Field");
});

// Register a callback just before submit.


_myData.registerGetValueCallback(_myData.fieldName, function () {
if (_latitudeBox == null &amp;&amp; _longitudeBox == null)
return '';
else {
_latitude = _latitudeBox.value;
_longitude = _longitudeBox.value;

if (_latitude != null &amp;&amp; _longitude != null)


return "Point(" + _longitude + " " + _latitude + ")";
}
});
_myData.updateControlValue(_myData.fieldName, _value);

var result = '<div width="100%" id=' + STSHtmlEncode(_inputId_Div) + '>';


result += '<div><span>Latitude:</span><input id=' + STSHtmlEncode(_inputId_Latitude) + ' type="text" name="Latitude" /></div>';
result += '<div><span>Longitude:</span><input id=' + STSHtmlEncode(_inputId_Longitude) + ' type="text" name="Longitude" /></div>';
result += '</div>';
return result;

},
RenderGeolocationField: function (inCtx, field, listItem, listSchema) {
var fldvalue = CustomGeolocationFieldTemplate.ParseGeolocationValue(listItem[field.Name]);
var result = '';

if (fldvalue != null) {
var result = '<div>';
result += '<span>Latitude:</span><span>' + fldvalue.latitude + '</span><span>Longitude:</span><span>' + fldvalue.longitude + '</span>';
result += '</div>';
}
return result;
}
};
})();
function _registerCustomGeolocationFieldTemplate() {

var geolocationFieldContext = {};


geolocationFieldContext.Templates = {};
geolocationFieldContext.Templates.Fields = {

'CustomGeolocationField': {
'View': CustomGeolocationFieldTemplate.RenderGeolocationField,
'DisplayForm': CustomGeolocationFieldTemplate.SPFieldGeolocation_Display,
'EditForm': CustomGeolocationFieldTemplate.SPFieldGeolocation_Edit,
'EditForm': CustomGeolocationFieldTemplate.SPFieldGeolocation_Edit,
'NewForm': CustomGeolocationFieldTemplate.SPFieldGeolocation_Edit
}
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(geolocationFieldContext);
}
ExecuteOrDelayUntilScriptLoaded(_registerCustomGeolocationFieldTemplate, 'clienttemplates.js');
})();

Step 4: Create a field type definition


A field type definition is an XML file with a name like fldtypes*.xml that is deployed to %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\TEMPL ATE\XML. A
field definition file contains the information that SharePoint Foundation needs to correctly render the field in list views, and on the Display, Edit, and New forms. Most importantly, the
definition contains information about the assembly that contains the compiled field type. For more information about field type definitions, see How to: Create a Custom Field Type
Definition.

To create the field type definition


1. In Visual Studio, build the project. The project is not finished, but you need to build at this time to generate a GUID and a Public Key Token for the assembly.
2. Open the fldtypes_CustomGeolocationControl.xml file, and replace its contents with the following markup.

?xml version="1.0" encoding="utf-8" ?>

<FieldTypes>
<FieldType>
<Field Name="TypeName">CustomGeolocationField</Field>
<Field Name="ParentType">Geolocation</Field>
<Field Name="TypeDisplayName">Custom Geolocation field</Field>
<Field Name="TypeShortDescription"> Custom Geolocation field </Field>
<Field Name="UserCreatable">TRUE</Field>
<Field Name="ShowOnListCreate">TRUE</Field>
<Field Name="ShowOnSurveyCreate">TRUE</Field>
<Field Name="ShowOnDocumentLibraryCreate">TRUE</Field>
<Field Name="ShowOnColumnTemplateCreate">TRUE</Field>
<Field Name="FieldTypeClass">CustomGeolocationField.CustomGeolocationField,$SharePoint.Project.AssemblyFullName$</Field>
<Field Name="SQLType">nvarchar</Field>
</FieldType>
</FieldTypes>

This file defines the custom field type for SharePoint. For details about the purpose and meaning of its elements, see [Custom Field Type Definition](http://msdn.microsoft.com/library/b3315997-6

1. The value of the element is the fully qualified name of your custom field class followed by a comma and then a Visual Studio token ( $SharePoint.Project.AssemblyFullName$ ). When you
compile the project, a copy of this file is created in which the token is replaced by the full four-part name of the assembly. That copy is deployed when you choose Deploy Solution on
the Visual Studio Build menu in Visual Studio 2012.

Step 5: Build and test the custom field type


After you deploy a custom field to the SharePoint server, a new custom column is available for you to add to any SharePoint list on the server where the solution is deployed.
1. Choose the F5 key.
NOTE

When you choose F5, Visual Studio builds the solution, deploys the solution, and opens the SharePoint website where the solution is deployed.
2. Create a custom list and add a new Custom Geolocation field column.
3. Add one item to the list, and provide Longitude and Latitude values for the Custom Geolocation column.
4. Figure 2 shows the create column page with the new custom field type.
Figure 2. Creating a new custom field type column

See also
Integrating location and map functionality in SharePoint
How to: Add a Geolocation column to a list programmatically in SharePoint
How to: Customize a field type using client-side rendering
SharePoint: Create a Geolocation field that renders maps using Nokia Maps
How to: Create a Custom Field Type
Deploying files using Mapped Folders
Search in SharePoint
5/3/2018 • 7 minutes to read Edit Online

Understand the extensibility building blocks in Search in SharePoint and how you can use these building blocks to suit your use cases. Search in SharePoint enables users to find relevant
information more quickly and easily than ever before and makes it easy for Search administrators to customize the search experience. It also provides several API sets for more advanced
customizations and solutions.
See the following articles for a good introduction to general SharePoint development concepts; you may find it helpful to review these before proceeding:
Set up a general development environment for SharePoint
Choose the right API set in SharePoint
SharePoint Add-ins compared with SharePoint solutions
Deciding between SharePoint Add-ins and SharePoint solutions

Search architecture overview


Search in SharePoint includes a wide variety of improvements and new features. With this version, Search in SharePoint is re-architected to a single enterprise search platform. The search
architecture consists of the following areas:
Crawl and content processing
Index
Query processing
Search administration
Analytics
These areas consist of components and databases that work cohesively to perform the search operation. Figure 1 provides an overall view of the different areas of search architecture, and
the components and databases within that work cohesively to perform the search operation.
Figure 1. Search component interaction

For a more detailed view, see Technical Diagrams -- Search and Overview of search in SharePoint.

Crawl and content processing


The crawl and content processing architecture consists of the following:
Crawl component
Crawls content sources to collect crawled properties and metadata from crawled items and sends this information to the content processing component.
Crawl database
Contains information about crawled items, such as last crawl time, the last crawl ID, and the type of update during the last crawl.
Content processing component
Crawls content sources to collect crawled properties and metadata from crawled items and sends this information to the index component.

Index
The index component receives the processed items from the content processing component and writes them to the search index. This component also handles incoming queries, retrieves
information from the search index, and sends back the result set to the query processing component.

Query processing
The query processing component analyzes and processes search queries and results. The processed query is then submitted to the index component, which returns a set of search results for
the query.
Search administration
Search administration is composed of the search administration component and its corresponding database.
Search administration component
Runs the system processes for search, and adds and initializes new instances of search components.
Search administration database
Stores search configuration data.

Analytics
The analytics architecture consists of the analytics processing component, analytics reporting database, and link database.
Analytics processing component
Performs search analytics and usage analytics.
Link database
Stores information extracted by the content processing component and search click information.
Analytics reporting database
Stores the results of usage analytics.
Event store
Stores usage events that are captured on the front-end.

Search extensibility points


The Search in SharePoint architecture provides several extensibility points to support customization scenarios. In this section, we'll describe these points and show you where you can find
more information about developing for these scenarios.

Connector framework
The crawl component crawls content by invoking connectors or protocol handlers that interact with content sources to retrieve data. Search in SharePoint includes a connector framework
that you can use to customize and build connectors to crawl new content sources. For detailed information about the connector framework architecture and how to extend it, see Search
connector framework in SharePoint.

Custom content processing


Within the content processing component, you can use the Content Enrichment web service callout to modify the managed properties of crawled items before they are added to the search
index. This web service callout calls out to any external content enrichment web service that you create. For more information, see Custom content processing with the Content Enrichment
web service callout. For a step-by-step implementation of a content enrichment web service, see How to: Use the Content Enrichment web service callout for SharePoint Server. The blog
post Customize the SharePoint search experience with a Content Enrichment web service is also a good resource

Query APIs
Search in SharePoint provides several query APIs, giving you lots of ways to access search results, so that you can return search results in a variety of custom solution types.
Table 1 shows the APIs that you can use to program Search in SharePoint and where to find them.
Table 1. Search APIs

API NAME CL AS S LIB R AR Y O R S CHEMA AND PATH

.NET client object model (CSOM) Microsoft.SharePoint.Client.Search.dll


%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\ISAPI

Silverlight CSOM Microsoft.SharePoint.Client.Search.Silverlight.dll


%ProgramFiles%\Common Files\Microsoft Shared\web server
extensions\15\TEMPLATE\LAYOUTS\ClientBin

JavaScript CSOM SP.search.js


%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\TEMPLATE\LAYOUTS

Representational State Transfer (REST) service endpoints http://server/_api/search/query


http://server/_api/search/suggest

Server object model Microsoft.Office.Server.Search.dll


%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\ISAPI

For more information, see Using the SharePoint search Query APIs.

Analytics
To help identify and surface the content that users consider to be the most useful and relevant, the analytics processing component analyzes both the content itself, and also the way that
users interact with it. These analyses are done by timer jobs that are responsible for performing analysis lifecycle tasks such as starting, stopping, pausing, and resuming an analysis job when
requested. You can manipulate these timer jobs through the Microsoft.Office.Server.Search.Analytics namespace. For in-depth information about analytics in SharePoint, see Overview of
analytics processing in SharePoint.

Custom ranking models


Search results can be ordered in various ways, one of which is by rank score. Rank scores are calculated by the search engine using ranking models. SharePoint provides fourteen ranking
models by default. However, if you are not satisfied with the way your search results are ordered, you can use a custom ranking model. To learn more about the process of creating a custom
ranking model and tuning it, see Customizing ranking models to improve relevance in SharePoint.

Custom security trimming


Search in SharePoint performs security trimming of search results that are based on the identity of the user submitting the query, at query time, by using security information obtained from
the crawl component. However, in some cases, you may need to implement custom security trimming. SharePoint provides two interfaces to accomplish this task: ISecurityTrimmerPre and
ISecurityTrimmerPost .
The pre-trimmer interface ( ISecurityTrimmerPre) carries out pre-query evaluation, where the search query is rewritten to add security information before the search query is matched to
the search index. In contrast, the post-trimmer interface ( ISecurityTrimmerPost) carries out post-query evaluation, where the search results are pruned before they are returned to the user.
For more information about the two interfaces, see Custom security trimming for Search in SharePoint. For step-by-step information on how to implement a security trimmer interface, see
How to: Use a custom security trimmer for SharePoint Server search results.

Content Search web part


The Content Search web part is a web part that can display dynamic content that was previously crawled and added to the search index. Each instance of the web part is associated with a
search query and shows the results for that particular search query. When users browse to a page that contains a Content Search web part, a search query is automatically issued, and the
corresponding search results are returned from the search index. You can use the Content Search web part whenever you want to display content that is populated by automatically
generated search queries. In some cases, you may want to extend the Content Search web part, which is exposed through the Microsoft.Office.Server.Search.WebControls namespace as
ContentBySearchWebPart . To learn about how to extend the ContentBySearchWebPart so that the web part understands custom properties, see User segmentation in SharePoint.

Search-driven mobile apps using the Navigation and Event Logging REST interfaces
SharePoint provides two new REST interfaces: Navigation and Event Logging. You can use them to create search-driven mobile apps for mobile devices, such as phones and tablets, that run
on operating systems other than Windows. This feature lets you display the product catalog on a mobile device in an alternate way, instead of using a mobile channel. See How to: Build
search-driven mobile apps with the Navigation and Event Logging REST interfaces for a detailed example of how to create such an app.

In this section
What's new in SharePoint search for developers
Searching new content with SharePoint Search
Configure search in SharePoint
Building search queries in SharePoint
SharePoint Search REST API overview
Customizing search results in SharePoint
Sorting search results in SharePoint
Customizing ranking models to improve relevance in SharePoint
Custom security trimming for Search in SharePoint
Exporting and importing search configuration settings in SharePoint

See also
Changes from SharePoint 2010 to SharePoint
Technical Diagrams -- Search
Add SharePoint capabilities
What's new in SharePoint search for developers
3/26/2018 • 7 minutes to read Edit Online

Learn about the new features available for developers in Search in SharePoint.

Search client object model for access to Query object model functionality for online, on-premises, and mobile
development
SharePoint Search includes a client object model (CSOM) that enables access to most of the Query object model functionality for online, on-premises, and mobile development. You can use
the Search CSOM to create client applications that run on a machine that does not have SharePoint installed to return SharePoint search results.
The Search CSOM includes a Microsoft .NET Framework managed client object model and JavaScript object model, and it is built on SharePoint. First, client code accesses the SharePoint
CSOM. Then, client code accesses the Search CSOM.
To use the Search .NET Framework managed CSOM, you must get a ClientContext instance (located in the Microsoft.SharePoint.Client namespace in the Microsoft.SharePoint.Client.dll).
Then, use the object model in the Microsoft.SharePoint.Client.Search.Query namespace in the Microsoft.Office.Server.Search.Client.dll. For more information about the SharePoint CSOM,
see SharePoint 2010 Client Object Model. For more information about the ClientContext object, which is the entry point to the CSOM, see Client Context as Central Object.
The Search CSOM returns the search results data from the server in JavaScript Object Notation (JSON). The JSON for the search results data contains a ResultTableCollection collection
composed of ResultTable objects that represent different result sets.

SQL Syntax Support Removed


Custom search solutions in SharePoint do not support SQL syntax. Search in SharePoint supports FQL syntax and KQL syntax for custom search solutions. You cannot use SQL syntax in
custom search solutions using any technologies, including the Query server object model, the client object model, and the Search REST service. Custom search solutions that use SQL syntax
with the Query server object model and the Query web service that were created in earlier versions of SharePoint Server will not work when you upgrade them to SharePoint. Queries
submitted via these applications will return an error. For more information about using FQL syntax and KQL syntax, see Keyword Query Language (KQL) syntax reference and FAST Query
Language (FQL.md) syntax reference.

Search REST service for remote execution of queries from client applications
SharePoint includes a Representational State Transfer (REST) service that enables you to remotely execute queries against the SharePoint Search service from client applications by using
any technology that supports REST web requests. The Search REST service exposes two endpoints, query and suggest, and will support both GET and POST operations. Results are
returned in either XML or JSON format.
The following is the access point for the service: http://server/_api/search/ . You can also specify the site in the URL, as follows: http://server/site/_api/search/ . The search service returns
results from the entire site collection, so the same results are returned for both ways to access the service.
You can also use the URL that references client.svc to access the service, as follows: http://server/_vti_bin/client.svc/search/ . However, using _api is the preferred convention.
Use the following access point to access the service metadata:
http://server/_api/$metadata

For general information about the REST service in SharePoint, see Use OData query operations in SharePoint REST requests.

SharePoint Search Query web service is deprecated


The Query web service (located in the path http://server/site/_vti_bin/search.asmx ) is deprecated in SharePoint. If you write new applications, avoid using this deprecated feature and
instead use the new Query CSOM or Query REST service. If you modify existing applications, we strongly encourage you to remove any dependency on this feature.

SharePoint Search Query object model enhancements


Query properties provide information about a search query. In SharePoint Search, a property bag was added to the query and result classes to enable user-defined query properties. You can
access existing query properties via the property on one of the query classes, as follows:
KeywordQuery.EnableStemming

Or you can use the property bag, as follows:


KeywordQuery.Properties["EnableStemming"]

You can access user-defined properties only by using the property bag, as follows:
KeywordQuery.Properties["UserDefinedProperty"]

SharePoint Search includes query properties in the property bag, including new query properties such as:
BypassResultTypes Specifies whether the search result item type is returned for the query results. Specify true to return no result type; otherwise, false.
EnableInterleaving Specifies whether the result sets generated by executing query rule actions to add a result block are mixed with the result set for the original query. Specify true
to mix the generated result set with the original result set; otherwise, false.
EnableQueryRules Specifies whether query rules are turned on for this query. Specify true to enable query rules for the query; otherwise, false.
You can specify any property in the property bag, including user-defined properties, as query rule conditions. You use query rules to customize the search experience for the kinds of queries
that are important to your users. When a query meets conditions specified in a query rule, the rule specifies actions to improve the relevance of the associated search results.

Keyword query language enhancements


SharePoint includes improvements to the Keyword query language, which are described in this section.

Improved NEAR operator


In SharePoint Server 2010, the NEAR operator implied a maximum token distance of 8 and preserved the ordering of the input tokens. In SharePoint, the NEAR operator no longer
preserves the ordering of tokens. In addition, the NEAR operator now receives an optional parameter that indicates maximum token distance. However, the default value is still 8. If you must
use the previous behavior, use ONEAR instead.
The NEAR operator can be used in property restriction expressions, as shown in the following example:
"acquisition" NEAR "debt"

This query matches items where the tokens "acquisition" and "debt" appear within the same document, with a maximum token distance of 8 (which is the default value of n if no value is
provided). The order of the tokens is not significant for the match.
If you require a smaller token distance, you can specify it as follows:
"acquisition" NEAR(n=3) "debt"

This query matches items where the two tokens "acquisition" and "debt" appear within the same document, with a maximum token distance of 3. The order of the tokens is not significant for
the match.

New ONEAR operator


The ONEAR operator provides ordered near functionality. It receives an optional parameter that indicates maximum token distance; the default value is 8.
The ONEAR operator preserves the order of the input expressions. For unordered proximity, use NEAR.
You can use the ONEAR operator in property restriction expressions, as shown in the following example:
"acquisition" ONEAR "debt"

This query matches items where the two tokens "acquisition" and "debt" appear within the same document, with a maximum token distance of 8 (which is the default value of n if no value is
provided). The order of the tokens must match for an item to be returned.
If you require a smaller token distance, you can specify it as follows:
"acquisition" ONEAR(n=3) "debt"

This query matches items where the two tokens "acquisition" and "debt" appear within the same document, with a maximum token distance of 3. The order of the tokens must match for an
item to be returned.

New XRANK operator


In SharePoint Server 2010, the XRANK operator was available only with FAST Query language (FQL). SharePoint introduces a new and powerful XRANK operator.
The XRANK operator provides dynamic control of ranking. This operator boosts the dynamic rank of items based on the occurrence of certain terms without changing items that match the
query.

Rich results framework for customizing search results UI


SharePoint Search includes a new results framework that makes it easy to customize the appearance (look and feel) of the search results user interface (UI). Now, instead of writing a custom
XSLT to change how search results are displayed, you can customize the appearance of important types of results by using display templates and result types.

Display templates
Display templates define the visual layout and behavior of a result type by using HTML, CSS, and JavaScript. You can customize the existing display templates or create display templates by
using an HTML editor and upload them to the display templates gallery.

Result types
Result types define how to display a set of search results based on a collection of the following:
Rules Determine when to apply a result type, based on the specified conditions. Rule conditions can be joined by using equality, comparison, and logical operators.
Properties Determine the list of managed properties for the result. You must add managed properties to the list before you map the managed property to a display template.
Display templates Define the visual layout of the result type.
Administrators can create and manage result types at the site level or service application level; no custom coding is required.

Connector framework enhancements


SharePoint Search enables you to retrieve claims information for content stored in custom external data sources that are crawled by using the connector framework.
The connector framework also provides improved exception capturing and logging to help you troubleshoot errors encountered when crawling content sources using custom connectors that
are built on top of the connector framework. For information about the connector framework, see Search connector framework in SharePoint.

See also
Searching new content with SharePoint Search
Configure search in SharePoint
Building search queries in SharePoint
How to: Use a custom security trimmer for SharePoint Server search results
Searching new content with SharePoint Search
3/26/2018 • 2 minutes to read Edit Online

Learn how to make content available for users to search with SharePoint.

Making content available for search in SharePoint


Search in SharePoint provides two approaches for processing queries to return search results—federated search and content crawling.
Federated search In this approach, search results are returned for content that is not crawled by your search server. The query is forwarded to an external content repository where it is
processed by that repository's search engine. The repository's search engine then returns the results to the search server. The search server formats and renders the results from the external
repository to display on the search results page. This approach offers the following advantages:
You require no additional capacity requirements for the content index, as content is not crawled by Search in SharePoint.
You can take advantage of a repository's existing search engine. For example, you can federate to an Internet search engine to search the web.
You can optimize the content repository's search engine for the repository's specific set of content, which might provide better search performance on the content set.
You can access repositories that are secured against crawls, but which can be accessed by search queries.
Content crawling In this approach, results are returned from the Search service application's content index based on the user's query. The content index contains content that is crawled by
the Search service application, and includes text content and metadata for each content item. This approach enables you to:
Sort results by relevance.
Control how frequently the content index is updated.
Specify what metadata is crawled.
Perform a single backup operation for crawled content.

In this section
Search connector framework in SharePoint
Enhancing the BDC model file for Search in SharePoint
How to: Crawl associated external content types in SharePoint
How to: Crawl binary large objects (BLOBs) in SharePoint
How to: Crawl associated external content types in SharePoint
How to: Configure item-level security in SharePoint
Search connector framework in SharePoint
4/13/2018 • 9 minutes to read Edit Online

Learn about the SharePoint indexing connectors, the connector framework, and how you can create custom BCS indexing connectors to search external systems.

Making content available for search in SharePoint


Search in SharePoint provides two approaches for processing queries to return search results—federated search and content crawling.
Federated search In this approach, search results are returned for content that is not crawled by your search server. The query is forwarded to an external content repository where it is
processed by that repository's search engine. The repository's search engine then returns the results to the search server. The search server formats and renders the results from the external
repository to display on the search results page. This approach offers the following advantages:
You require no additional capacity requirements for the content index, because content is not crawled by Search in SharePoint.
You can take advantage of a repository's existing search engine. For example, you can federate to an Internet search engine to search the web.
You can optimize the content repository's search engine for the repository's specific set of content, which might provide better search performance on the content set.
You can access repositories that are secured against crawls, but that can be accessed by search queries.
Content crawling In this approach, results are returned from the Search service application's content index based on the user's query. The content index contains content that is crawled by
the Search service application, and includes text content and metadata for each content item. This approach enables you to:
Sort results by relevance.
Control how frequently the content index is updated.
Specify what metadata is crawled.
Perform a single backup operation for crawled content.

Crawling content with indexing connectors in SharePoint


The crawler uses indexing connectors to access the content to crawl. The indexing connector is the component that knows how to connect to the content source, what to crawl, and how to
crawl it. In earlier versions of SharePoint, these were known as protocol handlers, components that are based on custom interfaces running unmanaged C++ code.
Search in SharePoint includes a connector framework, introduced in SharePoint Server 2010 and built on Microsoft Business Connectivity Services (BCS), which provides a simpler
approach to developing indexing connectors. With the connector framework, the crawler uses indexing connectors based on BCS to crawl external content. SharePoint uses both protocol
handler-based indexing connectors and BCS indexing connectors to crawl content.
Figure 1 provides a high-level overview of the SharePoint indexing connector story.

BCS overview for Search in SharePoint


BCS is the umbrella of tools and infrastructure that enables you to connect to external systems from SharePoint. Figure 2 shows a high-level view of the BCS architecture, with the relevant
areas for Search highlighted.
Figure 2. BCS architecture including Search
BCS makes the connection to the external data based on the external content type definition in the metadata store. The metadata store contains the following information for an external
content type:
Connectivity information Describes how to connect to the external system.
Entity information Describes the structure of the external data.
Operations Describes methods used to access the external data. In the case of databases and web services, these are methods supported by the external system: SQL statements for
database connectors and web methods for web services. For .NET and custom BCS indexing connectors, these are methods that are implemented in the connector assembly, which is
the component DLL you create for the indexing connector.
This information is specified in the external content type's BDC model file. For more information about BDC models and what they contain, see BDC Model Infrastructure.
For details about BCS architecture and functionality, see Business Connectivity Services Overview and Mechanics of Using Business Connectivity Services.

Using the connector framework


To crawl external data, you have to add one of the content source types that support connecting to external data. Table 1 lists these content source types.
Table 1. Content source types that support BCS indexing connectors

CO NTENT S O U R CE T YPE D ES CR IPTIO N

Line of Business Data Use this content source for database and web service BCS indexing connectors.

Custom Repository Use this content source for .NET and custom BCS indexing connectors.

The connector framework enables you to create BCS indexing connectors to connect to external content that you want to crawl and include in the content index. The BCS indexing connector
is used by the crawler to communicate with the external data source. At crawl time, the crawler calls the BCS indexing connector to fetch the data from the external system and pass it back to
the crawler. The BCS indexing connector also parses the access URLs understood by Search and the identifiers understood by BCS as they are passed between BCS and Search during the
crawl process.
BCS indexing connectors are composed of the following:

The BDC model file The file that provides the structure of the data, and that provides connection information to the external system.
The connector The component containing the code that connects to the external system and parses the access URLs and BCS identifiers.

For BCS indexing connectors based on the Line of Business Data content source types, Search includes built-in connectors, so you have to create only a BDC model file.
For BCS indexing connectors based on the Custom Repository content source types, you must develop a custom component in addition to a BDC model file to connect to the external data.
Figure 3 shows a high-level view of the search connector framework architecture.
Figure 3. Search connector framework architecture

BCS indexing connectors


SharePoint supports the following types of BCS indexing connectors:
Database connector SharePoint includes a predefined BCS connector that supports connecting to databases, so you can create a database BCS indexing connector without writing
any code—just create the BDC model file for the connector.
WCF (web services) connector SharePoint includes a predefined BCS connector that supports connecting to web services, so you can create a web service BCS indexing connector
without writing any code—just create the BDC model file for the connector.
NOTE

Although you don't have to write code to create a connector for web services, the web service must include methods that provide the same functionality that the .NET BCS connector
provides, to pass the external business data to BCS. For information about creating a web service, see Creating .NET Connectivity Assemblies and Web Services. For code examples,
see Sample Orders ASP.NET Web Service Sample and Sample Orders WCF Service Sample.
.NET BCS connector SharePoint does not include a predefined BCS connector for .NET connectors, so in addition to creating a BDC model file, you must also create a .NET
component for the BCS indexing connector. You must implement the required stereotyped operations to support crawling the data, and implement methods for parsing the access
URLs and BDC identifiers.
Custom BCS connector SharePoint does not include a predefined BCS connector for custom .NET connectors, so in addition to creating a BDC model file, you must also create a
.NET component for the BCS indexing connector, just as you must for the .NET BCS connector. You must implement the required stereotyped operations to support crawling the data,
and implement methods for parsing the access URLs and BDC identifiers. You must also implement the ISystemUtility interface.

Building BCS indexing connectors


When you develop a BCS indexing connector—whether you're just creating the BDC model file for database and web service indexing connectors, or creating the BDC model file and coding
the BCS connector component for .NET and custom indexing connectors—you need to think about the following:
Connectivity How to connect to the external data repository, for example, the server address, IP address, or database instance name. Also includes the authentication information
used to connect to the external data repository.
Structure of repository To read the data, the connector must know how the repository is organized. Is it hierarchical, enumerical, or does it have to traverse links?
Incremental crawls To reduce the performance load on the external data repository, give the connector the ability to do incremental crawls in addition to full crawls. For this, the
connector must recognize what data has changed since the last crawl and be able to crawl only that data. This can be done by using a timestamp-based incremental crawl or a change
log-based crawl. The approach you implement depends on the APIs provided by the repository and the freshness goals for the content.
Securing data In most scenarios, not all data is accessible to all users. It's important that this also works with search, so when a user searches by using the search UI, the user can see
only the results he or she has access to. This means the connector must know how to read the security of the external system, and bring that security-related information back during
the crawl into the index. For example, you could implement crawl-time storage of Windows NT access control lists (ACLs).
Table 2 describes the stereotyped operations that apply when you create a BCS indexing connector for SharePoint.
Table 2. BCS stereotyped operations supported by Search in SharePoint

O PER ATIO N D ES CR IPTIO N

Finder Core operation required when creating a BCS connector. This operation retrieves the list of items of the
external content source. See Implementing a Finder.

SpecificFinder Core operation required when creating a BCS connector. This operation retrieves individual items from
the external content source. See Implementing a SpecificFinder.

ChangedIdEnumerator Required to implement changelog-based incremental crawls. See Implementing a ChangedIdEnumerator

DeletedIdEnumerator Required to implement changelog-based incremental crawls. See Implementing a DeletedIdEnumerator

BinarySecurityDescriptorAccessor Required to implement item-level security. Returns the security descriptor for an item from the external
content source. See Implementing a BinarySecurityDescriptorAccessor.

StreamAccessor Required to enable crawling of attachments from the external content source. Returns the attachment as
a data stream. See Implementing a StreamAccessor.

Tooling support for developing BCS indexing connectors


BCS provides tooling support for BCS connectors in SharePoint Designer and Visual Studio.
SharePoint Designer tooling support for BCS connectors
SharePoint Designer provides a limited set of capabilities; you can use it to create BDC model files for existing BCS connector types, such as database, web service, and .NET BCS connectors.
You can also use it to export BDC model files from one BCS service application to another BCS service application.
Visual Studio tooling support for BCS connectors
You can use Visual Studio to create the component for .NET BCS connectors and custom BCS connectors. For .NET BCS connectors, Visual Studio provides the Business Data Connectivity
Model project template, which includes a set of visual designers and code management capabilities to enable you to more easily create, debug, and deploy the .NET component and the
associated BDC model file for the .NET BCS connector. There is no corresponding project template for custom BCS connectors.

Connector framework enhancements in SharePoint


In SharePoint the connector framework supports BCS connectors retrieving claims information for content that is stored in custom external data repositories.
The connector framework also provides improved exception capturing and logging to help you troubleshoot errors encountered when crawling content sources by using BCS connectors.

See also
Enhancing the BDC model file for Search in SharePoint
How to: Crawl associated external content types in SharePoint
How to: Crawl binary large objects (BLOBs) in SharePoint
How to: Crawl associated external content types in SharePoint
How to: Configure item-level security in SharePoint
Enhancing the BDC model file for Search in SharePoint
3/26/2018 • 6 minutes to read Edit Online

Learn about the properties in the BDC metadata model that are applicable to BCS indexing connectors which enable Search in SharePoint to crawl external data.

Search properties for BDC model files


The connector framework in Search enables you to crawl external data, making it available in search results through BCS indexing connectors. The BCS indexing connector is used by the
crawler to communicate with the external data source. At crawl time, the crawler calls the BCS indexing connector to fetch the data from the external system and pass it back to the crawler.
BCS indexing connectors are composed of the following:

BDC model file The file that provides the connection information to the external system and the structure of the data.
Connector The component containing the code that connects to the external system and parses the access URLs and BCS identifiers.

The BDC metadata model includes several properties that are applicable to Search, many of which are required to support BCS indexing connector crawling.
The following table describes the BDC model properties that are applicable to Search.
Table 1. Search properties for BDC model files

NAME ME TAD ATA O B JECT D ES CR IPTIO N

ShowInSearchUI Model Specifies that an LobSystemInstance element in the model file


should be displayed in the search user interface. This value is
ignored for custom connectors.

InputUriProcessor LobSystem Specifies the name of the class that processes the input URL before
passing it to the connector. Applies to .NET and custom BCS
indexing connectors. For more information, see Creating a Custom
Indexing Connector.

OutputUriProcessor LobSystem Specifies the name of the class that processes the output URL
before passing it to the search system from the connector. Applies
to .NET and custom BCS indexing connectors. For more information,
see Creating a Custom Indexing Connector.

SystemUtilityTypeName LobSystem Specifies the name of the class that implements the
StructuredRepositorySystemUtility class. Applies to custom BCS
indexing connectors. For more information, see Creating a Custom
Indexing Connector.

Title Entity Specifies the title of the external content type to display in search
results.

DefaultLocale Entity Specifies the locale string. You can override this value by using the
LCIDField property or the CultureField property.

RootFinder Method Specifies the Finder method to use to enumerate the items to crawl.
For example, when connecting to a database, this could be the
SELECT statement or the list of tables to crawl.

DirectoryLink Method Specifies that BCS should navigate associations. Required for
hierarchical crawling.

DeletedCountField Method Specifies the deleted count value. This property is ignored unless it
contains an integer greater than zero.

WindowsSecurityDescriptorField Method Specifies the Windows Security descriptor for the item. If not
specified, the GetSecurityDescriptor method is called. If the
GetSecurityDescriptor is not defined, all external items are
assigned the Everyone access control list (ACL).

AuthorField Method Specifies the author name to display in search results.

DisplayUriField Method Specifies the URL to display in search results. If specified, this
property overrides the profile page URL provided by BCS. If not
specified, the URL displayed in search results starts with bdc3://,
and is not understood by the browser.

LastModifiedTimeStampField Method Specifies the external item's timestamp to display in search results.
This value is also used for incremental crawling.

DescriptionField Method Specifies the description to display in search results.

LCIDField Method Specifies the locale ID (LCID) for the DescriptionField. If this is not
specified, the default word breaker is used.

CultureField Method Specifies the culture for the DescriptionField.

Extension Method Specifies the file name extension for the crawlable stream. If not
specified, the default extension is .txt.
NAME ME TAD ATA O B JECT D ES CR IPTIO N

MimeType Method Specifies the MIME type for the crawlable stream. If not specified,
the default extension is .txt. If the Extension field and MimeType
field are both specified, the value specified in the MimeType field is
used.

UseClientCachingForSearch Method Specifies whether the crawler caches the content during
enumeration. If the content is cached, the crawler does not make
another trip to the content source when it crawls individual items.

EnumerateIdsOnly FilterDescriptor Specifies whether to return IDs only in the IDEnumerator.

CrawlStartTime FilterDescriptor Contains the start time of the last crawl.

SynchronizationCookie FilterDescriptor Specifies that the external content source returns a cookie after a
crawl, which is then resent by the indexing connector during the
next enumeration call. The external content source uses the cookie
to determine what has changed since the last crawl. This property is
used with ChangedIDEnumerator and DeletedIDEnumerator
method instances.

Property TypeDescriptor Specifies the struct array used by search for properties. Consists of
the following:
PropertyName
PropertyValue
PropertyCulture

Text TypeDescriptor Specifies the struct array used by search for attachments. Consists
of the following:
TextExtension
TextContentType
TextValue

BDC model file changes to improve performance when crawling external data
When you want to create a BDC model file for an external system that you want to enable for search, you can enhance the model file to optimize performance when crawling external
systems. This section describes ways to modify the BDC model file to improve performance.

Use inline property I/O when retrieving large-scale data


In general, if some of the data returned for an item is large scale, instead of returning it with the SpecificFinder method, you should use one of the following specialized methods to retrieve
the data:
Use the BinarySecurityDescriptorAccessor method when passing a security access control list (ACL) instead of the WindowsSecurityDescriptor property.
Use the StreamAccessor method when passing streams.
Unless network latency is high, the improved performance is usually better than the cost of an extra trip to the external system.

Enumeration optimization when crawling external systems


Do not enumerate more than 100,000 items per call to the external system. Long-running enumerations can cause intermittent interruptions and prevent a crawl from completing. We
recommend that your BDC model structures the data into logical folders that can be enumerated individually, as shown in the following example.
This example demonstrates enumerating against a database table with one million rows, but with a fixed set of values in ColumnA. In this scenario, you can consider ColumnA as the external
content type and write an enumerator for this set of values by using the following SQL statement.

SELECT DISTINCT( ISNULL(ColumnA,'unknown')) as ColumnA FROM table

Next, define the specific finder using the following SQL statement.

SELECT DISTINCT( ISNULL(ColumnA,'unknown')) as ColumnA FROM table where ColumnA = @Value

Finally, you must define the association navigation operation, as follows.

Select * from table where ColumnA=@value

Any method should begin returning results within two minutes, or the crawler will cancel the call. For example, a complex SQL statement that uses a LIKE clause may take longer than two
minutes to complete, and would cause the crawler to cancel the call.

Improving crawl speed with the UseClientCachingForSearch property


The UseClientCachingForSearch property improves the speed of full crawls by caching the item during enumeration. Using this property is also recommended when implementing
incremental crawls that are based on change logs, because it improves incremental crawl speed.

Important: If items are larger than 30 kilobytes on average, do not set this property, as it will lead to a significant number of cache misses and negate performance gains.

Security in BDC model files


If the repository uses NTLM authentication, we recommend that you specify PassThrough authentication for crawling.
Profile pages may require that you use the Secure Store Service because of the multi-hop delegation problem from the front-end web server. If you encounter this problem, you can optimize
the crawl while still allowing profile pages by creating two similar LobSystemInstance instances. The first instance should use credentials from the Secure Store Service authentication. This
instance should not contain the ShowInSearchUI property. The second instance should use PassThrough authentication, and should contain the ShowInSearchUI property. Profile pages
use the first LobSystemInstance instance, and the crawler uses the second instance.
NOTE

This requires that you set the ShowInSearchUI property at the LobSystemInstance level instead of at the LobSystem level.

See also
Search connector framework in SharePoint
BDC Model Infrastructure
Authoring BDC Models
Setting up a development environment for BCS in SharePoint
How to: Use SharePoint Designer to Create a BDC Model File for a Custom Connector
Crawl associated external content types in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn how to use the search specific properties in the Business Data Connectivity (BDC) service metadata model for crawling associations, and the different user experiences that you can
enable.

Crawling the associated external content type


Microsoft Business Connectivity Services (BCS) enables you to link two related external content types, which then enables you to fetch related external content. For example, you can fetch
external content from two SQL Server database table-based external content types that are based on foreign keys. This concept of linking two related external content types is known as an
association . For more information about associations, see Adding Associations Between External Content Types.
In the context of the Search connector framework, the source external content type of an association is referred to as the parent external content type. The Search crawler can crawl external
content types that are associated with the parent in two ways: as attachments or as children. These external content type associations affect the following:
User experience
Incremental crawls
Processing crawl deletions

User experience effects from external content type associations


A child external content type has its own search result URL and profile page, if the profile page has been created. The search result URL is the URL that is displayed if the user searches for a
term in the child external content type data.
The external content type for an attachment does not have its own search result URL. So if the user searches for a term in the attachment external item, the URL for the parent external
content type is displayed instead. You can set this URL to the profile page URL of the parent. The profile page for the parent external content type will display all the fields from the
attachment external content type that are exposed by the association navigator.

Incremental crawl effects from external content type associations


Child external items are re-crawled and updated for timestamp-based incremental crawls if the timestamp of the child external item changes.
For attachment external content types, the timestamp of the parent external item is interpreted as the timestamp of the attachment external item. This means that any changes in the
attachment external item are picked up by an incremental crawl only when the timestamp of the parent external item changes.

Processing crawl deletions effects from external content type associations


When processing crawl deletions, if the parent external content type is deleted from the index, the Search crawler deletes the associated attachment external content types and child external
content types from the index.

Crawling associated external content type attachments


To mark an association so that it is crawled as an attachment, add the AttachmentAccessor property to the Association method instance, as follows.

<Association Name="AttachmentsNavigate Association" Type="AssociationNavigator" ...>


<Properties>
<Property Name="ForeignFieldMappings" Type="System.String">....... </Property>
<Property Name="AttachmentAccessor" Type="System.String">x</Property>
</Properties>
<SourceEntity Namespace="ParentExternalContentType" Name="Parent" />
<DestinationEntity Namespace="AttachmentExternalContentType" Name="Attachment External Content Type" />
</Association>

NOTE

You can specify any value for the AttachmentAccessor property; Search does not examine this value.

Crawling associated external content types as child external content types


To mark an association so that it is crawled as a child external content type, add the DirectoryLink property to the Association method instance, as follows.

<Association Name="ChildrenNavigator Association" Type="AssociationNavigator" ...>


<Properties>
<Property Name="DirectoryLink" Type="System.String">x</Property>
</Properties>
<SourceEntity Namespace="ParentExternalContentType" Name="Parent" />
<DestinationEntity Namespace="ChildExternalContentType" Name="Child External Content Type" />
</Association>

NOTE

You can specify any value for the DirectoryLink property. Search does not examine this value.

See also
Search connector framework in SharePoint
Adding Associations Between External Content Types
Association Element in MethodInstances (BDCMetadata Schema)
Step 4 (Optional): Define Associations
Crawl binary large objects (BLOBs) in SharePoint
3/26/2018 • 3 minutes to read Edit Online

Learn how to modify the BDC model file for a database BCS indexing connector to enable the Search in SharePoint crawler to crawl binary large object (BLOB) data stored in a SQL Server
database.

Crawling BLOB data


The Business Data Connectivity (BDC) service supports reading BLOB data types, which is useful for streaming BLOB data from external systems. For this to work, you need to ensure that
the database table containing the external data is set up to support this. You then add a StreamAccessor method to the BDC model file for the external content source's BCS indexing
connector.

Configuring the SQL Server database table for BLOB data


The Microsoft SQL Server database table must have a column that specifies either the extension or the MIME type of the BLOB data. If the database table schema does not include a column
with this information, you must add it to the schema. The following tables contain an example of a database table schema with this column and sample values for it that are stored in the
database table.
Table 1. Sample database table schema

CO LU MN NAME D ATA T YPE

Id Int

DisplayName nvarchar(50)

Extension nvarchar(50)

Data varbinary(MAX)

ContentType nvarchar(MAX)

Table 2. Sample database table values

ID D IS PL AY NAME E X TENS IO N D ATA CO NTENT T YPE

1 File1 .docx 0x504B… application/vnd.openxmlformats-


officedocument.wordprocessingml.doc
ument

2 File2 .doc 0xD… application/msword

3 File3 .txt OxE… text/plain

Modifying the BDC model file to enable crawling of BLOB data


After you confirm that the database table contains the extension or MIME type information for the BLOB data, you can use Microsoft SharePoint Designer to create an external content type
that is based on the table containing the BLOB data. Then, you can create all the operations. For more information, see How to: Create External Content Types and How to: Create an External
Content Type Based on a SQL Server Table.
After you create the BLOB external content type, you are ready to modify the BDC model file to enable crawling. You cannot make these modifications in SharePoint Designer. So you must
export the BDC model file, and use an XML editor to make these changes manually.

To export the BDC model file for the BLOB external content type
1. In SharePoint Designer, click External Content Types in the left navigation to display the external content types that are defined in that site's service application's BDC metadata
store.
2. In the External Content Types list, select the BLOB external content type. Then, click Export BDC Model on the Server ribbon.
3. Type a name in the BDC Model Name text box, and then click OK.
4. Select the location where you want to save the BDC model (.bdcm) file, and then click Save.

To enable crawling of the BLOB external content type


1. In an XML editor, open the BDC model file you created in the previous section.
2. Create a new method that returns the BLOB field. You should define a StreamAccessor type method instance for this method, as shown in the following example.
NOTE

The table name in this example is Attachment.


<Method Name="GetData">
<Properties>
<Property Name="RdbCommandText" Type="System.String">SELECT Data FROM [dbo].[Attachment] WHERE [Id] = @Id </Property>
<Property Name="RdbCommandType" Type="System.Data.CommandType, System.Data, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089">Text</Property>
</Properties>
<Parameters>
<Parameter Direction="In" Name="@Id">
<TypeDescriptor TypeName="System.Int32" IdentifierName="Id" Name="Id" />
</Parameter>
<Parameter Name="StreamData" Direction="Return">
<TypeDescriptor TypeName="System.Data.IDataReader, System.Data,
Version=2.0.3600.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
IsCollection="true" Name="DataReaderTypeDescriptorName">
<TypeDescriptors>
<TypeDescriptor TypeName="System.Data.IDataRecord, System.Data,
Version=2.0.3600.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089"
Name="DataRecordTypeDescriptorName">
<TypeDescriptors>
<TypeDescriptor TypeName="System.Data.SqlTypes.SqlBytes, System.Data,
Version=2.0.3600.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089" Name="Data" />
</TypeDescriptors>
</TypeDescriptor>
</TypeDescriptors>
</TypeDescriptor>
</Parameter>
</Parameters>
<MethodInstances>
<MethodInstance Name="DataAccessor"
Type="StreamAccessor"
ReturnParameterName="StreamData"
ReturnTypeDescriptorName="Data">
<Properties>
<!-- If extension field is available-->
<Property Name="Extension" Type="System.String">Extension</Property>
<!--If MimeType is available-->
<Property Name="ContentType" Type="System.String">ContentType</Property>
<!--If attachments is to be displayed in profile pages, add the following property-->
<Property Name="MimeTypeField" Type="System.String">ContentType</Property>
</Properties>
</MethodInstance>
</MethodInstances>
</Method>

If the MIME type is the same for all the BLOBs, you can replace this line of code from the previous example:

<Property Name="ContentType" Type="System.String">ContentType</Property>

with the following line of code:


<Property Name=" ContentType " Type="System.String">application/vnd.openxmlformats-officedocument.wordprocessingml.document</Property>

1. Re-import the model file by using the Business Connectivity Services service application administration UI.
2. Create the content source for the external content type.
3. Launch a full crawl of the content source.

See also
Search connector framework in SharePoint
How to: Create External Content Types
XML Snippet: Modeling a StreamAccessor Method
Configure item-level security in SharePoint
3/26/2018 • 3 minutes to read Edit Online

Learn how to configure item level security when crawling external data with BCS indexing connectors in SharePoint.

External systems with NTLM authentication


For external systems that support NTLM authentication, the security descriptor can be obtained for each instance of the external content type at crawl time and stored in the content index.
During query time, the security descriptor of the user who is submitting the search query is compared to the stored security descriptor to determine whether the user has access to the item.
This is the fastest way to perform security trimming on the result set. The metadata model for the external system must indicate where the security descriptor can be found as an external
content type field or method.

External content type field


Microsoft SharePoint stores the security descriptor if the field of the external content type that contains the descriptor is marked by using the WindowsSecurityDescriptorField property,
as shown in the following example.

<Method Name="Item SpecificFinder ">


<Properties>
<Property Name="RdbCommandType" Type="System.Data.CommandType, System.Data,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">Text</Property>
<Property Name="RdbCommandText" Type="System.String">SELECT [Identifier] ,
[SecurityDescriptor] FROM [Test].[dbo].[Items] WHERE [Identifier] = @Identifier</Property>
<Property Name="BackEndObjectType" Type="System.String">SqlServerTable</Property>
<Property Name="BackEndObject" Type="System.String">Items</Property>
<Property Name="Schema" Type="System.String">dbo</Property>
</Properties>
<Parameters>
<Parameter Direction="In" Name="@Identifier">
<TypeDescriptor TypeName="System.Int32" IdentifierName="Identifier" Name="Identifier" />
</Parameter>
<Parameter Direction="Return" Name="BaseItemsRead Item">
<TypeDescriptor TypeName="System.Data.IDataReader, System.Data, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089" IsCollection="true" Name="BaseItemsRead Item">
<TypeDescriptors>
<TypeDescriptor TypeName="System.Data.IDataRecord, System.Data, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089" Name="BaseItemsRead ItemElement">
<TypeDescriptors>
<TypeDescriptor TypeName="System.Int32" IdentifierName="Identifier" Name="Identifier"/>
<TypeDescriptor TypeName="System.Byte[], mscorlib, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089" IsCollection="true" Name="SecurityDescriptor">
<TypeDescriptors>
<TypeDescriptor TypeName="System.Byte" Name="SecurityDescriptorElement" />
</TypeDescriptors>
</TypeDescriptor>
</TypeDescriptors>
</TypeDescriptor>
</TypeDescriptors>
</TypeDescriptor>
</Parameter>
</Parameters>
<MethodInstances>
<MethodInstance Type="SpecificFinder" ReturnParameterName="BaseItemsRead Item"
ReturnTypeDescriptorName="BaseItemsRead ItemElement" Name="BaseItemsRead Item"
DefaultDisplayName="ReadSecurity">
<Properties>
<Property Name="WindowsSecurityDescriptorField" Type="System.String">
SecurityDescriptor
</Property>
</Properties>
</MethodInstance>
</MethodInstances>
</Method>

NOTE

ems are limited to a specific size, which access control lists (ACL) can easily exceed. Therefore, the Search connector framework ignores requests to cache items if they contain a security
descriptor field.

External content type method


If you have a method defined in the metadata model that returns the security descriptor for an item based on its identifier, you can use the BinarySecurityDescriptorAccessor method
stereotype, as shown in the following example.
<Method Name="GetItemSecurity" LobName="GetItemSecurity">
<Parameters>
<Parameter Name="itemId" Direction="In">
<TypeDescriptor Name="itemId" TypeName="System.Int32, mscorlib,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
IdentifierEntityNamespace="MS.Internal.Test.Automation.Search.Scater"
IdentifierEntityName="Item" IdentifierName="ItemId" />
</Parameter>
<Parameter Name="Return" Direction="Return">
<TypeDescriptor Name="SecurityDescriptor" TypeName="System.Byte[],
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
IsCollection="true">
<TypeDescriptors>
<TypeDescriptor Name="Item" TypeName="System.Byte, mscorlib,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</TypeDescriptors>
</TypeDescriptor>
</Parameter>
</Parameters>
<MethodInstances>
<MethodInstance Name="GetItemSecurity_Instance" Type="BinarySecurityDescriptorAccessor"
ReturnParameterName="Return" ReturnTypeDescriptorName="SecurityDescriptor"
ReturnTypeDescriptorLevel="0">
<Properties>
<Property Name="WindowsSecurityDescriptorField" Type="System.String">
SecurityDescriptor
</Property>
</Properties>
<AccessControlList>
<AccessControlEntry Principal="NT AUTHORITY\\Authenticated Users">
<Right BdcRight="Execute" />
</AccessControlEntry>
</AccessControlList>
</MethodInstance>
</MethodInstances>
</Method>

The following code is the method signature for the method that is specified in the previous example.

Public static Byte[]GetItemSecurity (string id)


{

External systems with authentication schemes that can be mapped to NTLM authentication
If the external system does not support NTLM authentication, but the external system users can be mapped to Windows users by using a mapping table, you can use the approach described
in the previous two code examples to provide item level security. For this to work, the web service or Windows Communication Foundation (WCF) service exposed by the external system
must include a method that converts the external system users to Windows users internally, and then returns a Windows security descriptor for each URL. The following example shows how
you could code this method.

/// Returns the security descriptor for a user.


/// </summary>
/// <param name="domain"></param>
/// <param name="username"></param>
/// <returns></returns>

private Byte[] GetSecurityDescriptor(string domain, string username)


{
NTAccount acc = new NTAccount(domain, username);
SecurityIdentifier sid = (SecurityIdentifier)acc.Translate(typeof(SecurityIdentifier));
CommonSecurityDescriptor sd = new CommonSecurityDescriptor(false, false, ControlFlags.None,
sid, null, null, null);
sd.SetDiscretionaryAclProtection(true, false);

//Deny access to all users.


SecurityIdentifier everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
sd.DiscretionaryAcl.RemoveAccess(AccessControlType.Allow, everyone,
unchecked((int)0xffffffffL), InheritanceFlags.None, PropagationFlags.None);

//Grant full access to a specified user.


sd.DiscretionaryAcl.AddAccess(AccessControlType.Allow, sid,
unchecked((int)0xffffffffL), InheritanceFlags.None, PropagationFlags.None);

byte[] secDes = new Byte[sd.BinaryLength];


sd.GetBinaryForm(secDes, 0);

return secDes;
}

See also
Search connector framework in SharePoint
Implementing a BinarySecurityDescriptorAccessor
Enhancing the BDC model file for Search in SharePoint
Configure search in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn about the two types of customization in SharePoint search: adding a custom word breaker and adding a custom step to modify managed properties for crawled items during content
processing.

Adding a custom word breaker in SharePoint


A custom word breaker can be added to tune word breaking behavior according to your needs. You can use a custom word breaker to replace the existing word breaker of the same
language. Alternately, you can use a custom word breaker to replace the existing word breaker with that of a different language.

Adding a custom step to modify managed properties in SharePoint


A custom step can be added to modify managed properties in the form of an external content enrichment web service. The content enrichment web service is a service that you can create to
receive a callout from the web service client inside the content processing component. A configurable payload is then submitted to the web service, and the response is merged into the
crawled item before it is added to the search index.

In this section
Custom word breakers in SharePoint
Custom content processing with the Content Enrichment web service callout

See also
Search in SharePoint
What's new in SharePoint search for developers
Custom word breakers in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn about word breaking in SharePoint. Word breaking is one of the key Natural Language Processing (NLP) features that enable search and improve search results (or recall). Word
breakers split a stream of text into individual words or tokens on which you can base additional language processing. Word breakers are language-specific. In addition to built-in word
breakers, Search in SharePoint enables the use of custom word breakers so that users can tune word breaking behavior according to their needs. See Supported languages for word breaker
customizations in SharePoint for a list languages supported for word breaker customization.
For information on how to write a word breaker refer to the following articles
Implementing a Word Breaker
IWordBreaker interface

How to switch to a custom word breaker in SharePoint


Caution: When you replace existing word breakers, you modify the registry at your own risk. Serious problems might occur if you modify the registry incorrectly by using Registry
Editor or by using another method. These problems might require that you reinstall the operating system. Microsoft cannot ensure that these problems can be solved. Switching to a
different word breaker might also cause serious problems during indexing and querying. Before you modify the registry, back up the registry and ensure that you know how to restore
the registry if a problem occurs.

Take the following steps to replace the existing word breaker with a custom word breaker or replace the existing word breaker with a word breaker in another language.
1. Open the Registry Editor, as follows:
2. Choose Start, and then choose Run.
3. In the Open dialog box, type Regedit, and then choose OK.
4. In Registry Editor, select the following registry subkey:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\15.0\Search\Setup\ContentIndexCommon\LanguageResources\Default\ language from the list below
5. In the right pane, open the shortcut menu for the WBDLLPathOverride registry value, and then choose Modify.
6. In the Edit String dialog box, in the Value data box, type the path to your custom word breaker DLL, and then choose OK. The new DLL should be located in the same path as the
existing DLL that is being replaced.
7. In the right pane, open the shortcut menu for the WBreakerClass registry value, and then choose Modify.
8. In the Edit String dialog box, in the Value data box, type the class ID of your custom word breaker, and then choose OK.
9. Restart the SharePoint Search Host Controller and SharePoint.
10. Do a full re-crawl.

Supported languages for word breaker customizations in SharePoint


The following languages are supported for word breaker customization:
Arabic
Bengali
Bulgarian
Catalan
Chinese (People's Republic of China)
Chinese (Taiwan)
Croatian
Czech
Danish
Dutch (Dutch)
English (United States)
Estonian
Finnish
French (Standard)
German (Standard)
Greek
Gujarati
Hebrew
Hindi
Hungarian
Icelandic
Indonesian
Italian (Default)
Japanese
Kannada
Kazakh
Korean
Latvian
Lithuanian
Malay
Malayalam
Marathi
Norwegian
Polish
Portuguese (Portuguese)
Punjabi
Romanian
Russian
Serbian (Cyrillic)
Slovak
Slovenian
Spanish (Modern Sort)
Swedish
Tamil
Telugu
Thai
Turkish
Ukrainian
Urdu
Vietnamese

See also
Configure search in SharePoint
Implementing a Word Breaker
IWordBreaker interface
Custom content processing with the Content Enrichment web service callout
3/26/2018 • 5 minutes to read Edit Online

Learn about the content enrichment web service callout in SharePoint that enables developers to create an external web service to modify managed properties for crawled items during
content processing. Search in SharePoint enables users to modify the managed properties of crawled items before they are indexed by calling out to an external content enrichment web
service. The ability to modify managed properties for items during content processing is helpful when performing tasks such as data cleansing, entity extraction, classification, and tagging.
Figure 1. Content enrichment within content processing

Figure 1 shows a part of the process that takes place in the content processing component. The content enrichment web service is a SOAP-based service that you can create to receive a
callout from the web service client inside the content processing component. Based on Figure 1, the web service client refers to the Content Enrichment operator inside the content
processing component; theweb service refers to the SOAP web service that you implement.The web service receives a configurable payload from the content processing component. Then,
the resulting response from the web service is merged into the crawled item before it is added to the search index. The web service client works with managed properties that you can
configure as input properties or as output properties. Input properties are sent to the web service; output properties are returned by the web service. Certain managed properties are hidden
or are read-only and can't be sent to the web service or received from the web service. See How to list all read-only managed properties for the Content Enrichment web service for
information about how to verify which managed properties are read-only.

Important: The content enrichment callout step can only be configured with a single web service endpoint. Any kind of fault tolerance, or routing capabilities to support multiple
implementations must be handled by the developer implementing the web service. In addition, the developer may have various web service implementations hosted at different
endpoints; however, at any given time, only one of these endpoints can be used in the configuration.

Content enrichment web service contract


The web service client is a SOAP (version 1.1) RPC client with a predefined behavior. The web service contract has the following characteristics:
The content processing component sends a SOAP RPC call to a configurable endpoint over HTTP.
The payload contains an array of property objects.
The web service performs some custom logic on the array of property objects, and returns an array of modified or new property objects.
The web service must send a response to the web service client within a given timeout.
No specific authentication or encryption mechanisms are supported as part of the contract. You can, however, apply your own security on the transport mechanism.

Configuring the Content Enrichment web service client


To configure the web service client, you use the following Windows PowerShell cmdlets:
Get-SPEnterpriseSearchContentEnrichmentConfiguration
Set-SPEnterpriseSearchContentEnrichmentConfiguration
Remove-SPEnterpriseSearchContentEnrichmentConfiguration
New-SPEnterpriseSearchContentEnrichmentConfiguration
Table 1 lists the properties you can configure through the Windows PowerShell cmdlets mentioned previously.
Table 1. Properties that are configurable for the client by using Windows PowerShell cmdlets

CO NFIG U R ATIO N PR O PER T Y D ES CR IPTIO N D EFAU LT V ALU E

Endpoint Specifies the URL of the external web service. Empty.

InputProperties The managed properties that the external web service receives. Empty.

OutputProperties The managed properties that the external web service returns. Empty.

Timeout The amount of time until the web service times out in milliseconds. 5000 milliseconds; Valid range [100, 30000].
Depending on FailureMode, the item fails to be processed or a
warning is written to the ULS log.

SendRawData Enables or disables sending raw data to the web service. False.

MaxRawDataSize The maximum size of raw data sent to the web service in kilobytes 5120 kilobytes.
(KB). If the binary data of an item exceeds this limit, the item is not
sent. This does not prevent the InputProperties from being sent,
and the OutputProperties from being received.
CO NFIG U R ATIO N PR O PER T Y D ES CR IPTIO N D EFAU LT V ALU E

FailureMode Controls the behavior of the web service client when errors occur. Error.
When FailureMode is set to ERROR, any problems that occur
during content enrichment processing send a failed callback for that
particular item.
When FailureMode is set to WARNING, the item is indexed,
without any modifications by the web service and a warning is
written to the ULS log.

DebugMode A mode that when set to true enables the content enrichment False.
client to send all managed properties to the client without expecting
any properties in return. Any configured Trigger property,
InputProperties property, and OutputProperties property are
ignored.

Trigger A Boolean predicate that is executed on every crawled item. If the Empty.
predicate evaluates to true, the record is sent to the web service.
Otherwise, the item is passed through to the search index.

How to list all read-only managed properties for the Content Enrichment web service
Certain managed properties are read-only and cannot be output from the web service. These properties can be listed by using the Get-SPEnterpriseSearchServiceApplication and Get-
SPEnterpriseSearchMetadataManagedPropertyWindows PowerShell cmdlets, shown in the following example:

$ssa = Get-SPEnterpriseSearchServiceApplication
Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $ssa | ?{$_.IsReadOnly -or $_.MappingDisallowed -or $_.DeleteDisallowed}

About trigger conditions for configuring the web service callout


A trigger condition is an expression that is used to configure the web service callout. If a trigger condition evaluates to true, the web service client performs a callout for that record. If a
trigger condition evaluates to false, the web service client does not perform a callout and passes the crawled item to the search index. Alternatively, if no trigger condition is configured; all
items are sent to the web service.
Trigger conditions use an expression language to refer to the values of managed properties. You can use the operators and functions in the expression language to build simple or complex
trigger conditions so you can determine when to perform a web service callout.
Table 2 lists examples of trigger conditions.
Table 2. Trigger condition examples for configuring the Content Enrichment web service callout

E X PR ES S IO N D ES CR IPTIO N R EQ U IR EMENTS

MP1 > 2 Returns true if the value of the managed property named MP1 is MP1 must have a numeric type.
greater than 2.

IsNull(MP2) Returns true if the managed property named MP2 is not present MP2 can be of any type.
for the crawled item or is empty/null.

StartsWith(MP1, "sample") AND MP2 != 18 Returns true if the value in the managed property MP1 starts with MP1 must be of type string and MP2 must be a numeric type.
"sample" and the value of managed property MP2 is not 18.

IsDay(MP1, 2009, 12, 24) Checks whether the managed property MP1 contains a DateTime MP1 must be of type DateTime.
that falls on December 24, 2009.

See Trigger expressions syntax in SharePoint for the elements that can be used in a trigger expression and a list of supported functions.

Implementing the Content Enrichment external web service


For a basic implementation, do the following:
1. Include the Microsoft.Office.Server.Search.ContentProcessingEnrichment.dll located in C:\\Program Files\\Microsoft Office Servers\\15.0\\Search\\Applications\\External in
your project as a reference.
2. Implement IContentProcessingEnrichmentService as a web service.

See also
Configure search in SharePoint
Custom content processing with the Content Enrichment web service callout
Use the Content Enrichment web service callout for SharePoint Server
4/10/2018 • 7 minutes to read Edit Online

Learn how to implement the Content Enrichment web service in SharePoint to modify the managed properties of crawled items before they are indexed.
Search in SharePoint enables developers to add a custom step to content processing to modify the managed properties of crawled items before they are indexed. This custom step requires
the implementation of an external web service--the Content Enrichment web service--that can enrich managed properties of items being processed; and then configuring the system to call
this external web service.
Implementation of the external content enrichment web service relies on interfaces under the Microsoft.Office.Server.Search.ContentProcessingEnrichment namespace.

Windows PowerShell Cmdlets to use with the Content Enrichment web service
The Content Enrichment functionality is configured and enabled with the following Windows PowerShell cmdlets:
Get-SPEnterpriseSearchContentEnrichmentConfiguration
Set-SPEnterpriseSearchContentEnrichmentConfiguration
Remove-SPEnterpriseSearchContentEnrichmentConfiguration
New-SPEnterpriseSearchContentEnrichmentConfiguration
These Windows PowerShell cmdlets enable an administrator to configure the following:
A custom set of managed properties to be sent to the external web service.
A custom set of managed properties to be returned by the external web service.
A trigger condition, that represents a predicate to execute for every item being processed. If a trigger condition is used, the external web service is called only when the trigger
evaluates to true. If no trigger condition is used, all items are sent to the external web service.
A FailureMode that enables the web service to either fail items that cannot be processed during the content enrichment step or pass these items through without any modification. If
the items are failed, they are not indexed and a warning is written to the ULS log.
A DebugMode, that enables rapid prototyping of the external web service. When enabled, the external web service receives all available managed properties. In DebugMode, the
trigger condition is ignored and any managed properties output by the web service are also ignored.
A SendRawData switch that sends the raw data of an item in binary form. This is useful when more metadata is required than what can be retrieved from the parsed version of the
item.
In addition, there are options for specifying size limits and timeouts. See Custom content processing with the Content Enrichment web service callout for a full list of configurable properties.

Prerequisites for using the Content Enrichment web service callout for SharePoint
To complete this how-to, you must have the following installed in your development environment:
Search in SharePoint
Visual Studio 2010 or similar .NET Framework-compatible development tool
Administrator privileges on your SharePoint installation
A server on which you can host the service with IIS
You must also know how to create a site in IIS and deploy a service to it

Set up a content enrichment service project


In this step, you will create the service implementation project and then add the required references to the project.

To create the project for a content enrichment service


1. In Visual Studio, on the menu bar choose File, New, Project.
2. In Project types, under Visual C#, choose WCF.
3. Under Templates, choose WCF Service Application. In the Name field, type ContentProcessingEnrichmentService, and then choose the OK button.
4. Delete the automatically generated Service1 class and Service1 interface.

To add references to the content enrichment service project


1. On the Project menu, choose Add Reference.
2. Choose Browse and locate the Microsoft.Office.Server.Search.ContentProcessingEnrichment assembly in your SharePoint installation folder under Installation Path\Microsoft
Office Servers\15.0\Search\Applications\External.
NOTE

If SharePoint is installed on a machine other than your development machine, copy the assembly over to your development machine and reference it from there.

Create a content enrichment service


Your content processing enrichment service must implement the IContentProcessingEnrichmentService interface from the Microsoft.Office.Server.Search.ContentProcessingEnrichment
namespace. The code example in this section is a basic implementation of this interface.
The implementation requires two managed properties for each item received via the external web service: Author and Filename. The Author is a list of String objects and the Filename is
a String object.
The IContentProcessingEnrichmentService implementation writes the raw binary data to a temporary location on disk, with Filename as the name of the file. Then, a new name is
added to the list of authors and returned to the content processing component.
> [!NOTE]
> If the data source for the crawl is an external data source, the ItemRawData property will not have a data stream, but will be null. The string representation of the raw data will be returned i

To create the class file for the content enrichment service


1. On the Project menu, choose Add New Item.
2. Under Visual C# in Installed Templates, choose Web, and then choose WCF Service.
3. Type ContentProcessingEnrichmentService.svc, and then choose Add.
4. Delete the IContentProcessingEnrichmentService.cs interface that is created.

To modify the default code in the ContentProcessingEnrichmentService class


1. Replace the existing using directives with the following using directives at the beginning of the class.

using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Office.Server.Search.ContentProcessingEnrichment;
using Microsoft.Office.Server.Search.ContentProcessingEnrichment.PropertyTypes;

1. Delete the DoWork method.

To implement the IContentProcessingEnrichmentService interface method


1. Add the following code inside the class to define the required constants and members.

// Defines the name of the managed property 'Filename'.


private const string FileNameProperty = "Filename";

// Defines the name of the managed property 'Author'


private const string AuthorProperty = "Author";

// Defines the temporary directory where binary data will be stored.


private const string TempDirectory = @"C:\\Temp";

// Defines the error code for managed properties with an unexpected type.
private const int UnexpectedType = 1;

// Defines the error code for encountering unexpected exceptions.


private const int UnexpectedError = 2;

private readonly ProcessedItem processedItemHolder = new ProcessedItem


{
ItemProperties = new List<AbstractProperty>()
};

1. Add the following code for the ProcessItem method.


public ProcessedItem ProcessItem(Item item)
{
processedItemHolder.ErrorCode = 0;
processedItemHolder.ItemProperties.Clear();
try
{
// Iterate over each property received and locate the two properties we
// configured the system to send.
foreach (var property in item.ItemProperties)
{
// Check if this is the author property.
if (property.Name.Equals(AuthorProperty, StringComparison.Ordinal))
{
var author = property as Property<List<string>>;
if (author == null)
{
// The author property was not of the expected type.
// Update the error code and return.
processedItemHolder.ErrorCode = UnexpectedType;
return processedItemHolder;
}
// Adding a new author to the list so it will become searchable.
author.Value.Add("ExampleService");
processedItemHolder.ItemProperties.Add(author);
}
else if (property.Name.Equals(FileNameProperty, StringComparison.Ordinal))
{
var filename = property as Property<string>;
if (filename == null)
{
// The file name property was not of the expected type.
// Update error code and return.
processedItemHolder.ErrorCode = UnexpectedType;
return processedItemHolder;
}
if (!string.IsNullOrEmpty(filename.Value))
{
var fullFilePath = string.Join(char.ToString(Path.DirectorySeparatorChar), TempDirectory, filename.Value);
if (item.RawData != null)
{
var outputFile = File.Create(fullFilePath);
using (var writer = new BinaryWriter(outputFile))
{
writer.Write(item.RawData);
}
}
}
}
}
}
catch (Exception)
{
processedItemHolder.ErrorCode = UnexpectedError;
} return processedItemHolder;
}

1. Modify web.config to accept messages up to 8 MB, and configure readerQuotas to be a sufficiently large value.
2. Add the following inside <system.serviceModel>.

<bindings>
<basicHttpBinding>
<!-- The service will accept a maximum blob of 8 MB. -->
<binding maxReceivedMessageSize = "8388608">
<readerQuotas maxDepth="32"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>

Build the project and deploy it to your IIS site.

Configure SharePoint
Open the SharePoint Management Shell, and enter the following sequence of Windows PowerShell cmdlets.

$ssa = Get-SPEnterpriseSearchServiceApplication
$config = New-SPEnterpriseSearchContentEnrichmentConfiguration
$config.Endpoint = http://Site_URL/ContentEnrichmentService.svc
$config.InputProperties = "Author", "Filename"
$config.OutputProperties = "Author"
$config.SendRawData = $True
$config.MaxRawDataSize = 8192
Set-SPEnterpriseSearchContentEnrichmentConfiguration -SearchApplication
$ssa -ContentEnrichmentConfiguration $config

The sequence of Windows PowerShell cmdlets help you to first create a configuration object by using the New-SPEnterpriseSearchContentEnrichmentConfiguration cmdlet. The
configuration object is then pointed toward your service implementation; as a best practice, use http://localhost:808 for Site_URL.
The managed properties Author and Filename are sent to your service for every item that is being processed. In addition, you have informed the web service client that the service will
output a single managed property, Author. In additional to managed properties, the web service client is configured to send the raw data of the item with a limitation on the size of the data.
Finally, the Set-SPEnterpriseSearchContentEnrichmentConfigurationcmdlet is used to store the entire configuration. After this cmdlet returns, the configuration is active and the crawl
component uses this configuration for its next crawl process.
After this is finished, you can start a full crawl of your site. If the service is working correctly, you should be able to monitor the temporary folder on the server hosting your site for the
documents written to disk.
You can remove the configuration later by using the following Windows PowerShell cmdlet.

Remove-SPEnterpriseSearchContentEnrichmentConfiguration -SearchApplication $ssa

See also
Start, pause, resume, or stop a crawl
Configure search in SharePoint
Custom content processing with the Content Enrichment web service callout
Trigger expressions syntax in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn about trigger expressions you can use to create trigger conditions to configure the web service callout in SharePoint.

Elements used in the syntax of trigger expressions


Elements that can be used in a trigger expression are:
Operators
Managed property value access
Literals
Functions
Constants
NOTE

The string " Null" is reserved for the value Null.

Operators in trigger expression syntax


Table 1 describes the operators supported by the trigger expression language, with order of precedence being from highest to lowest. Operators in the same category have equal precedence.
Several operators have two versions of their syntax.
Table 1. Supported operators for trigger expression syntax

CATEG O R Y E X PR ES S IO N D ES CR IPTIO N

Unary - Arithmetic negation


!, NOT Logical negation

Multiplicative * Multiplication
/ Division
%, mod Remainder

Additive + Addition
- Subtraction
& String concatenation

Relational =, == Equality
!=, <> Inequality
< Less than
> Greater than
<= Less than or equal
>= Greater than or equal

Logical AND &&, AND Logical AND

Logical OR OR Logical OR

Managed property access in trigger expressions


Managed properties in the crawled items are referenced by their name; the name is not in quotation marks ("") and is case-sensitive.

Literals in trigger expressions


The following data types can be expressed as literals: String, Int32, Double, and Boolean.

Functions in trigger expressions


A wide collection of functions ranging from mathematical functions such as Floor to functions for use with particular data types, such as Lists . You can use these functions individually or
you can nest them.
bool? ListContains<T>(IList<T> list, T obj)

int? Count<TElement>(IList<TElement> list)

TElement Item<TElement>(IList<TElement> list, int? index)

bool IsInsideRange(DateTime? date, long? fromTicks, long? toTicks)

DateTime Now()

DateTime? ToDate(string date, string format)

int? Day(DateTime? date)

int? DayOfWeek(DateTime? date)

int? DayOfYear(DateTime? date)

int? GetDatePart(DateTime? date, DatePartConstant datePartConstant)

int? Hour(DateTime? date)


int? Minute(DateTime? date)

int? Month(DateTime? date)

int? Quarter(DateTime? date)

int? Second(DateTime? date)

int? Year(DateTime? date)

long? GetDateDiff(DateTime? occursFirst, DateTime? occursLast, DatePartConstant datePartConstant)

string Extension(string arg)

string FileName(string arg)

string FileName(string arg, bool? excludeExtension)

bool IsNull(object value)

bool? IsDate(string input, string format)

object IfThenElse(bool? condition, object thenBranch, object elseBranch)

decimal? Ceiling(decimal? number)

decimal? Floor(decimal? number)

double? Ceiling(double? number)

double? Floor(double? number)

double? Sqrt(double? number)

bool? Contains(string arg, string contained)

bool? EndsWith(string arg, string suffix)

bool? IsMatch(string input, string pattern)

bool? IsMatch(string input, string pattern, int? start, RegexOptionConstant options)

bool? IsMatch(string input, string pattern, RegexOptionConstant options)

bool? IsNullOrEmpty(string input)

bool? StartsWith(string arg, string prefix)

int? IndexOf(string arg, string toFind)

int? IndexOfRegex(string input, string regex)

int? LastIndexOf(string arg, string toFind)

int? Length(string arg)

string Match(string input, string pattern)

string Match(string input, string pattern, int? start, int? length, RegexOptionConstant options)

string Match(string input, string pattern, int? start, RegexOptionConstant options)

string Match(string input, string pattern, RegexOptionConstant options)

string Substring(string arg, int? start)

string Substring(string arg, int? start, int? length)

string ToLower(string arg)

string Trim(string value)

Constants in trigger expressions


There are two sets of constants that can be used with specific functions: DatePartConstant and RegexOptionConstant. Table 2 lists the two examples of these constants and where you
can use them.
Table 2. Trigger expression constants and usage in SharePoint

G R O U P O F CO NS TANTS E X AMPLES U S AG E

DatePartConstant Day, Month, Year, Hour, Minute, Second. With the GetDatePart function

RegexOptionConstant IgnoreCase With the IsMatch, Match, ReplaceRegex, and IndexOfRegex


functions.

See also
Custom content processing with the Content Enrichment web service callout
How to: Use the Content Enrichment web service callout for SharePoint Server
Building search queries in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn about the search syntax supported in SharePoint for building query rules and search queries.

Supported search syntax in SharePoint for building search queries


SharePoint search supports Keyword Query Language (KQL) and FAST Query Language (FQL) search syntax for building search queries.
Keyword Query Language (KQL)
KQL is the default query language for building search queries. Using KQL, you specify the search terms or property restrictions that are passed to the SharePoint search service.
FAST Query Language (FQL)
FQL is a structured query language that supports advanced query operators. You can use FQL when you want to create complex queries that you want to pass programmatically to the
SharePoint search service. FQL isn't intended to be exposed to end users, and is disabled by default.
To enable FQL, use the EnableFQL property. Then, copy the default result source and modify the Query Transformation string {?{searchTerms} -ContentClass=urn:content-class:SPSPeople} ,
at one of these levels -- Search Service Application (SSA), Site Collection, or Site -- and in one of the following ways:
Remove the KQL filter, -ContentClass:urn:content-class:SPSPeople , from the Query Transformation. The resulting Query Transformation string will be: {?{searchTerms}}

Replace the Query Transformation string with an FQL equivalent, such as {?andnot({searchTerms},filter(contentclass:"urn:content-class:SPSPeople*"))} .
For more information about result sources and how they work, see to: Understanding result sources and Configure result sources for search in SharePoint.

In this section
Keyword Query Language (KQL) syntax reference
FAST Query Language (FQL) syntax reference
Using the SharePoint search Query APIs

See also
Search in SharePoint
Overview of query processing in SharePoint
Query variables in SharePoint
Keyword Query Language (KQL) syntax reference
5/10/2018 • 18 minutes to read Edit Online

Learn to construct KQL queries for Search in SharePoint. This syntax reference describes KQL query elements and how to use property restrictions and operators in KQL queries.

Elements of a KQL query


A KQL query consists of one or more of the following elements:
Free text-keywords—words or phrases
Property restrictions
You can combine KQL query elements with one or more of the available operators.
If the KQL query contains only operators or is empty, it isn't valid. KQL queries are case-insensitive but the operators are case-sensitive (uppercase).
NOTE

The length limit of a KQL query varies depending on how you create it. If you create the KQL query by using the default SharePoint search front end, the length limit is 2,048 characters.
However, KQL queries you create programmatically by using the Query object model have a default length limit of 4,096 characters. You can increase this limit up to 20,480 characters by
using the MaxKeywordQueryTextLength property or the DiscoveryMaxKeywordQueryTextLength property (for eDiscovery).

Constructing free-text queries using KQL


When you construct your KQL query by using free-text expressions, Search in SharePoint matches results for the terms you chose for the query based on terms stored in the full-text index.
This includes managed property values where FullTextQueriable is set to true.
Free text KQL queries are case-insensitive but the operators must be in uppercase. You can construct KQL queries by using one or more of the following as free-text expressions:
A word (includes one or more characters without spaces or punctuation)
A phrase (includes two or more words together, separated by spaces; however, the words must be enclosed in double quotation marks)
To construct complex queries, you can combine multiple free-text expressions with KQL query operators. If there are multiple free-text expressions without any operators in between them,
the query behavior is the same as using the AND operator.

Using words in the free-text KQL query


When you use words in a free-text KQL query, Search in SharePoint returns results based on exact matches of your words with the terms stored in the full-text index. You can use just a part
of a word, from the beginning of the word, by using the wildcard operator (*) to enable prefix matching. In prefix matching, Search in SharePoint matches results with terms that contain the
word followed by zero or more characters.
For example, the following KQL queries return content items that contain the terms "federated" and "search":
federated search

federat* search

search fed*

KQL queries don't support suffix matching.

Using phrases in the free-text KQL query


When you use phrases in a free-text KQL query, Search in SharePoint returns only the items in which the words in your phrase are located next to each other. To specify a phrase in a KQL
query, you must use double quotation marks.
KQL queries don't support suffix matching, so you can't use the wildcard operator before a phrase in free-text queries. However, you can use the wildcard operator after a phrase.

Property restriction queries in KQL


Using KQL, you can construct queries that use property restrictions to narrow the focus of the query to match only results based on a specified condition.

Specifying property restrictions


A basic property restriction consists of the following:
<Property Name><Property Operator><Property Value>

Table 1 lists some examples of valid property restrictions syntax in KQL queries.
Table 1. Valid property restriction syntax

S YNTAX R E TU R NS

author:"John Smith" Returns content items authored by John Smith.

filetype:docx Returns Microsoft Word documents.

filename:budget.xlsx Returns content items with the file name budget.xlsx .

The property restriction must not include white space between the property name, property operator, and the property value, or the property restriction is treated as a free-text query. The
length of a property restriction is limited to 2,048 characters.
In the following examples, the white space causes the query to return content items containing the terms "author" and "John Smith", instead of content items authored by John Smith:
author: "John Smith"

author :"John Smith"


author : "John Smith"

In other words, the previous property restrictions are equivalent to the following:
author "John Smith"

Specifying property names for property restrictions


You must specify a valid managed property name for the property restriction. By default, Search in SharePoint includes several managed properties for documents.
To specify a property restriction for a crawled property value, you must first map the crawled property to a managed property. See Managed and crawled properties in Plan the end-user
search experience.
The managed property must be Queryable so that you can search for that managed property in a document. In addition, the managed property may be Retrievable for the managed
property to be retrieved. However, the managed property doesn't have to be Retrievable to carry out property searches.

Property operators that are supported in property restrictions


Search in SharePoint supports several property operators for property restrictions, as shown in Table 2.
Table 2. Valid property operators for property restrictions

O PER ATO R D ES CR IPTIO N S U PPO R TED MANAG ED PR O PER T Y T YPE

: Returns results where the value specified in the property restriction Text
is equal to the property value that is stored in the Property Store DateTime
database, or matches individual terms in the property value that is Integer
stored in the full-text index. Decimal
Double
YesNo

= Returns search results where the property value is equal to the Text
value specified in the property restriction. DateTime
Note: We do not recommend combining the = operator together Integer
with asterisk ( \*) when you do exact matching. Decimal
Double
YesNo

< Returns results where the property value is less than the value DateTime
specified in the property restriction. Integer
Decimal
Double

> Returns search results where the property value is greater than the DateTime
value specified in the property restriction. Integer
Decimal
Double

<= Returns search results where the property value is less than or equal DateTime
to the value specified in the property restriction. Integer
Decimal
Double

>= Returns search results where the property value is greater than or DateTime
equal to the value specified in the property restriction. Integer
Decimal
Double

<> Returns search results where the property value does not equal the DateTime
value specified in the property restriction. Integer
Decimal
Text
Double
YesNo

.. Returns search results where the property value falls within the DateTime
range specified in the property restriction. Integer
For example, the range A..B represents a set of values from A to B Decimal
where both A and B are inclusive. For date ranges this means from Double
the beginning of day A to the end of day B.

Specifying property values


You must specify a property value that is a valid data type for the managed property's type. Table 3 lists these type mappings.
Table 3. Valid data type mappings for managed property types

MANAG ED T YPE D ATA T YPE

Text String

Integer Int64

Double System.Double

Decimal Decimal

DateTime() DateTime

YesNo Boolean

Text property values


For text property values, the matching behavior depends on whether the property is stored in the full-text index or in the search index.
Property values in the full-text index
Property values are stored in the full-text index when the FullTextQueriable property is set to true for a managed property. You can configure this only for string properties. Property
values that are specified in the query are matched against individual terms that are stored in the full-text index. Use the NoWordBreaker property to specify whether to match with the whole
property value.
For example, if you're searching for a content item authored by Paul Shakespear, the following KQL query returns matching results:
author:Shakespear

author:Paul

Prefix matching is also supported. You can use the wildcard operator (*), but isn't required when you specify individual words. Continuing with the previous example, the following KQL
query returns content items authored by Paul Shakespear as matches:
author:Shakesp*

When you specify a phrase for the property value, matched results must contain the specified phrase within the property value that is stored in the full-text index. The following query
example returns content items with the text "Advanced Search" in the title, such as "Advanced Search XML", "Learning About the Advanced Search web part", and so on:
title:"Advanced Search"

Prefix matching is also supported with phrases specified in property values, but you must use the wildcard operator (*) in the query, and it is supported only at the end of the phrase, as
follows:
title:"Advanced Sear*"

The following queries do not return the expected results:


title:"Advan* Search"

title:"Advanced Sear"

Numerical values for properties


For numerical property values, which include the Integer, Double, and Decimal managed types, the property restriction is matched against the entire value of the property.

Date or time values for properties


KQL provides the datetime data type for date and time.The following ISO 8601-compatible datetime formats are supported in queries:
YYYY-MM-DD
YYYY-MM-DDThh:mm:ss
YYYY-MM-DDThh:mm:ssZ
YYYY-MM-DDThh:mm:ssfrZ
In these datetime formats:
YYYY specifies a four-digit year.
NOTE

Only four-digit years are supported.


MM specifies a two-digit month. For example, 01 = January.
DD specifies a two-digit day of the month (01 through 31).
T specifies the letter "T".
hh specifies a two-digits hour (00 through 23); A.M./P.M. indication is not allowed.
mm specifies a two-digit minute (00 through 59).
ss specifies a two-digit second (00 through 59).
fr specifies an optional fraction of seconds, ss; between 1 to 7 digits that follows the . after the seconds. For example, 2012-09-27T11:57:34.1234567.
All date/time values must be specified according to the UTC (Coordinated Universal Time), also known as GMT (Greenwich Mean Time) time zone. The UTC time zone identifier (a trailing
"Z" character) is optional.
Relevant date intervals supported by KQL
KQL enables you to build search queries that support relative "day" range query, with reserved keywords as shown in Table 4. Use double quotation marks ("") for date intervals with a space
between their names.

NAME O F D ATE INTER V AL D ES CR IPTIO N

today Represents the time from the beginning of the current day until the end of the current day.

yesterday Represents the time from the beginning of the day until the end of the day that precedes the current
day.

this week Represents the time from the beginning of the current week until the end of the current week. The
culture in which the query text was formulated is taken into account to determine the first day of the
week.

this month Represents the time from the beginning of the current month until the end of the current month.

last month Represents the entire month that precedes the current month.

this year Represents the time from the beginning of the current year until the end of the current year.
NAME O F D ATE INTER V AL D ES CR IPTIO N

last year Represents the entire year that precedes the current year.

Using multiple property restrictions within a KQL query


Search in SharePoint supports the use of multiple property restrictions within the same KQL query. You can use either the same property for more than one property restriction, or a
different property for each property restriction.
When you use multiple instances of the same property restriction, matches are based on the union of the property restrictions in the KQL query. Matches would include content items
authored by John Smith or Jane Smith, as follows:
author:"John Smith" author:"Jane Smith"

This functionally is the same as using the OR Boolean operator, as follows:


author:"John Smith" OR author:"Jane Smith"

When you use different property restrictions, matches are based on an intersection of the property restrictions in the KQL query, as follows:
author:"John Smith" filetype:docx

Matches would include Microsoft Word documents authored by John Smith. This is the same as using the AND Boolean operator, as follows:
author:"John Smith" AND filetype:docx

KQL operators for complex queries


KQL syntax includes several operators that you can use to construct complex queries.

Boolean operators
You use Boolean operators to broaden or narrow your search. You can use Boolean operators with free text expressions and property restrictions in KQL queries. Table 5 lists the supported
Boolean operators.
Table 5. Boolean operators supported in KQL

O PER ATO R D ES CR IPTIO N

AND Returns search results that include all of the free text expressions, or property restrictions specified with
the AND operator. You must specify a valid free text expression and/or a valid property restriction both
preceding and following the AND operator. This is the same as using the plus ("+") character.

NOT Returns search results that don't include the specified free text expressions or property restrictions. You
must specify a valid free text expression and/or a valid property restriction following the NOT operator.
This is the same as using the minus ("-") character.

OR Returns search results that include one or more of the specified free text expressions or property
restrictions. You must specify a valid free text expression and/or a valid property restriction both
preceding and following the OR operator.

Proximity operators
You use proximity operators to match the results where the specified search terms are within close proximity to each other. Proximity operators can be used with free-text expressions only;
they are not supported with property restrictions in KQL queries. There are two proximity operators: NEAR and ONEAR.
NEAR operator
The NEAR operator matches the results where the specified search terms are within close proximity to each other, without preserving the order of the terms. The syntax for NEAR is as
follows:
<expression> NEAR(n=4) <expression>

Where n is an optional parameter that indicates maximum distance between the terms. The value of n is an integer >= 0 with a default of 8.
The parameter n can be specified as n=v where v represents the value, or shortened to only v; such as NEAR(4) where v is 4.
For example:
"acquisition" NEAR "debt"

This query matches items where the terms "acquisition" and "debt" appear within the same item, where an instance of "acquisition" is followed by up to eight other terms, and then an
instance of the term "debt"; or vice versa. The order of the terms is not significant for the match.
If you need a smaller distance between the terms, you can specify it. The following query matches items where the terms "acquisition" and "debt" appear within the same item, where a
maximum distance of 3 between the terms. Once again the order of the terms does not affect the match.
"acquisition" NEAR(n=3) "debt"

NOTE

In SharePoint the NEAR operator no longer preserves the ordering of tokens. In addition, the NEAR operator now receives an optional parameter that indicates maximum token distance.
However, the default value is still 8. If you must use the previous behavior, use ONEAR instead.
ONEAR operator
The ONEAR operator matches the results where the specified search terms are within close proximity to each other, while preserving the order of the terms. The syntax for ONEAR is as
follows, where n is an optional parameter that indicates maximum distance between the terms. The value of n is an integer >= 0 with a default of 8.
<expression> ONEAR(n=4) <expression>

The parameter n can be specified as n=v where v represents the value, or shortened to only v; such as ONEAR(4) where v is 4.
For example, the following query matches items where the terms "acquisition" and "debt" appear within the same item, where an instance of "acquisition" is followed by up to eight other
terms, and then an instance of the term "debt". The order of the terms must match for an item to be returned:
"acquisition" ONEAR "debt"

If you require a smaller distance between the terms, you can specify it as follows. This query matches items where the terms "acquisition" and "debt" appear within the same item, where a
maximum distance of 3 between the terms. The order of the terms must match for an item to be returned:
"acquisition" ONEAR(n=3) "debt"

Synonym operators
You use the WORDS operator to specify that the terms in the query are synonyms, and that results returned should match either of the specified terms. You can use the WORDS operator
with free text expressions only; it is not supported with property restrictions in KQL queries.
The following query example matches results that contain either the term "TV" or the term "television". This matching behavior is the same as if you had used the following query:
WORDS(TV, Television)

TV OR Television

These queries differ in how the results are ranked. When you use the WORDS operator, the terms "TV" and "television" are treated as synonyms instead of separate terms. Therefore,
instances of either term are ranked as if they were the same term. For example, a content item that contained one instance of the term "television" and five instances of the term "TV" would
be ranked the same as a content item with six instances of the term "TV".

Wildcard operator
You use the wildcard operator—the asterisk character (" * ")—to enable prefix matching. You can specify part of a word, from the beginning of the word, followed by the wildcard operator, in
your query, as follows. This query would match results that include terms beginning with "serv", followed by zero or more characters, such as serve, server, service, and so on:
serv*

Inclusion and exclusion operators


You can specify whether the results that are returned should include or exclude content that matches the value specified in the free text expression or the property restriction by using the
inclusion and exclusion operators, described in Table 6.
Table 6. Operators for including and excluding content in results

NAME O PER ATO R B EHAV IO R

Inclusion "+" Includes content with values that match the inclusion.
This is the default behavior if no character is specified. This is the
same as using the AND operator.

Exclusion "-" Excludes content with values that match the exclusion. This is the
same as using the NOT operator.

Dynamic ranking operator


You use the XRANK operator to boost the dynamic rank of items based on certain term occurrences within the match expression, without changing which items match the query. An
XRANK expression contains one component that must be matched, the match expression, and one or more components that contribute only to dynamic ranking, the rank expression. At least
one of the parameters, excluding n, must be specified for an XRANK expression to be valid.
NOTE

Query latency (and probability of timeout) increases when using complex queries and especially when using xrank operators. The increase in query latency depends on the number of
XRANK operators and the number of hits in the match expression and rank expression components in the query tree.
Match expressions may be any valid KQL expression, including nested XRANK expressions. Rank expressions may be any valid KQL expression without XRANK expressions. If your KQL
queries have multiple XRANK operators, the final dynamic rank value is calculated as a sum of boosts across all XRANK operators.
NOTE

Use parenthesis to explicitly indicate the order of computation for KQL queries that have more than one XRANK operator at the same level.
You can use the XRANK operator in the following syntax:
<match expression> XRANK(cb=100, rb=0.4, pb=0.4, avgb=0.4, stdb=0.4, nb=0.4, n=200) <rank expression>

The XRANK operator's dynamic ranking calculation is based on this formula:

Table 7 lists the basic parameters available for the XRANK operator.
Table 7. XRANK operator parameters

PAR AME TER V ALU E D ES CR IPTIO N

n <integer_value> Specifies the number of results to compute statistics from.


This parameter does not affect the number of results that the
dynamic rank contributes to; it is just a means to exclude irrelevant
items from the statistics calculations.
Default: 0. A zero value carries the semantic of all documents .

nb <float_value> The nb parameter refers to normalized boost. This parameter


specifies the factor that is multiplied with the product of the
variance and average score of the rank values of the results set.
f in the XRANK formula.
Typically, normalized boost, nb, is the only parameter that is modified. This parameter provides the necessary control to promote or demote a particular item, without taking standard
deviation into account.
The following advanced parameters are also available. However, typically they're not used.
Table 8. Advanced parameters for XRANK

PAR AME TER V ALU E D ES CR IPTIO N

cb <float_value> The cb parameter refers to constant boost.


Default: 0.
a in the XRANK formula.

stdb <float_value> The stdb parameter refers to standard deviation boost.


Default: 0.
e in the XRANK formula.

avgb <float_value> The avgb parameter refers to average boost.


Default: 0.
d in the XRANK formula.

rb <float_value> The rb parameter refers to range boost. This factor is multiplied with
the range of rank values in the results set.
Default: 0.
b in the XRANK formula.

pb <float_value> The pb parameter refers to percentage boost. This factor is


multiplied with the item's own rank compared to the minimum value
in the corpus.
Default: 0.
c in the XRANK formula.

Examples
Example 1. The following expression matches items for which the default full-text index contains either "cat" or "dog". The expression increases dynamic rank of those items with a constant
boost of 100 for items that also contain "thoroughbred".
(cat OR dog) XRANK(cb=100) thoroughbred

Example 2. The following expression matches items for which the default full-text index contains either "cat" or "dog". The expression increases dynamic rank of those items with a
normalized boost of 1.5 for items that also contain "thoroughbred".
(cat OR dog) XRANK(nb=1.5) thoroughbred

Example 3. The following expression matches items for which the default full-text index contains either "cat" or "dog". The expression increases dynamic rank of those items with a constant
boost of 100 and a normalized boost of 1.5, for items that also contain "thoroughbred".
(cat OR dog) XRANK(cb=100, nb=1.5) thoroughbred

Example 4. The following expression matches all items containing the term "animals", and boosts dynamic rank as follows:
Dynamic rank of items that contain the term "dogs" is boosted by 100 points.
Dynamic rank of items that contain the term "cats" is boosted by 200 points.
Dynamic rank of items that contain both the terms "dogs" and "cats" is boosted by 300 points.
(animals XRANK(cb=100) dogs) XRANK(cb=200) cats

Parenthesis
You can combine different parts of a keyword query by using the opening parenthesis character " ( " and closing parenthesis character " ) ". Each opening parenthesis " ( " must have a
matching closing parenthesis " ) ". A white space before or after a parenthesis does not affect the query.

See also
Building search queries in SharePoint
FAST Query Language (FQL) syntax reference
3/26/2018 • 30 minutes to read Edit Online

Learn about constructing complex search queries for Search in SharePoint using the FAST Query Language (FQL). This reference describes the elements of an FQL query and how to use
property specifications, token expressions, and operators in your FQL queries.

Introduction to FQL and query language subexpressions and expressions in SharePoint


The FAST Query Language (FQL) is a powerful query language that enables developers to perform exact searches and to narrow the scope of your search to values that belong to a specific
managed property or a full-text index.
A query language expression can contain nested subexpressions that include query terms, property specifications, and operators, as described in Table 1.
Table 1. Subexpressions in query language expressions

ITEM D ES CR IPTIO N

Token expressions One or more query terms, phrases, or numeric values to search for in a query.

Property specification A property or full-text index to match with the affected expression.

Operators Keywords that specify Boolean operations (such as AND, OR) or other constraints to operands (such as
FILTER.)

FQL query example


The following FQL query example searches for the terms "hello" and "world" in the body managed property of an indexed item:
body:string("hello world", mode="and")

In the example:
body: limits the scope of the query to the body managed property within the item.
"hello world" is the operand to the STRING operator, which indicates the terms to search for.
mode="and" indicates that the logical query operator AND will be applied to "hello world" .
The length of FAST Query Language queries is limited to 2,048 characters.

Property specification in FQL


A property specification limits the scope of the affected expression to specific regions of the indexed content. Such a region can be identified by a full-text index or a managed property.
Managed properties of type Text and YesNo are evaluated as text. All other managed property types, including the Datetime type, are evaluated as numeric values.
If you don't include a property specification for an expression, the search engine attempts to match the default full-text index defined in the index schema.
The property name must always precede a colon ( In operator), and numeric operators must always include a property specification.
A property specification (the In Operator) may be applied to the following query entities:
A single term or phrase, as follows:
author:shakespeare

title:"to be or not to be"

An operator, for example, the STRING operator, as follows: title:string("to be or not to be") In this case the property specification applies to the complete operator expression.

Examples
Each of the following expressions matches items that have both "much" and "nothing" in the title managed property.
title:and(much, nothing)

and(title:much, title:nothing)

title:string("much nothing", mode="and")

Token expressions in FQL


Token expressions are words, phrases, or numeric values that are matched against the index.
A text token expression can be a single word or a phrase enclosed in double quotation marks.
A numeric token expression can be a single value or a value range expression.

Wildcard expressions
A wildcard expression indicates a single term or phrase that includes the Asterisk ("\*") character; asterisk implies a match of zero or more characters, excluding whitespace. FQL supports
prefix search for individual text managed properties and full-text indexes.
Wildcard expression examples
The following is a list of valid uses of wildcard expressions in FQL:
text*

string("this examp*")

Numeric term expressions


Each numeric term expression must include a property specification of a compatible index schema data type. Table 2 lists the numeric data types that can be used in FQL.
Table 2. Numeric data types that can be used in FQL

FQ L T YPE CO MPATIB LE IND E X S CHEMA T YPES D ES CR IPTIO N

Int Integer 64 bit integer.

Float Double 64-bit (double precision) floating point.

Decimal Decimal 128-bit decimal

Datetime Datetime A date and time value.


The date/time support in FQL enables the same numeric operations
on date/time values as on other numeric values.

Date and time query expressions


FQL provides the datetime data type for date and time.
The following ISO 8601-compatible datetime formats are supported in queries:
YYYY-MM-DD
YYYY-MM-DDThh:mm:ss
YYYY-MM-DDThh:mm:ssZ
YYYY-MM-DDThh:mm:ssfrZ
In these datetime formats:
YYYY specifies a four-digit year.
NOTE

Only four-digit years are supported.


MM specifies a two-digit month. For example, 01 = January.
DD specifies a two-digit day of the month (01 through 31).
T specifies the letter "T".
hh specifies a two-digits hour (00 through 23); A.M./P.M. indication is not allowed.
mm specifies a two-digit minute (00 through 59).
ss specifies a two-digit second (00 through 59).
fr specifies an optional fraction of seconds, ss; between 1 to 7 digits that follows the . after the seconds. For example, 2012-09-27T11:57:34.1234567.
All date/time values must be specified according to the UTC (Coordinated Universal Time), also known as GMT (Greenwich Mean Time) time zone. The UTC time zone identifier (a trailing
"Z" character) is optional.

Reserved words, special characters, and escaping


The following words are reserved within FQL.
and, or, any, andnot, count, decimal, rank, near, onear, int, in32, int64, float, double, datetime, max, min, range, phrase, scope, filter, not, string, starts-with, ends-with, equals,
words, xrank.

If you want to express any of these words as terms in a query expression, you must enclose them in double quotation marks as shown in the following examples:
or("any", "and", "xrank")

string("any and xrank", mode="OR")

phrase(this, is, a, "phrase")

Tip: Reserved words and characters are not case-sensitive, but using lowercase characters are recommended for future compatibility.

FQL does not always require a string to be enclosed in double quotation marks. For example, and(cat, dog) is valid FQL even though cat and dog are not in double quotation marks.
However, we recommend that you use double quotation marks to avoid conflicts with reserved words.
The query terms are tokenized according to your locale setting. The tokenization process removes certain special characters. Because special characters are removed, the following FQL
expressions are equivalent.
and("[king]", "<queen>")

and("king", "queen")

When a query includes terms from user input or another application, use the string("<query terms>", mode="AND|OR|PHRASE") operator to avoid conflict with reserved words in the query
language. You must also remove possible double quotation marks from the user-provided query.

FQL Operators
FAST Query Language (FQL) operators are keywords that specify Boolean operations or other constraints to operands. The FQL operator syntax is as follows:
[property-spec:]operator(operand [,operand]* [, parameter="value"]*)

In the syntax:
property-spec is an optional property specification followed by the "in" operator.
operator is a keyword that specifies an operation to perform.
operand is a term expression or another operator.
parameter is the name of a value that changes the behavior of the operator.
value is the value to use for the parameter name.
Operator names, parameter names, and parameter text values are case-insensitive. White space is allowed within the operator body, but is ignored unless it is enclosed in double quotation
marks. The length of FAST Query Language queries is limited to 2,048 characters.
Table 3 lists the types of operators supported by FQL.
Table 3. FQL supported operator types

T YPE D ES CR IPTIO N O PER ATO R S

String Enables you to specify query operations on a string of terms. This is STRING
the most common operator to use on text terms.

Boolean Enables you to combine terms and sub-expressions in a query. AND, OR, ANY, ANDNOT, NOT, COUNT, COUNT

Proximity Enables you to specify the proximity of the query terms in a NEAR, ONEAR, PHRASE, STARTS-WITH, ENDS-WITH, EQUALS
matching sequence of text.

Numeric Enables you to specify numeric conditions in the query. RANGE , INT, FLOAT, DATETIME, DECIMAL

Relevance Enables you to impact the relevance evaluation of a query. XRANK and FILTER

Table 4 provides a list of the supported operators.


Table 4. FQL supported operators

O PER ATO R D ES CR IPTIO N T YPE

AND Returns only items that match all AND operands. Boolean

ANDNOT Returns only items that match the first operand and that don't Boolean
match the subsequent operands.

ANY Similar to the OR operator except that the dynamic rank (the Boolean
relevance score in the result set.md) is affected by neither the
number of operands that match nor the distance between the
terms in the item.

COUNT Enables you to specify the number of query term occurrences an Boolean
item must include to be returned as a result. The operand may be a
single query term, a phrase, or wildcard query term.

DATETIME Provides explicit typing of numeric values. Numeric


The explicit type conversion is optional and usually is not needed.
The type of the query term is detected according to the type of the
target numeric managed property.

DECIMAL Provides explicit typing of numeric values. Numeric


The explicit type conversion is optional and usually is not needed.
The type of the query term is detected according to the type of the
target numeric managed property.

ENDS-WITH Specifies that a word or phrase must appear in the end of a Proximity
managed property.

EQUALS Specifies that a word or phrase term or phrase must provide an Proximity
exact token match with the managed property.

FILTER Used to query metadata or other structured data. Relevance

FLOAT Provides explicit typing of numeric values. Numeric


The explicit type conversion is optional and usually is not needed.
The type of the query term is detected according to the type of the
target numeric managed property.

INT Provides explicit typing of numeric values. Numeric


The explicit type conversion is optional and usually is not needed.
The type of the query term is detected according to the type of the
target numeric managed property.

NEAR Restricts the result set to items that have N terms within a certain Proximity
distance of one another.

NOT Returns only items that exclude the operand. Boolean

ONEAR The ordered variant of NEAR, and requires an ordered match of the Proximity
terms. The ONEAR operator can be used to restrict the result set to
items that have N terms within a certain distance of Returns only
items that don't match the operand. The operand may be any valid
FQL expression.one another.

OR Returns only items that match at least one of the OR operands. Boolean
Items that match will get a higher dynamic rank (relevance score in
the result set.md) if more of the OR operands match.
O PER ATO R D ES CR IPTIO N T YPE

PHRASE Returns only items that match an exact string of tokens. Proximity

RANGE Enables range matching expressions. The RANGE operator is used Numeric
for numeric and date/time managed properties.

STARTS-WITH Specifies that a word or phrase must appear in the start of a Proximity
managed property.

STRING Define a Boolean matching condition to a text string. String

XRANK Enables you to boost the dynamic rank of items based on certain Relevance
term occurrences without changing which items match the query. A
XRANK expression contains one component that must be matched,
and one or more components that contribute only to dynamic
ranking.
NOTE

In SharePoint, the RANK operator is deprecated and will no longer have any effect. Use XRANK instead.

AND
Returns only items that match all AND operands. The operands may be a single term or any valid FQL sub-expression.
Syntax
and(operand, operand [, operand]*)

Parameters
Not applicable.
Examples
The following expression matches items for which the default full-text index contains "cat", "dog", and "fox".
and(cat, dog, fox)

ANDNOT
Returns only items that match the first operand and that don't match the subsequent operands. The operands may be a single term or any valid FQL sub-expression.
Syntax
andnot(operand, operand [,operand]*)

Parameters
Not applicable.
Examples
Example 1. The following expression matches items for which the default full-text index contains "cat" but not "dog".
andnot(cat, dog)

Example 2. The following expression matches items for which the default full-text index contains "dog" but neither "beagle" nor "chihuahua".
andnot(dog, beagle, chihuahua)

ANY
NOTE

In SharePoint, the ANY operator is deprecated. Use the OR operator instead.


Similar to the OR operator except that the dynamic rank (the relevance score in the result set) is affected by neither the number of operands that match nor the distance between the terms in
the item. The operands may be a single term or any valid FQL sub-expression.
The dynamic ranking component for this part of the query is based on the best matching term within the ANY expression.
NOTE

he difference from OR is related only to the ranking within the result set. The same total set of items will match the query.
Syntax
any(operand, operand [,operand]*)

Parameters
Not applicable.
Examples
The following expression matches items for which the default full-text index contains "cat" or "dog".
If the index contains both "cat" and "dog", but "cat" is considered a better match, the 'item's dynamic rank will be based on "cat" with no consideration given to "dog".
any(cat, dog)

COUNT
Specifies the of number query term occurrences an item must include for the item to be returned as a result. The operand may be a single query term, a phrase, or a wildcard query term.
Syntax
property-spec:count(operand [,from=<numeric value>, to=<numeric value>])

Parameters
PAR AME TER V ALU E D ES CR IPTIO N

From <numeric_value> The value of the from parameter must be a positive integer that
specifies the minimum number of times that the specified operand
must be matched.
If the from parameter is not specified, no lower limit will exist.

to <numeric_value> The value of the to parameter must be a positive integer that


specifies the non-inclusive maximum number of times that the
specified operand must be matched. For example, a to value of 11
specifies 10 times or fewer.
If the to parameter is not specified, no upper limit will exist.

Examples
Example 1. The following expression matches at least 5 occurrences of the word "cat".
count(cat, from=5)

Example 2. The following expression matches at least 5 but not 10 or more occurrences of the word "cat".
count(cat, from=5, to=10)

Example 3. Each of the following expressions matches at least 3 occurrences of a certain word, and that word can be either "cat" or "dog".
count(or(cat, dog), from=3)count(string("cat dog", mode="or"), from=3)

The following table contains examples of managed property string values and states whether they match the two expressions in Example 3.

MATCH? TE X T

Yes My cat likes my dog, but my dog hates my cat.

No My bird likes my newt, but my dog hates my cat.

DATETIME
Provides explicit typing of date/time numeric values. The operand is a date/time string formatted according to the syntax specified in Token expressions in FQL.
The explicit type conversion is optional and usually is not needed. The type of the query term is detected according to the type of the target numeric managed property.
Syntax
datetime(<date/time string>)

Parameters
Not applicable.

DECIMAL
Provides explicit typing of decimal values. The operand is a decimal value according to the syntax specified in Token expressions in FQL.
The explicit type conversion is optional and usually is not needed. The type of the query term is detected according to the type of the target numeric managed property.
Syntax
decimal(<decimal point value>)

Parameters
Not applicable.

ENDS-WITH
Specifies that a word or phrase must appear in the end of a managed property (boundary matching).
Boundary matching is not supported on numeric managed properties. Numeric managed properties will always be subject to exact or value range matching.
Some applications may require that you are able to perform an exact match of a managed property. For example, this may be a product name managed property, where the full name of
one product is a substring of another product name.
Syntax
ends-with(<term or phrase>)

Parameters
Not applicable.
Examples
The following expression matches items with the values "Mr Adam Jones" and "Adam Jones" in the "author" managed property. It will not match items with the value "Adam Jones sr".
author:ends-with("adam jones")

Remarks
Boundary matching can be applied to all the text of the managed property, or to individual strings within a managed property that contains a list of string values, for example, a list of names.
In this case, you may want to match the exact content of each string, and to avoid query matching across string boundaries.
To apply boundary match queries, you must configure the relevant managed property in the index schema.
By enabling the Boundary Match feature for the managed property, you can do the following:
Use explicit boundary match queries.
Prevent phrases from matching across string boundaries. For managed properties that contain multiple strings, this feature will ensure that a string does not match words before or
after a boundary indication.

EQUALS
Specifies that a word or phrase must provide an exact token match with the managed property.
Syntax
equals(<term or phrase>)

Parameters
Not applicable.
Examples
The following example will match items with the values "Adam Jones" in the "author" managed property. It will not match items with the values "Adam Jones sr" or "Mr Adam Jones".
author:equals("adam jones")

Remarks
See also ENDS-WITH.

FILTER
Used to query metadata or other structured data.
Using the FILTER operator automatically implies the following for the specified query:
Linguistics will be set to linguistics="OFF".
Ranking will be disabled.
No query highlighting will be used in the hit highlighted summary for the query result hit.

Tip: If you use the STRING operator inside a FILTER expression, by default, linguistics is disabled. You can enable linguistics processing within each STRING expression inside FILTER
by using the operand linguistics="ON" .

Syntax
filter(<any valid FQL operator expression>)

Parameters
Not applicable.
Examples
The following expression matches items that have a Title managed property that contains "sonata" and a Doctype managed property that contains only the token "audio". No linguistic
matching will be performed on "audio". Because the FILTER token will be used to match "audio", that text will not be highlighted in the hit highlighted summary.
and(title:sonata, filter(doctype:equals("audio")))

Remarks
If you must restrict your query to match at least one of a large set of integer values in a numeric property, you can express this in two functionally equivalent ways:
and(string("hello world"), filter(property-spec:or(1, 20, 453, ... , 3473)))

and(string("hello world"), filter(property-spec:int("1 20 453 ... 3473", mode="or")))

The second example uses the INT operator by using a string with the set of numeric values in double quotation marks. This provides a significantly better query performance when filtering
with a large set of numeric values.
If you must filter a large set of values, you should consider using numeric values instead of string values, and express your queries by using the optimized syntax.

FLOAT
Provides explicit typing of floating point numeric values. The operand is a floating point value according to the syntax specified in Token expressions in FQL.
The explicit type conversion is optional and usually is not needed. The type of the query term is detected according to the type of the target numeric managed property.
Syntax
float(<floating point value>)

Parameters
Not applicable.

INT
Provides explicit typing of integer values. The operand is an integer value according to the syntax specified in Token expressions in FQL.
The explicit type conversion is optional and usually is not needed. The type of the query term is detected according to the type of the target numeric managed property.
The INT operator can also be used to express a set of integer values as arguments to Boolean FQL operators. This provides a performance efficient way to provide a set of integer values in a
query, as the values that are passed by using the INT operator are not parsed by the FQL query parser but passed directly to the query matching component.
Syntax
int(<integer value>)

int("value, value, ??? , value")

The first syntax specifies a single integer. The second syntax specifies a comma-separated list of integer values enclosed in double quotation marks.
Parameters
Not applicable.
Examples
If you need to restrict your query to match at least one of a large set of integer values in a numeric property, you can express this by using the INT operator:
and(string("hello world"), filter(id:int("1 20 49 124 453 985 3473", mode="or")))

NEAR
Restricts the result set to items that have N terms within a certain distance of one another.
The order of the query terms is not important for the matching, only the distance.
Any number of terms can be combined with the NEAR operators.
NEAR operands may be single terms, phrases, or Boolean OR or ANY operator expressions. Wildcards are accepted.
If multiple operands of the NEAR operator match the same indexed token, they are considered near one another.
Syntax
near(arg, arg [, arg]* [, N=<numeric value>])

Parameters
PAR AME TER V ALU E D ES CR IPTIO N

N <numeric_value> Specifies the maximum number of words that is allowed to appear


between the terms (explicit proximity).
If NEAR includes more than two operands, the maximum number of
words allowed between the terms ( N) is counted within the whole
expression.
Default: 4

Examples
Example 1. The following expression matches strings that contain both "cat" and "dog" if no more than four indexed tokens (default) separate them.
near(cat, dog)

Example 2. The following expression matches strings that contain "cat", "dog", "fox", and "wolf" if no more than four indexed tokens separate them.
near(cat, dog, fox, wolf)

The following table contains examples of managed property string values and states whether they match the previous expression in Example 2.

MATCH? TE X T

Yes The picture shows a cat, a dog, a fox, and a wolf.

Yes (with stemming) Dogs, foxes, and wolves are canines, but cats are felines.

No The picture shows a cat with a dog, a fox, and a wolf.

The following expression matches all the strings in the previous table.
near(cat, dog, fox, wolf, N=5)

Remarks
NEAR/ONEAR term distance considerations
N indicates the maximum number of words that are allowed to appear between the query terms within the matching segment of the item. If NEAR or ONEAR includes more than two
operands, the maximum number of words allowed between the query terms ( N) is counted within the segment of the item matching all the NEAR or ONEAR terms.
NEAR or ONEAR operates on tokenized text. This means that special characters such as comma (" , "), period (" . "), colon (" : "), or semicolon (" ; ") will be treated as white space. The term
"distance" relates to tokens within the indexed text.
If you use ONEAR or NEAR with equal operands, the operator will work as follows:
near(a, a, n=x)

This query will always return true if at least one instance of '' a '' appears within the context. This also means that NEAR cannot be used as a COUNT operator. For more information about
counting term occurrences, see the COUNT operator.
NEAR applied to phrases will also match overlapping phrases in the text.
If a token in the matching segment matches more than one operand to the NEAR or ONEAR expression, the query may match even if the number of nonmatching tokens within the
matching segment exceeds the value of ' N' in the NEAR or ONEAR operator expression. For example, an overlap can be overlapping phrases. If the number of token overlap matches is '
O ', the query will match if not more than ' N+O ' non-matching tokens appear within the matching segment of the item.

NEAR or ONEAR with NOT


The NOT operator cannot be used inside the NEAR or ONEAR operator. The following is incorrect FQL syntax:
near(audi,not(bmw),n=2)

NOT
Returns only items that don't match the operand. The operand may be any valid FQL expression.
Syntax
not(operand)

Parameters
Not applicable.

ONEAR
The ordered variant of NEAR, and requires an ordered match of the terms. The ONEAR operator can be used to restrict the result set to items that have N terms within a certain distance of
one another.
Syntax
onear(arg, arg [, arg]* [, N=<numeric value>])

Parameters
PAR AME TER V ALU E D ES CR IPTIO N

N <numeric_value> Specifies the maximum number of words that are allowed to appear
between the terms (explicit proximity).
If ONEAR includes more than two operands, the maximum number
of words allowed between the terms ( N) is counted within the
whole expression.
Default: 4

Examples
Example 1. The following expression matches all the occurrences of the words "cat", "dog", "fox", and "wolf" that appears in order, if no more than four indexed tokens separate them.
onear(cat, dog, fox, wolf)

The following table contains examples of managed property string values, and states whether they match the previous expression.

MATCH? TE X T

Yes The picture shows a cat, a dog, a fox, and a wolf.

No Dogs, foxes, and wolves are canines, but cats are felines.

No The picture shows a cat with a dog, a fox, and a wolf.

Example 2. The following expression matches (with stemming) the text in the second row of the previous table.
onear(dog, fox, wolf, cat, N=5)

Example 3. The following expression matches the text in the first and third rows of the preceding table.
onear(cat, dog, fox, wolf, N=5)

Remarks
See also NEAR.

OR
Returns only items that match at least one of the OR operands. Items that match will get a higher dynamic rank (relevance score in the result set) if more of the OR operands match. The
operands may be a single term or any valid FQL sub-expression.
Syntax
or(operand, operand [,operand]*)

Parameters
Not applicable.
Examples
The following expression matches all the items for which the default full-text index contains either "cat" or "dog". If an item's default full-text index contains both "cat" and "dog", it will match
and have a higher dynamic rank than it would if it contained only one of the tokens.
or(cat, dog)

PHRASE
Searches for an exact string of tokens.
The PHRASE operands can be single terms. Wildcards are accepted.
Syntax
phrase(term [, term]*)

Parameters
Not applicable.
Remarks
See also STRING.

RANGE
Use the RANGE operator for numeric and date/time managed properties. The operator enables range matching expressions.
Syntax
range(start, stop [,from="GE"|"GT"] [,to="LE"|"LT"])

Parameters
PAR AME TER V ALU E D ES CR IPTIO N

start <numeric_value>|<date/time_value> Start value for the range.


To specify that the range has no lower bound, use the reserved
word min.

stop <numeric_value>|<date/time_value> End value for the range.


To specify that the range has no upper bound, use the reserved
word max.
PAR AME TER V ALU E D ES CR IPTIO N

from GE|GT Optional parameter that indicates the open or close start interval.
Valid values:
GE Greater than or equal to the start value (>= start of
interval).
GT Greater than the start value (> start of interval).
Default: GE

to LE|LT Optional parameter that indicates the open or close end interval.
Valid values:
LE Less than or equal to the end value (<= end of interval).
LT Less than the end value (< end of interval).
Default: LT

Examples
The following expression matches a description property starting with the phrase "big accomplishments" appearing in items with a size of at least 10 000 bytes.
and(size:range(10000, max), description:starts-with("big accomplishments"))

STARTS-WITH
Specifies a word or phrase that must appear at the start of a managed property.
Syntax
starts-with(<term or phrase>)

Parameters
Not applicable.
Examples
The following expression will match items with the values "Adam Jones sr" and "Adam Jones" in the author managed property. It will not match items with the value "Mr Adam Jones".
author:starts-with("adam jones")

Remarks
For additional remarks on boundary matching, see ENDS-WITH.

STRING
Defines a Boolean matching condition to a text string.
The operand is a text string (one or more terms) that is to be matched. The string is followed by zero or more parameters.
The STRING operator can also be used as a type conversion. The query string("24.5") , for example, will treat the numeric value "24.5" as a text string.
Syntax
string("<text string>"

[, mode=<mode>]

[, n=<near>]

[, weight=<n>]

[, linguistics=<on|off>]

[, wildcard=<on|off>])

Parameters
PAR AME TER V ALU E D ES CR IPTIO N

mode <mode> The mode parameter specifies how to evaluate the <text string>
value. The following list shows valid values.
"PHRASE" - phrase(term [,term]*)
M O DE E Q U IV A L E N T O P E R A T O R
E X P R E S S IO N

"PHRASE" phrase(term [,term]*)

"AND" and(term, term [,term]*)

"OR" or(term, term [,term]*)

"ANY" any(term, term [,term]*)

"NEAR" near(term, term [,term]*, N)

"ONEAR" onear(term, term [,term]*, N)

Default: "PHRASE"

n <numeric_value> This parameter indicates the maximum term distance for mode=
"NEAR" or mode= "ONEAR".
The following expressions are equivalent:
string("hello world", mode="NEAR", n=5)
near(hello, world, n=5)
Default: 4
PAR AME TER V ALU E D ES CR IPTIO N

weight <numeric_value> This parameter is a positive numeric value indicating term weight for
dynamic ranking.
A lower value indicates that a term should contribute less to the
ranking. A higher value indicates that a term should contribute
more to the ranking. A value of zero for the weight parameter
specifies that a term should not affect dynamic rank.
The weight parameter applies to all the terms in the STRING
expression.
TIP: The weight parameter will affect only full-text index queries.
Default: 100.

linguistics on|off Disables/enables all linguistics features for the string (lemmatization,
synonyms, spelling checking) if they are enabled for the query.
You can use this parameter to switch off linguistic processing for a
given term or string while you still want the term or string to
contribute to ranking.
Default: "ON"

wildcard on|off This parameter controls wildcard expansion of terms inside the <text
string>. This setting overrides any wildcard settings in query
parameters, and allows extended wildcard characters to be enabled
or disabled on specific parts of the query.
The following are valid values:
"ON" Specifies that the character "*" is evaluated as
wildcard. A "*" character matches zero or more characters.
"OFF" Specifies that the characters "*" is not evaluated as
wildcard.
Default: "ON"
NOTE

In SharePoint the minexpansion, maxexpansion and annotation_class parameters for the STRING operator are obsolete.
Examples
Example 1. Because the default string mode is " PHRASE ", each of the following expressions returns the same results.
"what light through yonder window breaks"string("what light through yonder window breaks")string("what light through yonder window breaks", mode="phrase")phrase(what, light, through,
yonder, window, breaks)

Example 2. The following string token expression and the AND operator expression return the same results.
string("cat dog fox", mode="and")and(cat, dog, fox)

Example 3. The following string token expression and OR operator expression return the same results.
string("coyote saguaro", mode="or")or(coyote, saguaro)

Example 4. The following string token expression and ANY operator expression return the same results.
string("coyote saguaro", mode="any")any(coyote, saguaro)

Example 5. The following string token expression and NEAR operator expression return the same results.
string("coyote saguaro", mode="near")near(coyote, saguaro)

Example 6. The following string token expression and NEAR operator expression return the same results.
string("cat dog fox wolf", mode="near", N=4)near(cat, dog, fox, wolf, N=4)

Example 7. The following string token expression and ONEAR operator expression return the same results.
string("cat dog fox wolf", mode="onear")onear(cat, dog, fox, wolf)

Example 8. The following string token expression matches the word "nobler" with linguistic features disabled, so other forms of the word (such as "ennobling") are not matched by using
stemming.
string("nobler", linguistics="off")

Example 9. The following expression matches items that contain either "cat" or "dog ", but the expression increases the dynamic rank of items that contain "dog" more than items that
contain "cat".
or(string("cat", weight="200"), string("dog", weight="500"))

Remarks
Relevance weight for dynamic ranking
The main effect of the weight parameter is for OR queries. It can also have some effect on AND queries. The dynamic rank algorithm can imply that different terms give different rank
contribution depending on where in the item the term match occurs.
The difference in rank contribution can also be based on term frequency and inverse item frequency. The following is an example:
Query: and(string("a"), string("b", weight=200))

Index schema: The title managed property has more weight than the body managed property.
Index item 1 includes term 'a' in the title and term 'b' in the body.
Index item 2 includes term 'a' in the body and term 'b' in the title.
In this example, item 2 will get the highest total rank, as the items with higher dynamic rank contribution will get even more boost.

Tip: The relative term boost (positive or negative) is applied to the dynamic rank component of the total rank. However, proximity boost (distance between words) rank calculations are
not affected by the term weighting. The relative weighting does not always imply that the total rank for the item is modified according to the percentage given. > The following query will
search for the terms "peter", "paul", or "mary", where "peter" will have twice as much rank contribution as the two other terms. > or(peter, string("paul mary", mode="OR", weight=50))
Handling strings with special characters
Special characters such as comma (","), semicolon (";"), colon (":"), period ("."), minus ("-"), underline ("_"), or forward slash ("/") are treated as white space inside a string expression enclosed
in double quotation marks. This is related to the tokenization process. These characters also imply an implicit phrasing of the tokens separated by these characters.
The following query expressions are equivalent.
title:string("animals birds", mode="phrase")title:"animals/birds"title:string("animals/birds", mode="and")title:string("animals/birds", mode="or")

The following query expressions are equivalent.


title:or(string("animals birds", mode="phrase"), string("animals insects", mode="phrase"))title:string("animals/birds animals/insects", mode="or")

The following query expressions are equivalent.


body:string("help contoso com", mode="phrase")body:string("help@contoso.com")

Tokenized phrase matching


You can search for an exact string of tokens by using the STRING operator with mode="phrase" or the PHRASE operator.
All such phrase operations imply a tokenized phrase match. This means that special characters such as comma (" , "), semicolon (" ; "), colon (" : "), underscore (" _ "), minus (" - "), or forward
slash (" / ") are treated as white space. This is related to the tokenization process.

XRANK
Boosts the dynamic rank of items based on certain term occurrences within the match expression, without changing which items match the query. An XRANK expression consists of one
component that must be matched, the match expression, and one or more components that contribute only to dynamic ranking, the rank expression. At least one of the parameters, excluding
n, must be specified for an XRANK expression to be valid.
Match expressions may be any valid FQL expression, including nested XRANK expressions. Rank expressions may be any valid FQL expression without XRANK expressions. If your FQL
queries have multiple XRANK operators, the final dynamic rank value is calculated as a sum of boosts across all XRANK operators.
NOTE

In SharePoint Server 2010, the XRANK operator had two parameters: boost and boostall, as well as the following syntax:
xrank(operand, rank-operand [, rank-operand]* [,boost=n] [,boostall=yes]) . This syntax along with its parameters is deprecated in SharePoint. We recommend the use of the new syntax and
parameters instead.
Syntax
xrank(<match expression> [, <rank-expression>]*, rank-parameter[, rank-parameter]*)

Formula

Parameters
PAR AME TER V ALU E D ES CR IPTIO N

N <integer_value> Specifies the number of results to compute statistics from.


This parameter does not affect the number of results that the
dynamic rank contributes to; it is just a means to exclude irrelevant
items from the statistics calculations.
Default: 0. A zero value carries the sematic of all documents .

Nb <float_value> The nb parameter refers to normalized boost. This parameter


specifies the factor that is multiplied with the product of the
variance and average score of the rank values of the results set.
f in the XRANK formula.

Typically normalized boost, nb, is the only parameter that is modified. This parameter provides the necessary control to promote or demote a particular item, without taking standard
deviation into account.
Advanced parameters
The following advanced parameters are also available. However, typically they aren't used.

PAR AME TER V ALU E D ES CR IPTIO N

cb <float_value> The cb parameter refers to constant boost.


Default: 0.
a in the XRANK formula.

stdb <float_value> The stdb parameter refers to standard deviation boost.


Default: 0.
e in the XRANK formula.

avgb <float_value> The avgb parameter refers to average boost. This factor is multiplied
with the average rank value of the results set.
Default: 0.
d in the XRANK formula.

rb <float_value> The rb parameter refers to range boost. This factor is multiplied with
the range of rank values in the results set.
Default: 0.
b in the XRANK formula.
PAR AME TER V ALU E D ES CR IPTIO N

pb <float_value> The pb parameter refers to percentage boost. This factor is


multiplied with the item's own rank compared to the minimum value
in the corpus.
Default: 0.
c in the XRANK formula.

Examples
Example 1. The following expression matches items for which the default full-text index contains either "cat" or "dog". The expression increases dynamic rank of those items with a constant
boost of 100 for items that also contain "thoroughbred".
xrank(or(cat, dog), thoroughbred, cb=100)

Example 2. The following expression matches items for which the default full-text index contains either "cat" or "dog". The expression increases dynamic rank of those items with a
normalized boost of 1.5 for items that also contain "thoroughbred".
xrank(or(cat, dog), thoroughbred, nb=1.5)

Example 3. The following expression matches items for which the default full-text index contains either "cat" or "dog". The expression increases dynamic rank of those items with a constant
boost of 100 and a normalized boost of 1.5, for items that also contain "thoroughbred".
xrank(or(cat, dog), thoroughbred, cb=100, nb=1.5)

Example 4. The following expression matches all items containing the term "animals", and boosts dynamic rank as follows:
Dynamic rank of items that contain the term "dogs" is boosted by 100 points.
Dynamic rank of items that contain the term "cats" is boosted by 200 points.
Dynamic rank of items that contain both the terms "dogs" and "cats" is boosted by 300 points.
xrank(xrank(animals, dogs, cb=100), cats, cb=200)

See also
Building search queries in SharePoint
Using the SharePoint search Query APIs
7/12/2018 • 3 minutes to read Edit Online

Learn about the query APIs available in SharePoint that enable you to add search functionality to custom solutions and applications.

SharePoint Query APIs


Search in SharePoint provides several query APIs, giving you lots of ways to access search results, so that you can return search results in a variety of custom solution types.
In addition to the server object model that was available in previous versions of SharePoint, Search in SharePoint also provides the following:
Client object model (CSOM)
JavaScript object model (JSOM)
Representational State Transfer (REST) service
Table 1 shows the APIs that you can use to program search queries and the path to the source file on the server.
Table 1. Search APIs

API NAME CL AS S LIB R AR Y O R S CHEMA AND PATH

.NET CSOM Microsoft.SharePoint.Client.Search.dll


%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\ISAPI

Silverlight CSOM Microsoft.SharePoint.Client.Search.Silverlight.dll


%ProgramFiles%\Common Files\Microsoft Shared\web server
extensions\15\TEMPLATE\LAYOUTS\ClientBin

JavaScript CSOM SP.search.js


%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\TEMPLATE\LAYOUTS

REST service endpoints http://server/_api/search/query


http://server/_api/search/suggest

Server object model Microsoft.Office.Server.Search.dll


%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\ISAPI

As a best practice in SharePoint development, use client APIs when you can. Client APIs include the .NET, Silverlight, Phone, and JavaScript client object models, and the REST service. For
more information about the APIs in SharePoint and when to use them, see Choose the right API set in SharePoint.

Query using the .NET client object model


Search in SharePoint includes a client object model that enables access to search results for online, on-premises, and mobile development. The Search in SharePoint CSOM is built on the
SharePoint CSOM. Therefore, your client code first needs to access the SharePoint CSOM and then access the Search in SharePoint CSOM. For more information about the SharePoint
CSOM, see SharePoint 2010 Client Object Model. For more information about the ClientContext class, which is the entry point to the CSOM, see Client Context as Central Object.
For the .NET managed CSOM, get a ClientContext instance (located in the Microsoft.SharePoint.Client namespace in the Microsoft.SharePoint.Client.dll). Then use the object model in the
Microsoft.SharePoint.Client.Search.Query namespace in the Microsoft.SharePoint.Client.Search.dll.
Here's a basic example.

using (ClientContext clientContext = new ClientContext("http://<serverName>/sites/<siteCollectionPath>"))


{
KeywordQuery keywordQuery = new KeywordQuery(clientContext);
keywordQuery.QueryText = "SharePoint";
SearchExecutor searchExecutor = new SearchExecutor(clientContext);
ClientResult<ResultTableCollection> results = searchExecutor.ExecuteQuery(keywordQuery);
clientContext.ExecuteQuery();
}

To download an example, see the following code sample posted by SharePoint MVP Corey Roth: SharePoint: Query Search with the Managed Client Object Model.

Query using the JavaScript client object model


For the JavaScript CSOM, get a ClientContext instance, and then use the object model in the SP.Search.js file.
Here's a basic example.

var clientContext = new SP.ClientContext("<serverRelativeUrl>");


var contextSite = clientContext.get_site();
var keywordQuery = new Microsoft.SharePoint.Client.Search.Query.KeywordQuery(clientContext);
keywordQuery.set_queryText("SharePoint");
var searchExecutor = new Microsoft.SharePoint.Client.Search.Query.SearchExecutor(clientContext);
var results = searchExecutor.executeQuery(keywordQuery);
context.executeQueryAsync(onQuerySuccess, onQueryError);

To download an example, see the following code sample posted by SharePoint MVP Corey Roth: SharePoint: Querying Search with the JavaScript Client Object Model.

Query using the REST service


SharePoint includes a REST service that enables you to remotely execute queries against the SharePoint Search service from client applications by using any technology that supports REST
web requests. The Search REST service exposes two endpoints, query and suggest, and will support both GET and POST operations. Results are returned in either XML or JavaScript
Object Notation (JSON) format.
The following is the access point for the service: http://server/_api/search/ . You can also specify the site in the URL, as follows: http://server/site/_api/search/ . The search service returns
results from the entire site collection, so the same results are returned for both ways to access the service.
See SharePoint Search REST API overview and Retrieving query suggestions using the Search REST service for more information.

Query using the .NET server object model


Applications that use the server object model must run directly on a server that is running SharePoint. The search Query server object model resides in the
Microsoft.Office.Server.Search.Query namespace, which is located in Microsoft.Office.Server.Search.dll.
As in SharePoint Server 2010, you use the KeywordQuery class to define the query, and then called the Execute() method to submit the query. In SharePoint, the Execute method is
obsolete, and while it will still work, you should use the SearchExecutor class instead. To submit the query, call the ExecuteQuery() method, passing the instance of the KeywordQuery class
in the call.
Here's a basic example.

using (SPSite siteCollection = new SPSite("<serverRelativeUrl>"))


{
KeywordQuery keywordQuery = new KeywordQuery(siteCollection);
keywordQuery.QueryText = "SharePoint";
SearchExecutor searchExecutor = new SearchExecutor();
ResultTableCollection resultTableCollection = searchExecutor.ExecuteQuery(keywordQuery);
resultTableCollection = resultTableCollection.Filter("TableType", KnownTableTypes.RelevantResults);
ResultTable resultTable = resultTableCollection.FirstOrDefault();
DataTable dataTable = resultTable.Table;
}

To download an example, see the following code sample posted by SharePoint MVP Corey Roth: SharePoint: Query Search with the KeywordQuery Class.

See also
Building search queries in SharePoint
SharePoint Search REST API overview
SharePoint: Using the search REST service from an app for SharePoint
SharePoint Search REST API overview
7/9/2018 • 12 minutes to read Edit Online

Add search functionality to client and mobile applications using the Search REST service in SharePoint and any technology that supports REST web requests.

Querying with the Search REST service


Search in SharePoint includes a Search REST service you can use to add search functionality to your client and mobile applications by using any technology that supports REST web
requests. You can use the Search REST service to submit Keyword Query Language (KQL) or FAST Query Language (FQL) queries in your SharePoint Add-ins, remote client applications,
mobile applications, and other applications.
The Search REST service supports both HTTP POST and HTTP GET requests.

GET requests
Construct the URI for query GET requests to the Search REST service as follows:
/_api/search/query

For GET requests, you specify the query parameters in the URL. You can construct the GET request URL in two ways:

http://server/_api/search/query?query_parameter=value&amp;query_parameter=value

http://server/_api/search/query(query_parameter=value&amp;query_parameter=<value>)

POST requests
You construct the URI for query POST requests to the Search REST service as follows:
/_api/search/postquery

For POST requests, you pass the query parameters in the request in JavaScript Object Notation (JSON) format.
The HTTP POST version of the Search REST service supports all parameters supported by the HTTP GET version. However, some of the parameters have different data types, as described
in Table 1.
Table 1. Query parameters with different data types for POST requests

PAR AME TER D ATA T YPE

SelectProperties string[]

RefinementFilters string[]

SortList Sort

HithighlightedProperties string[]

Properties Microsoft.SharePoint.Client.Search.Query.KeywordQueryProperties

Use POST requests in the following scenarios:


When you'll exceed the URL length restriction with a GET request.
When you can't specify the query parameters in a simple URL. For example, if you have to pass parameter values that contain a complex type array, or comma-separated strings, you
have more flexibility when constructing the POST request.
When you use the ReorderingRules parameter because it is supported only with POST requests.

Using query parameters with the Search REST service


When you make a call to the Search REST service, you specify query parameters with the request. Search in SharePoint uses these query parameters to construct the search query. With a
GET request, you specify the query parameters in the URL. For POST requests, you pass the query parameters in the body in JavaScript Object Notation (JSON) format.
The following sections describe the query parameters you can use to submit search queries with the Search REST service.

QueryText parameter
A string that contains the text for the search query.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'
Sample POST request

{
'request': {
'Querytext': 'sharepoint',
'RowLimit':20,
'ClientType':'ContentSearchRegular'
}
}

QueryTemplate
A string that contains the text that replaces the query text, as part of a query transform.
Sample GET request
http://server/_api/search/query?querytext='sharepoint'&querytemplate='{searchterms} author:johndoe'
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'Querytemplate' : '{searchterms} Author:johndoe'
}

EnableInterleaving
A Boolean value that specifies whether the result tables that are returned for the result block are mixed with the result tables that are returned for the original query.
true to mix the ResultTables; otherwise, false. The default value is true.
Change this value only if you want to provide your own interleaving implementation.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&enableinterleaving=true
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'EnableInterleaving' : 'True'
}

SourceId
The result source ID to use for executing the search query.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&sourceid='8413cd39-2156-4e00-b54d-11efd9abdb89'
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'SourceId' : '8413cd39-2156-4e00-b54d-11efd9abdb89'
}

RankingModelId
The ID of the ranking model to use for the query.
Sample GET request
http:// server/api/search/query?querytext='sharepoint'&rankingmodelid= _CustomRankingModelID
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'RankingModelId' : 'CustomRankingModelID '
}

StartRow
The first row that is included in the search results that are returned. You use this parameter when you want to implement paging for search results.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&startrow=10
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'StartRow' : '10'
}

RowLimit
The maximum number of rows overall that are returned in the search results. Compared to RowsPerPage, RowLimit is the maximum number of rows returned overall.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&rowlimit=30
Sample POST request
{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'RowLimit' : '30'
}

RowsPerPage
The maximum number of rows to return per page. Compared to RowLimit, RowsPerPage refers to the maximum number of rows to return per page, and is used primarily when you want to
implement paging for search results.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&rowsperpage=10
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'RowsPerPage' : '10'
}

SelectProperties
The managed properties to return in the search results. To return a managed property, set the property's retrievable flag to true in the search schema.
For GET requests, you specify the SelectProperties parameter in a string containing a comma-separated list of properties. For POST requests, you specify the SelectProperties parameter as
a string array.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&selectproperties='Title,Author'
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'SelectProperties' : {
'results' : [
'Title,
Author'
]
}
}

Culture
The locale ID (LCID) for the query (see Locale IDs Assigned by Microsoft).
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&culture=1044
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'Culture' : '1044'
}

RefinementFilters
The set of refinement filters used when issuing a refinement query. For GET requests, the RefinementFilters parameter is specified as an FQL filter. For POST requests, the RefinementFilters
parameter is specified as an array of FQL filters.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&refinementfilters='fileExtension:equals("docx")'
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'RefinementFilters' : {
'results' : ['fileExtension:equals("docx")']
}
}

Refiners
The set of refiners to return in a search result.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&refiners='author,size'
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext':'sharepoint',
'Refiners': 'author,size',
}
}

HiddenConstraints
The additional query terms to append to the query.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&hiddenconstraints='developer'
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext':'sharepoint',
'HiddenConstraints':'developer'
}

SortList
The list of properties by which the search results are ordered.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&sortlist='rank:descending,modifiedby:ascending'
Sample POST request

{
'__metadata' : {'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'SortList' :
{
'results' : [
{
'Property':'Created',
'Direction': '0'
},
{
'Property':'FileExtension',
'Direction': '1'
}
]
}
}

EnableStemming
A Boolean value that specifies whether stemming is enabled.
true if the stemming is enabled; otherwise, false. The default value is true.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&enablestemming=false
Sample POST request

{
'__metadata' : {'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'EnableStemming : 'False'
}

TrimDuplicates
A Boolean value that specifies whether duplicate items are removed from the results.
true to remove the duplicate items; otherwise, false. The default value is true.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&trimduplicates=false
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext':'sharepoint',
'TrimDuplicates':'False'
}

Timeout
The amount of time in milliseconds before the query request times out. The default value is 30000.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&timeout=60000
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext':'sharepoint',
'Timeout':'60000'
}

EnableNicknames
A Boolean value that specifies whether the exact terms in the search query are used to find matches, or if nicknames are used also.
true if nicknames are used; otherwise, false. The default value is false.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&enablenicknames=true
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext':'sharepoint',
'EnableNicknames':'True'
}

EnablePhonetic
A Boolean value that specifies whether the phonetic forms of the query terms are used to find matches.
true if phonetic forms are used; otherwise, false. The default value is false.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&enablephonetic=true
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext':'sharepoint',
'EnablePhonetic':'True'
}

EnableFql
A Boolean value that specifies whether the query uses the FAST Query Language (FQL).
true if the query is an FQL query; otherwise, false. The default value is false.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&enablefql=true
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext':'sharepoint',
'EnableFQL':'True'
}

HithighlightedProperties
The properties to highlight in the search result summary when the property value matches the search terms entered by the user. For GET requests, Specify in a string containing a comma-
separated list of properties. For POST requests, specify as an array of strings.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&hithighlightedproperties='Title'
Sample POST request

{
'__metadata' : {'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'HitHighlightedProperties' : {
'results' : [
'Title'
]
}
}

BypassResultTypes
A Boolean value that specifies whether to perform result type processing for the query.
true to perform result type processing; otherwise, false. The default value is false.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&bypassresulttypes=true
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'BypassResultTypes' : 'true'
}

ProcessBestBets
A Boolean value that specifies whether to return best bet results for the query.
true to return best bets; otherwise, false. This parameter is used only when EnableQueryRules is set to true, otherwise it is ignored. The default value is false.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&processbestbets=true&enablequeryrules=true
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'ProcessBestBets' : 'true',
'EnableQueryRules' : 'true'
}

ClientType
The type of the client that issued the query.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&clienttype='custom'
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext':'sharepoint',
'ClientType':'custom'
}

PersonalizationData
The GUID for the user who submitted the search query.
Sample GET request
http:// <server>/api/search/query?querytext='sharepoint'&personalizationdata=' <GUID>_'
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'PersonalizationData' : ' <GUID> '
}

ResultsURL
The URL for the search results page.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&resultsurl='http://server/site/resultspage.aspx'
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint'
'ResultURL' : 'http://server/site/resultspage.aspx'
}

QueryTag
Custom tags that identify the query. You can specify multiple query tags, separated by semicolons.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext':'sharepoint'
}

Properties
Additional properties for the query. GET requests support only string values. POST requests support values of any type.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&properties='termid:guid'
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext':'sharepoint',
'Properties' : {
'results' : [
{
'Name' : 'sampleBooleanProperty',
'Value' :
{
'BoolVal' : 'True',
'QueryPropertyValueTypeIndex' : 3
}
},
{
'Name' : 'sampleIntProperty',
'Value' :
{
'IntVal' : '1234',
'QueryPropertyValueTypeIndex' : 2
}
}
]
}
}

NOTE

QueryPropertyValueType specifies the type for the property; each type has a specific index value.

EnableQueryRules
A Boolean value that specifies whether to enable query rules for the query.
true to enable query rules; otherwise, false. The default value is true.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&enablequeryrules=false
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'EnableQueryRules' : 'false'
}

ReorderingRules
Special rules for reordering search results. These rules can specify that documents matching certain conditions are ranked higher or lower in the results. This property applies only when
search results are sorted based on rank. You must use a POST request for this property; it does not work in a GET request.
In the following example, MatchType refers to ReorderingRuleMatchType . In the following example, 'MatchType' : '0' specifies ResultContainsKeyword .
Sample POST request

{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'ReorderingRules' : {
'results' : [
{
'MatchValue' : '<someValue>',
'Boost' : '10',
'MatchType' : '0'
}
]
}
}

ProcessPersonalFavorites
A Boolean value that specifies whether to return personal favorites with the search results.
true to return personal favorites; otherwise false.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&processpersonalfavorites=true
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'ProcessPersonalFavorites' : 'false'
}

QueryTemplatePropertiesUrl
The location of the queryparametertemplate.xml file. This file is used to enable anonymous users to make Search REST queries.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&querytemplatepropertiesurl='spfile://webroot/queryparametertemplate.xml'
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
QueryTemplatePropertiesUrl : 'spfile://webroot/queryparametertemplate.xml'
}

HitHighlightedMultivaluePropertyLimit
The number of properties to show hit highlighting for in the search results.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&hithighlightedmultivaluepropertylimit=2
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'HitHighlihtedMultivaluePropertyLimit' : '2'
}

EnableOrderingHitHighlightedProperty
A Boolean value that specifies whether the hit highlighted properties can be ordered.
true to enable ordering rules; otherwise false.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&enableorderinghithighlightedproperty=false
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'EnableOrderingHitHighlightedProperty' : 'false'
}

CollapseSpecification
The managed properties that are used to determine how to collapse individual search results. Results are collapsed into one or a specified number of results if they match any of the
individual collapse specifications. Within a single collapse specification, results are collapsed if their properties match all individual properties in the collapse specification.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&collapsespecification='Author:1 ContentType:2'
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'CollapseSpecification' : 'Author:1 ContentType:2'
}

EnableSorting
A Boolean value that specifies whether to sort search results.
I true to sort search results using SortList, or by rank if SortList is empty. false to leave results unsorted.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&enablesorting=false
Sample POST request
{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'EnableSorting' : 'false'
}

GenerateBlockRankLog
A Boolean value that specifies whether to return block rank log information in the BlockRankLog property of the interleaved result table. A block rank log contains the textual information
on the block score and the documents that were de-duplicated.
true to return block rank log information; otherwise, false.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&generateblockranklog=true
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'GenerateBlockRankLog' : 'true'
}

UIlanguage
The locale identifier (LCID) of the user interface (see Locale IDs Assigned by Microsoft).
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&uilanguage=1044
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'UILanguage' : '1044'
}

DesiredSnippetLength
The preferred number of characters to display in the hit-highlighted summary generated for a search result.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&desiredsnippetlength=80
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'DesiredSnippetLength' : '80'
}

MaxSnippetLength
The maximum number of characters to display in the hit-highlighted summary generated for a search result.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&maxsnippetlength=100
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'MaxSnippetLength' : '100'
}

SummaryLength
The number of characters to display in the result summary for a search result.
Sample GET request
http:// server/_api/search/query?querytext='sharepoint'&summarylength=150
Sample POST request

{
'__metadata':{'type':'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'sharepoint',
'Summarylength' : '150'
}
Enabling anonymous Search REST queries
You can configure search to support Search REST queries from anonymous users. Site administrators can decide what query parameters to expose to anonymous users by using the
queryparametertemplate.xml file. This section describes how to configure your site to enable anonymous access, and create the queryparametertemplate.xml file.

To enable anonymous Search REST queries


1. Enable anonymous access on the web application and publishing site. For more information about how to do this, see Manage permission policies for a web application in SharePoint
and Plan for user authentication methods in SharePoint on TechNet.
2. Add a new document library named QueryPropertiesTemplate to the publishing site.
3. Create an XML file named queryparametertemplate.xml, and copy the following XML to the file.

<QueryPropertiesTemplate xmlns="http://www.microsoft.com/sharepoint/search/KnownTypes/2008/08" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">


<QueryProperties i:type="KeywordQueryProperties">
<EnableStemming>true</EnableStemming>
<FarmId>FarmID</FarmId>
<IgnoreAllNoiseQuery>true</IgnoreAllNoiseQuery>
<KeywordInclusion>AllKeywords</KeywordInclusion>
<SiteId>SiteID</SiteId>
<SummaryLength>180</SummaryLength>
<TrimDuplicates>true</TrimDuplicates>
<WcfTimeout>120000</WcfTimeout>
<WebId>WebID</WebId>
<Properties xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:KeyValueOfstringanyType>
<a:Key>_IsEntSearchLicensed</a:Key>
<a:Value i:type="b:boolean" xmlns:b="http://www.w3.org/2001/XMLSchema">true</a:Value>
</a:KeyValueOfstringanyType>
<a:KeyValueOfstringanyType>
<a:Key>EnableSorting</a:Key>
<a:Value i:type="b:boolean" xmlns:b="http://www.w3.org/2001/XMLSchema">true</a:Value>
</a:KeyValueOfstringanyType>
<a:KeyValueOfstringanyType>
<a:Key>MaxKeywordQueryTextLength</a:Key>
<a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">4096</a:Value>
</a:KeyValueOfstringanyType>
<a:KeyValueOfstringanyType>
<a:Key>TryCache</a:Key>
<a:Value i:type="b:boolean" xmlns:b="http://www.w3.org/2001/XMLSchema">true</a:Value>
</a:KeyValueOfstringanyType>
</Properties>
<PropertiesContractVersion>15.0.0.0</PropertiesContractVersion>
<EnableFQL>false</EnableFQL>
<EnableSpellcheck>Suggest</EnableSpellcheck>
<EnableUrlSmashing>true</EnableUrlSmashing>
<IsCachable>false</IsCachable>
<MaxShallowRefinementHits>100</MaxShallowRefinementHits>
<MaxSummaryLength>185</MaxSummaryLength>
<MaxUrlLength>2048</MaxUrlLength>
<SimilarType>None</SimilarType>
<SortSimilar>true</SortSimilar>
<TrimDuplicatesIncludeId>0</TrimDuplicatesIncludeId>
<TrimDuplicatesKeepCount>1</TrimDuplicatesKeepCount>
</QueryProperties>
<WhiteList xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:string>RowLimit</a:string>
<a:string>SortList</a:string>
<a:string>StartRow</a:string>
<a:string>RefinementFilters</a:string>
<a:string>Culture</a:string>
<a:string>RankingModelId</a:string>
<a:string>TrimDuplicatesIncludeId</a:string>
<a:string>ReorderingRules</a:string>
<a:string>EnableQueryRules</a:string>
<a:string>HiddenConstraints</a:string>
<a:string>QueryText</a:string>
<a:string>QueryTemplate</a:string>
</WhiteList>
</QueryPropertiesTemplate>

1. Update the SiteId, FarmId, and WebId elements with the values for your farm, website and publishing site collection.
2. Save queryparametertemplate.xml to the QueryPropertiesTemplate document library.
3. Add the QueryTemplatePropertiesUrl parameter to your Search REST call, specifyingspfile://webroot/queryparametertemplate.xml as the value.

queryparametertemplate.xml file
The primary elements in the queryparametertemplate.xml file are:
QueryProperties element
Contains a serialized QueryProperties object.
WhiteList element
Contains the list of query properties that the anonymous user is allowed to set.
When an anonymous Search REST query is submitted, the query object is constructed using what's specified in the QueryProperties element. Then, all the properties that are listed in the
whitelist are copied from the incoming query to the newly constructed query object.

In this section
Retrieving query suggestions using the Search REST service
See also
Search in SharePoint
SharePoint: Using the search REST service from an app for SharePoint
What's new in SharePoint search for developers
Use OData query operations in SharePoint REST requests
Retrieving query suggestions using the Search REST service
3/26/2018 • 2 minutes to read Edit Online

Learn how you can use the Search REST service from your client and mobile applications to retrieve query suggestions from Search in SharePoint. Query suggestions, also known as search
suggestions, are phrases that users have already searched for and that are displayed or "suggested" to them as they type their queries. You can use Search in SharePoint to turn on pre-query
and post-query suggestions. These suggestions appear in a list below the Search box as a user types a query. For more information about query suggestions and how to enable them, see
Manage query suggestions in SharePoint.

Suggest endpoint in the Search REST service


The Search REST service includes a Suggest endpoint you can use in any technology that supports REST web requests to retrieve query suggestions that the search system generates for a
query from client or mobile applications.
The URI for GET requests to the Search REST service's Suggest endpoint is:
/_api/search/suggest

The query suggestion parameters are specified in the URL. You can construct the request URL in two ways:

http://server/_api/search/suggest?parameter=value&amp;parameter=value

http://server/_api/search/suggest(parameter=value&amp;parameter=value)

NOTE

The Search REST service doesn't support anonymous requests to the Suggest endpoint.

Query suggestion parameters


The following sections describe the parameters you can use for the Suggest endpoint.

Querytext
A string that contains the text for the search query.
Sample GET request
http:// server/_api/search/suggest?querytext='sharepoint'

iNumberOfQuerySuggestions
The number of query suggestions to retrieve. Must be greater than zero (0). The default value is 5.
Sample GET request
http:// server/_api/search/suggest?querytext='sharepoint'&inumberofquerysuggestions=3

iNumberOfResultSuggestions
The number of personal results to retrieve. Must be greater than zero (0). The default value is 5.
Sample GET request
http:// server/_api/search/suggest?querytext='sharepoint'&inumberofresultsuggestions=4

fPreQuerySuggestions
A Boolean value that specifies whether to retrieve pre-query or post-query suggestions. true to return pre-query suggestions; otherwise, false. The default value is false.
Sample GET request
http:// server/_api/search/suggest?querytext='sharepoint'&fprequerysuggestions=true

fHitHighlighting
A Boolean value that specifies whether to hit-highlight or format in bold the query suggestions. true to format in bold the terms in the returned query suggestions that match terms in the
specified query; otherwise, false. The default value is true.
Sample GET request
http:// server/_api/search/suggest?querytext='sharepoint'&fhithighlighting=false

fCapitalizeFirstLetters
A Boolean value that specifies whether to capitalize the first letter in each term in the returned query suggestions. true to capitalize the first letter in each term; otherwise, false. The default
value is false.
Sample GET request
http:// server/_api/search/suggest?querytext='sharepoint'&fcapitalizefirstletters=false

Culture
The locale ID (LCID) for the query (see Locale IDs Assigned by Microsoft).
Sample GET request
http:// server/_api/search/suggest?querytext='sharepoint'&culture=1044

EnableStemming
A Boolean value that specifies whether stemming is enabled. true to enable stemming; otherwise, false. The default value is true.
Sample GET request
http:// server/_api/search/suggest?querytext='sharepoint'&enablestemming=false

ShowPeopleNameSuggestions
A Boolean value that specifies whether to include people names in the returned query suggestions. true to include people names in the returned query suggestions; otherwise, false. The
default value is true.
Sample GET request
http:// server/_api/search/suggest?querytext='sharepoint'&showpeoplenamesuggestions=false

EnableQueryRules
A Boolean value that specifies whether to turn on query rules for this query. true to turn on query rules; otherwise, false. The default value is true.
Sample GET request
http:// server/_api/search/suggest?querytext='sharepoint'&enablequeryrules=false

fPrefixMatchAllTerms
A Boolean value that specifies whether to return query suggestions for prefix matches. true to return query suggestions based on prefix matches, otherwise, false when query suggestions
should match the full query word.
Sample GET request
http:// server/_api/search/suggest?querytext='sharepoint'&fprefixmatchallterms=false

See also
SharePoint Search REST API overview
Search in SharePoint
SharePoint: Using the search REST service from an app for SharePoint
What's new in SharePoint search for developers
Use OData query operations in SharePoint REST requests
Search add-ins in SharePoint
5/3/2018 • 4 minutes to read Edit Online

Learn about search SharePoint Add-ins and how you can create your own search add-ins. The add-ins you create can be added to the SharePoint add-ins catalog so that they can be used in
both on-premises deployment and Office 365. Search add-ins only work with data that is stored in the search index and not with the original source documents. SharePoint Add-ins are self-
contained pieces of functionality that extend the capabilities of a SharePoint website. These add-ins solve specific business and end-user needs by integrating the best of the web and
SharePoint. An add-in can contain various SharePoint elements like Lists, Remote Event Receivers, Content Types, Workflows, Workflow Custom Activities, Site Columns, Modules, Menu
Item Custom Actions, Client web parts, and Search Configurations. For more information, see SharePoint Add-ins.
A search add-in is an SharePoint Add-in that uses search functionality. In a search add-in, you can use the SharePoint Search API to locate content. Depending on the type of permissions set
up in your add-in manifest, you can search either inside or outside the contents of the add-in. In addition, you can also use a search add-in to distribute search configurations from one
SharePoint installation to another. The core design of a search add-in depends on the deployment method that you choose. The following section summarizes the available options and their
benefits. For more information, see Choose patterns for developing and hosting your SharePoint Add-in

Deploy your search add-ins


There are two ways to deploy your search add-in:
1. SharePoint hosted - On-premises deployment. The search add-in is hosted inside the corporate network on the company's servers. The company's administrators manage the add-in.
This scenario offers flexibility in deployment and support because the hardware and software is maintained locally by the administrators.
2. Provider hosted - Any web server hosting. The search add-in is hosted by any provider, outside of the customer's SharePoint server.

Search add-in development environment


To create a search add-in, use following environment:
Microsoft Visual Studio 2012 or Microsoft Visual Studio 2013 or Visual Studio 2015
With Visual Studio 2013 and later, you can publish your search add-ins to both on-premises or in Office 365. For more information about the development environments and how to use
them to create search add-ins, see Set up a general development environment for SharePoint.

APIs for search add-ins


You can use the wide range of search-related APIs that SharePoint offers for search add-ins. The following table lists these APIs and the location of their class libraries.
SharePoint APIs for Search add-ins

API NAME CL AS S LIB R AR Y

.NET client object model (CSOM) Microsoft.SharePoint.Client.Search.dll

Silverlight CSOM Microsoft.SharePoint.Client.Search.Silverlight.dll

ECMAScript (JavaScript, JScript) object model (JSOM) SP.search.js

Search REST API http://server/_api/search/query

Code examples
Here are some code examples using the different APIs. Each code example sends a simple Search query that contains the keyword "SharePoint" to the Search service application (SSA).
Client-side Object Model (CSOM)

using (ClientContext clientContext = new ClientContext("http://localhost"))


{
KeywordQuery keywordQuery = new KeywordQuery(clientContext);
keywordQuery.QueryText = "*";
SearchExecutor searchExecutor = new SearchExecutor(clientContext);
ClientResult<ResultTableCollection> results =
searchExecutor.ExecuteQuery(keywordQuery);
clientContext.ExecuteQuery();
}

JavaScript Object Model (JSOM)

var keywordQuery = new


Microsoft.SharePoint.Client.Search.Query.KeywordQuery(context);
keywordQuery.set_queryText('SharePoint');
var searchExecutor = new Microsoft.SharePoint.Client.Search.Query.SearchExecutor(context);
results = searchExecutor.executeQuery(keywordQuery);
context.executeQueryAsync(onQuerySuccess, onQueryFail);

REST
HTTP GET request

http://mylocalhost/_api/search/query?querytext='SharePoint'

HTTP POST request


{
'__metadata' : {'type' : 'Microsoft.Office.Server.Search.REST.SearchRequest'},
'Querytext' : 'SharePoint'
}

Search add-in permissions


Search add-ins send query requests to the Search service application (SSA), and the add-ins require different types of permissions to function correctly. You can configure these permissions
via the add-in manifest file, which is a part of each SharePoint add-in. You can modify the add-in manifest file directly with a text editor, or you can modify it with Visual Studio or Napa, as
shown in the following figures.
Figure 1: Setting up permissions for search add-ins in Visual Studio 2015

Figure 2: Setting up permissions for search add-ins in "Napa" Office 365 Development Tools

An SharePoint Add-in has its own identity and is associated with a security principal, called an add-in principal. Like users and groups, an add-in principal has certain permissions and rights.
The add-in principal has full control rights to the add-in web, so it only needs to request permissions to SharePoint resources in the host web or other locations outside the add-in web, such
as site collections. Unlike other SharePoint Add-ins, a search add-in requires only user-level permissions, known as QueryAsUserIgnoreAppPrincipal. This permission lets you query the
search add-in based on the user's permissions. This means that search results will be returned based on the user's ACLs.

Request permissions in the add-in manifest file


The add-in manifest file is in XML format and can be edited directly. To get permissions, you write a request, as shown in the following example:

<AppPermissionRequests>
<AppPermissionRequest Scope="http://sharepoint/search" Right="QueryAsUserIgnoreAppPrincipal" />
</AppPermissionRequests>

See also
SharePoint Add-ins
Choose patterns for developing and hosting your SharePoint Add-in
Add-in permissions in SharePoint
Add-in authorization policy types in SharePoint
Important aspects of the SharePoint Add-in architecture and development landscape
Explore the app manifest structure and the package of a SharePoint Add-in
Add search capabilities to your add-ins for SharePoint
Exporting and importing search configuration settings in SharePoint
Export and import customized search configuration settings in SharePoint (TechNet)
Customizing search results in SharePoint
3/26/2018 • 5 minutes to read Edit Online

Learn how to group similar items or remove duplicate items in a search result set in SharePoint so you can display these results in a concise, readable way. In search results, grouping
collapses two or more similar items in a search result set to make their display more readable for a user. Duplicate removal of search results is a part of grouping, where items that are
identical or nearly identical are removed from the result set. Depending on the settings set by the SharePoint administrator, the user might be able to expand the search result set later and
see the individual results that were collapsed.
The following are examples of ways to group search results:
Duplicate detection, where nearly identical documents are removed from the result set.
Site collapsing, where only the most relevant item found in each site is shown in the result set.
Document set collapsing, where only one hit is displayed for each document library in SharePoint.
You can specify the criteria for collapsing or duplicate trimming programmatically by using the following KeywordQuery properties within the Query object model:
CollapseSpecification
TrimDuplicates
TrimDuplicatesOnProperty
TrimDuplicatesKeepCount
TrimDuplicatesIncludeId

Collapse similar search results using the CollapseSpecification property


The CollapseSpecification property takes a Spec parameter that can contain multiple fields separated either by a comma or a space, which evaluated together specify a set of criteria used
for collapsing.
Syntax
CollapseSpecification = Spec

The following table lists the fields of the Spec parameter.


Table 1. Spec parameter fields

ELEMENT IN PAR AME TER D ES CR IPTIO N

Spec Subspec(<space>Subspec)*

Subspec Prop(','Prop)*[':'Dups]

Prop A valid managed property or an alias of a managed property. Prop is case-insensitive. The managed
property must be queryable and either sortable or refineable.

Dups An integer specifying the number of items to retain. The default value is 1.

Properties are combined by using the OR operator.

, Properties are combined by using the AND operator.

* Indicates more items.

() or [] Indicates optional items.

If the fields in Spec are separated by commas, the fields are combined by using the AND operator. If all of the specified fields are matched, the items are collapsed.
In contrast, if the fields in Spec are separated by spaces, the fields (or Subspecs) are combined by using an expansion that includes both the AND operator and OR operator. For example, an
expression such as Category:3 Product:2 is internally transformed to the following expression (Category AND Product) OR (Category) with a counter for each; hence a maximum of two of the
former and three of the latter. Items are collapsed if some of the specified fields are matched.

Examples of using CollapseSpecification


The following table shows a product catalog from the Contoso company. The next set of examples use this catalog to show how the CollapseSpecification property works.

CATEG O R Y PR O D U CT V AR IANT TITLE

Laptops WWI 19W X0196 Black Computer 1

Laptops Adventure Works 12 M1201 Red Computer 2

Laptops Adventure Works 15.4W M1548 White Computer 3

Laptops Proseware 19 X910 Black Computer 4

Laptops Proseware Laptop19 X910 Black Computer 5

Desktops Adventure Works 2.33 XD233 Silver Computer 6

Desktops WWI 2.33 X2330 Black Computer 7


CATEG O R Y PR O D U CT V AR IANT TITLE

Desktops Adventure Works 1.60 ED160 White Computer 8

Desktops WWI 3.0 M0300 Silver Computer 9

Example: group by Category


First, group the items based on Category and show the top two (hence "Category:2" ) for each group. Then, for each Category, show a corresponding number of unique (hence
"Product:1") Products.
Syntax
CollapseSpecification="Category:2 Product:1"

This should return the following results.

CATEG O R Y PR O D U CT V AR IANT TITLE

Laptops WWI 19W X0196 Black Computer 1

Laptops Adventure 12 M1201 Red Computer 2

Desktops Adventure Works 2.33 XD233 Silver Computer 6

Desktops WWI 2.33 X2330 Black Computer 7

Use the following code to collapse the search results by using the CollapseSpecification property.

using (var context = new ClientContext("http://localhost"))


{
var query = new KeywordQuery(context)
{
QueryText = "Title:Computer",
CollapseSpecification = "Category:3 Product:1",
};

var executor = new SearchExecutor(context);


var results = executor.ExecuteQuery(query);

context.ExecuteQuery();

foreach (var result in results.Value[0].ResultRows)


{
Console.WriteLine(result["Title"]);
}
}

Example: group by Category and Product


First, group the items based on both Category and Product. Then, show each unique combination.
Syntax
CollapseSpecification="Category,Product:1"

This should return the following results.

CATEG O R Y PR O D U CT V AR IANT TITLE

Laptops WWI 19W X0196 Black Computer 1

Laptops Adventure Works 12 M1201 Red Computer 2

Laptops Proseware 19 X910 Black Computer 4

Desktops Adventure Works 2.33 XD233 Silver Computer 6

Desktops WWI 2.33 X2330 Black Computer 7

Trim duplicate search results using the TrimDuplicates property


Use TrimDuplicates to specify whether to trim away the duplicate search results from the result set. TrimDuplicates is true by default.
If you use TrimDuplicates with either TrimDuplicatesOnProperty or preferably CollapseSpecification, TrimDuplicates is set to false.
Syntax
TrimDuplicates = <$true | $false>

Trim duplicate search results using the TrimDuplicatesOnProperty property


Use TrimDuplicatesOnProperty to specify whether to use a non-default managed property as the basis for duplicate trimming. The default value is the DocumentSignature managed
property. The managed property must be of type Integer or String. By using a managed property that represents a grouping of items, you can use this feature for field collapsing.
Syntax
TrimDuplicatesOnProperty = <managed property>

NOTE

In SharePoint, use CollapseSpecification wherever possible. TrimDuplicatesOnProperty is available for backward compatibility only.
Trim duplicate search results using the TrimDuplicatesKeepCount property
Use TrimDuplicatesKeepCount to specify the number of documents to retain when TrimDuplicates is true. If TrimDuplicates is based on a managed property that can be used as a
group identifier, for example a site ID, you can control how many results are returned for each group. The items returned are those with the highest dynamic rank within each group.
Syntax
TrimDuplicatesKeepCount = <number>

Retrieve duplicate search results using the TrimDuplicatesIncludeId property


Use TrimDuplicatesIncludeId to retrieve the duplicates of a document when TrimDuplicates is true and TrimDuplicatesOnProperty or CollapseSpecification is set to false.
The document ID, docid, is used to retrieve the duplicates of a particular document.
Syntax
TrimDuplicatesIncludeId = <docid>

NOTE

The fcoid managed property in FAST Search Server 2010 for SharePoint has been replaced with the docid managed property in SharePoint.

See also
KeywordQuery
Overview of the search schema in SharePoint
Sorting search results in SharePoint
3/26/2018 • 12 minutes to read Edit Online

Sort search results programmatically—by rank, by managed property value, by a formula expression, or in random order—by using the Query object model in SharePoint. You can sort the
search results for SharePoint in four ways:
Sort search results by rank: Enables you to sort the search result by relevance rank.
Sort search results by managed property value: Enables you to sort the search result based on the value of one or more managed properties.
Sort search results by a formula expression: Enables you to sort the search result by a formula specified in the query request.
Sort search results in random order: Enables you to sort the query result in random order, or add a random component to the sort order.
This article focuses on sorting search results programmatically. To learn how to sort search results using SharePoint query rules, see the following articles:
Change ranked search results in Manage query rules
Change ranked search results in Create query rules for web content management

How to specify sorting in a query request


When you use the Query object model, you can choose the sort criteria by providing a sort specification through the SortList property of the KeywordQuery class. The SortList property is
of type SortCollection , which represents a collection of Sort objects.
A Sort object defines a way to sort search results; it consists of a value you want to order search results on ( Property ) and a direction in which you want to order the results ( Direction ). The
direction is of type SortDirection() and can be ascending or descending.
If you have multiple values in SortList , the sorting is performed based on the sequence in which the values appear. This means that every Sort object represents a sort order level. Any
succeeding level does not change the ordering of results that were differentiated by previous ones, but it may affect the internal ordering of results that have the same sort values for the
previous levels.
Apart from the Query object model, SharePoint also provides a Search REST service that you can use to query the search index with your client or mobile applications. The Search REST
service supports both HTTP POST and HTTP GET requests. For more information on how to construct URIs for these requests, see Querying with the Search REST service.

Sort search results by rank


By default, search results are sorted by relevance rank. This means that SharePoint places the most relevant results on top in the search result set. If you sort by rank, the results are always
sorted in descending order. But you can change the sort order to ascending by using SortDirection() .
You can also influence the rank calculation in the query string, in one of two ways:
By using the XRANK operator available in Keyword Query Language (KQL) syntax reference and FAST Query Language (FQL) syntax reference. You can use XRANK to apply a
conditional rank boosting if a specific query condition is met.
By choosing a relevance weight for dynamic ranking. When using FQL, you can specify an individual relevance weight for each STRING operator.

Sort search results by managed property value


You can specify search result sorting based on the value of one or more managed properties. This means that SharePoint performs the sorting based on all results that match the query.
You can sort based on text and numeric properties. For text properties, the sorting is based on standard text string sorting. In contrast, for numeric properties (including managed properties
of type DateTime ), the sorting is based on numeric value.

Example
The following example shows how to sort search results by using the Size managed property.

using (var context = new ClientContext("http://localhost"))


{
var query = new KeywordQuery(context)
{
QueryText = "home"
};
query.SortList.Add("Size", SortDirection.Descending);

var executor = new SearchExecutor(context);


var results = executor.ExecuteQuery(query);

context.ExecuteQuery();

foreach (var result in results.Value[0].ResultRows)


{
Console.WriteLine(result["Title"] + " Size:" + result["Size"]);
}
}

Alternatively, you could use the Search REST API to sort search results by using the Size property with the following call.

http://localhost/_api/search/query?querytext='home'&amp;sortlist='size:descending'

Sort search results by a formula expression


You can specify search result sorting based on a sort specification that uses a mathematical formula to create the sorting value.
The sort by formula feature is an extension of the single-level and multilevel sorting functionality for search results. The feature enables you to specify a formula instead of a managed
property as sorting criteria.
By using the sort by formula feature, you can apply mathematical operations on the value of one or more managed properties for each item in the query result.
The following are examples that can be implemented by using a formula to specify search result sorting:
K-nearest neighbor algorithm to classify documents.
Euclidean distance or Manhattan distance to calculate geographical distances.
Preferred value, for example, to sort documents based on how far a given managed property value is from a preferred value.
The sort by formula feature does not include control of statistical dynamic rank parameters, such as term frequency and proximity.
The formula is evaluated left to right and uses standard mathematical-operator precedence. That is, functions and parenthetical groups are evaluated first, multiplication and division
operations are performed next, and addition and subtraction operations are performed last.

Important: The final result of a formula must be in the value range of a 32-bit signed integer. Otherwise, the sorting may be incorrect.

Specifying the sort formula in a query


You specify a sort formula instead of a managed property in the sort specification of the query request.
The sort specification has the following format: [formula:<sort-formula>]

In the format, is the sort formula expression.


NOTE

The square brackets are part of the sort specification syntax.


The default sort direction is descending. You may also use a formula that sorts by ascending value, for example, if the formula specifies a geographical distance.
The following code example shows how to specify sort by formula with ascending sort order by using the Query object model.

using (var context = new ClientContext("http://localhost"))


{
var query = new KeywordQuery(context)
{
QueryText = "home"
};
query.SortList.Add("[formula:abs(2000-size)]", SortDirection.Ascending);

var executor = new SearchExecutor(context);


var results = executor.ExecuteQuery(query);

context.ExecuteQuery();

foreach (var result in results.Value[0].ResultRows)


{
Console.WriteLine(result["Title"]);
}
}

Alternatively, you could use the Search REST API to sort search results by using the Size property with the following call.

http://localhost/_api/search/query?querytext='home'&amp;sortlist='[formula:abs(2000-size)]:ascending'

Using managed properties in the sort formula


You can apply a sort formula on the value of managed properties of type Integer , Decimal , and Datetime() . You must enable sorting for the specified managed property in the search
schema.
For more managed properties of type Decimal , the value is multiplied by 10^(decimal digits) before being used in the formula evaluation.
For managed properties of type Datetime() , the value is converted to the number of 100 nanoseconds since January 1 29000 BC before being used in the formula evaluation. There are 366
days in the year.

Sort formula expressions


Table 1 lists the functions you can use in the sort formula expression. The expression must not contain spaces.
Table 1. Functions for sort formula expressions

FU NCTIO N D ES CR IPTIO N

+ Specifies addition.

- Specifies subtraction.

* Specifies multiplication.

/ Specifies division.
Note: By default, a division by zero results in an exception, and the query returns with an error. By using
the errtolast operator, you can avoid the query error and instead place the failing items at the end of
the result set.

rank A special keyword that represents the dynamic rank of an item.


Example: abs(rank-100) will use the distance from rank value 100 as the sorting criteria.

[0-9.]+ Specifies that numbers can be given as integer or double values.


Examples: 503, 3.14, 5.4352262
FU NCTIO N D ES CR IPTIO N

[a-z0-9]+] Specifies that any character sequence not recognized as a function name is treated as a managed
property name. You must enable sorting for the specified managed property in the search schema.
Example: You can define a managed property named height with sorting enabled. This enables you to
use "height" as an expression in the formula. The formula will use the value of the height managed
property.

( and ) Used to group calculations ensuring correct precedence.


Example: 4*(3+2)

sqrt(n) The square root of n.

exp(n) The exponential function that is equivalent to pow(2.71828182846,n)

log(n) The natural logarithm of n.

abs(n) The absolute value of n.

ceil(n) The ceiling of n. That is, if n is not a whole number, round up to the next whole number. If n is a whole
number, use n.

floor(n) The floor of n. That is, if n is not a whole number, round down to the next whole number. If n is a whole
number, use n.

round(n) The rounding of n to the nearest even whole number. Also known as "Bankers rounding" or "Round half
to even".

sin(n) The sine of n radians.

cos(n) The cosine of n radians.

tan(n) The tangent of n radians.

asin(n) The arcsine, in radians, of n.

acos(n) The arccosine, in radians, of n.

atan(n) The arctangent, in radians, of n.

pow(x,y) The value of x raised to the power of y.


Note: The value of y must be a real number.

atan2(y,x) A two-argument arctangent of the angle in radians between the positive x axis and the specified
Cartesian coordinate (x,y).

bucket(b,n1,n2,…) An operator that can be used to provide discrete values for given value distribution ranges for an
expression.
The expression b can be a managed property or any other formula expression. The arguments n1, n2, …
represent numeric thresholds. You can specify an arbitrary number of bucket thresholds.
Note: You must arrange the arguments n1, n2, n3, … in the following order: n1 < n2 < n3 < ... with
n1 >= 0 . A given value for the input expression b is rounded down to the closest numeric threshold
given. If lower than the lowest threshold given, the resulting value is zero.

errtolast(x) An operator that can be used to control how to handle formula exceptions; x can be any formula
expression. If the calculation of this formula expression leads to a mathematical exception for an item in
the result set, such as division by zero, these items appear at the end of the sort list, regardless of
specified sort direction.

Performance characteristics for sort by formula


Using a sort formula implies that the formula calculations are applied to all matching items in the result set. This means that the query performance impact depends on the number of items
that match the query.
Long formulas with many operators require more processing time than short formulas.

Using sort by formula for geographical distance


You can use sort by formula to apply a ranking based on distance. This requires that you include managed properties that represent the latitude and longitude of each item.
For example, you can use one of the following standard formulas:
Manhattan distance
Euclidian distance (see example 2)
Haversine formula

Important: Use managed properties of type Decimal or Float to represent the latitude and longitude values.

Examples
The following examples show how to specify the sort formula using the Query object model.
Example 1. Place the items that have the height managed property closest to 20 on top of the result list.
using (var context = new ClientContext("http://localhost"))
{
var query = new KeywordQuery(context)
{
QueryText = "home"
};
query.SortList.Add("[formula:abs(20-height)]", SortDirection.Ascending);

var executor = new SearchExecutor(context);


var results = executor.ExecuteQuery(query);

context.ExecuteQuery();

foreach (var result in results.Value[0].ResultRows)


{
Console.WriteLine(result["Title"]);
}
}

Alternatively, you could use the Search REST API to place the items that have the height managed property closest to 20 on top of the result list, with the following call.

http://localhost/_api/search/query?querytext='home'&amp;sortlist='[formula:abs(20-height)]:ascending

Example 2. Sort by true 3-D Euclidean distance from a given position (for example, user's position) based on position information that is provided in the managed properties latitude,
longitude and height. The following formula provides the 3-D Euclidean distance, given that the base position is 50/100/200 (latitude/longitude/height).
sqrt(pow(50-latitude,2)+pow(100-longitude,2)+pow(200-height,2))

If you want to apply a distance-based sorting (not combining the distance with other parameters in a formula), you can remove the sqrt() component, as it does not change the sorting
sequence; but it improves the query performance.

using (var context = new ClientContext("http://localhost"))


{
var query = new KeywordQuery(context)
{
QueryText = "home"
};
query.SortList.Add("[formula:pow(50-latitude,2)+pow(100-longitude,2)+pow(200-height,2)]", SortDirection.Ascending);

var executor = new SearchExecutor(context);


var results = executor.ExecuteQuery(query);

context.ExecuteQuery();

foreach (var result in results.Value[0].ResultRows)


{
Console.WriteLine(result["Title"]);
}
}

Example 3. Round the values of size into buckets, rounding values down to one of the following: 0, 5, 15, 50, 100; sort with largest values first.

using (var context = new ClientContext("http://localhost"))


{
var query = new KeywordQuery(context)
{
QueryText = "home"
};
query.SortList.Add("[formula:bucket(size,5,15,50,100)]", SortDirection.Ascending);

var executor = new SearchExecutor(context);


var results = executor.ExecuteQuery(query);

context.ExecuteQuery();

foreach (var result in results.Value[0].ResultRows)


{
Console.WriteLine(result["Title"]);
}
}

Sort search results in random order


You may apply random sorting of the query result, or add a random component to the result sorting.
The random sort specification has the following format: [random:seed=<seed>:hashfield=<managed property>]

NOTE

The square brackets are part of the sort specification syntax.


Table 2 explains the parameters to the random sort specification.
Table 2. Parameters for the random sort specification

PAR AME TER D ES CR IPTIO N R EQ U IR ED

Seed The seed for the random value generation. Yes


The seed value is input to a function that generates a random
number. This random number is used in the final sorting.Using only
the seed option will give you a randomly sorted query result set.
The sorting order for the same query (when using the same seed)
may change after an index update.
PAR AME TER D ES CR IPTIO N R EQ U IR ED

Hashfield A managed property that is used as the hash value for the random No
generation. You can use this parameter to ensure that the sorting
order for the same query (when using the same seed) does not
change after an index update.
The managed property must be of type Integer and must be
Sortable() . You may fill this managed property with random or
unique values (for example a sequence number populated by an
item processing stage).

By providing the same seed for equal queries, items will be presented in the same order. This enables you to preserve the same random order when paging through search results. Use the
hashfield parameter if you want to preserve the same random order when an index update accidentally occurs between the queries.

Examples
The following examples show how to specify random sorting by using the Query object model.
Example 1. Sort the entire result set in random order.

using (var context = new ClientContext("http://localhost"))


{
var query = new KeywordQuery(context)
{
QueryText = "home"
};
query.SortList.Add("[random:seed=5432]", SortDirection.Ascending);

var executor = new SearchExecutor(context);


var results = executor.ExecuteQuery(query);

context.ExecuteQuery();

foreach (var result in results.Value[0].ResultRows)


{
Console.WriteLine(result["Title"]);
}
}

Alternatively, you could use the Search REST API to sort the entire result set in random order, with the following call.

http://localhost/_api/search/query?querytext='home'&amp;sortlist='[random:seed=5432]:ascending

Example 2. Sort the entire result set in random order. Preserve the same random sequence for the same query with the same seed, even if an index switch occurs. A custom managed
property named hashvalue must be available in the search schema, and populated with random or sequential numeric values for all indexed items.

using (var context = new ClientContext("http://localhost"))


{
var query = new KeywordQuery(context)
{
QueryText = "home"
};
query.SortList.Add("[random:seed=6543:hashfield=hashvalue]", SortDirection.Ascending);

var executor = new SearchExecutor(context);


var results = executor.ExecuteQuery(query);

context.ExecuteQuery();

foreach (var result in results.Value[0].ResultRows)


{
Console.WriteLine(result["Title"]);
}
}

See also
Search in SharePoint
Keyword Query Language (KQL) syntax reference
FAST Query Language (FQL) syntax reference
SharePoint Search REST API overview
Overview of crawled and managed properties in SharePoint
Customizing ranking models to improve relevance in SharePoint
3/26/2018 • 22 minutes to read Edit Online

Improve search relevance by customizing ranking models to calculate rank scores (relevance rank) accurately using rank features in SharePoint. You can sort search results in SharePoint in
four ways, one of which is by rank score. When you sort search results by rank score, SharePoint places the most relevant results on top in the search result set.
A search result is relevant if it receives a high rank score, which is a specific numeric score calculated by the search engine using a ranking model. A ranking model is a list of one or more
rank stages that contain a set of rank features. The ranking model defines how the search engine calculates the relevance rank using various factors, which are represented in the ranking
model as rank features. Factors used to calculate the relevance rank include, but are not limited to, the following:
The appearance of query terms in the full-text index, which includes information such as a document's title and body.
The metadata associated with a particular item, such as a document's file type or URL length.
The anchor text associated with URL links that point to a particular item.
The information about user clicks for each item.
The proximity of query terms in a document's body or title.

Start your ranking model customization based on a SharePoint ranking model template
To make your customization easier, start by using one of the default ranking models in SharePoint as a template. Then, modify that ranking model to suit your data set.
SharePoint provides 14 ranking models by default. See What is a ranking model? (on TechNet) for detailed information about these ranking models and their purpose.

Important: If you install the SharePoint cumulative update of August 2013, we recommend using the Search Ranking Model with Two Linear Stages as the base model for your
custom ranking model. The Search Ranking Model with Two Linear Stages is a copy of the Default Search Model with a linear second stage instead of a neural network second
stage.

You use the following Windows PowerShell cmdlets to customize ranking models:
Get-SPEnterpriseSearchRankingModel
New-SPEnterpriseSearchRankingModel
Remove-SPEnterpriseSearchRankingModel
Set-SPEnterpriseSearchRankingModel

To list all available ranking models


1. Open the SharePoint Management Shell as an Administrator.
2. Run the following sequence of Windows PowerShell cmdlets.

$ssa = Get-SPEnterpriseSearchServiceApplication -Identity "Search Service Application"


$owner = Get-SPenterpriseSearchOwner -Level ssa
Get-SPEnterpriseSearchRankingModel -SearchApplication $ssa -Owner $owner

To retrieve a default ranking model to use as a template


1. Open the SharePoint Management Shell as an Administrator.
2. Run the following sequence of Windows PowerShell cmdlets; filename.xml is the name of a file in which you want to save the ranking model.

$ssa = Get-SPEnterpriseSearchServiceApplication
$owner = Get-SPenterpriseSearchOwner -Level ssa
$defaultRankingModel = Get-SPEnterpriseSearchRankingModel -SearchApplication $ssa -Owner $owner | Where-Object { $_.IsDefault -eq $True }
$defaultRankingModel.RankingModelXML > filename.xml

If you install the SharePoint cumulative update of August 2013, you can use the following procedure to retrieve the search ranking model with two linear stages to use as a template for your
custom ranking model.

To retrieve the search ranking model with two linear stages to use as a template
1. Open the SharePoint Management Shell as an Administrator.
2. Run the following sequence of Windows PowerShell cmdlets; filename.xml is the name of a file in which you want to save the ranking model.

$ssa = Get-SPEnterpriseSearchServiceApplication
$owner = Get-SPenterpriseSearchOwner -Level ssa
$twoLinearStagesRankingModel = Get-SPEnterpriseSearchRankingModel -SearchApplication $ssa -Owner $owner -Identity 5E9EE87D-4A68-420A-9D58-8913BEEAA6F2
$twoLinearStagesRankingModel.RankingModelXML > filename.xml

To deploy a custom ranking model


1. From the list of available ranking models, copy the GUID of the ranking model that you want to use as a template. (See To list all available ranking models for the sequence of
Windows PowerShell cmdlets to use.)
2. Run the following sequence of Windows PowerShell cmdlets using the GUID copied in step 1 for .
$ssa = Get-SPEnterpriseSearchServiceApplication
$owner = Get-SPenterpriseSearchOwner -Level ssa
$rm = Get-SPEnterpriseSearchRankingModel -Identity <GUID> -SearchApplication $ssa -Owner $owner
$rm.RankingModelXML > myrm.xml

1. Edit the myrm.xml file in an XML editor. You must use new GUID values for the id attributes in RankModel2Stage element and all RankingModel2NN elements. To get a new GUID
value you can for example use the following Windows PowerShell command: [guid]::NewGuid()
2. Create a new ranking model with the New-SPEnterpriseSearchRankingModel cmdlet by running the following commands.

$myRankingModel = Get-Content .\\myrm.xml


$myRankingModel = [String]$myRankingModel
$ssa = Get-SPEnterpriseSearchServiceApplication
$owner = Get-SPenterpriseSearchOwner -Level ssa
$newrm = New-SPEnterpriseSearchRankingModel -SearchApplication $ssa -Owner $owner -RankingModelXML $myRankingModel

Rank detail
Important: We provide the rank detail and the accompanying ExplainRank page as a convenience and only to assist you in tuning and debugging your own custom ranking models. The
contents of the rank detail and the accompanying ExplainRank page are not supported, and are subject to change without notice in future software patches and updates.

The rank detail is an XML document that provides detailed information about rank score calculation for a single item that matches a given user query. The rank detail is stored in a special
managed property, called rankdetail.
Each rank feature in a ranking model has a separate XML node in the rank detail that describes details of the rank score calculation. The rank detail is provided only for queries that have
search results that don't exceed 100 items.
Conceptually, the overall format of the rank detail looks like the following example.

<rank_log version='15.0.0000.1000' id='[internal guid of ranking model used for calculation]' >
<query tree='[representation of user query used for ranking]'/>
<stage type='linear'>
[Details of rank calculation of the first ranking stage. One XML node for each rank feature.]
<stage_model>
[Definition of the first stage of the ranking model]
</stage_model>
</stage>
<stage type='neural_net' >
[Details of rank calculation of the second ranking stage. One XML node for each rank feature.]
<stage_model>
[Definition of the second stage of the ranking model]
</stage_model>
</stage>
</rank_log>

To retrieve the rank detail, you need to be the administrator of the Search service application (SSA).

To retrieve the rank detail


1. Open the SharePoint Management Shell as an Administrator.
2. Run the following sequence of Windows PowerShell cmdlets, and substitute <query_text> and with actual values.

$app = Get-SPEnterpriseSearchServiceApplication
$searchAppProxy = Get-spenterprisesearchserviceapplicationproxy | Where-Object { ($_.ServiceEndpointUri.PathAndQuery -like $app.Uri.PathAndQuery)}
$request = New-Object Microsoft.Office.Server.Search.Query.KeywordQuery($searchAppProxy)
$request.ResultTypes = [Microsoft.Office.Server.Search.Query.ResultType]::RelevantResults
$request.QueryText = "<query_text> AND path:""<url>"""
$request.SelectProperties.Add("rankdetail")
$searchexecutor = new-Object Microsoft.Office.Server.Search.Query.SearchExecutor
$resultTables = $searchexecutor.ExecuteQuery($request)
$resultTables[([Microsoft.Office.Server.Search.Query.ResultType]::RelevantResults)].Table

Understanding the rank score calculation via the ExplainRank page


SharePoint provides the ExplainRank page that is located in the layouts folder ( <searchCenter>/_layouts/15/ ). This page contains detailed information on the rank score for each rank
feature based on a given search query, a document ID, and an optional ranking model ID. The information is obtained and parsed from the rank detail.
You can access the ExplainRank page with the following URL:
http://<searchCenter>/_layouts/15/ExplainRank.aspx?q={x}&amp;d={y}&amp;rm={z}

Where:
x is the search query.
y is the document ID.
z is the optional ranking model ID. If no ranking model ID is provided, the default ranking model is used.
Just like with the rank detail, to view the ExplainRank page, you need to be the administrator of the Search service application (SSA).

Tune your ranking model with rank features


Rank features work like tuning dials for a ranking model. The following sections describe the rank features that are available in the default SharePoint ranking model and how they contribute
to relevance rank calculation.

BM25
The BM25 rank feature ranks items based on the appearance of query terms in the full-text index. The input to BM25 can be any of the managed properties in the full-text index.
NOTE

The BM25 rank feature used in this context is the fielded version, BM25F.
The BM25 rank feature calculates the relevance rank score using the following formula.

Where:
D is a document, represented as a list of textual fields such as the title or body.
Q is the user query, represented as a list of query terms, t.
S defines the list of fields that contribute to relevance ranking; this list is defined by the ranking model.
w_f is a numeric value that defines the relative weight of the field _f ??? S; this value is defined by the ranking model.
b_f is a numeric value that defines the document length normalization for each field _f ??? S.
TF_f (t,D) is the number of occurrences of query term _t in the field f of document D.
DL_f (D) is the total number of words in field _f of document D.
N is the total amount of documents in the index.
n_t is an amount of documents that have term _t in at least one of their properties.
AVDL_f is the average _DL_f (D)_ across all indexed documents.
_k_1 is a scalar parameter; this value is defined by the ranking model.
You must map the managed properties used for the BM25 rank feature to the default full-text index in the Choose advanced searchable settings UI.
Within a user query, query terms that are part of the following operators are excluded from relevance rank calculations: NOT(???) in FQL, NOT(???) in KQL, and FILTER(???) in FQL.
In addition, query terms that are under scope, for example, title:apple AND body:orange , are excluded from relevance rank calculations.
Example BM25 rank feature definition

<BM25Main name="ContentRank" k1="1">


<Layer1Weights>
<Weight>0.26236235707678</Weight>
</Layer1Weights>
<Properties>
<Property name="body" w="0.019391078235467" b="0.44402228898786156" propertyName="body" />
<Property name="Title" w="0.36096989709360422" b="0.38179554361297785" propertyName="Title" />
<Property name="Author" w="0.15808522836934547" b="0.13896219383271818" propertyName="Author" />
<Property name="Filename" w="0.15115036355698144" b="0.96245017871125826" propertyName="Filename" />
<Property name="QLogClickedText" w="0.3092664171701901" b="0.056446823262849853" propertyName="QLogClickedText" />
<Property name="AnchorText" w="0.021768362296187508" b="0.74173561196103566" propertyName="AnchorText" />
<Property name="SocialTag" w="0.10217215754116529" b="0.55968554315932328" propertyName="SocialTag" />
</Properties>
</BM25Main>

Example rank detail for BM25 rank feature


<bm25 name='ContentRank'>
<schema pid_mapping='[1:content::7:%default] [2:content::1:%default] [3:content::5:%default] [56:content::2:%default] [100:content::3:link] [10:content::6:link] [264:content::14:link] ' pids_not_
<query_term term='WORDS(content:integration, content:integrations, content:integrations)'>
<index name='content' N='10035' n='8'
avdl='1 2.98018 2.00427 1 1 2.39394 1 637.308 1 1 1 1 1 1 1 1 '>
<group id='%default'
ext_doc_id='55' int_doc_id='16' precalc='0' tf_prime='0.500486' weight='1'
tf='0 1 1 0 0 0 0 11 0 0 0 0 0 0 0 0 '
dl='0 4 9 0 0 2 0 1291 0 0 0 0 0 0 0 0 '/>
<group id='link'/>
</index>
<rank score='2.37967' score_acc='2.37967' term_weight='7.13439'/>
</query_term>

<query_term term='WORDS(content:effort, content:efforts, content:efforts)'>


<index name='content' N='10035' n='9'
avdl='1 2.98018 2.00427 1 1 2.39394 1 637.308 1 1 1 1 1 1 1 1 '>
<group id='%default'/>
<group id='link'/>
</index>
<rank score='0' score_acc='2.37967' term_weight='7.01661'/>
</query_term>

<query_term term='PHRASE(content:fastserver, content:plugin)'>


<index name='content' N='10035' n='3'
avdl='1 2.98018 2.00427 1 1 2.39394 1 637.308 1 1 1 1 1 1 1 1 '>
<group id='%default'
ext_doc_id='55' int_doc_id='16' precalc='0' tf_prime='0.0399696' weight='1'
tf='0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 '
dl='0 4 9 0 0 2 0 1291 0 0 0 0 0 0 0 0 '/>
<group id='link'/>
</index>
<rank score='0.311896' score_acc='2.69157' term_weight='8.11522'/>
</query_term>
<final score='2.69157' transformed='2.69157' normalized='2.69157' hidden_nodes_adds='0.706166 '/>
</bm25>

Weight groups
In a custom ranking model, you can have two or more managed properties that are mapped to the same weight group in the search schema. In such cases, content of these managed
properties is combined in the full-text index and can't be ranked separately in BM25 calculation. This effect is the same as setting equal values for the _w_f and _b_f parameters within each
group of managed properties, mapped to the same weight group in the search schema. To prevent this, map managed properties to one of the 16 different weight groups available in the
search schema.
Weight groups are also known as context. See Influencing the ranking of search results by using the search schema (on TechNet) for more information about the relationship between a
managed property and its context.

Static
The static rank feature ranks items based on numeric managed properties that are stored in the search index. The numeric managed properties used for relevance rank calculation in static
rank features must be of type Integer and set to Refinable or Sortable in the search schema. You can't use multivalued managed properties in combination with the static rank feature.
Before the static rank feature can be aggregated with other rank features, each static rank feature is preprocessed via a single transformation. Table 1 lists all supported transform functions.
Table 1. Supported transform functions for the static and proximity rank features

Example static rank feature definition

<Static name="clickdistance" default="5" propertyName="clickdistance">


<Transform type="InvRational" k="0.27618729159042193" />
<Layer1Weights>
<Weight>0.616326852981262</Weight>
</Layer1Weights>
</Static>

Example rank detail for a static rank feature


<static_feature name='clickdistance' property_name='clickdistance'
used_default='1' raw_value='5' raw_value_transformed='5'
transformed='0.420003' normalized='0.420003'
hidden_nodes_adds='0.258859 '/>

Bucketed static
The bucketed static rank feature ranks documents based on their file type and language. The definition of a bucketed static rank feature within a ranking model depends on whether the rank
feature is part of a linear model or a neural network. The following examples apply only to linear models. For neural networks, the number of <Add> attributes for each bucket must match
the number of hidden nodes in the neural network.
The managed properties used for relevance rank calculation in bucketed static rank features must be of type Integer and set to Refinable or Sortable in the search schema. You can't use
multivalued managed properties in combination with the bucketed static rank feature.
Example bucketed static rank feature definition for file type
Every document has an associated file type that the content processing component detects and stores in the search index as a zero-based integer value. When you use the bucketed static
rank feature to rank documents based on their file types, each document type is associated with a specific relevance rank score. For example, in the following definition, the bucket 2
corresponds to a .ppt document; the node <Add>0.680984743282165</Add> defines additional rank points that are added to the relevance rank scores for all .ppt documents.

<BucketedStatic name="InternalFileType" default="0" propertyName="InternalFileType">


<Bucket name="Html" value="0">
<HiddenNodesAdds>
<Add>0.464062832328107</Add>
</HiddenNodesAdds>
</Bucket>
<Bucket name="Doc" value="1">
<HiddenNodesAdds>
<Add>0.551558196047853</Add>
</HiddenNodesAdds>
</Bucket>
<Bucket name="Ppt" value="2">
<HiddenNodesAdds>
<Add>0.680984743282165</Add>
</HiddenNodesAdds>
</Bucket>
<Bucket name="Xls" value="3">
<HiddenNodesAdds>
<Add>-0.143152682829863</Add>
</HiddenNodesAdds>
</Bucket>
<Bucket name="Xml" value="4">
<HiddenNodesAdds>
<Add>-1.29219869408375</Add>
</HiddenNodesAdds>
</Bucket>
<Bucket name="Txt" value="5">
<HiddenNodesAdds>
<Add>-0.456669562992298</Add>
</HiddenNodesAdds>
</Bucket>
<Bucket name="ListItems" value="6">
<HiddenNodesAdds>
<Add>0.170944938307345</Add>
</HiddenNodesAdds>
</Bucket>
<Bucket name="Message" value="7">
<HiddenNodesAdds>
<Add>-0.0666769377412764</Add>
</HiddenNodesAdds>
</Bucket>
<Bucket name="Image" value="8">
<HiddenNodesAdds>
<Add>0.106988843357609</Add>
</HiddenNodesAdds>
</Bucket>
</BucketedStatic>

Example bucketed static rank feature definition for document language


The content processing component detects the language for each document automatically before it's added to the search index. When you use the bucketed static rank feature to rank
documents based on their language, you can define how to calculate the rank score based on whether the document's language that was automatically detected matches the query's
language.
At query time, information about the user's language is written to the search engine as a query property.

Proximity
The proximity rank feature ranks items depending on the distance between query terms inside the full-text index. The rank score is boosted if two query terms appear in the same managed
properties within the full-text index. Proximity calculations are expensive in terms of disk activity and CPU consumption; as a result, proximity boost is carried out only during the second
stage of the default SharePoint rank model (if available).
You can evaluate the proximity rank feature by using several different options, controlled by attributes described in Table 2.
Table 2. Attributes that control evaluation of proximity rank features

AT TR IB U TES D ES CR IPTIO N
AT TR IB U TES D ES CR IPTIO N

isExact=0 In this mode, the proximity algorithm attempts to find the minimal span (distance) of the subset of
query terms in a document.
The proximity algorithm considers fragments that contain query terms in the same orders as they
appear in the user query. If no fragment exists for all of the query terms, then the proximity algorithm
considers fragments that contain all but one of the query terms. This process is iterated with the number
of query terms reduced each time, until the length of the fragment exceeds maxMinSpan .
maxMinSpan is an attribute within the proximity rank feature that specifies a threshold defining the
maximum length of a fragment.
An ideal fragment is one that contains all query terms but is less than maxMinSpan .

isExact=1 In this mode, the proximity algorithm attempts to find a consecutive snippet of document that contains
all of the query terms (or query phrase).

isDiscounted This attribute is applicable to both isExact=1 and isExact=0 . When isDiscounted is enabled, the
proximity value is multiplied by this fraction: (number of occurrences of the best fragment or exact hits)
divided by (number of occurrences of the rarest query term in this context).

proximity="complete" In this mode, the proximity rank feature only boosts documents where the whole user query text occurs
within a specific managed property.

proximity="perfect" This mode is similar to complete mode, but is applied to short fields, such as title. The proximity rank
feature only boosts documents where the whole user query text matches an exact title within a specific
managed property. If the title contains additional terms outside of the user query, the item isn't
considered by the proximity algorithm.

default This attribute applies only to single-term queries. For items that contain the query term, the default
value is used as the rank score output by the proximity rank feature.
The perfect proximity is an exception to this rule. For perfect proximity, the default value is never
used. Instead, single-term queries are processed in the same way as other queries.

Example proximity rank feature definition


The following example is an excerpt from the default SharePoint rank model. In this model, the proximity feature is only part of the second stage calculation, which involves a neural network.
Therefore, the example contains multiple weight elements, <LayerWeights> , which correspond to the number of neurons in the hidden layer of the neural network.

<MinSpan name="Title_MinSpanExactDiscounted" default="0.43654446989518952" maxMinSpan="1" isExact="1" isDiscounted="1" propertyName="Title">


<Normalize SDev="0.20833333333333334" Mean="0.375" />
<Transform type="Linear" a="1" b="0" maxx="10000" />
<Layer1Weights>
<Weight>0.0399835450090479</Weight>
<Weight>-0.00693681478614802</Weight>
<Weight>0.0286196612755843</Weight>
<Weight>0.11775902923563</Weight>
<Weight>0.0885860088190342</Weight>
<Weight>0.102859503886488</Weight>
</Layer1Weights>
</MinSpan>

You must map the managed properties used in proximity rank features to the default full-text index in search schema.
Example rank detail for proximity rank feature

<proximity_feature name='Title_MinSpanExactDiscounted' pid='2'


proximity_type='exact_discounted'
used_default='0' raw_value='0' transformed='0'
normalized='-1.8'
hidden_nodes_adds='-0.0719704 0.0124863 -0.0515154 -0.211966 -0.159455 -0.185147 ' />

Dynamic
The dynamic rank feature ranks an item depending on whether the query property matches a given managed property. If there is a match, the item's rank score is multiplied with a specific
value to distinguish that particular item. The weight attribute is used to control how much this feature affects the overall rank score.
NOTE

The dynamic rank feature is not customizable; it's for internal use only. However, if you install the SharePoint cumulative update of August 2013, the AnchortextComplete rank feature is a
customizable dynamic rank feature that is part of the default ranking model.
Example dynamic rank feature definition

<Dynamic name="AnchortextComplete" pid="501" default="0" property="AnchortextCompleteQueryProperty">


<Transform type="Rational" k="0.91495552365614574" />
<Layer1Weights>
<Weight>0.715419978898093</Weight>
</Layer1Weights>
</Dynamic>

Freshness
The default SharePoint ranking model doesn't boost the rank of search results based on their freshness. You can achieve this by adding a new static rank feature that combines information
from the LastModifiedTime managed property with the DateTimeUtcNow query property, using the freshness transform function. The freshness transform function is the only
transform that you can use for this freshness rank feature, because it converts the age of the item from an internal representation into days.
The freshness transform is based on the following formula:
Where:
c and _y_future are defined in the ranking model.
x is the age of an item in days.
The value of _y_future defines the freshness boost for items that have LastModifiedTime greater than the current date and time.
Example freshness rank feature definition

<Static name='freshboost' propertyName='LastModifiedTime' default='-1' convertPropertyToDatetime='1' rawValueTransform='compare' property='DateTimeUtcNow'>


<Transform type="Freshness" constant="0.0333" futureValue="2" />
<Layer1Weights>
<Weight>1.0</Weight>
</Layer1Weights>
</Static>

Example rank detail for freshness rank feature using an old document (approximately 580 days old)

<static_feature name='freshboost' property_name='LastModifiedTime' raw_value_transform='compare' used_default='0' property_value_found='1' property_value='9807115930137649186' raw_value='9.80661e

Example rank detail for freshness rank feature using a new document (<1 day old)

<static_feature name='freshboost' property_name='LastModifiedTime' raw_value_transform='compare' used_default='0' property_value_found='1' property_value='9807115934928966979' raw_value='9.80712e

Aggregation of rank features


A ranking model consists of various rank features that are considered together to calculate a rank score.

Two-stage ranking models


A ranking model can have two rank stages. In the first stage, the ranking model applies relatively inexpensive rank features to get a gross ranking of the results. In the second stage, the
ranking model applies additional and more expensive rank features to the items with the highest rank scores.
The SharePoint default ranking model is an example of two-stage ranking model. In this model, the second stage works with the top 1000 items with the highest rank score that result from
the first stage.
When the ranking process in the first stage is complete, the search engine re-sorts all of the items, including the items that were excluded from the second stage. This usually results in items
from the second stage having a lower rank score when compared to items in the first stage.
However, to ensure that the search engine re-sorts the items accurately, items from the second stage must have a higher rank score than items from the first stage. To solve this dilemma, the
rank scores of the second stage are boosted. The search engine performs this calculation automatically, based on a combination of rank features.
NOTE

If you install the SharePoint cumulative update of August 2013, the default ranking model uses a linear first stage and a neural network second stage. The Search Ranking Model with
Two Linear Stages is a copy of the Default Search Model with two linear stages. We recommend using this model as the base model for your custom ranking model because it is easier to
tune a linear model than a model containing a neural network.
Linear model
The liner model defines a linear combination of rank scores from rank features.
The rank score provided by linear models is computed using the following formula:

Where:
score is the output rank score produced by the linear model.
M is the number of rank features excluding bucketed static rank features.
K is the number of bucketed static rank features.
_f_j is the value of _j_th feature after transformation.
_w_j is the contribution weight of _j_th feature to the linear combination.
Neural network
The neural network defines a nonlinear combination of rank scores from rank features. Currently, SharePoint supports neural networks that are limited to one hidden layer with up to eight
neurons.
The ranking score produced by a neural network is computed using the following formula:
Where:
score is the output rank score produced by the neural network.
N is the number of neurons in the hidden layer of the neural network.
M is the number of rank features, excluding bucketed static rank features.
K is the number of bucketed static rank features.
_W_i is the contribution weight of _i_th hidden neuron.
_t_i is the threshold of _i_th hidden neuron.
_W_i,j is the contribution weight of _j_th feature to _i_th hidden neuron.
_b_i,k is the addition from the _k_th bucketed static feature to _i_th hidden neuron.
The overall schema of rank score computation with a two-layer neural network is represented in the following diagram. This diagram doesn't consider the bucketed static rank feature that
contributes to neural networks by adding custom values directly into hidden nodes, without any transformation or normalization.
Figure 1. Overall schema of rank score computation with a two-layer neural network

Precalculation in BM25 and static rank features


In a ranking model, BM25 and static rank features can benefit from precalculations to improve query latency for query terms that frequently occur in items. This query latency improvement
is achieved with the cost of additional indexing, both in terms of disk space used by the search index and CPU consumption.
You should use precalculation only in the first stage of a ranking model. Consequently, if precalculation is enabled, the rank detail of the first stage will not be complete.
To enable precalculation, set the precalcEnabled attribute to 1 in the rank stage definition. You can only use precalculation once in a ranking model.

Query properties
Query properties is a ranking mechanism that populates additional information useful for rank score calculation. For example, query properties can be the time and date when the query was
run, which can be used by the freshness rank feature. Table 3 lists the query properties available for ranking. You can't configure query properties.
Table 3. Query properties for ranking

Q U ER Y PR O PER T Y D ES CR IPTIO N

AnchortextCompleteQueryProperty Boosts complete anchor text.

DateTimeUtcNow Current date and time. This query property can be used by the freshness rank feature.

DetectedLanguageRanking ID of the query language. This query property is used by the DetectedLanguageRanking rank feature.

PersonalizationData Ranks personalized data.

RecommendedforQueryProperty Ranks recommendations.

Example 1: Basic ranking model with one linear stage containing a single static rank feature
This ranking model assumes that the customer has created a managed property named CustomRating. The static rank feature requires CustomRating to be of Integer data type and to be
configured as Sortable or Refinable in the search schema. For each document in the result set, the rank score produced by this ranking model is equal to the value of CustomRating for that
document. The effect of this model is similar to sorting all search results, descending, with the CustomRating managed property.
<?xml version="1.0"?>
<RankingModel2Stage name="RankModel1"
description="Rank model -- example 1"
id="D3FAF680-D213-4916-A95A-0409031643F8"
xmlns="urn:Microsoft.Search.Ranking.Model.2NN">
<RankingModel2NN id="619F2ECD-24F7-41CD-824C-234FC2EFDDCA" precalcEnabled="0" >
<HiddenNodes count="1">
<Thresholds>
<Threshold>0</Threshold>
</Thresholds>
<Layer2Weights>
<Weight>1</Weight>
</Layer2Weights>
</HiddenNodes>
<RankingFeatures>
<Static name="CustomRating" propertyName="CustomRating" default="0.0">
<Transform type="Linear" a="1" b="0" maxx="1000"/>
<Layer1Weights>
<Weight>1.0</Weight>
</Layer1Weights>
</Static>
</RankingFeatures>
</RankingModel2NN>
</RankingModel2Stage>

Example 2: More complex ranking model with one linear stage and four rank features
This ranking model with one linear stage contains these four rank features:
BM25 This rank feature is based on managed properties Title and body; the w attribute for title is set so that hits of query terms in Title are two times (2x) more important than hits
of query terms in body.
UrlDepth This rank feature is based on the UrlDepth managed property, which is available by default in SharePoint installations. UrlDepth contains the number of backslashes (\) in
the URL of a document. The inverse rational ( InvRational ) transform ensures that documents with shorter URLs receive higher rank scores.
TitleProximity This rank feature boosts documents if some of the query terms occur close to each other in the title of these documents.
InternalFileType This rank feature boosts documents of type HTML, DOC, XLS, or PPT. The names of the buckets in the definition of the rank model are provided for readability only.
NOTE

The InternalFileType managed property, available by default, uses the value zero ( 0 ) to encode HTML documents, value 1 for DOC, value 2 for XLS and so on. See the definition
of the Default SharePoint rank model for a list of all file types used for the FileType managed property.
<?xml version="1.0"?>
<RankingModel2Stage name=" RankModel2"
description="Rank model -- example 2"
id="DE48A3A1-67CE-44A2-9712-E8A5128787CF"
xmlns="urn:Microsoft.Search.Ranking.Model.2NN">
<RankingModel2NN id="A0A030D1-805D-437E-A001-CC151ED7473A" precalcEnabled="0">
<HiddenNodes count="1">
<Thresholds>
<Threshold>0</Threshold>
</Thresholds>
<Layer2Weights>
<Weight>1</Weight>
</Layer2Weights>
</HiddenNodes>
<RankingFeatures>
<BM25Main name="BM25" k1="1">
<Layer1Weights>
<Weight>1</Weight>
</Layer1Weights>
<Properties>
<Property name="Title" propertyName="Title" w="2" b="0.5" />
<Property name="body" propertyName="body" w="1" b="0.5" />
</Properties>
</BM25Main>
<Static name="UrlDepth" propertyName="UrlDepth" default="1">
<Transform type="InvRational" k="1.5"/>
<Layer1Weights>
<Weight>0.5</Weight>
</Layer1Weights>
</Static>
<MinSpan name="TitleProximity" propertyName="Title" default="0" maxMinSpan="1" isExact="0" isDiscounted="0">
<Normalize SDev="1" Mean="0"/>
<Transform type="Linear" a="1" b="-0.5" maxx="2"/>
<Layer1Weights>
<Weight>1.2</Weight>
</Layer1Weights>
</MinSpan>
<BucketedStatic name="InternalFileType" propertyName="InternalFileType" default="0">
<Bucket name="http" value="0">
<HiddenNodesAdds>
<Add>1.5</Add>
</HiddenNodesAdds>
</Bucket>
<Bucket name="doc" value="1">
<HiddenNodesAdds>
<Add>2.5</Add>
</HiddenNodesAdds>
</Bucket>
<Bucket name="ppt" value="2">
<HiddenNodesAdds>
<Add>0.5</Add>
</HiddenNodesAdds>
</Bucket>
<Bucket name="xls" value="3">
<HiddenNodesAdds>
<Add>-3.5</Add>
</HiddenNodesAdds>
</Bucket>
</BucketedStatic>
</RankingFeatures>
</RankingModel2NN>
</RankingModel2Stage>

See also
Search in SharePoint
Keyword Query Language (KQL) syntax reference
FAST Query Language (FQL) syntax reference
Overview of search result ranking in SharePoint
Create a custom ranking model by using the Ranking Model Tuning App
Custom security trimming for Search in SharePoint
5/3/2018 • 7 minutes to read Edit Online

Learn about the two kinds of custom security trimmer interfaces, ISecurityTrimmerPre and ISecurityTrimmerPost, and the steps you must take to create a custom security trimmer. At
query time, Search in SharePoint performs security trimming of search results that are based on the identity of the user submitting the query, by using the security information obtained
from the crawl component.
You might have certain scenarios, however, in which the built-in security trimming results aren't sufficient for your requirements. In such scenarios, you need to implement custom security
trimming. Search in SharePoint provides support for custom security trimming through the ISecurityTrimmerPre interface, ISecurityTrimmerPost interface, and ISecurityTrimmer2 interface
(deprecated) in the Microsoft.Office.Server.Search.Query namespace.
NOTE

Custom pre-trimmers don't support Windows SIDs in ACLs, only claims. If any of the SID claim types are returned from a custom pre-trimmer, the resulting ACEs in the index will be
encoded as a claim, not as SID. Hence they do not match Windows user identities that are based on SIDs.

Implementing the interfaces for custom security trimming


The ISecurityTrimmerPre interface carries out pre-trimming, or pre-query evaluation, where the search query is rewritten to add security information before the search query is matched to
the search index. The ISecurityTrimmerPost interface carries out post-trimming, or post-query evaluation, where the search results are pruned before they are returned to the user.
We recommend the use of pre-trimming for performance and general correctness; pre-trimming prevents information leakage for refiner data and hit count instances. Post-trimmers can be
used in cases where the security trimming cannot be represented accurately with query filters; for example, if there is a need to filter away documents depending on the local time of the user
issuing the query, such as during official business hours only.

Implementing the ISecurityTrimmerPre interface


To create a custom security pre-trimmer for search results, you must create a component that implements the ISecurityTrimmerPre interface.
The ISecurityTrimmerPre interface contains two methods that you must implement: Initialize(NameValueCollection, SearchServiceApplication) and AddAccess(Boolean, Claims) .
Initialize Method
The Initialize method is executed when the security pre-trimmer is loaded into the worker process, and does not execute again until the worker process is recycled. Two parameters are
passed into the method:
staticProperties: A NameValueCollection object containing the configuration properties that are specified for the security trimmer when it is registered with the Search service
application.
searchApplication: A SearchServiceApplication object that represents the Search service application.
AddAccess Method
The AddAccess method is executed once per pre-trimmer, for each incoming query before the query is evaluated.
Two parameters are passed into this method:
sessionProperties: A [T:System.Collections.Generic.IDictionary<String,Object>] object that contains the properties of the query.
userIdentity: A IIdentity object that contains the user identity.

Implementing the ISecurityTrimmerPost interface


To create a custom security post-trimmer for search results, you must create a component that implements the ISecurityTrimmerPost interface.
The ISecurityTrimmerPost interface contains two methods that you must implement: Initialize(NameValueCollection, SearchServiceApplication) and CheckAccess(IList, IList,
IDictionary<String, Object>, IIdentity).
Initialize method
The Initialize method is executed when the security trimmer is loaded into the worker process, and does not execute again until the worker process is recycled. Two parameters are passed
into the method:and
staticProperties: A NameValueCollection object containing the configuration properties specified for the security trimmer when it is registered with the Search service application.
searchApplication: A SearchServiceApplication object that represents the Search service application.
CheckAccess method
The CheckAccess method is executed once per post-trimmer, for each result set query, after the query is evaluated.
Four parameters are passed into this method:
documentUrls: A IList<T> object that contain the URLs for each content item from the search results that match the crawl rule.
documentAcls: A IList<T> object containing item ACLs for each content item whose access is to be determined by the security trimmer implementation.
sessionProperties: A IDictionary<TKey, TValue> object containing the transient property bag.
userIdentity: An IIdentity object from which implementers can retrieve the user's identity.
The CheckAccess method returns a BitArray object that represents an array of true or false values, one for each content item URL in the IList object that is passed as the first parameter of
the method. The query processing component uses these values to perform the security post-trimming of the results. If the array value for a particular content item is true, the item is
included in the returned results; if the array value is false, the item is removed.
When implementing the CheckAccess method, you can use two pieces of information for each item to determine whether to return true or false for the item: the identity of the user who
submitted the query and the URL of the content item. Alternatively, you can also pass custom document ACL information from the connector to the CheckAccess method.
Retrieving the user identity for your security trimmer
You can retrieve the user's identity by accessing the thread's current principal, as shown in the following code example.

IIdentity userIdentity = System.Threading.Thread.CurrentPrincipal.Identity;


You must also include the following namespace directive.

using System.Security.Principal;

You can also retrieve the identity of the user from the CheckAccess method's passedUserIdentity parameter.
Passing document ACLs from the connector to your security trimmers
A connector, as the name implies, is a communication bridge between SharePoint and the external system that hosts the external data. If you are working with custom connectors, you can
pass the document's ACL information directly to the post-trimmer by setting the docaclmeta document property. As long as the configured connectors and post-trimmers have the same
format and interpretation of the field, you are free to use it to pass custom data.
The strings stored in docaclmeta by the connector will surface in the documentAcls parameter when the CheckAccess method of the custom security trimmer is invoked. The regular
document ACLs in the docacl property are processed by basic security trimming and are not visible to the custom security trimmer. Similarly, the docaclmeta property does not have any
effect on basic security trimming.
Post-trimmers and their effect on refiner count for security trimmers
When working with post-trimmers, it is important to notice that there are two types of result tables: RelevantResults and the RefinementResults. Post-trimmers are applied only to the
result hits in the RelevantResults. Consequently, there may be refiners related to the post-trimmed hits and the RefinementResults count may be larger than or equal to the
RelevantResults. You can address this behavior in two ways:
Exclude the sensitive refiners from the refinement panel in the default web part so that no information is leaked via the refiners.
Use a custom web part to display results or refiners when using post-trimmers so that the RefinementResults may be elegantly hidden in cases where the RefinementResults count
exceeds the RelevantResults count.

Retrieving individual configuration properties for your security trimmer


You can access an individual configuration property by using the property name that was specified when the security post-trimmer was registered. For example, the following code retrieves
the value for a configuration property named CheckLimit.

public void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication)


{
if (staticProperties["CheckLimitProperty"] != null)
{
intCheckLimit = Convert.ToInt32(staticProperties["CheckLimitProperty"]);
}
}

Deploying the custom security trimmer component


After you create the custom security trimmer, you must deploy it to the global assembly cache on any server in the Query role. Step 2 in How to: Use a custom security trimmer for
SharePoint Server search results describes the process for deploying the custom security trimmer to the global assembly cache.

Registering the custom security trimmer


For post-trimmers, you must associate a custom security trimmer registration with a specific Search service application and crawl rule; for pre-trimmers, this is optional.
You use the SPEnterpriseSearchSecurityTrimmer cmdlet of the SharePoint Management Shell to register a custom security trimmer.
The following table describes the parameters that the cmdlet uses.
Table 1. Parameters used by the SPEnterpriseSearchSecurityTrimmer cmdlet

PAR AME TER D ES CR IPTIO N

SearchApplication Required. The name of the Search service application, for example "Search Service Application".

typeName Required. The strong name of the custom security trimmer assembly.

RulePath Required for post-trimmers; optional for pre-trimmers. The crawl rule for the security trimmer.
Note: We recommend using one crawl rule per content source.

id Required. The security trimmer identifier (ID). This value is unique; if a security trimmer is registered with
an ID that is already registered for another security trimmer, the registration for the first trimmer is
overwritten with the registration for the second trimmer.

properties Optional. The name-value pairs specifying the configuration properties. Must be in the following format:
Name1~Value1~Name2~Value~???

For an example of a basic command for registering a custom security trimmer and a sample that specifies the configuration properties, see How to: Use a custom security trimmer for
SharePoint Server search results.

See also
How to: Use a custom security trimmer for SharePoint Server search results
ISecurityTrimmerPre
ISecurityTrimmerPost
Overview of Business Connectivity Services in SharePoint
Use a custom security trimmer for SharePoint Server search results
3/26/2018 • 7 minutes to read Edit Online

This how-to guides you through the steps to implement—create, deploy, and register—a custom security trimmer for Search in SharePoint by using Microsoft Visual Studio 2010.
Search in SharePoint performs query-time security trimming of search results. However, there may be scenarios in which you want to perform custom security trimming. Search in
SharePoint provides support for these scenarios through the Microsoft.Office.Server.Search.Query.ISecurityTrimmerPre , Microsoft.Office.Server.Search.Query.ISecurityTrimmerPost , and
ISecurityTrimmer2 (deprecated) interfaces in the Microsoft.Office.Server.Search.Query namespace.
There are two kinds of custom security trimming: Pre-trimming and post-trimming. Pre-trimming refers to pre-query evaluation where the query is rewritten to add security information
before the query is matched to the search index. Post-trimming refers to post-query evaluation where the search results are pruned before they are returned to the user. We recommend the
use of pre-trimming for performance and general correctness; post-trimming prevents information leakage for refiner data and hit count instances.
The security trimmer registration process enables you to specify configuration properties for the custom security trimmer.

Overview
Custom Security Trimming in Search in SharePoint consists of two interfaces that can be used to carry out pre-trimming or post-trimming of your search results. This how-to focuses on
both interfaces, describing the steps necessary to create and register your own security trimmers.

Prerequisites
To complete this how-to, you must have the following installed in your development environment:
Search in Microsoft SharePoint
Microsoft Visual Studio 2010 or similar Microsoft .NET Framework-compatible development tool

Set up a custom security trimmer project


In this step, you will create the custom security trimmer project, and then add the required references to the project.

To create the project for a custom security trimmer


1. Open Visual Studio and choose File, New, Project.
2. In Project types, under C#, choose SharePoint.
3. Under Templates, choose Empty SharePoint Project. In the Name field, type CustomSecurityTrimmerSample, and then choose the OK button.
4. In the SharePoint Customization Wizard, choose Deploy as a farm solution, and then choose Finish.

To add references to the custom security trimmer project


1. On the Project menu, choose Add Reference.
2. On the .NET tab, choose the references with the following component names, and then choose the OK button:
Microsoft Search component
You should see two entries on the .NET tab with the component name Microsoft Search component. Select the entry where the Path column is
\ISAPI\Microsoft.Office.Server.Search.dll. If this entry is missing from the .NET tab in the Add References dialog box, you must add the reference from the Browse tab by
using the path to the Microsoft.Office.Server.Search.dll.
Microsoft.IdentityModel
If Microsoft.IdentityModel is not listed on the .NET tab, you must add the reference to the Microsoft.IdentityModel.dll from the Browse tab, by using the following path:
%ProgramFiles%\\Reference Assemblies\\Microsoft\\Windows Identity Foundation\\v4.0.

Create a custom security pre-trimmer


To create the class file for the security pre-trimmer
1. On the Project menu, choose Add New Item.
2. Under Visual C# Items in Installed Templates, choose Code, and then choose Class.
3. Type CustomSecurityPreTrimmer.cs, and then choose Add.

Writing the custom security pre-trimmer code


Your custom security trimmer must implement the ISecurityTrimmerPre interface. The following code example is a basic implementation of this interface.

To modify the default code in CustomSecurityPreTrimmer


1. Add the following using directives at the beginning of the class.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Security.Principal;
using Microsoft.IdentityModel.Claims;
using Microsoft.Office.Server.Search.Query;
using Microsoft.Office.Server.Search.Administration;

1. Specify that the CustomSecurityPreTrimmer class implements the ISecurityTrimmerPre interface in the class declaration, as shown in the following code.
public class CustomSecurityPreTrimmer : ISecurityTrimmerPre

To implement the ISecurityTrimmerPre interface methods


1. Add the following code for the Initialize() method declaration.

public void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication)


{

The basic version of this sample does not include any code in the **Initialize** method.

1. Add the following code for the AddAccess() method declaration.

public IEnumerable<Tuple<Claim, bool>> AddAccess(


IDictionary<string, object> sessionProperties, IIdentity passedUserIdentity)
{
//AddAccess method implementation, see steps 3-5.
}

1. For the first part of the AddAccess method implementation, we find out who the user is by looking at the passedUserIdentity.

if (passedUserIdentity == null)
{
throw new ArgumentException("AddAccess method is called with invalid user identity
parameter", "passedUserIdentity");
}

String strUser = null;


var claimsIdentity = (IClaimsIdentity)passedUserIdentity;
if (claimsIdentity != null)
{
foreach (var claim in claimsIdentity.Claims)
{
if (claim == null)
{
continue;
}

// strUser is "domain\\\\user" format when web app is in Claims Windows Mode


if (SPClaimTypes.Equals(claim.ClaimType, SPClaimTypes.UserLogonName))
{
strUser = claim.Value;
break;
}

// strUser2 is "S-1-5-21-2127521184-1604012920-1887927527-66602" when web app is


in Legacy Windows Mode
// In this case we need to convert it into NT user format.
if (SPClaimTypes.Equals(claim.ClaimType, ClaimTypes.PrimarySid))
{
strUser = claim.Value;
SecurityIdentifier sid = new SecurityIdentifier(strUser);
strUser = sid.Translate(typeof(NTAccount)).Value;
break;
}
}
}

1. Create a list, populate the list with claims and return the list, as shown in the following code.

var claims = new LinkedList<Tuple<Claim, bool>>();


if (!string.IsNullOrEmpty(strUser))
{
var groupMembership = GetMembership(strUser);
if (!string.IsNullOrEmpty(groupMembership))
{
var groups = groupMembership.Split(new[] {';'},
StringSplitOptions.RemoveEmptyEntries);
foreach (var group in groups)
{
claims.AddLast(new Tuple<Claim, bool>(
new Claim("http://schemas.happy.bdc.microsoft.com/claims/acl", group), false));
}
}
}
return claims;
}

The **GetMembership** method contains the custom logic of your trimmer.

Create a custom security post-trimmer


To create the class file for the security post-trimmer
1. On the Project menu, choose Add New Item.
2. Under Visual C# Items in Installed Templates, choose Code, and then choose Class..
3. Type CustomSecurityPostTrimmer.cs, and then choose Add.

Writing the custom security post-trimmer code


Your custom security trimmer must implement the ISecurityTrimmerPost interface. The code example in this section is a basic implementation of this interface.

To modify the default code in CustomSecurityPostTrimmer


1. Add the following using directives at the beginning of the class:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Security.Principal;
using Microsoft.IdentityModel.Claims;
using Microsoft.Office.Server.Search.Query;
using Microsoft.Office.Server.Search.Administration;

1. Specify that the CustomSecurityPostTrimmer class implements the ISecurityTrimmerPost interface in the class declaration, as follows:

public class CustomSecurityPostTrimmer : ISecurityTrimmerPost

To implement the ISecurityTrimmerPost interface methods


1. Add the following code for the Initialize() method declaration.

public void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication)


{

The basic version of this sample does not include any code in the Initialize method.

1. Add the following code for the CheckAccess() method declaration.

public BitArray CheckAccess(IList<string> documentCrawlUrls, IList<string> documentAcls, IDictionary<string, object> sessionProperties, IIdentity passedUserIdentity)
{
//CheckAccess method implementation, see steps 3-5.
}

1. For the first part of the CheckAccess method implementation, declare and initialize a BitArray variable to store the results of the access check for each URL in the documentCrawlUrls
collection, and retrieve the user who submitted the query, as shown in the following code.

if (documentCrawlUrls == null)
{
throw new ArgumentException("CheckAccess method is called with invalid URL list",
"documentCrawlUrls");
}
if (documentAcls == null)
{
throw new ArgumentException("CheckAccess method is called with invalid documentAcls
list", "documentAcls");
}
if (passedUserIdentity == null)
{
throw new ArgumentException("CheckAccess method is called with invalid user identity
parameter", "passedUserIdentity");
}

1. Loop through each crawl URL in the collection, and perform the access check to determine if the user who submitted the query can access the crawl URL's associated content item, as
shown in the following code.

// Initialize the bit array with TRUE value which means all results are visible by default.
var urlStatusArray = new BitArray(documentCrawlUrls.Count, true);
var claimsIdentity = (IClaimsIdentity)passedUserIdentity;
if (claimsIdentity != null)
{
var userGroups = GetGroupList(claimsIdentity.Claims);
var numberDocs = documentCrawlUrls.Count;
for (var i = 0; i < numberDocs; ++i)
{
if (!string.IsNullOrEmpty(documentAcls[i]))
{
urlStatusArray[i] = VerifyAccess(documentAcls[i], userGroups);
}
}
}

If the user has access to the content item, set the value of the **BitArray** item at that index, **urlStatusArray[i]**, to **true**; otherwise, set it to **false**.

1. Set the return value of the CheckAccess method to urlStatusArray, as shown in the following code.
return urlStatusArray;

Register the custom security trimmer


This step describes how to configure the custom security trimmer, and includes the following tasks:
Registering the custom security trimmer for the Search service application by using the Windows PowerShell cmdlets.
Restarting the SharePoint search host controller (SPSearchHostController).

Register the custom security trimmer


You use the SharePoint Management Shell to register a custom security trimmer with ClassName. In our case, ClassName could be either CustomSecurityPreTrimmer or
CustomSecurityPostTrimmer. The following procedure shows how to register a custom security trimmer, with the ID set to 1 for the Search service application.

To register the custom security trimmer


1. In Windows Explorer, locate CustomSecurityTrimmerSample.dll in the path <Local_Drive>:\WINDOWS\assembly.
2. Open the shortcut menu for the file, and then choose Properties.
3. On the General tab in the Properties dialog box, select the token and copy it.
4. Open the SharePoint Management Shell. For information about using this tool, see Administering Service Applications Using the SharePoint 2010 Management Shell
5. At the command prompt, type the following command.

New-SPEnterpriseSearchSecurityTrimmer -SearchApplication "Search Service Application"


-typeName "CustomSecurityTrimmerSample.ClassName, CustomSecurityTrimmerSample,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=token" -RulePath "xmldoc://*"

In the command, replace _ClassName_ either with **CustomSecurityPreTrimmer** or **CustomSecurityPostTrimmer** and _token_ with the Public Key Token for the CustomSecurityTrimmerSample.dll file.

> [!NOTE]
> If you have multiple front-end web servers, you must deploy your security trimmer to the global assembly cache on all the front-end web servers in the farm.

1. Verify that your security trimmer is registered with the following PowerShell cmdlets.

$searchApp = Get-SPEnterpriseSearchServiceApplication
$searchApp | Get-SPEnterpriseSearchSecurityTrimmer

Your security trimmer must be visible in the results.

To restart the SharePoint search host controller


You can restart the Search Service by typing the following PowerShell cmdlet.

net restart sphostcontrollerservice

See also
Custom security trimming for Search in SharePoint
Microsoft.Office.Server.Search.Query.ISecurityTrimmerPre
Microsoft.Office.Server.Search.Query.ISecurityTrimmerPost
Microsoft.Office.Server.Search.Query.PluggableAccessCheckException
Exporting and importing search configuration settings in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Get code examples that show you how to export and import customized search configuration settings. These settings include all customized query rules, result sources, result types, ranking
models, and site search settings. SharePoint exposes this functionality through the Microsoft.Office.Server.Search.Portability namespace.You can also export customized search configuration
settings from a Search service application (SSA) and import the settings to site collections and sites.
NOTE

You can't import customized search configuration settings to an SSA, or export the default search configuration settings.

Export search configuration settings


The following code shows how to use SearchConfigurationPortability to export your site's search configuration settings. The code uses an example site http://yoursite/sites/publishing1 ,
which you'd replace with your own site. fileName refers to the file where the search configuration settings are stored; owner specifies the SPWeb level at which the search configuration
settings are obtained.

private static void Export(string fileName)


{
SPSite site = new SPSite("http://yoursite/sites/publishing1");
SearchConfigurationPortability conf = new SearchConfigurationPortability(site);
SearchObjectOwner owner = new SearchObjectOwner(SearchObjectLevel.SPWeb, site.OpenWeb());
var buff = conf.ExportSearchConfiguration(owner);
File.WriteAllText(fileName, buff);
site.Close();
}

Import search configuration settings


The following code shows how to import search configuration settings from a file by using SearchConfigurationPortability and replace the existing search settings on a specified site,
http://yoursite/sites/publishing1 . fileName refers to the file where the search configuration settings are stored; owner specifies the SPWeb level at which the search configuration settings
are obtained.

private static void Import(string fileName)


{
SPSite site = new SPSite("http://yoursite/sites/publishing1");
SearchConfigurationPortability conf = new SearchConfigurationPortability(site);
SearchObjectOwner owner = new SearchObjectOwner(SearchObjectLevel.SPWeb, site.OpenWeb());
conf.ImportSearchConfiguration(owner, File.ReadAllText(fileName));
site.Close();
}

See also
Search in SharePoint
Export and import customized search configuration settings in SharePoint
Query Refinement in SharePoint
5/3/2018 • 11 minutes to read Edit Online

Learn how to use SharePoint query refinement features programmatically when you are working with search queries and results. You can use query refinement features to provide end users
with refinement options that are relevant for their queries. These features let the end user drill down into search results by using refinement data computed for the results. Refinement data is
calculated by the index component, based on the aggregation of managed property statistics for all of the results of a search query.
Typically, query refinement is used for metadata associated with the indexed items, such as creation date, author, or file types that appear in the item. By using the refinement options, you can
refine your query to display only items created during a certain time period, or display only items of a specific file type.

Using refiners in the Query Object Model


There are two queries involved in query refinement:
1. You can request for a set of refiners to be returned in the search results by adding a refiner spec to the end user's query. A refiner spec is the input for the Refiners property. This query
is run against the search index. The search results will consist of relevant results and refinement data.
2. You can use the refinement data to drill down into the search results by, creating a refined query. Add the RefinementFilters property to the query so that the final search results will
meet the requirements of both the original query text from the end user and the selected refinement option from the refinement data.
The following sections describe these steps in detail, and provide code examples.

Adding refiners to the end-user's query by using refiner specs


You can specify the requested query refiners by using the Refiners property of the KeywordQuery class. Use the following syntax to specify the requested query refiners:
<refiner>[,<refiner>]*

Each refiner has the following format:


<refiner-name>[(parameter=value[,parameter=value]*)]?

Where:
<refiner-name> is the name of the managed property associated with the refiner. This managed property must be set to Refinable or Sortable in the search schema.
The optional list of parameter=value pairs specifies non-default configuration values for the named refiner. If a parameter for a refiner is not listed inside the parentheses, the search
schema configuration gives you the default setting. Table 1 lists possible values for the parameter=value pairs.
NOTE

When you specify refiners, the minimum requirement is to specify a refiner-name , which is a managed property.
Example
Refiners = "FileType"

Or, you can also use the advanced syntax to adjust the refiner settings.
Example
Refiners = "FileType,Write(discretize=manual/2013-01-01/2013-08-22/2013-09-15/2013-09-21/2013-09-22),companies"

Table 1: List of parameters for refiners

PAR AME TER D ES CR IPTIO N

deephits Overrides the default number of hits that is used as the basis for refinement computation. When refiners
are produced, all results for the query will be evaluated. Normally, using this parameter will improve
search performance.
Syntax
deephits=<integer value>
Example
price(deephits=1000)
Note: This limit applies within each index partition. The actual number of hits that are evaluated will be
larger than this value due to the aggregation across search partitions.
PAR AME TER D ES CR IPTIO N

discretize Specifies custom intervals (refinement bins) for numeric refiners.


Syntax
discretize=manual/<threshold>/<threshold>[/<threshold>]*
Example
write(discretize=manual/2013-01-01/2013-08-22/2013-09-15/2013-09-21/2013-09-22)
The <threshold> attribute specifies the threshold for each refinement bin.
There is one interval for everything below the first threshold specified, one interval between each
consecutive threshold, and one interval for everything above the last threshold.
For a refiner of type DateTime, specify the threshold according to one of the following ISO 8601-
compatible formats:
YYYY-MM-DD
YYYY-MM-DDThh:mm:ss
YYYY-MM-DDThh:mm:ss:Z
The format values specify the following:
YYYY - Four-digit year. Only four-digit years are supported.
MM - Two-digit month. 01 = January.
DD - Two-digit day of month (01 through 31).
T - The letter "T".
hh - Two-digit hour (00 through 23). A.M. or P.M. indication is not allowed.
mm - Two-digit minute (00 through 59).
ss - Two-digit second (00 through 59).
Important: All date/time values must be specified according to the Coordinated Universal Time (UTC),
also known as Greenwich Mean Time (GMT) zone. The UTC zone identifier (a trailing "Z" character) is
optional.

sort Defines how to sort the bins within a string refiner.


Syntax
sort=<property>/<direction>
The attributes perform the following:
<property> - Specifies the sorting algorithm. These lowercase values are valid:
frequency - Orders by occurrence within the bins.
name - Orders by label name.
number - Treats the strings as numeric and uses numeric sorting. This value can be useful
to specify discrete values, for example, to perform numeric sorting of a value that is
contained in a managed property of type String.
<direction> - Specifies the sorting direction. These lowercase values are valid :
descending
ascending
Example
sort=name/ascending
Default: frequency/descending

filter Defines how bins within a refiner of type String are filtered before they are returned to the client.
Syntax
filter=<bins>/<freq>/<prefix>[<levels>]
The attributes perform the following:
<bins> - Specifies the maximum number of returned bins.
After sorting the bins within the refiner, use this attribute to truncate any trailing bins. For
example, if bins=10, only the first 10 bins are returned, according to the specified sorting
algorithm.
<freq> - Limits the number of returned bins.
Use this attribute to remove bins that have low frequency counts. For example, freq=2 indicates
that only the bins with 2 or more members are returned.
<prefix> - Specifies that only bins with a name that begins with this prefix are returned.
The wildcard character "*" will match all names.
Example
filter=30/2/*
<levels> - Specifies the levels of taxonomy.
Use this attribute to filter hierarchical refiner output based on taxonomy levels. The attribute
should be a positive integer n. The default value is n=0. If n>0, only refiner entries that contain
less than n taxonomy path separator symbols ("/") will be returned. If n=0, no level filtering is
performed. The level separator is the forward slash character ("/").
Be aware of the performance cost of using a large taxonomy navigator. The filtering is performed
as part of the result processing.
Note: This parameter applies application-specific result-side filtering. This differs from the cutoff
parameter, which applies limitations in every index partition for performance reasons.
PAR AME TER D ES CR IPTIO N

cutoff Limits the data that must be transferred and processed for deep string refiners. You can configure the
refiners to return only the most relevant values (bins).
Note: This cutoff filtering is performed within each index partition. This differs from the filter parameter,
which performs result-side filtering only. You can combine the two parameters.
Syntax
cutoff=<frequency>/<minbins>/<maxbins>
The attributes perform the following:
<maxbins> - Limits the number of bins.
This parameter limits the number of unique values (bins) that will be returned for a refiner. It is
the preferred way to increase search performance when string refiners with large number of bins
are returned. "0" implies that the default value specified in the search schema is used.
<frequency> - Limits the number of bins by frequency.
If the number of occurrences of a refiner value in a result set is less than or equal to the
frequency value, the refiner value is not returned. "0" implies that the default value according to
the search schema is used.
<minbins> - Specifies the minimum value for frequency cutoff.
If the number of unique refiner values for the query is less than this value, no frequency cutoff is
performed, and all refiner values are returned from that search partition. When cutoff by
frequency is used, this parameter can be used to specify a minimum number of unique refiner
values that will be returned regardless of the number of occurrences. The default value of this
attribute is "0", indicating that frequency cutoff is performed regardless of the number of unique
navigator values. "0" implies that the default value specified in the index schema is used.
Note: Use <frequency> and <minbins> with care. We recommend that you use only <maxbins>.

Example: Adding refiners


The following CSOM example shows how to programmatically request three refiners: FileType, Write, and Companies. Write represents the last modified date for the item, and uses the
advanced syntax to return fixed-size date/time bins.

using (var context = new ClientContext("http://<serverName>/<siteCollectionPath>"))


{
var query = new KeywordQuery(context)
{
QueryText = "home",
Refiners = "FileType,Write(discretize=manual/2013-01-01/2013-08-22/2013-09-
15/2013-09-21/2013-09-22),companies"
};

var executor = new SearchExecutor(context);


var results = executor.ExecuteQuery(query);

context.ExecuteQuery();

ResultTable relevantResultsTable = results.Value[0];


ResultTable refinerResultsTable = results.Value[1];
Console.WriteLine(refinerResultsTable.RowCount + " refinement options:");
foreach (var refinementOption in refinerResultsTable.ResultRows)
{
Console.WriteLine("RefinerName: '{0}' RefinementName: '{1}'
RefinementValue: '{2}' RefinementToken: '{3}' RefinementCount: '{4}'",
refinementOption["RefinerName"],
refinementOption["RefinementName"],
refinementOption["RefinementValue"],
refinementOption["RefinementToken"],
refinementOption["RefinementCount"]
);
}
}

Understanding the refinement data in the search result


If you have enabled query refinement for a managed property in your query, the query result contains refinement data split into refinement bins. This data is located in the
RefinementResults table ( RefinementResults ) within the ResultTableCollection . One refinement bin represents a specific value or value range for the managed property.The
RefinementResults table contains one row per refinement bin, and contains the columns, as specified in Table 2.
Table 2: Data returned for refinement bins

PAR AME TER D ES CR IPTIO N

RefinerName The name of the query refiner.

RefinementName The string that represents the refinement bin. This string is typically used when presenting the
refinement options to the users on a search result page.

RefinementValue An implementation-specific formatted string that represents refinement. This data is returned for
debugging and is typically not required for the client.

RefinementToken A string that represents the refinement bin to use with RefinerName when you perform a refined
query.

RefinementCount The result count for this refinement bin. This data represents the number of items (including duplicates)
in the search result with a value for the given managed property that falls into this refinement bin.

Example: Refinement data


Table 3 below contains two rows of refinement data. The first row holds refinement data for indexed items, where the file type is HTML. The second row holds refinement data for indexed
items, where the last modified time is from 2013/09/21 until 2013/09/22.
Table 3: Format and contents of refinement data
R EFINER NAME R EFINEMENTNAME R EFINEMENT V ALU E R EFINEMENT TO K EN R EFINEMENTCO U NT

FileType Html Html "????68746d6c" 50553

Write From 2013-09-21T00:00:00Z up to From 2013-09-21T00:00:00Z up to range(2013-09-21T00:00:00Z, 2013- 37


2013-09-22T00:00:00Z 2013-09-22T00:00:00Z 09-22T00:00:00Z)

Creating a refined query


A search result presents refinement options in the form of string values or value ranges. Each string value or numeric value range is called a refinement bin, and each refinement bin has an
associated RefinementToken value. A refinement option is associated with a managed property, which is provided by the RefinerName value.
Both the RefinementToken and RefinerName values are concatenated to create a refinement filter string. This string represents a filter that can be used to limit search result items to
include only items where a managed property has a value within a refinement bin. In short:
refinement filter = <RefinerName>:<RefinementToken>

You can provide one or more refinement filters for a refined query by adding refinement filters to the RefinementFilters property of the KeywordQuery class. Multiple refinement filters
enable you to provide multilevel drill-down into the search results, and to apply refinement on multivalued properties. For example, you can refine the query to items that have two authors -
each represented by a refinement bin - but exclude items that have only one of the authors.

Example 1: Creating a refined query for HTML file types


The following CSOM example shows how to programmatically perform a refinement, to limit the search results to those of HTML file type only. As mentioned in Example: Refinement data,
refinement data related to this refinement option has RefinerName set to Filetype and RefinementToken set to "????68746d6c".

using (var context = new ClientContext("http://<serverName>/<siteCollectionPath>"))


{
var query = new KeywordQuery(context)
{
QueryText = "home"
};

query.RefinementFilters.Add("FileType:\\"????68746d6c\\"");
var executor = new SearchExecutor(context);
var results = executor.ExecuteQuery(query);

context.ExecuteQuery();

ResultTable relevantResultsTable = results.Value[0];


var resultCount = 1;
foreach (var relevantResult in relevantResultsTable.ResultRows)
{
Console.WriteLine("Relevant result number {0} has file type {1}.",
resultCount, relevantResult["FileType"]);
resultCount++;
}
}

Example 2: Creating a refined query by using previously obtained refinement data


The following CSOM example shows how to run a query with a refiner spec to create refinement data which is subsequently used to perform refinement. This example simulates the process
of an end user selecting the first refinement option.
using (var context = new ClientContext("http://<serverName>/<siteCollectionPath>"))
{
// Step 1: Run the query with refiner spec to provide refinement data in search result
var query = new KeywordQuery(context)
{
QueryText = "home",
Refiners = "FileType,Write(discretize=manual/2013-01-01/2013-08-22/
2013-09-15/2013-09-21/2013-09-22),companies"
};

Console.WriteLine("Run query '{0}' with refiner spec '{1}'.", query.QueryText,


query.Refiners);
var executor = new SearchExecutor(context);
var results = executor.ExecuteQuery(query);
context.ExecuteQuery();

// The query has been run and we can now look at the refinement data, to view the
// refinement options
ResultTable relevantResultsTable = results.Value[0];
ResultTable refinerResultsTable = results.Value[1];
Console.WriteLine("Got back {0} refinement options in the result:",
refinerResultsTable.RowCount);

foreach (var refinementOption in refinerResultsTable.ResultRows)


{
Console.WriteLine("RefinerName: '{0}' RefinementName: '{1}'
RefinementValue: '{2}' RefinementToken: '{3}' RefinementCount: '{4}'",
refinementOption["RefinerName"],
refinementOption["RefinementName"],
refinementOption["RefinementValue"],
refinementOption["RefinementToken"],
refinementOption["RefinementCount"]
);
}

// Step 2: Run the refined query with refinement filter to drill down into
// the search results. This example uses the first refinement option in the refinement
// data, if available. This simulates an end user selecting this refinement option.
var refinementOptionArray = refinerResultsTable.ResultRows.ToArray();

if (refinementOptionArray.Length > 0)
{
var firstRefinementOption = refinementOptionArray[6];
// Construct the refinement filter by concatenation
var refinementFilter = firstRefinementOption["RefinerName"] + ":" +
firstRefinementOption["RefinementToken"];
var refinedQuery = new KeywordQuery(context)
{
QueryText = query.QueryText
};
refinedQuery.RefinementFilters.Add(refinementFilter);
refinedQuery.SelectProperties.Add("FileType");
refinedQuery.SelectProperties.Add("Write");
refinedQuery.SelectProperties.Add("Companies");
Console.WriteLine("Run query '{0}' with refinement filter '{1}'",
refinedQuery.QueryText, refinementFilter);
var refinedResults = executor.ExecuteQuery(refinedQuery);
context.ExecuteQuery();
ResultTable refinedRelevantResultsTable = refinedResults.Value[0];
var resultCount = 1;
foreach (var relevantResult in refinedRelevantResultsTable.ResultRows)
{
Console.WriteLine("Relevant result number {0} has FileType='{1}',
Write='{2}', Companies='{3}'",
resultCount,
relevantResult["FileType"],
relevantResult["Write"],
relevantResult["Companies"]
);
resultCount++;
}
}
}

See also
Configure properties of the Refinement web part in SharePoint
Overview of the search schema in SharePoint

See also
Other resources
Index Schema (FAST Search Server 2010 for SharePoint)
Refiner Element in Microsoft.Search.Query Schema
Business Connectivity Services in SharePoint
3/26/2018 • 3 minutes to read Edit Online

Learn what Business Connectivity Services (BCS) is, what you can do with it, and the information you need to get started developing BCS applications in SharePoint. You can use SharePoint
as a hub for creating rich productivity and collaboration solutions that can work with a variety of external systems. Business Connectivity Services (BCS) provides the infrastructure that
enables SharePoint to bring data from those external systems into a central system. By providing a flexible and extensible means to describe the external system data source and how to
interact with it, BCS makes a compelling argument for using SharePoint as the central interface for working with legacy business systems in addition to new SharePoint Add-ins.

What can BCS do?


BCS provides mechanisms to enable experienced users, developers, and business unit IT professionals to do the following much more easily:
Reveal external data from enterprise applications, web services, and OData services in SharePoint and in rich-client Office applications.
Provide Office-type behaviors (such as Contacts, Tasks, and Appointments) and capabilities to external data and services.
Provide complete interaction with the data, including write-back capabilities from Office applications and SharePoint Server to the underlying external system data and business
objects.
Enable offline use of external data and processes.
Bridge the unstructured world of documents and people and the appropriate structured data that is locked in external systems.

Components of BCS
Figure 1 shows the features that are included in SharePoint and Office 2013.
Figure 1. Business Connectivity Services feature set

Using external content types in BCS


External content types are the core of BCS. They enable you to manage and reuse the metadata and behaviors of a business entity, such as Customer or Order, from a central location. They
enable users to interact with that external data and process it in a more meaningful way.
For example, consider a business entity, such as a customer. You want to be able to pull data from your proprietary database and work with it in SharePoint. You also want to be able to allow
your field salespeople to take data offline in Outlook 2013. Or, you might want the user to be able to choose a customer from a list of customers in an orders contract document inside
Microsoft Word. To make all this possible, you can create a single external content type and then reuse it anywhere you need it.
For more information about using external content types in BCS, see External content types in SharePoint.

Developing solutions using BCS


You can build a broad spectrum of solutions in SharePoint by using BCS. These include simple solutions that rely on native capabilities with little or no customization, intermediate solutions
that involve customizing features in SharePoint and Office 2013, and advanced solutions that enable complex scenarios and rich applications that extend their functionality. Advanced
solutions involve writing code using Visual Studio. They can be either complete end-to-end solutions, or reusable code-based components that are included in an intermediate solution.
BCS empowers business users to quickly and easily address a broad array of external data needs by using a web browser and a Microsoft Office client application, such as Word or Excel.
Without writing code, users can assemble composite solutions by using BCS features, such as external lists and external data columns, and reusable BCS components, which are created by
developers and approved by IT, in Office client applications and SharePoint sites. These solutions enable business users (and their teams) to work with external data as easily as with
SharePoint data, either offline or connected, or directly in Office 2013.
For information about how to get started, see Setting up a development environment for BCS in SharePoint.

Using OData with Business Connectivity Services in SharePoint


The Open Data Protocol (OData) is a web protocol that lets you expose data to the web using technologies such as HTTP, JavaScript Object Notation (JSON), and AtomPub. Access to the
data is through specially constructed URLs. This architecture lets you interact with data using a variety of technologies.
For more information, see Using OData sources with Business Connectivity Services in SharePoint.
In this section
What's new in Business Connectivity Services in SharePoint
Get started with Business Connectivity Services in SharePoint
External content types in SharePoint
Using OData sources with Business Connectivity Services in SharePoint
External events and alerts in SharePoint
Add-in-scoped external content types in SharePoint
Get started using the client object model with external data in SharePoint
Business Connectivity Services programmers reference for SharePoint

See also
Add SharePoint capabilities
Setting up a development environment for BCS in SharePoint
SharePoint development overview
What's new in Business Connectivity Services in SharePoint
7/12/2018 • 2 minutes to read Edit Online

Learn about changes and new features in Business Connectivity Services (BCS) for SharePoint, including enhanced support for REST, OData, external events, and app-scoped external
content types. Business Connectivity Services (BCS) was introduced in SharePoint 2010 as an improvement to the Business Data Catalog created for Office SharePoint Server 2007. BCS
enables SharePoint to access data from external data systems such as SAP, ERP, and CRM, in addition to other data-driven applications that are exposed through Windows Communication
Foundation (WCF) services or Open Data (OData) endpoints.

New features and functionality in Business Connectivity Services in SharePoint


BCS is improved and enhanced for SharePoint, including the new functionality listed in Table 1.
Table 1. What's new in BCS

NE W FE ATU R E FO R MO R E INFO R MATIO N

SharePoint can now connect to OData sources. Using OData sources with Business Connectivity Services in SharePoint

SharePoint can receive events from external systems. External events and alerts in SharePoint

External content types can now be scoped at the application level. Add-in-scoped external content types in SharePoint

Support for Representational State Transfer (REST) and the client object model is enhanced. Get started using the client object model with external data in SharePoint

See also
Business Connectivity Services in SharePoint
Get started with Business Connectivity Services in SharePoint
Business Connectivity Services programmers reference for SharePoint
Get started with Business Connectivity Services in SharePoint
5/3/2018 • 4 minutes to read Edit Online

Learn the basics of what Business Connectivity Services (BCS) provides to developers of SharePoint solutions, along with how to get started using BCS in various types of solutions.

What is Business Connectivity Services?


Business Connectivity Services (BCS) was introduced in SharePoint Server 2010 as an evolution of the Business Data Catalog released in Office SharePoint Server 2007. BCS enables
SharePoint to work with data that is hosted externally. Possible sources can include databases, web services, Windows Communication Foundation (WCF) services, Open Data Protocol
(OData) sources, and other proprietary data that is accessed by using custom .NET assemblies.

In a dynamic workplace, information workers need access to data that resides in separate software worlds, for example:
Structured data that exists in the organization's enterprise applications, such as enterprise resource planning (ERP) and customer resource management (CRM) applications.
Unstructured data in business productivity applications, such as those in Microsoft Office, in team and collaboration applications such as SharePoint, and in Web 2.0 services such as
Internet applications, wikis, blogs, and social networking sites.
Although most information workers spend much of their work time within the productivity applications (for example, the Microsoft Office environment), they also need a way to integrate
that environment with the enterprise applications and collaboration software and services they use. BCS provides that capability in SharePoint.

Get started with Business Connectivity Services


To get started developing with BCS, you will need the following:
SharePoint
Visual Studio
Office Developer Tools for Visual Studio 2012
or
SharePoint Designer
For information about how to set up your development environment, see Set up a general development environment for SharePoint.

Business Connectivity Services essentials


The following table highlights the core concepts that you will need to be familiar with to start developing BCS solutions.
Table 1. Core concepts for understanding BCS

AR TICLE D ES CR IPTIO N

Entity Data Model Key Concepts The Entity Data Model (EDM) uses three key concepts to describe the structure of data: entity type,
association type, and property. These are the most important concepts in describing the structure of
data in any implementation of the EDM.

Basic Security Practices for Web Applications The topic of creating a secure web application is extensive. It requires study to understand security
vulnerabilities. You also need to become familiar with the security facilities of the Windows operating
system, the .NET Framework, and ASP.NET. Finally, it is essential to understand how to use these security
features to counter threats.

WCF Data Services WCF Data Services, formerly known as ADO.NET Data Services, enable the creation and consumption of
OData services for the web.

Open Data Protocol (OData) OData is an industry standard protocol for accessing data through URLs. It basically sits on top of the
HTTP protocol to provide read and write functions using existing HTTP verbs.

Internet Information Services Internet Information Services (IIS) is the platform that SharePoint runs on. You should understand how
to create websites, virtual directories, web services, URLs, web security, and other technologies related to
IIS.

External content types in SharePoint External content types are descriptions of the external systems that they represent. They are reusable
when imported into SharePoint and can be used to create complex code-free solutions using SharePoint
Designer 2013, Outlook 2013, web parts, external lists, and custom client applications.

Get started using the client object model with external data in SharePoint SharePoint provides the ability to access all objects through a carefully constructed URL. BCS has been
extended to provide this same functionality.

What can you do with Business Connectivity Services?


With BCS, you can bring information into SharePoint from many different sources. For example, you can bring data from an external SQL Server database, a traditional web service, a WCF
service, proprietary systems, and OData services.
Table 2. Basic tasks for working with Business Connectivity Services

TAS K D ES CR IPTIO N

External content types in SharePoint Learn about creating Business Connectivity Services (BCS) external content types.
TAS K D ES CR IPTIO N

How to: Create an external content type from an OData source in SharePoint Find information that is needed to get started creating external content types based on OData sources
and using that data in SharePoint or Office components.

How to: Create external event receivers Learn the concepts behind creating event receivers that can be attached to external lists and will execute
when the external data that the list represents is updated.

How to: Create an add-in-scoped external content type in SharePoint Learn how to create external content types that are installed or scoped at the app level, enabling
developers to create data-rich apps using external data sources.

How to: Use the client code library to access external data in SharePoint Learn how to use the SharePoint client object model to work with BCS in SharePoint.

Beyond the basics: Learn more about Business Connectivity Services


When you master the basic concepts of BCS, you can use the more advanced features to build many powerful types of solutions.
Table 3. Advanced concepts in BCS

TO PIC D ES CR IPTIO N

How to: Create an OData data service for use as a BCS external system Learn how to create an Internet-addressable WCF service that uses OData to send notifications to
SharePoint when the underlying data changes. These notifications are used to trigger events that are
attached to external lists.

BDC model schema reference for SharePoint Find reference documentation for the schema of the BDC model.

BCS client object model reference for SharePoint Get a summary of the objects that are available for creating client-side scripts using the SharePoint client
object model to access external data exposed by Business Connectivity Services (BCS).

BCS REST API reference for SharePoint Find reference information for constructing Representational State Transfer (REST) URIs used for accessing
and manipulating OData sources.

See also
Business Connectivity Services in SharePoint
Open Data Protocol website
External content types in SharePoint
Using OData sources with Business Connectivity Services in SharePoint
External events and alerts in SharePoint
Add-in-scoped external content types in SharePoint
Get started using the client object model with external data in SharePoint
Setting up a development environment for BCS in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn about setting up a development environment for developing SharePoint solutions and SharePoint Add-ins using Business Connectivity Services (BCS). You can create SharePoint
solutions and SharePoint Add-ins by using BCS on a client computer or on a server computer, depending on the type of solution you are building.

Building server-based solutions and SharePoint Add-ins


Typically, the majority of BCS solutions and apps will be hosted in a server environment. These server solutions and apps provide the greatest amount of flexibility with all of the features of
BCS in SharePoint.
For server-based solutions, it is usually best to develop the solution on a local computer where SharePoint is installed and then, when the solution is built and tested, deploy it to the
production server. You can install a development environment on either a host workstation or on one or more virtual computers that are running Windows Server 2008 Service Pack 2.

Setting up an environment to build SharePoint Add-ins


The environment that you use for developing apps with BCS is the same as for developing any SharePoint Add-in.
To learn how to install the components of a development environment, including the operating system, SharePoint, Visual Studio 2012, and Office Developer Tools for Visual Studio 2012,
follow the instructions in Set up a general development environment for SharePoint.

Building client-based solutions


Client-based solutions enable Office 2013 client applications to access the same external data that a SharePoint solution or SharePoint Add-in can. You can do this by implementing code
using the BCS Client Cache. The client components communicate with BCS through client-side code and the client cache. This provides Office client applications with the rich data that is
available to SharePoint through external content types.
Because these solutions don't require code, you can use SharePoint Designer 2013 and Office 2013.

See also
Set up an on-premises development environment for SharePoint Add-ins
Get started with Business Connectivity Services in SharePoint
Business Connectivity Services in SharePoint
SharePoint development overview
External content types in SharePoint
5/3/2018 • 5 minutes to read Edit Online

Learn what you can do with external content types and what you need to start creating them in SharePoint.

What is an external content type?


The external content type is a core concept of Business Connectivity Services (BCS). Used throughout the functionality and services offered by BCS, external content types are reusable
metadata descriptions of connectivity information and data definitions plus the behaviors you want to apply to a certain category of external data.
External content types enable you to manage and reuse the metadata and behaviors of a business entity, such as a customer or order from a central location, and enable users to interact with
that external data and processes in a more meaningful way.
The following are some of the benefits of using external content types:
Provide reusability: An external content type is a reusable data definition of a business entity. After you create it, you can use it with any of the presentation features in BCS to
provide a rich user experience to interact with external data.
Encapsulate complexities of external systems: External content types enable information workers to assemble business solutions without having to handle the complexities of the
external systems, such as connectivity information and code interfaces. After someone creates an external content type, it is available to users for use in any way they need (provided
they have the permissions to perform that operation and access the external data). However, the user does not need to know anything about the location of the external data or how to
connect to it.
Provide built-in Office and SharePoint behavior: External content types provide Office item-type behaviors (such as Contacts, Tasks, Calendars in Outlook, documents in Word,
and lists in SharePoint Workspace); SharePoint behaviors (such as lists, web parts, and profile pages); and capabilities (such as the ability to search or work offline) to external data and
services. So users can work in their familiar work environments without having to hunt for data or learn and interact with different (and proprietary) user interfaces.
Help provide more secure access: External content types adhere to the security put in place by both the external system and SharePoint. You can have full control of who accesses
what data by configuring security in SharePoint.
Simplify maintenance: Because external content types can be created once and used by multiple solutions in various scenarios, you can manage them easily. For example, you can
manage their access permissions and connection and data definitions in one central location.
Enable external data search: You can use SharePoint Server search from an intranet portal to look up information about a specific external content type, such as a customer.
SharePoint Server search retrieves the data directly from the external system. Consequently, users can get the information they need without having to get approval or install a
separate application.
Enable working offline: You can take external content types offline in Outlook 2013. Business Connectivity Services (BCS) provides rich cache and offline work features and
supports cache-based operations. Users can manipulate external data seamlessly and efficiently, even when they are offline or if the server connectivity is slow, intermittent, or
unavailable. The read/write operations performed against cached business entities are synchronized when a connection to the server becomes available.

Prerequisites for working with BCS external content types


To get started creating external content types, you will need the following:
SharePoint
Visual Studio 2012
Office Developer Tools for Visual Studio 2012
or
SharePoint Designer 2013
To set up a development environment for creating external content types, see Set up a general development environment for SharePoint.

What can you do with external content types?


When SharePoint is configured to communicate with the external system, you can use the external content types to create the following objects to present the underlying data:
External lists
An external list enables access to data from external systems in the same way that SharePoint list data is accessed. External lists use external content types as their data sources.
External lists enable you to use the metadata that is already defined about an external content type to create a SharePoint list that has external data that looks and performs like any
other SharePoint list.
You can also take external lists offline to be used in Outlook 2013. This allows you to work with external data just like native Outlook Item types, such as Contacts, Tasks, and Posts, and
use the external data in Office client applications.
External lists enable writing back to the external system if the external system allows it, and if it is modeled accordingly by the external content type. This implies that users can edit
external data directly from within. Any changes that were made to the items in the list are synchronized automatically with the external system. Also by using the Refresh data button
in the list, you can synchronize and get updated data from the external system automatically.
External Data Columns
The external data column enables users to add data from external content types to standard SharePoint lists. Just like an external list, external data columns can display data from any
external content type that is modeled in Business Connectivity Services (BCS).
Business Data web parts
SharePoint provides five different web parts for working with external data: Business Data List, Business Data Item, Business Data Item Builder, Business Data Related List, and
Business Data Actions.
External Content Type Picker
An External Content Type Picker provides picking and resolving functionality to the user. You can embed a picker in a form or page for scenarios where a user should be able to choose
an external content type from the list of available external content types.
External Item Picker
An External Item Picker provides picking and resolving functionality for external items on the server and in rich-client Office applications. You can embed a picker in a form or page for
scenarios where a user should be able to pick an external item, such as a customer from a list of customers.
Profile Pages
Profile Pages are SharePoint pages in SharePoint that display the details about an external item. Just like any other SharePoint web parts page, you can customize this page to show
details of an external item.
Custom pages and applications
You can use the SharePoint programmability options, such as the SharePoint object model, client object model, and Representational State Transfer (REST) URLs.
Table 1 contains examples of tasks that illustrate working with external content types.
Table 1. Basic tasks for working with external content types

TAS K D ES CR IPTIO N

How to: Create an external content type from an OData source in SharePoint Learn how to use Visual Studio 2012 to discover a published OData source, and create a reusable
external content type for use in SharePoint Business Connectivity Services (BCS).

How to: Create external content types for SQL Server in SharePoint Learn how to create an external content type based on a SQL Server database.

See also
Business Connectivity Services in SharePoint
How to: Create an add-in-scoped external content type in SharePoint
How to: Create external content types for SQL Server in SharePoint
Get started with Business Connectivity Services in SharePoint
What's new in Business Connectivity Services in SharePoint
Create external content types for SQL Server in SharePoint
3/26/2018 • 15 minutes to read Edit Online

Learn how to create an external content type for SQL Server in SharePoint.
Creating an external content type is a pivotal task when you are working with external data. An external content type contains important information about connections, access, methods of
operation, columns, filters, and other metadata that is used to retrieve the data from the external data source.

Before you begin


Working with external data requires several prerequisite tasks to enable secure access to the data. The following information can help you plan your next steps. Also, if you have problems
trying to work with external data, this information can help you identify the issue. To access external data, you or an administrator must do the following:
Prepare SQL Server A database administrator needs to provide permissions to make sure that that the right people have access to the data and that the data does not end up in the wrong
hands. The database administrator must also create a SQL Server account that has db_owner permission. The database administrator might also want to create specific tables, views, queries,
column aliases, and so on to limit the results to just what is needed and to help improve performance.
Configure SharePoint services An administrator must activate Business Connectivity Services (BCS) and the Secure Store Service.
Configure the Secure Store service An administrator must determine the best access mode for the external data source, create a target application, and set the credentials for the target
application.
Configure Business Data Connectivity Services An administrator must make sure that the user who creates the external content type has permission to the Business Data Connectivity
(BDC) metadata store and that appropriate users have access to the external content type on which the external list is based.
Be sure Office 2013 is ready to use To synchronize external data with Office 2013 products, you must use Windows 7 or a later version, and make sure that the Office installation option
for Business Connectivity Services (BCS) is enabled (this is the default). This option installs the Business Connectivity Services Client Runtime which does the following: caches and
synchronizes with external data, maps business data to external content types, displays the external item picker in Office products, and runs custom solutions inside Office products. You must
also have SQL Server Compact 4.0, .NET Framework 4, and WCF Data Services 5.0 for OData V3 on each client computer (If necessary, you are automatically prompted to download the
software).

Define general information


1. Start Microsoft SharePoint Designer 2013.
2. Click Open Site, and then enter the appropriate site name.
3. In the Navigation pane, under Site Objects, select External Content Types.
NOTE

SharePoint Designer 2013 groups external content types by the namespace in the initial window of the External Content Type Designer.
4. To open the External Content Type Designer, on the ribbon, click External Content Type.
5. On the New External Content Type page, do the following:
Next to Name, click New external content type, and then enter a unique name for the external content type.
Next to Display Name, enter a different name if you want a more descriptive display name.

Define general and Office behaviors


1. In the Office Item Type drop-down list, select one of the following:
Generic List Select this option for any type of list.
Appointment, Contact, Task, or Post Select this option if you are creating a list that behaves like an Outlook Contact, Task, Appointment, or Post item. The Office item type that you
select here determines the Outlook behavior that you want to attach to the external content type. For example, a Customer external content type behaves as a native Contact Item in
Outlook.
1. In the Offline Sync for External List check box, make sure Enabled is selected, which is the default.
NOTE

If you disable this option, then the SharePoint Connect to Outlook command is not available for an external list.
NOTE

The Farm and Site feature, Offline Synchronization for External Lists, must also be active. This feature is active by default at the Farm level, but not active by default at the site level.

Create a connection to the external data


1. To specify the SQL Server database for the external content type, click Click here to discover external data sources and define operations.
2. Click Add Connection, select SQL Server in the External Data Source Type Selection dialog box, and then click OK.
3. In the SQL Server Connection dialog box, enter the name of the server, the database name, an optional description, and then click OK.
4. To choose an authentication mode, select one of the following:
Connect with User's Identity Uses the Pass-through authentication mode.
Connect with Impersonated Windows Identity Uses the WindowsCredentials authentication mode.
Connect with Impersonated Custom Identity Uses the RDBCredentials authentication mode.
1. In the Secure Store Application ID box, enter the target application ID name created in the Secure Store Service.
2. Click OK.
SharePoint Designer 2013 validates and tests the connection information. If you see messages, you must resolve them before you continue.
Select a table, view, or routine
1. In the Data Source Explorer, expand the database to view the tables, views, and routines that it contains.
2. Select a table, view, or routine.

Define operations
1. In the Data Source Explorer, right-click the table, view, or routine, and then select one of the following:
Create All Operations Defines a create item, delete item, read item, read list, and update item operation.
NOTE

Create All Operations is available only for tables and views. Routines require specific operations.
New Read Item Operation Defines a read item operation.
New Read List Operation Defines a read list operation.
New Update Operation Defines an update item operation.
New Delete Read Defines a delete item operation.
Refresh Refreshes the list of tables, views, and routines in the Data Source Explorer.
1. Click Next.
NOTE

On views that span multiple tables, make sure that that write operations are supported. Otherwise, Create All Operations or New Update Operation might fail.
Always define at least a New Read Item Operation and New Read List Operation because SharePoint features, such as external lists, rely on these operations.
Choose specific operations, instead of Create All Operations, when the table or view does not support certain operations.

Add columns
1. To specify the columns that you want to display from the table or view, click Next.
2. In the Parameters Configuration dialog box, by default all columns (known as Data Source Elements) are selected. To remove unnecessary columns, clear the corresponding check
boxes.
NOTE

Unlike a native SharePoint list, you cannot change the column name of an external list. Consider using an SQL column alias to provide a more meaningful name or a shorter name.
3. To select an identifier field, click and highlight a field (typically a unique-valued field), and then under Properties, click Map to Identifier.
IM P O R T A N T

To prevent specific fields from being updated, such as an ID or primary key field, clear the Required check box, but select the Read-Only check box, which is needed to retrieve items so you
can update other fields.
 T IP

Always carefully read the messages in the Errors and Warnings pane. They provide useful information to confirm your actions or troubleshoot any issues. Periodically click the Errors and
Warnings pane and make sure that there are no more errors or warnings.

Map Outlook fields


If your external content type maps to an Outlook item type, you must map one or more fields from your external content type to the Outlook item fields. When you map an external content
type, such as a Customer, to an Outlook item type, such as a Contact, you must explicitly map the individual fields in the external content type, such as Customer First Name, Customer Last
Name, Customer Address, and Customer Phone, to their respective Outlook item type fields, such as a contact's FirstName, LastName, BusinessAddress, and BusinessPhone.
For the each field, do the following:
1. Click and highlight the field.
2. Under Properties, next to Office property, click the down arrow. and then select the appropriate matching field.
NOTE

You do not need to map all the corresponding fields. However, the fields shown in the following table must be mapped.
Table: Outlook item type mapped to Outlook item field

O U TLO O K ITEM T YPE O U TLO O K ITEM FIELD

Contact LastName

Task Subject

Appointment Start, End, and Subject

Post Subject

Unmapped fields, depending on the number, are displayed as extended properties as follows:
Adjoining Appended to the form region at the bottom of an Outlook form's default page (two to five fields).
Separate Added as a new page to an Outlook form (six or more fields).

Set up the external item picker control


The external item picker control allows users to select a field, such as an ID field or a field that has unique values, to conveniently choose an item. This control is available in SharePoint and
Office 2013 products. For example, users can use this control to choose an item from an external list of customers and Word 2013 enables this control for use with content controls that are
linked to external data columns.It's a good idea to select the specific columns you want to display in the external item picker control because the default operation is to show all the columns,
which in most cases, is not necessary.
1. For each field that you want displayed in the external content item picker, click and highlight the field, and then under Properties, click the Show in Picker check box.
2. Click Next.
NOTE

All filters that you define are displayed in the external item picker control. Although you cannot remove specific filters from the external item picker control, you can define a default filter by
clicking Is Default in the Filter configuration dialog box when you are creating or modifying the filter.

Define filters
If you do not define a filter, an external list returns all of the data up to the Business Connectivity Services (BCS) throttle limit (by default, 2,000 items) or all the data that is defined in the
external content type, if less than the current throttle limit. In addition, the entire processing of the results occurs within the SharePoint product. It's a good idea to define at least one filter. In
general, there are two types of filters that you need to be aware:
Data Source Filter When you create an external content type filter, which is known as a Data Source Filter, the filter operation occurs within the SQL Server database. This is
important when you are working with lots of data because you can offload processing from SharePoint products to the external database and gain performance improvements. After
you create the external list, you can use the Data Source Filter by creating a view that specifies different filter values in the Data Source Filter section of the List View settings page.
SharePoint filter Users can still filter the data by using a SharePoint filter, either the column header filter or by using the Filters section in the List View settings page. In this case,
the filter operation occurs within the SharePoint product, not within the SQL Server database.
A good strategy to consider is to create a set of external list views based on specific Data Source Filters that make sure that larger amounts of data are filtered first in the external data source,
and then users can further filter and refine the results by using SharePoint filters.
You can create several different types of filters. For each filter that you create, do the following:
1. Under Properties, next to Data Source Element, select a field.
2. Under Properties, next to Filter, click Click to Add to display the Filter Configuration dialog box.
3. Click Add Filter Parameter.
4. In the New Filter box, enter a filter name.
5. In the Filter Type box, select a filter type:
Comparisons

A Comparison filter limits what items are returned based on a condition (such as State = "New Jersey") and is converted to an SQL WHERE clause.

1. In the Filter Type box, select Comparison.


2. In the Operator box, select an operation.
3. In the Filter Field box, make sure that the field that you want to compare is selected.
4. If you want values entered by the user to match by case, click Case Sensitive.
5. If you want to display a list of possible matches ??n the external item picker control when there is more than one matching item, select Use to create match list in external item
picker.
6. Click OK.
7. Under Properties, next to Default Value, enter the initial value that you want to filter by, if the user does not enter a value. If you do not enter a value, the external list does not
display any items.
Wildcards

A Wildcard filter limits what items are returned based on a user-entered string value (such as State Contains "New") and is converted to an SQL LIKE clause. Valid SQL Server wildcard characters a

1. In the Filter Type box, select Wildcard.


2. In the Filter Field box, select a field.
3. If you want values entered by the user to match by case, click Case Sensitive.
4. If you want to display a list of possible matches ??n the external item picker control when there is more than one matching item, select Use to create match list in external item
picker.
5. Click OK.
6. Under Properties, next to Default Value, enter the initial value that you want to filter by, if the user does not enter a value. If you do not enter a value, the external list does not
display any items. It's a good idea to enter an * (asterisk) as the default.
Limit

In most cases, you must define a Limit Filter for Read and Read List operations. If you do not define a **Default Limit** value, no data is retrieved from the external data source. Ensure that th

1. In the Filter Type box, select Limit.


2. In the Number box, enter a number.
3. If you want to display a list of possible matches ??n the external item picker control when there is more than one matching item, select Use to create match list in external item
picker.
4. Under Properties, next to Default Value, enter the initial value that you want to filter by, if the user does not enter a value. If you do not enter a value, the external list does not
display any items.
5. Click OK.
NOTE
The SQL Server database administrator might want to create specific tables, views, indexes, and optimized queries to limit the results to just what is needed and to help improve
performance.
Page Number

Use the external content type Page Number to supersede the SharePoint page limit defined in the **List View** page of the external list. Here's the difference:

The external content type Page Number first processes the results within the SQL Server database, and then returns and displays only the number of rows determined by the Page
Size value.
The SharePoint page limit returns all the rows up to the Default Value size from the SQL Server database, and then displays the number of rows determined by the SharePoint page
limit value in the List View settings page.

Using the external content type Page Number is generally more efficient. In addition, the **Order** value helps make sure that an accurate display of the results returned.

1. In the Filter Type box, select Page Number.


2. In the Page Size box, enter a number.
3. In the Order box, select a sort direction.
4. Click OK.
5. Under Properties, next to Default Value, enter the initial value that you want to filter by, if the user does not enter a value. If you do not enter a value, the external list does not
display any items.
6. If you want to display but not modify a field, click and highlight the field, and then under Properties, select Read-Only.
7. If you want to make sure that a field always has a value when it's created or modified, click and highlight the field, and then under Properties, select Required.
8. To provide a descriptive name in the external item picker control of the Data Source Element name, which is derived from the SQL Server column name, click and highlight the field,
and then under Properties, in the Display Name box, enter a name.
9. To define a default value for the filter (which also displays in the Data Source Filter section of the List View settings page), under Filter Parameters, click and highlight the filter, and
then in the Default Value box, enter an appropriate value. If you do not enter a value, then when that filter is used for the first time, no items are displayed.

Set the Title field for an external list


1. On the ribbon, click Summary View.
2. In the Fields section, under Field Name, select a field.

Important: In general, it's a good idea to make the Title a field that has a unique value. The Title field is used to display list or InfoPath forms. Once you set the Title field, you
cannot change it.

3. On the ribbon, click Set as Title.

Complete the external content type


On the Quick Access Toolbar, click Save. This stores the external content type definition in the Business Data Connectivity metadata store.
NOTE

To provide better performance, Business Data Connectivity caches all the objects in the metadata store and updates changes by using a timer job that runs every minute. It might take up to
one minute for changes to propagate to all the servers in the farm, but changes are immediate on the server where you make the change.
The external content type is now available for use in SharePoint and Office 2013 products.

See also
External content types in SharePoint
Deploy a Business Connectivity Services on-premises solution in SharePoint
Using OData sources with Business Connectivity Services in SharePoint
Configure the Secure Store Service in SharePoint
Create associations in SharePoint
3/26/2018 • 2 minutes to read Edit Online

An association is a way to create a relationship between external data entities. You create an association between two external content types so that you can join the data together over
foreign keys. For example, while viewing a customer profile, you might want to see the latest orders placed by that customer and the items in each order.

Basic tasks for working with associations


The following articles were written for SharePoint Server 2010 and SharePoint Designer 2010. The content is still appropriate for SharePoint and SharePoint Designer 2013, although there
might be some variations in the user interface.

TAS K D ES CR IPTIO N

Adding Associations Between External Content Types Provides overview information about associations.

Tooling Associations in SharePoint Designer (BCS Team Blog) Explains the concepts behind associations and contains two demos.

Creating SharePoint Server External Content Type Associations with SharePoint Designer Shows how to create associations between external content types in SharePoint Designer without using
code.

Defining Associations in Business Connectivity Services Using SharePoint Designer Shows how to create advanced associations between external content types.

See also
External content types in SharePoint
Business Connectivity Services in SharePoint
Add-in-scoped external content types in SharePoint
3/26/2018 • 4 minutes to read Edit Online

Learn about external content types that are installed or scoped at the add-in level in SharePoint and enable you to create data-rich SharePoint Add-ins using external data sources.

Overview of add-in-scoped external content types in SharePoint


In SharePoint 2010, you can install and use external content types only at the farm level. This often causes problems for developers because even for simple applications, an administrator
had to be involved because of the access rights that are needed to install at the farm level.
In SharePoint, applications are basically isolated into more autonomous units called add-ins. Add-ins contain all the resources they need to run. This approach enables a running application
to be insulated from other applications. The benefits of this architecture are as follows:
You can create add-ins that are aligned with the new application model of SharePoint.
You can create add-ins that access external data from SAP, Netflix, and proprietary and other types of data without involving the tenant administrator.
Access to external applications is maintained through Business Connectivity Services (BCS), which provides a consistent and uniform interface that can be used by other SharePoint
applications.
Add-in-scoped external content types provide access to external data within an app.

Prerequisites for working with add-in-scoped external content types


The following are the requirements for developing external content types that are scoped at the add-in level:
Visual Studio 2012
Office Developer Tools for Visual Studio 2012
SharePoint
For information about setting up your SharePoint development environment, see Set up a general development environment for SharePoint.

Add-in-scoped external content type essentials


Table 1 contains some core concepts that you should be familiar with when working with add-in-scoped external content types.
Table 1. Core concepts for understanding add-in-scoped external content types

AR TICLE D ES CR IPTIO N

External content types in SharePoint Learn how to create BCS external content types.

SharePoint Add-ins Learn about the new add-in model in SharePoint that enables you to create add-ins, which are small,
easy-to-use solutions for end users.

Get started creating SharePoint-hosted SharePoint Add-ins Learn how to create a basic SharePoint-hosted add-in by using the Office Developer Tools for Visual
Studio 2012.

What can you do with add-in-scoped external content types?


The primary reason for adding an add-in-scoped external content type is to provide access to external data from an individual add-in. This allows you to do the following:
Limit access to external content types to a particular app.
Deploy external content types within an app.

Create add-in-scoped external content types


The concept of a file-based metadata catalog was introduced in SharePoint 2010. It enables you to specify a file that contains the XML needed to define external content types. This file can be
deployed within a WSP package and pertains only to the application that it is scoped for. By using this metadata file, external content types can be restricted to the add-in level.
In SharePoint, SPListDataSource has been modified to add a property that indicates the scope of the application.
This class serves as the bridge between SPList and an external list. Use the associated SPList to retrieve entity fields and data. Retrieve an instance of SPListDataSource from the
HasExternalDataSource property. When HasExternalDataSource is not null, the SPList object's data is external to SharePoint.
When you want to add an add-in-scoped external content type, this property is set to Add-in.
The MetadataCatalogFileName property is used to define the BDC model file that contains the external content type definition. This property can be defined declaratively or
programmatically, but not in the SharePoint user interface (UI).
The following example shows how to set the MetadataCatalogFileName property declaratively.

<DataSource>
<Property Name="Entity" Value="Customer" />
<Property Name="EntityNamespace" Value="SAP" />
<Property Name="LobSystemInstanceName" Value="SAPClient1" />
<Property Name="SpecificFinder" Value="ReadCustomer" />
<Property Name=" MetadataCatalogFileName" Value="BDCMetadata.bdcm" />
</DataSource>

NOTE

Site administrators can install add-ins that use App-Scoped-ECTs, but only SiteCollection administrators can grant permissions for Apps to Use BCS Connections.

Deploy an add-in-scoped external content type in a custom Feature in a WSP file


You can include a BDC model in a WSP file for deployment. The following example shows how to include a BDC model in the app.

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<BdcModel Path="BDCMetadata.bdcm">
</BdcModel>
</Elements>

IM P O R T A N T

Only one BDC model file can be included per add-in. While the file name in this example is BDCMetadata.bdcm, the model file can actually be any name you choose as long as the file name
matches that is in the Path attribute of the BDC model file.
NOTE

Only Open Data protocol (OData) connections are allowed for add-in-scoped external content types.

Set security credentials for an external system


In order to access data on a secured external system, you must configure the BDC model with the appropriate credentials.
The following example shows how to set security credentials for an external system in add-in-scoped external content types by modifying the Elements.xml file of the app.

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<BdcModel Path="BDCMetadata.bdcm">
<LobSystem Name="SAP">
<LobSystemInstance Name="SAPInst" RequireCredentials="true" CredentialsDescription="Credentials to connect to SAP"/>
</LobSystem>
<LobSystem Name="SQL">
<LobSystemInstance Name="App Database" DataSource="SQL-Azure" RequireCredentials="true" />
</LobSystem>
</BdcModel>
</Elements>

In this section
How to: Create an add-in-scoped external content type in SharePoint
How to: Access external data with REST in SharePoint

See also
Business Connectivity Services in SharePoint
Business Connectivity Services programmers reference for SharePoint
SharePoint Add-ins
External content types in SharePoint
External events and alerts in SharePoint
What's new in Business Connectivity Services in SharePoint
Get started with Business Connectivity Services in SharePoint
Create an add-in-scoped external content type in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn how to create external content types that can be installed, secured, and used in an SharePoint Add-in.

Prerequisites for developing add-in-scoped external content types


To get started developing add-in-scoped external content types, you need the following:
SharePoint
Visual Studio 2012
Office Developer Tools for Visual Studio 2012
A published OData service available through the Internet
For information about setting up a SharePoint development environment, see Set up a general development environment for SharePoint.

Create an add-in-scoped external content type


The following steps show how to create an external content type based on an Open Data protocol (OData) source, and how to modify it to be scoped to your SharePoint Add-in.

To create a new SharePoint Add-in


1. Open Visual Studio 2012.
2. Create an Add-in for SharePoint project.
3. Specify the add-in settings, including add-in name, the site URL for debugging the add-in, and how you would like to host the add-in (Autohosted, Provider-hosted, or SharePoint-
hosted). For more information, see Choose patterns for developing and hosting your SharePoint Add-in.
4. Choose Finish to create the app.
For complete steps for creating SharePoint Add-ins, see the following:
Get started creating provider-hosted SharePoint Add-ins
How to: Create a basic autohosted app for SharePoint
Get started creating SharePoint-hosted SharePoint Add-ins

To generate the external content type


1. In Solution Explorer, open the shortcut menu for the project, and choose Add, Content types for External Data source.
This starts a wizard that helps you find the selected data source and create the BDC model.
2. On the Set OData Source page, enter the URL of the OData service that you want to connect to. The URL should look something like this:
http://services.odata.org/Northwind/Northwind.svc/ .

Specify a name for your OData source.


NOTE

For this example, you will use the Northwind service that is available from the producers list located on the Open Data Protocol website.
3. A list appears showing data entities that are being exposed by the OData Service. Select one or more of the entities, and choose Finish.

To deploy the add-in-scoped external content type


Press F5 to compile the project and upload the project files to SharePoint.

See also
Add-in-scoped external content types in SharePoint
Choose patterns for developing and hosting your SharePoint Add-in
SharePoint Add-ins
External content types in SharePoint
Get started with Business Connectivity Services in SharePoint
Business Connectivity Services in SharePoint
Convert an add-in-scoped external content type to tenant-scoped
3/26/2018 • 2 minutes to read Edit Online

Learn how to create an OData-based external content type using Visual Studio 2012 auto-generation tools and import it into the Business Connectivity Services (BCS) metadata store so
that it can be used across an entire tenant workspace. BDC models are complex XML definitions of an external data source. They are used when defining external content types for BCS. They
are very difficult to build manually, so tools have been built to automatically generate the files using Visual Studio 2012 and Office Developer Tools for Visual Studio 2012. Using these tools,
you can create an .app package using Visual Studio publishing, and then open that package to extract the model file.

Extract the BDC model file from a Visual Studio add-in package
The following steps show you how to create the OData-based external content type and then import it into the BCS metadata store so that it can be used across an entire tenant workspace.

To create a BDC model file from an OData source


1. In Visual Studio 2012, create an Add-in for SharePoint project.
2. Specify the add-in settings, including add-in name, the site URL for debugging the add-in, and how you want to host the add-in ( Autohosted, Provider-hosted, or SharePoint-
hosted). For more information, see Choose patterns for developing and hosting your SharePoint Add-in.
3. Choose Finish to create the app.
4. In Solution Explorer, open the shortcut menu for the project, and choose Add, Content types for External Data source.
This starts a wizard that helps you find the selected data source and create the BDC model.
5. On the Set OData Source page, enter the URL of the OData service that you want to connect to. The URL should look something like this:
http://services.odata.org/Northwind/Northwind.svc/ .

Specify a name for your OData source.


NOTE

For this example, you will use the Northwind service that is available from the producers list located on the Open Data Protocol website.
6. A list appears showing data entities that are being exposed by the OData Service. Select one or more of the entities, and choose Finish.

To deploy the add-in-scoped external content type as an add-in package


1. In Visual Studio, on the Build menu, choose Publish.
2. Name the package, specify the save location on your local hard drive, and choose Finish.

To extract the model file from the .app package


1. Open the folder where the .app package is created.
2. Change the file name extension from.app to.zip.
3. Extract the ZIP package to a local folder.
4. Open the extracted folder to find the WSP file.
5. Move the WSP file to another location.
6. Change the .wsp file name extension on this file to .cab.
7. Open the .cab file, and you will find the Bdcmodel.bdcm file.
8. Save the Bdcmodel.bdcm file to another location.

To import the model file using SharePoint Central Administration pages


1. Open SharePoint Online or SharePoint on-premises Central Administration pages.
2. Choose Manage serve applications.
3. Choose Business Data Connectivity Service.
4. Choose the Import link on the server ribbon.
5. Choose the Browse button to specify the location where you extracted the .bdcm file.
6. Keep the default settings, and then choose Import.

See also
External content types in SharePoint
How to: Create an add-in-scoped external content type in SharePoint
How to: Create an external content type from an OData source in SharePoint
Get started with Business Connectivity Services in SharePoint
Open Data Protocol
Access external data by using REST in SharePoint
3/26/2018 • 4 minutes to read Edit Online

Learn how to access external data from SharePoint by using Representational State Transfer (REST) URLs for Business Connectivity Services (BCS). This article shows how to set up an
external list that retrieves data from an Open Data protocol (OData) source.

Prerequisites for accessing external data using REST


To access external data from SharePoint by using REST, you need the following:
SharePoint
Visual Studio 2012
Office Developer Tools for Visual Studio 2012
A functioning SharePoint Add-ins development environment: Follow the instructions in Set up a general development environment for SharePoint.
Access to the public OData.org producers

Core concepts to know when accessing external data with REST


The SharePoint REST service provides a way to access external data using a specially constructed URL. To understand how it works and how to use it, see the following articles.
Table 1. Core concepts for REST in SharePoint

AR TICLE TITLE D ES CR IPTIO N

Use OData query operations in SharePoint REST requests Learn how to use the SharePoint REST service, which provides a REST programming interface comparable
to the existing client object model.

Get to know the SharePoint REST service Get the basics of using the SharePoint REST service to access and update SharePoint data, using the
REST and OData web protocol standards.

Using the SharePoint REST service Learn how to navigate the SharePoint data structure as it is represented in the REST service, perform
common CRUD (create, read, update, and delete) operations on SharePoint items via the REST service,
synchronize SharePoint items across applications, and control item concurrency.

Create an SharePoint Add-in to access external data using REST


The following procedures guide you through setting up an SharePoint Add-in and configuring a webpage to make requests using REST functions to retrieve data from an external data
source.

To create an SharePoint Add-in


1. Open Visual Studio 2012.
2. Create an App for SharePoint project.
3. Specify the app settings, including app name, the site URL for debugging the app, and how you want to host the app (Autohosted, Provider-hosted, SharePoint-hosted). For more
information about hosting options, see Choose patterns for developing and hosting your SharePoint Add-in.
4. Choose Finish to create the app.

To generate the external content type


1. In Solution Explorer, open the shortcut menu for the project, and choose Add, Content Types for External Data Source.
2. In the Specify OData Source page, enter the URL of the OData service you want to connect to. In this case, use the Northwind OData source published at
http://www.odata.org/ecosystem. Set the URL for the OData service to http://services.odata.org/Northwind/Northwind.svc/ , and provide a name for the data source.
Choose Next.
3. This displays a list of data entities that are being exposed by the OData Service. Select the Customers entity. Ensure that the Create list instances for the selected data entities
(except Service Operations) check box is selected.
4. Choose Finish.

Code example: Add scripts and HTML to the Home.aspx page


At this point, you have an external content type and an external list that will display the data from the Northwind OData source.
The next objective is to modify the default.aspx page that was created when you created your app. You will add a container to hold the results of the query that is executed with the page
loads. By executing the scripts on the page load event, you ensure that the script is executed every time the page is browsed, and the resulting REST calls are made to the Northwind OData
source to add records to the page.

To add the container to the Default.aspx page


1. In Solution Explorer, open the Default.aspx page in the Pages module.
2. Add the following div element to the page.

<div id="displayDiv"></div>

1. Save the page.


Finally, you add code to the App.js file that executes when the page loads.
To modify the App.js file to make REST calls
1. Open the App.js file in the Scripts module of your SharePoint project.
2. Paste the following code at the end of the file.

$(document).ready(function () {

// Namespace
window.AppLevelECT = window.AppLevelECT || {};

// Constructor
AppLevelECT.Grid = function (hostElement, surlWeb) {
this.hostElement = hostElement;
if (surlWeb.length > 0 &amp;&amp; surlWeb.substring(surlWeb.length - 1, surlWeb.length) != "/")
surlWeb += "/";
this.surlWeb = surlWeb;
}

// Prototype
AppLevelECT.Grid.prototype = {

init: function () {

$.ajax({
url: this.surlWeb + "_api/lists/getbytitle('Customer')/items?$select=BdcIdentity,CustomerID,ContactName",
headers: {
"accept": "application/json",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: this.showItems
});
},

showItems: function (data) {


var items = [];

items.push("<table>");
items.push('<tr><td>Customer ID</td><td>Customer Name</td></tr>');

$.each(data.d.results, function (key, val) {


items.push('<tr id="' + val.BdcIdentity + '"><td>' +
val.CustomerID + '</td><td>' +
val.ContactName + '</td></tr>');
});

items.push("</table>");

$("#displayDiv").html(items.join(''));
}
}

ExecuteOrDelayUntilScriptLoaded(getCustomers, "sp.js");
});

function getCustomers() {
var grid = new AppLevelECT.Grid($("#displayDiv"), _spPageContextInfo.webServerRelativeUrl);
grid.init();
}

Press F5 to deploy the app to SharePoint. Browse to the Default.aspx page in the app, and a list of customers appears on the page.

See also
Business Connectivity Services in SharePoint
Get to know the SharePoint REST service
Using the SharePoint REST service
Add-in-scoped external content types in SharePoint
What's new in Business Connectivity Services in SharePoint
Using OData sources with Business Connectivity Services in SharePoint
5/11/2018 • 2 minutes to read Edit Online

Learn how to get started creating external content types based on OData sources and using that data in SharePoint or Office 2013 components.

OData and the OData connector


The Open Data protocol (OData) lets you access a data source, such as a database, by browsing to a specially constructed URL. This allows for a simplified approach for connecting to and
working with data sources that are hosted within an organization.
OData is a protocol that uses HTTP, Atom, and JavaScript Object Notation (JSON) to enable developers to write applications that communicate with an ever-growing number of data
sources. Microsoft supports the creation of this standard as a way to enable the exchange of data between applications and data stores that can be accessed from the web.
The new OData connector enables SharePoint to communicate with OData providers.
In SharePoint, Business Connectivity Services (BCS) can communicate with OData sources, or producers, without having to code directly to the OData source. Producers expose their data in
a structured way via a web service. Some producers may allow updating of the underlying data, and some may allow only read access. For purposes of advertising what operations are
available, the producer has a service document found at a specified URL endpoint. SharePoint is already a producer of OData. SharePoint list data is exposed as an OData source for any
consumer that has the appropriate rights.

Examples of OData producers


The following are some examples of implementations of OData. These applications and services expose their data through the OData protocol.
SharePoint Foundation 2010
SharePoint Server 2010
SQL Azure
Microsoft Azure Table storage
Microsoft Azure Marketplace
SQL Server Reporting Services
Microsoft Dynamics CRM 2011
Windows Live
For a list of producers of OData services, see the Open Data Protocol website.

Prerequisites for working with the BCS OData connector


To develop OData-based external content types, you will need the following:
Visual Studio 2012
SharePoint
Office Developer Tools for Visual Studio 2012
For information about how to set up your development environment, see Set up a general development environment for SharePoint.

Creating external content types for OData data sources


For SharePoint to use the data exposed by a specific OData producer, an external content type must be created inside SharePoint. As with all SharePoint external content types, it contains all
the connectivity information that is needed to connect and communicate with the external system.
Creating an external content type that uses an OData data source is similar to creating any external content type. You can use Visual Studio 2012 to automatically generate OData external
content types. You merely provide the Representational State Transfer (REST) endpoint of the OData source when you create the external content type. For more information see How to:
Create an external content type from an OData source in SharePoint.

In this section
How to: Create an external content type from an OData source in SharePoint
How to: Create an OData data service for use as a BCS external system
How to: Create an external list using an OData data source in SharePoint

See also
Business Connectivity Services in SharePoint
External content types in SharePoint
What's new in Business Connectivity Services in SharePoint
Business Connectivity Services programmers reference for SharePoint
Create an external content type from an OData source in SharePoint
5/3/2018 • 3 minutes to read Edit Online

Learn how to use Visual Studio 2012 to discover a published OData source and create a reusable external content type for use in Business Connectivity Services (BCS) in SharePoint.

Prerequisites for creating OData-based external content types


To create an external content type from an Open Data protocol (OData) source, you will need the following:
An instance of SharePoint
Visual Studio 2012
Office Developer Tools for Visual Studio 2012
A published OData service available through the Internet
For information about how to set up your SharePoint development environment, see Set up a general development environment for SharePoint.
NOTE

SharePoint Designer 2013 can't be used to autogenerate BDC models from an OData source. You can use Visual Studio 2012 instead.

Core concepts for working with OData external content types


The following articles provide background information about OData and the OData connector in SharePoint.
Table 1. Core concepts for OData external content types

AR TICLE TITLE D ES CR IPTIO N

Using OData sources with Business Connectivity Services in SharePoint Get started with creating external content types based on OData sources, and learn how to use that
data in SharePoint or Office components.

External content types in SharePoint Learn about BCS external content types and what you need to start creating them in SharePoint.

Create an OData-based external content type


The following steps show how to use Visual Studio 2012 to create an external content type based on an OData source.

To create a new SharePoint Add-in


1. In Visual Studio 2012, create a new App for SharePoint project, which is located under the SharePoint template node.
2. Name your project, and choose OK.
3. To specify the SharePoint settings, enter a name for your app, and the URL of the SharePoint server you will be debugging against.
4. Choose Finish.
After the project is created, you use the new autogeneration tooling for OData sources and add a BDC model for the OData source to your app.

To add a new BDC model


1. In Solution Explorer, open the shortcut menu for the project, and choose Add, Content types for External Data source.
This starts a wizard that will help you discover the selected data source and create the BDC model.
2. The first page of the wizard is used to collect the URL of the data service. On the Specify OData Source page, enter the URL of the OData service that you want to connect to. The
URL should resemble the following: http://services.odata.org/Northwind/Northwind.svc/ .
NOTE

You will show the Northwind service that is available from the producers list found on the Open Data Protocol website.
3. Choose a name for your OData source, and then choose Next.
4. A list of data entities that are being exposed by the OData Service appears. Select one or more of the entities, and choose Finish.

To view the structure of the entities


Notice that Visual Studio created a new folder named External Content Types. Inside that folder, you will find a subfolder with the name of your new data source. If you further expand
this, you will see an item that represents the entity you selected. To view a graphical list of the entities and their types, open the ect file that you want to view.
You can also view the XML of the entities by opening the ect files in an XML editor.

Use a stream accessor for the OData source


Using the following code, you can access a data stream that the OData connector can use.
/*Invoke Stream Accessor Method */
internal void ExecuteStreamAccessorMethod(IEntityInstance entityInstance, string streamAccessorName)
{
this.Log.Comment("ExecuteStreamAccessorMethod enter");
this.Log.Comment("streamAccesor method" + streamAccessorName);
IStreamableField isf = entityInstance.GetStreamableField(streamAccessorName);
Stream resStream = isf.GetData();
using (BinaryReader reader = new BinaryReader(resStream))
{
using (FileStream fs = File.Create(@"C:\\" + entityInstance.GetIdentity().GetIdentifierValues()[0] + ".jpg"))
{
int bytesRead = 0;
do
{
int nrBytes = 80 * 1000 * 1000;
byte[] streamData = new byte[nrBytes];
bytesRead = reader.Read(streamData, 0, nrBytes);
this.Log.Comment("Total Bytes Read - " + bytesRead);
if (bytesRead > 0)
{
fs.Write(streamData, 0, bytesRead);
}
} while (bytesRead > 0);
}
}
isf.Dispose();
this.Log.Comment("ExecuteStreamAccessorMethod Exit" );
}

Next steps
After you have built an external content type, you can then use it to present data inside SharePoint by using the built-in objects (external lists, Business Data web parts, or custom code).
For more information, see How to: Create an external list using an OData data source in SharePoint.

See also
Using OData sources with Business Connectivity Services in SharePoint
External content types in SharePoint
What's new in Business Connectivity Services in SharePoint
Business Connectivity Services in SharePoint
Create an OData data service for use as a BCS external system
3/26/2018 • 6 minutes to read Edit Online

Learn how to create an Internet-addressable WCF service that uses OData to send notifications to SharePoint when the underlying data changes. These notifications are used to trigger
events that are attached to external lists.
This article describes how to create an ASP.NET Windows Communication Foundation (WCF) Data Service to expose the AdventureWorks 2012 LT sample database. This enables you to
access the data through the Open Data protocol (OData). When access is established through OData, you can configure a Business Connectivity Services (BCS) external content type that will
enable SharePoint to consume the data from the external database. To further enhance this OData source, you can add service contracts to the WCF service that will enable BCS to subscribe
to notifications that indicate that the external data has changed.

Prerequisites for creating the OData service


The following are required to create the OData service in this article:
A server hosting Internet Information Services (IIS)
.NET Framework 3.5 or later
SharePoint
AdventureWorks 20012 LT script
AdventureWorks 2012 LT Data
Visual Studio 2012
Office Developer Tools for Visual Studio 2012
For information about setting up your development environment, see Set up a general development environment for SharePoint.

Core concepts for creating an OData service


Table 1 lists articles that will help you understand the core concepts of building a WCF service using OData and external content.
Table 1. Core concepts for creating an OData service

R ES O U R CE D ES CR IPTIO N

Using OData sources with Business Connectivity Services in SharePoint Provides information to help you start creating external content types based on OData sources and
using that data in SharePoint or Office 2013 components.

How to: Create an external content type from an OData source in SharePoint Learn how to use Visual Studio 2012 to discover a published OData source and create a reusable
external content type to use in BCS in SharePoint.

Open Data Protocol Provides information about the Open Data protocol, including protocol definitions, architectural
information and usage examples.

WCF Data Services Overview WCF Data Services enables creation and consumption of data services for the web or an intranet by
using OData. OData enables you to expose your data as resources that are addressable by URIs.

Developing and Deploying WCF Data Services Provides information about developing and deploying WCF Data Services.

Steps involved in creating the external system


The following steps will need to be completed
Install the AdventureWorks 2012 LT sample database
Create the OData Service
Set access permissions
Test the service
Add capabilities for additional BCS functionality

Installing the sample database


An external system is usually a database and for that reason, this example shows how to use the AdventureWorks 2012 LT sample database to represent a proprietary datasource.
The following steps will

How to create the WCF OData service


Creating a Windows Communication Foundation (WCF) service that can be accessed through the OData protocol is relatively straightforward. Visual Studio 2012 provides several tools for
automatically discovering and modeling the data from various data sources. This allows you to create connections and interfaces to data in SQL Server databases and other types of data
stores that can then be worked with programmatically using an extensive object model.
However, for SharePoint to enable BCS to receive notifications from remote systems when the underlying data has changed, you must modify the WCF service to respond to those changes.

To create a new WCF project


1. In Visual Studio, on the File menu, choose New, Project.
2. In the New Project dialog box, choose the Web template, and then choose ASP.NET Web Application.
3. Enter AdventureWorksService for the project name, and choose OK.
4. In Solution Explorer, open the shortcut menu for the ASP.NET project that you just created, and choose Properties.
5. Select the Web tab, and set the value of the Specific port text box to8008.

To define the data model


1. In Solution Explorer, open the shortcut menu for the ASP.NET project, and choose Add New Item.
2. In the Add New Item dialog box, choose the Data template, and then choose ADO.NET Entity Data Model.
3. For the name of the data model, enter AdventureWorks.edmx.
4. In the Entity Data Model Wizard, choose Generate from Database, and then choose Next.
5. Connect the data model to the database by doing one of the following steps, and then choose Next.
If you do not have a database connection already configured, choose New Connection, and create a new connection.
If you have a database connection already configured to connect to the Northwind database, choose that connection in the list of connections.
On the final page of the wizard, select the check boxes for all tables in the database, and clear the check boxes for views and stored procedures.
1. Choose Finish to close the wizard.

To create the data service


1. In Solution Explorer, open the shortcut menu for your ASP.NET project, and then choose Add New Item.
2. In the Add New Item dialog box, choose WCF Data Service.
3. For the name of the service, enter AdventureWorks.
Visual Studio creates the XML markup and code files for the new service. By default, the code-editor window opens. In Solution Explorer, the service will have the name,
AdventureWorks, with the extension .svc.cs or .svc.vb.
4. Replace the comment /* TODO: put your data source class name here */ in the definition of the class that defines the data service with the type that is the entity container of the data
model, which in this case is AdventureWorksEntities. The class definition should look like the following:

public class AdventureWorks : DataService<AdventureWorksEntities>

By default, when a WCF service is created, it cannot be accessed due to its security configuration. The next step lets you specify who can access it, and what rights they have.

To enable access to data service resources


In the code for the data service, replace the placeholder code in the InitializeService function with the following.

config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);

This enables authorized clients to have read and write access to resources for the specified entity sets.

> [!NOTE]
> Any client that can access the ASP.NET application can also access the resources that are exposed by the data service. In a production data service, to prevent unauthorized access to resources,

For BCS to receive notifications, there must be a mechanism on the back-end data source that will accept a request to be added and removed from notification subscriptions.
The last step in creating the service is to add service operations for the Subscribe and Unsubscribe stereotypes that are defined in the BDC model.

To add service operations for Subscribe and Unsubscribe stereotypes


In the AdventureWorks.cs page, add the following string variable declaration.

public string subscriptionStorePath = @"\\\\[SHARE_NAME]\\SubscriptionStore\\SubscriptionStore.xml";

> [!NOTE]
> This file is an XML file that is updated with the new subscriptions. Access to this file will be made by the server process, so make sure you have granted sufficient rights for this file access

Then add the following two **WebGet** methods to handle the subscriptions.
[WebGet]
public string Subscribe(string deliveryUrl, string eventType)
{
string subscriptionId = Guid.NewGuid().ToString();

XmlDocument subscriptionStore = new XmlDocument();

subscriptionStore.Load(subscriptionStorePath);

// Add a new subscription element.


XmlNode newSubNode = subscriptionStore.CreateElement("Subscription");

// Add subscription ID element to the subscription element.


XmlNode subscriptionIdStart = subscriptionStore.CreateElement("SubscriptionID");
subscriptionIdStart.InnerText = subscriptionId;
newSubNode.AppendChild(subscriptionIdStart);

// Add delivery URL element to the subscription element.


XmlNode deliveryAddressStart = subscriptionStore.CreateElement("DeliveryAddress");
deliveryAddressStart.InnerText = deliveryUrl;
newSubNode.AppendChild(deliveryAddressStart);

// Add event type element to the subscription element.


XmlNode eventTypeStart = subscriptionStore.CreateElement("EventType");
eventTypeStart.InnerText = eventType;
newSubNode.AppendChild(eventTypeStart);

// Add the subscription element to the root element.


subscriptionStore.AppendChild(newSubNode);

subscriptionStore.Save(subscriptionStorePath);

return subscriptionId;
}

[WebGet]
public void Unsubscribe(string subscriptionId)
{
XmlDocument subscriptionStore = new XmlDocument();
subscriptionStore.Load(subscriptionStorePath);

XmlNodeList subscriptions = subscriptionStore.DocumentElement.ChildNodes;


foreach (XmlNode subscription in subscriptions)
{
XmlNodeList subscriptionList = subscription.ChildNodes;
if (subscriptionList.Item(0).InnerText == subscriptionId)
{
subscriptionStore.DocumentElement.RemoveChild(subscription);
break;
}
}

subscriptionStore.Save(subscriptionStorePath);
}

Next steps
To notify SharePoint that changes have been made, you also need to create a service that queries the data source for changes, and then sends notifications to all those subscribed to
notifications.

See also
Business Connectivity Services in SharePoint
Using OData sources with Business Connectivity Services in SharePoint
External content types in SharePoint
External events and alerts in SharePoint
How to: Create an external content type from an OData source in SharePoint
Business Connectivity Services programmers reference for SharePoint
Create an external list using an OData data source in SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn how to create an external list programmatically and bind it to an OData-based external content type in SharePoint. Although a power user or SharePoint administrator will likely create
an external list using SharePoint Designer 2013, a developer will be interested in the ability to create external lists using the tools of their trade, Visual Studio 2012 and the Office Developer
Tools for Visual Studio 2012. This gives them more flexibility to add functionality and to package a solution that includes Business Connectivity Services (BCS) features for later deployment
into one or many host environments.

Prerequisites for creating an external list


The following components are needed to create an external list from an OData source:
Visual Studio 2012
SharePoint
Office Developer Tools for Visual Studio 2012
A published external content type based on an OData source: For instructions, see How to: Create an external content type from an OData source in SharePoint.
For information about setting up a SharePoint development environment, see Set up a general development environment for SharePoint.

Core concepts for creating external lists


The following articles provide information about SharePoint Add-ins and other background information for creating external lists.
Table 1. Core concepts for external lists

AR TICLE TITLE D ES CR IPTIO N

Get started with Business Connectivity Services in SharePoint Learn about Business Connectivity Services and how you can expose external data in SharePoint.

SharePoint Add-ins Learn about the new app model in SharePoint that enables you to create apps, which are small, easy-to-
use solutions for end users.

Choose patterns for developing and hosting your SharePoint Add-in Learn about the different ways that you can host SharePoint Add-ins.

Create a new external list


The following procedures will show you how to create a new external list, bind it to OData-based external content type, and publish to SharePoint using Visual Studio 2012.
NOTE

The first step assumes that you have successfully created an external content type, as described in How to: Create an external content type from an OData source in SharePoint.

To add an external list automatically


1. If you just want to add a simple list to your project that reflects what is in your external content type, you can use the Visual Studio 2012 autogeneration tools. The list is created when
the external content type is created. When you select the Create list instances for the selected data entities (except Service Operations) check box found in the second step of
the autogeneration process (Select the Data Entities step), the wizard creates the XML declarations and add new external content types for each entity you selected.
2. Press F5 to deploy the project, and the new list is also deployed.
For testing purposes, you may want to modify the AppManifest.xml file so that the starting page of the app is the list you just created.

To modify the AppManifest.xml file


1. Open the AppManifest.xml file using an XML editor.
2. Find the <StartPage> tag.
3. Change the value to ~appWebUrl/Lists/Employees .
4. Save your changes.

To publish the project


Press F5 to deploy your project and external list.
Open a web browser, and navigate to the new list you created.

See also
Business Connectivity Services in SharePoint
Using OData sources with Business Connectivity Services in SharePoint
How to: Create an external content type from an OData source in SharePoint
How to: Create a basic autohosted app for SharePoint
Using OData sources with Business Connectivity Services in SharePoint
External events and alerts in SharePoint
3/26/2018 • 13 minutes to read Edit Online

Learn the concepts behind creating remote event receivers in SharePoint that can be attached to external lists and execute when the external data that the list represents is updated.

What are event receivers?


An event receiver is a piece of managed code that responds to SharePoint triggering events such as adding, moving, deleting, checking in, and checking out. When these events occur, and the
event receiver's criteria are met, the code that you write to provide additional functionality is executed. When SharePoint objects, such as lists, workflows and features, are configured to wait
on these events to occur, they are called event hosts.
Event receivers let you perform business logic when a specific event occurs. Essentially, these are the hooks where you can create code to handle certain conditions, make notifications,
update other systems, and so on. When you create event receivers, a DLL is generated. You can place that DLL into the global assembly cache, so that the event receivers are invoked in
response to any changes in an external system.
The following example contains a simple external event receiver in C# that executes when a new item is added to the list.

public class EntryContentEventReceiver : SPItemEventReceiver


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

// properties.ExternalNotificationMessage holds the message sent by the external


// system.
}

External event receivers can also be extended to work against an entity event receiver and as remote event receivers deployed as a service on-premise or in Microsoft Azure.

What are remote event receivers?


Remote event receivers are new for SharePoint. In a traditional SharePoint solution, you use an event receiver to handle events such as users creating or deleting lists or items in lists. In an
SharePoint Add-in, you use a remote event receiver to handle similar events. Remote event receivers work similarly to regular event receivers, except that remote event receivers handle
events that occur when an SharePoint Add-in is on a different system from its host web application.
Business Connectivity Services (BCS) uses remote event receivers attached to external lists and entities to allow you to write code that can react to changes in data hosted in the external
system.
To accommodate this, two stereotypes have been added to the schema of the BDC model: EventSubscriber and EventUnsubscriber.
NOTE

Event receivers are not supported in sandboxed solutions.

What features and capabilities does the new external event receiver infrastructure provide?
By using and extending the SharePoint event receiver features, BCS is able to add alerts, external list event receivers, and entity receivers to provide extended functionality.
Alerts: Alerts have been an integral part of SharePoint for several versions, but until SharePoint, they would not work with external lists. Now a user can create alerts on an external
list that have the same behavior as alerts on a standard SharePoint list.
External list event receivers: Event receivers can now be attached to external lists just like they can for standard lists. This provides an extensibility mechanism that lets you write
code that is executed at specific times.
Entity event receivers: Entity event receivers provide flexibility by letting you write more robust code that allows other operations like providing user context for filtering data. This
can allow better personalization and customized security.
Remote eventing in SharePoint makes several interesting scenarios possible. For example, you might have a "Sales Lead Tracking" application that lets a sales team be notified when new
sales leads are entered into an external lead application. When a new sales lead is entered, SharePoint is notified through the notification system that is part of the lead application.
SharePoint receives the notification and then creates new tasks for the specified salespeople to follow up on each new lead. By configuring the sales lead entry application on the external
system to send a notification to SharePoint on the creation of each new lead, SharePoint is kept completely up to date.

Prerequisites for using event receivers for external lists


To use event receivers for external lists, you need the following:
SharePoint
Visual Studio 2012
For more information about setting up a SharePoint development environment, see Set up a general development environment for SharePoint.

Configure the external system to notify SharePoint of external events


For external events to work, a number of components have to be installed and configured on both the SharePoint host and the external system.
You have to configure the external system so that it can do the following:
Determine when underlying data changes. For the external system to know when changes have been made, you have to create a mechanism for polling for specific changes. You
can do this by using a timed service that polls the data source at specific intervals.
Receive and record requests for subscriptions to change notifications. The external system has to implement a subscription store so that it can store who should receive change
notifications. The simplest solution is probably a database table. The table (or whatever mechanism you choose) should record SubscriptionID, Delivery Address, Event Type, and
Entity Name.
Post notifications to Representational State Transfer (REST) endpoints. To let SharePoint subscribers know that a change has occurred, the external system application needs to
send an HTTP WebRequest to the delivery address recorded in the subscription store. This delivery address is a RESTful endpoint generated by SharePoint during the subscription
process.

Configure SharePoint to allow communication with external systems


To allow communication with the external system, SharePoint must be configured with the following:
A BDC model with EventSubscriber and EventUnsubscriber stereotypes configured
Event receivers

How is external eventing enabled?


You can enable external eventing in SharePoint through Site Settings or by adding the following custom feature id to your project

<ActivationDependency FeatureTitle="BCSEvents" FeatureId="60c8481d-4b54-4853-ab9f-ed7e1c21d7e4" />

Eventing for an external system is enabled when SharePoint creates the delivery address and sends it to the external system during the Subscribe process.

Overall flow of external eventing between SharePoint and external systems


In Figure 1, notice that there are three distinct steps involved when using external event receivers: subscribe, notification, and unsubscribe.
Figure 1 Complete data flow for external notifications

EventSubscriber: subscribe to notifications


For a user (SharePoint object) to receive notifications when the underlying data has changed, the user must subscribe to the notifications for an entity. To allow this, the BDC Model schema
has been extended to include the Subscribe stereotype. The Subscribe stereotype is used by SharePoint to let the external system know that the sender is requesting to be notified of
changes to the underlying data.
Figure 2 demonstrates the flow of information between SharePoint and the external system during the Subscribe process.
Figure 2. Subscribe process flow
The following describes the general flow of the subscription process:
1. User requests a subscription for notifications. Using a custom user interface (a button on a page or a ribbon), SharePoint initiates a request to the external system app for
notifications.
2. SharePoint generates a delivery address. As part of the Subscribe process, SharePoint creates a REST endpoint where notifications will be delivered.
3. Subscription request is sent to the external system. SharePoint then encapsulates the requestor information along with the dynamically generated REST URL, and sends a web
request to the external system.
4. External system receives request. There are different possibilities for implementing a subscription store. In this example, you will use a SQL Server database table.
5. External system generates a subscriptionId. A new subscriptionId is generated using code in the line-of-business (LOB) application. The subscriptionId should be a GUID.
6. External system records the subscription. The external system application records the subscriptionId, delivery address, event type, and other information sent from SharePoint
into the subscription store.
7. External system sends the subscriptionId back to SharePoint. For SharePoint to correctly route the updates that are sent by the external system, the subscriptionId is sent back
to SharePoint and SharePoint records that information in its database.
The BDC model is working against a Subscribe function import. The metadata for function import is shown in this example.

FunctionImport

<EntityType Name="EntitySubscribe">
<Key>
<PropertyRef Name="SubscriptionId" />
</Key>
<Property Name="SubscriptionId" Type="Edm.Int32" Nullable="false"
p6:StoreGeneratedPattern="Identity"
xmlns:p6="http://schemas.microsoft.com/ado/2009/02/edm/annotation" />
<Property Name="EntityName" Type="Edm.String" MaxLength="250" FixedLength="false"
Unicode="true" />
<Property Name="DeliveryURL" Type="Edm.String" MaxLength="250" FixedLength="false"
Unicode="true" />
<Property Name="EventType" Type="Edm.Int32" />
<Property Name="UserId" Type="Edm.String" MaxLength="50" FixedLength="false"
Unicode="true" />
<Property Name="SubscribeTime" Type="Edm.Binary" MaxLength="8" FixedLength="true"
p6:StoreGeneratedPattern="Computed"
xmlns:p6="http://schemas.microsoft.com/ado/2009/02/edm/annotation" />
<Property Name="SelectColumns" Type="Edm.String" MaxLength="10" FixedLength="false"
Unicode="true" />
</EntityType>

Code example: BDC model with Subscribe


The following is an example of a BDC model with the Subscribe method added.
<Method Name="SubscribeCustomer" DefaultDisplayName="Customer Subscribe" IsStatic="true">
<Properties>
<Property Name="ODataEntityUrl" Type="System.String">/EntitySubscribes</Property>
<Property Name="ODataHttpMethod" Type="System.String">POST</Property>
<Property Name="ODataPayloadKind" Type="System.String">Entry</Property>
<Property Name="ODataFormat" Type="System.String">application/atom+xml</Property>
<Property Name="ODataServiceOperation" Type="System.Boolean">false</Property>
</Properties>
<AccessControlList>
<AccessControlEntry Principal="NT Authority\\Authenticated Users">
<Right BdcRight="Edit" />
<Right BdcRight="Execute" />
<Right BdcRight="SetPermissions" />
<Right BdcRight="SelectableInClients" />
</AccessControlEntry>
</AccessControlList>
<Parameters>
<Parameter Direction="In" Name="@DeliveryURL">
<TypeDescriptor TypeName="System.String" Name="DeliveryURL" >
<Properties>
<Property Name="IsDeliveryAddress" Type="System.Boolean">true</Property>
</Properties>
</TypeDescriptor>
</Parameter>
<Parameter Direction="In" Name="@EventType">
<TypeDescriptor TypeName="System.Int32" Name="EventType" >
<Properties>
<Property Name="IsEventType" Type="System.Boolean">true</Property>
</Properties>
</TypeDescriptor>
</Parameter>
<Parameter Direction="In" Name="@EntityName">
<TypeDescriptor TypeName="System.String" Name="EntityName" >
<DefaultValues>
<DefaultValue MethodInstanceName="SubscribeCustomer"
Type="System.String">Customers</DefaultValue>
</DefaultValues>
</TypeDescriptor>
</Parameter>
<Parameter Direction="In" Name="@SelectColumns">
<TypeDescriptor TypeName="System.String" Name="SelectColumns" >
<DefaultValues>
<DefaultValue MethodInstanceName="SubscribeCustomer" Type="System.String">*</DefaultValue>
</DefaultValues>
</TypeDescriptor>
</Parameter>
<Parameter Direction="Return" Name="SubscribeReturn">
<TypeDescriptor Name="SubscribeReturnRootTd" TypeName="Microsoft.BusinessData.Runtime.DynamicType">
<TypeDescriptors>
<TypeDescriptor Name="SubscriptionId" TypeName="System.String" >
<Properties>
<Property Name="SubscriptionIdName" Type="System.String">Default</Property>
</Properties>
<Interpretation>
<ConvertType LOBType="System.Int32" BDCType="System.String"/>
</Interpretation>
</TypeDescriptor>
<TypeDescriptor Name="DeliveryURL" TypeName="System.String" />
<TypeDescriptor Name="SelectColumns" TypeName="System.String" >
</TypeDescriptor>
<TypeDescriptor Name="EntityName" TypeName="System.String" />
<TypeDescriptor Name="EventType" TypeName="System.Int32" />
<TypeDescriptor Name="UserId" TypeName="System.String" />
<!--TypeDescriptor Name="SubscribeTime" TypeName="System." /-->
</TypeDescriptors>
</TypeDescriptor>
</Parameter>
</Parameters>
<MethodInstances>
<MethodInstance Type="EventSubscriber" ReturnParameterName="SubscribeReturn" ReturnTypeDescriptorPath="SubscribeReturnRootTd" Default="true" Name="SubscribeCustomer" DefaultDisplayName="Custo
<AccessControlList>
<AccessControlEntry Principal="NT Authority\\Authenticated Users">
<Right BdcRight="Edit" />
<Right BdcRight="Execute" />
<Right BdcRight="SetPermissions" />
<Right BdcRight="SelectableInClients" />
</AccessControlEntry>
</AccessControlList>
</MethodInstance>
</MethodInstances>
</Method>

Table 1 lists the important attributes of the BDC model that are needed to make the Subscribe stereotype work.
Table 1. BDC model attributes

AT TR IB U TE D ES CR IPTIO N

IsDeliveryAddress A Boolean flag used on a TypeDescriptor to indicate whether the delivery address provided is to be
used to deliver notifications.

IsEventType A Boolean flag used on a TypeDescriptor to indicate whether the event type provided is to be used as
the event type. Valid event types are ItemAdded, ItemUpdated, ItemDeleted, and so on.

SubscriptionIdName A string used on a TypeDescriptor that represents the name of a subscriptionId part.

Notifications
In SharePoint, the event-handling infrastructure has been enhanced to allow external data sources to notify SharePoint when information in the external system has been modified. Then,
when SharePoint receives a notification, event receivers that are associated with the SharePoint external list or entity can execute code to perform specified actions.
When a subscription is created, the external system needs a way to tell SharePoint about the changes that have occurred on a particular entity. The external system is expected to deliver
notifications to the delivery address as provided by SharePoint to the external system during the Subscribe process using an OData Atom-formatted payload.
Figure 3 shows the communication flow between the external system and SharePoint when a new record is added to the data in the external system.
Figure 3 Notification process

1. New record is added to external system. In this example, a new record is added to the external system using the application user interface or directly into the database.
2. External system application is notified of the change. The external system application has to be made aware of the changes that are happening to the underlying data. There are
a number of ways to do this. You can use SQL triggers that fire when data changes on specific tables, or you can create a polling mechanism to query the data store for changes. There
are other ways to accomplish this, but each will have to be evaluated with performance in mind.
3. External system sends notification request to SharePoint through delivery address. To communicate the changes, an Atom-formatted request has to be sent to the delivery
address that is stored in the LOB application's subscription store.

Notification payload
In constructing the notification, the LOB system has to create an HTTP payload that includes either the full details of the item that changed, or just the identity of the item that changed.
Identity: When the payload is sent as an identity, the payload is expected to have only information about the identity of the changed item. For example, for a customer in a Customers
entity, the payload would only contain the ID of the customer that has changed.
Full item: In this case, the payload is an entire record that has changed in the external system. In the customer example, the entire changed customer record is included.
NOTE

The full item is only supported when you use the OData connector.
The type of payload that is being sent by the external system must be indicated during the subscription process.
The following is an example of the BDC model property used for notifications.

<Property Name="NotificationParserType" Type="System.String">


ODataEntryContentNotificationParser
</Property>

If it is not specified, the default payload is an identity payload.

Notification delivery address (virtual address)


The subscription process initiated from SharePoint results in a virtual address being created by SharePoint, allowing an entry point for the external system to post notifications. The delivery
address is used by the external system to post those notifications. The delivery address is also passed to the external system during the subscription request.

EventUnsubscriber: remove subscription from the notifications list


The Unsubscribe operation removes a subscription from the notifications list.
Figure 4 shows that the UnSubscribe method is much simpler. Because the subscription ID was sent back to SharePoint, and SharePoint recorded it, all that is needed is to send the
UnSubscribe request with the correct subscription ID.
Figure 4 Code flow for UnSubscribe method

BDC model for Unsubscribe


The following XML example shows how you can create a BDC model that unsubscribes from the external system event notifications.
<Method Name="UnSubscribeExpenseReport" DefaultDisplayName="ExpenseReport
Unsubscribe">
<Properties>
<Property Name="ODataEntityUrl" Type="System.String">
/Subscriptions(@ID)</Property>
<Property Name="ODataHttpMethod" Type="System.String">DELETE</Property>
<Property Name="ODataPayloadKind" Type="System.String">Property</Property>
<Property Name="ODataServiceOperation" Type="System.Boolean">false</Property>
</Properties>
<AccessControlList>
<AccessControlEntry Principal="NT Authority\\Authenticated Users">
<Right BdcRight="Edit" />
<Right BdcRight="Execute" />
<Right BdcRight="SetPermissions" />
<Right BdcRight="SelectableInClients" />
</AccessControlEntry>
</AccessControlList>
<Parameters>
<Parameter Name="@ID" Direction="In">
<TypeDescriptor Name="ID" TypeName="System.Int32">
<Properties>
<Property Name="SubscriptionIdName" Type="System.String">ID</Property>
</Properties>
<Interpretation>
<ConvertType LOBType="System.Int32" BDCType="System.String" />
</Interpretation>
</TypeDescriptor>
</Parameter>
</Parameters>
<MethodInstances>
<MethodInstance Name="UnSubscribeExpenseReport" DefaultDisplayName="ExpenseReport
Unsubscribe" Type="EventUnsubscriber" Default="true">
<AccessControlList>
<AccessControlEntry Principal="NT Authority\\Authenticated Users">
<Right BdcRight="Edit" />
<Right BdcRight="Execute" />
<Right BdcRight="SetPermissions" />
<Right BdcRight="SelectableInClients" />
</AccessControlEntry>
</AccessControlList>
</MethodInstance>
</MethodInstances>
</Method>

<Method IsStatic="false" Name="Unsubscribe">


<AccessControlList>
<AccessControlEntry Principal="NT AUTHORITY\\Authenticated Users">
<Right BdcRight="Edit" />
<Right BdcRight="Execute" />
<Right BdcRight="SetPermissions" />
<Right BdcRight="SelectableInClients" />
</AccessControlEntry>
</AccessControlList>
<Parameters>
<Parameter Direction="In" Name="subscriptionId">
<TypeDescriptor TypeName="System.String" Name="subscriptionId"
IsSubscriptionId="true" />
</Parameter>
</Parameters>
<MethodInstances>
<MethodInstance Type="EventUnsubscriber" Default="true" Name="Unsubscribe"
DefaultDisplayName="UnSubscriber">
<Properties>
<Property Name="LastDesignedOfficeItemType" Type="System.String">None</Property>
</Properties>
<AccessControlList>
<AccessControlEntry Principal=" NT AUTHORITY\\Authenticated Users ">
<Right BdcRight="Edit" />
<Right BdcRight="Execute" />
<Right BdcRight="SetPermissions" />
<Right BdcRight="SelectableInClients" />
</AccessControlEntry>
</AccessControlList>
</MethodInstance>
</MethodInstances>
</Method>

Code example: Attach an event receiver to an external list


The following code provides an example of how to attach an event receiver to an external list. After it is attached, the event receiver listens for notifications from the external system about
updates, additions, and deletions that are performed on the native data.
private static void AddEventReceiver(string siteUrl, string listTitle)
{
string assembly = "SampleEventReceiver, Culture=neutral, Version=1.0.0.0,
PublicKeyToken=1bfafa687d2e46a7";
string className = "SampleEventReceiver.EntryContentEventReceiver";

try
{
using (SPSite site = new SPSite(siteUrl))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists[listTitle];
list.EventReceivers.Add(SPEventReceiverType.ItemAdded,
assembly, className);
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}

Beyond the basics: Learn more about using external event receivers
For more information about external events and alerts, see the following.
Table 2. Advanced concepts for working with external event receivers

AR TICLE D ES CR IPTIO N

How to: Create an OData data service for use as a BCS external system Learn how to create an Internet-addressable Windows Communication Foundation (WCF) service that
uses OData to send notifications to SharePoint when the underlying data changes. These notifications
are used to trigger events that are attached to external lists.

See also
What's new in Business Connectivity Services in SharePoint
Business Connectivity Services in SharePoint
Business Connectivity Services programmers reference for SharePoint
How to: Create external event receivers
Create external event receivers
3/26/2018 • 17 minutes to read Edit Online

Learn the steps for creating external event receivers for on-premises installations of Business Connectivity Services (BCS) external lists.
External event receivers are classes that enable SharePoint Add-ins to respond to events that occur to SharePoint items, such as lists or list items. For example, you can respond to list events,
such as adding or removing a field; list item events, such as adding or removing a list item or attachment to a list item; or web events, such as adding or deleting a site or site collection. You
can add a remote event receiver to an existing Visual Studio solution that contains an SharePoint Add-in.
This article accompanies the code sample SharePoint: Create a remote event receiver for external data. It shows how to create all the components needed to configure and use external
system event notifications. In this example, you will do the following:
1. Create an external system based on the Northwind sample database
2. Expose the sample data through OData by creating a Windows Communication Foundation (WCF) service.
3. Create a polling service that will monitor for changes in the data and notify SharePoint of those changes.
4. Create an external event receiver that executes when items are added to the external data and, as a result, creates a new list item on a notifications list.

Prerequisites and system set up


To complete this example, you will need the following prerequisites:
Visual Studio 2012
Office Developer Tools for Visual Studio 2013
SQL Server
SharePoint
Internet Information Services 7.0
Northwind sample database

Build the components for external systems


The biggest part of the configuration actually happens on the external system. For external event receivers to work correctly, the following components must be present and working on the
external system:
Subscription store: A table that contains information about the subscribers that want to be notified of changes to the external data.
Changes store: A table that is used to store the changes to the data items. It functions as temporary storage only because the polling service deletes the item in the table when
notifications are sent back to subscribers in SharePoint.
Polling service: Required in this scenario as a means of checking when data has been changed and submitted to the change table. The polling service queries the change table and
assembles a notification package that is sent to the SharePoint delivery address (REST endpoint) stored in the subscription store.
OData WCF Data Service: To expose the data from the external system's database, you have to create a WCF service. This service, running on Internet Information Services (IIS),
provides the RESTful interface and OData feed that is needed for this scenario.

Set up the external system


The first task is to set up the external system.

Attach the Northwind sample database


The first part of preparing the back-end system is to add the Northwind sample database to a running instance of SQL Server. If you already have the Northwind sample database installed,
you can run the scripts in the following section to create the additional objects needed for external eventing notifications to work.
However, if you don't have Northwind installed, see Installing the Northwind Sample Database.
The database is also included with the code sample: SharePoint: Create a remote event receiver for external data.

Create the subscription store


When the Northwind database is installed, open a new query window and execute the following script.

USE [Northwind]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[EntitySubscribe](
[SubscriptionId] [int] IDENTITY(1,1) NOT NULL,
[EntityName] [nvarchar](250) NULL,
[DeliveryURL] [nvarchar](250) NULL,
[EventType] [int] NULL,
[UserId] [nvarchar](50) NULL,
[SubscribeTime] [timestamp] NULL,
[SelectColumns] [nvarchar](10) NULL,
CONSTRAINT [PK_Subscribe] PRIMARY KEY CLUSTERED
(
[SubscriptionId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
This creates a table in the Northwind database named EntitySubscribe. This serves as the subscription store referred to earlier.

Create the change store


Run the following script to create the change table that will record changes to the data in the Customers table.

USE [Northwind]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Customers_Updates](


[CustomerID] [nchar](5) NOT NULL,
[CompanyName] [nvarchar](40) NOT NULL,
[ContactName] [nvarchar](30) NULL,
[ContactTitle] [nvarchar](30) NULL,
[Address] [nvarchar](60) NULL,
[City] [nvarchar](15) NULL,
[Region] [nvarchar](15) NULL,
[PostalCode] [nvarchar](10) NULL,
[Country] [nvarchar](15) NULL,
[Phone] [nvarchar](24) NULL,
[Fax] [nvarchar](24) NULL,
[TimeAdded] [datetime] NULL,
[EventType] [int] NULL,
CONSTRAINT [PK_Customers_Updates] PRIMARY KEY CLUSTERED
(
[CustomerID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

This adds a table named Customers_Updates that stores the information about the record that was added to the Customers table.

Create the change trigger


The change trigger is fired when changes happen to the Customers table. Whenever a record is added to Customers, SQL Server executes the trigger, which inserts a new record in the
Customers_Updates table with the information about the record.
To create the trigger, execute the following query.

USE [Northwind]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE trigger [dbo].[Customer_insupd] on [dbo].[Customers] for


INSERT
AS
DECLARE
@CustomerID nchar(5),
@CompanyName nvarchar(40),
@ContactName nvarchar(30) ,
@ContactTitle nvarchar(30) ,
@Address nvarchar(60) ,
@City nvarchar(15) ,
@Region nvarchar(15) ,
@PostalCode nvarchar(10) ,
@Country nvarchar(15) ,
@Phone nvarchar(24) ,
@Fax nvarchar(24),
@TimeAdded datetime,
@EventType int

Select @CustomerID = CustomerId, @CompanyName=CompanyName,


@ContactName=ContactName, @ContactTitle=ContactTitle,
@Address=Address, @City=City, @Region=Region,
@PostalCode =PostalCode, @Country=Country,
@Phone=Phone,@Fax=Fax,@EventType=1
from inserted

insert into Customers_Updates


(CustomerId,CompanyName,
ContactName, ContactTitle,
Address, City, Region,
PostalCode,Country,
Phone,Fax,TimeAdded,EventType) values
(@CustomerId,@CompanyName,
@ContactName, @ContactTitle,
@Address, @City, @Region,
@PostalCode,@Country,
@Phone,@Fax,SYSDATETIME(),@EventType)

GO

NOTE

f you are using your own custom stored procedures as defined in your BDC model, you might also want to create the delete and update triggers. The additional triggers are not be covered as
part of this scenario.
Create the stored procedures
If you are using direct table access with Business Connectivity Services, these procedures won't be necessary. However, if you are defining your own procedures and custom code on the
external system, you might want to add these to allow access to the table from SQL Server.

// DeleteEventRecords stored procedure


USE [Northwind]
GO
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[proc_DeleteEventRecords]


@CustomerID nchar(5), @EventType int
AS
Delete from Customers_Updates
WHERE CustomerID like @CustomerID AND EventType=@EventType

GO

The SubscribeEntity stored procedure will create a record in the subscription store.

// SubscribeEntity
USE [Northwind]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[SubscribeEntity]


@EntityName Varchar(255),
@EventType Integer,
@DeliveryAddress Varchar(255),
@SelectColumns Varchar(10)

AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

-- Insert statements for procedure here

Insert into EntitySubscribe(EntityName,DeliveryURL,EventType,SelectColumns)


values (@EntityName,@DeliveryAddress,@EventType,@SelectColumns)

END

GO

Create the OData Service


The OData feed is hosted inside a WCF Data Service. This WCF service is then hosted by IIS in a web application.
The following steps create a new ASP.NET WCF data service.

To create the WCF Data Service application


1. In Visual Studio 2012, on the File menu, choose New, Project.
2. In the New Project dialog box, under the Visual C# node, choose the Web template, and then choose ASP.NET Web Application.
3. Enter NorthwindService as the name of the project, and then choose OK.
Next, using the Visual Studio wizard, you discover the schema of the data source and use it to create an ADO.NET entity data model.

To define the data model


1. In Solution Explorer, open the shortcut menu for the ASP.NET project, and choose Add New Item.
2. In the Add New Item dialog box, choose the Data template, and then choose ADO.NET Entity Data Model.
3. For the name of the data model, enter Northwind.edmx.
4. In the Entity Data Model Wizard, choose Generate from Database, and then choose Next.
5. Connect the data model to the database by doing one of the following steps:
6. If you do not have a database connection already configured, choose New Connection and create a new connection. For more information, see How to: Create Connections to SQL
Server Databases. This SQL Server instance must have the Northwind sample database attached. Choose Next.
-or-
7. If you have a database connection already configured to connect to the Northwind database, choose that connection from the list of connections, and then choose Next.
8. On the final page of the wizard, select the check boxes for all tables in the database, and clear the check boxes for views and stored procedures.
9. Choose the Finish button to close the wizard.
In the next step, you create the actual service that is hosted by IIS that will provide the means to access external data through Representational State Transfer (REST).
To create the WCF Data Service
1. In Solution Explorer, open the shortcut menu for your ASP.NET project, and choose Add New Item.
2. In the Add New Item dialog box, choose WCF Data Service.
3. For the name of the service, enter Northwind.
4. In the code for the data service, in the definition of the class that defines the data service, replace the comment /* TODO: put your data source class name here */ with the type that is
the entity container of the data model, which in this case is NorthwindEntities . The class definition should look like the following.

public class Northwind : DataService<NorthwindEntities>

To set the security on the service


You now have to modify the security to allow access to the data from the OData feed by external consumers. When a WCF service is created, all access is denied by default. Make the
following changes to the class you just created.

config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);

Create the Subscribe service operation (optional)


The WCF service can also be coded with a means to handle the Subscribe and Unsubscribe requests from SharePoint. If you choose to create custom stored procedures for your application
these will each be handled by a service operation.
Subscribe: The Subscribe operation takes the request sent by SharePoint and retrieves the delivery address the event type and the entity. It also has to generate a subscriptionId and then
record all of these into the database table.

/// The Subscribe service operation maps directly to the Subscribe stereotype
/// found in the BDC model

[WebGet]
public string Subscribe(string deliveryUrl, string eventType)
{
// Generate a new Guid that will function as the subscriptionId.
string subscriptionId = new Guid().ToString();

// This sproc will be used to create the subscription in the database.


string subscribeSproc = "SubscribeEntity";

// Create connection to database.


using (SqlConnection conn = new SqlConnection(sqlConn))
{
SqlCommand cmd = new SqlCommand(subscribeSproc, conn);
cmd.Parameters.Add(new SqlParameter("SubscriptionId", subscriptionId));
cmd.Parameters.Add(new SqlParameter("EntityName", entityName));
cmd.Parameters.Add(new SqlParameter("EventType", eventType));
cmd.Parameters.Add(new SqlParameter("DeliveryAddress", deliveryUrl));
cmd.Parameters.Add(new SqlParameter("SelectColumns", selectColumns));

try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
throw e;
}
finally
{
conn.Close();
}

return subscriptionId;
}

NOTE

If SQL Server is set up for Windows authentication, it will try to authenticate the request with the App Pool identity. Make sure that the account configured in the App Pool has rights to read
and write in the database.

Create the polling service


The polling service is a Windows service that is responsible for querying the change table and creating and sending notifications to SharePoint or SharePoint Online at the specific delivery
address.
Next, you create a new Windows Service project that will be registered on the WCF host machine. Once the project is registered, you can view the running service in the Microsoft
Management Console (MMC).

To create a new project


1. Open Visual Studio 2012.
2. Create a new project using the Windows Service template, name the project PollingService, and choose the OK button.
3. When the project is created, open the PollingService.cs file in code view.
4. Add the following code in the newly created class.
public partial class PollingService : ServiceBase
{
string subscriptionStorePath = string.Empty;

public PollingService()
{
InitializeComponent();
}

protected override void OnStart(string[] args)


{

// This is the timer which fires every minute.


System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed += new System.Timers.ElapsedEventHandler(SendEventNotification);
aTimer.Interval = 60000;
aTimer.Enabled = true;
}
protected override void OnStop()
{}

private void SendEventNotification(object sender, EventArgs e)


{
try
{
List<ItemChange> events = itemChangeLookUp();
triggerEventPerSubscription(events);
}
catch (Exception ex)
{
EventLog.Log = "Application";
EventLog.Source = ServiceName;
EventLog.WriteEntry("PollingService" + ex.Message, EventLogEntryType.Error);
}
}

private void triggerEventPerSubscription(List<ItemChange> events)


{
foreach (ItemChange itemChangeEvent in events)
{
SendNotification(itemChangeEvent, itemChangeEvent.DeliveryAddress);
string message = string.Format("PollingService.TriggerEventPerSubscription: Notification sent for item {0} of eventType
{1}", itemChangeEvent.CustomerId, itemChangeEvent.EventType);
EventLog.Log = "Application";
EventLog.Source = ServiceName;
EventLog.WriteEntry(message);
}
}

private List<ItemChange> itemChangeLookUp()


{
EventLog.Log = "Application";
EventLog.Source = ServiceName;
EventLog.WriteEntry("Polling for Item Change");
List<ItemChange> itemChangeList = new List<ItemChange>();
string connectionString = "Data Source=.;Initial Catalog=Northwind;Integrated Security=true";

// Provide the query string with a parameter placeholder.


string queryString = "Proc_RetrieveEventRecords";

// Specify the parameter value.


int paramValue = -50;

using (SqlConnection connection = new SqlConnection(connectionString))


{
SqlCommand command = new SqlCommand(queryString, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("@TimeSince", paramValue);
try
{
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
ItemChange item = new ItemChange(reader["CustomerID"].ToString(), Int32.Parse(reader["EventType"].ToString()),
reader[14].ToString(), reader["DeliveryUrl"].ToString(), reader["CompanyName"].ToString(),
reader["ContactName"].ToString(),reader["ContactTitle"].ToString(), reader["Address"].ToString(),
reader["City"].ToString(), reader["Region"].ToString(), reader["Country"].ToString(), reader["PostalCode"].ToString(),
reader["Phone"].ToString(), reader["Fax"].ToString());
itemChangeList.Add(item);
}
reader.Close();
}
catch (Exception ex)
{
EventLog.Log = "Application";
EventLog.Source = ServiceName;
EventLog.WriteEntry("PollingService : ItemChangeLookup " + ex.Message, EventLogEntryType.Error);
}
}
string message = string.Format("{0} items changes", itemChangeList.Count);
EventLog.Log = "Application";
EventLog.Source = ServiceName;
EventLog.WriteEntry(message);

return itemChangeList;
}

The next step is to build an executable file that can be added to the running services on the OData computer.

To compile and deploy the polling service


1. Press F5 to build your project.
2. Open the Command Prompt for VS2012.
3. At the prompt, navigate to your project output location.
4. In the Bin directory, find the PollingService.exe file.
5. Enter installutil PollingService.exe and press Enter.
6. Verify that the service is running by running the Services MMC.

Required SharePoint components


To complete the whole system, the following components are required on the server that is running SharePoint.
External content type: The external content type is basically an XML definition of the external data source. For this scenario, you will use the new autogeneration tools in Visual
Studio 2012 to discover the data source and create the external content type automatically.
External event receiver: The remote or external event receiver is the thing that makes actions on external data changes possible in SharePoint. You can create event receivers for
external lists and for entities.
An event receiver that is created for an external list is similar to other event receivers for SharePoint lists. You create the code and attach it to the list. When an action is performed on
the data that is represented by the list, the event receiver executes.
An event receiver for entities is executed just like a list-based event receiver, except it doesn't need to be attached to a list. It receives notifications the same way, but it doesn't need the
interface that is associated with the list-based example. The benefit of this is that you can intercept the notifications programmatically and create code to perform some action. In this
scenario, that action is to create a new record in the notifications list
Notifications list: The notifications list is a simple SharePoint list that is used to record notifications received from the external system. For each new record added to the external
system, a record is created in the notifications list.

Set up the SharePoint components


Now that you have the external system set up, it's time to move on to creating the other half of the equation. You will now create the components to be hosted on SharePoint.

To create a new Visual Studio 2012 project


1. In Visual Studio 2012, choose New Project.
2. Choose the SharePoint app project template.
Office Developer Tools for Visual Studio 2013 added an autogeneration wizard that will discover a data source's schema and then create an external content type from that.

To add a new external content type


In Solution Explorer, open the shortcut menu for the project, and choose Add, Content Types for an External Data Source.
This starts the SharePoint Customization Wizard, which is used to build the external content type automatically.
For more information about how to create external content types, see How to: Create an external content type from an OData source in SharePoint.
You will now modify the XML that was generated in the previous step to add a method for Subscribe. This will allow BCS to communicate with the external system when someone subscribes
to be notified about external data changes.

To add the Subscribe method to the external content type XML


1. In Solution Explorer, find the new node named External Content Types.
2. Find the Customers.ect file, and open it with an XML editor.
3. Scroll down to the bottom of the page, and paste the following method into the <Methods> section.
<Method Name="SubscribeCustomer" DefaultDisplayName="Customer Subscribe" IsStatic="true">
<Properties>
<Property Name="ODataEntityUrl" Type="System.String">/EntitySubscribes</Property>
<Property Name="ODataHttpMethod" Type="System.String">POST</Property>
<Property Name="ODataPayloadKind" Type="System.String">Entry</Property>
<Property Name="ODataFormat" Type="System.String">application/atom+xml</Property>
<Property Name="ODataServiceOperation" Type="System.Boolean">false</Property>
</Properties>
<AccessControlList>
<AccessControlEntry Principal="NT Authority\\Authenticated Users">
<Right BdcRight="Edit" />
<Right BdcRight="Execute" />
<Right BdcRight="SetPermissions" />
<Right BdcRight="SelectableInClients" />
</AccessControlEntry>
</AccessControlList>
<Parameters>
<Parameter Direction="In" Name="@DeliveryURL">
<TypeDescriptor TypeName="System.String" Name="DeliveryURL" >
<Properties>
<Property Name="IsDeliveryAddress" Type="System.Boolean">true</Property>
</Properties>
</TypeDescriptor>
</Parameter>
<Parameter Direction="In" Name="@EventType">
<TypeDescriptor TypeName="System.Int32" Name="EventType" >
<Properties>
<Property Name="IsEventType" Type="System.Boolean">true</Property>
</Properties>
</TypeDescriptor>
</Parameter>
<Parameter Direction="In" Name="@EntityName">
<TypeDescriptor TypeName="System.String" Name="EntityName" >
<DefaultValues>
<DefaultValue MethodInstanceName="SubscribeCustomer" Type="System.String">Customers</DefaultValue>
</DefaultValues>
</TypeDescriptor>
</Parameter>
<Parameter Direction="In" Name="@SelectColumns">
<TypeDescriptor TypeName="System.String" Name="SelectColumns" >
<DefaultValues>
<DefaultValue MethodInstanceName="SubscribeCustomer" Type="System.String">*</DefaultValue>
</DefaultValues>
</TypeDescriptor>
</Parameter>
<Parameter Direction="Return" Name="SubscribeReturn">
<TypeDescriptor Name="SubscribeReturnRootTd" TypeName="Microsoft.BusinessData.Runtime.DynamicType">
<TypeDescriptors>
<TypeDescriptor Name="SubscriptionId" TypeName="System.String" >
<Properties>
<Property Name="SubscriptionIdName" Type="System.String">Default</Property>
</Properties>
<Interpretation>
<ConvertType LOBType="System.Int32" BDCType="System.String"/>
</Interpretation>
</TypeDescriptor>
<TypeDescriptor Name="DeliveryURL" TypeName="System.String" />
<TypeDescriptor Name="SelectColumns" TypeName="System.String" >
</TypeDescriptor>
<TypeDescriptor Name="EntityName" TypeName="System.String" />
<TypeDescriptor Name="EventType" TypeName="System.Int32" />
<TypeDescriptor Name="UserId" TypeName="System.String" />
<!--TypeDescriptor Name="SubscribeTime" TypeName="System." /-->
</TypeDescriptors>
</TypeDescriptor>
</Parameter>
</Parameters>
<MethodInstances>
<MethodInstance Type="EventSubscriber" ReturnParameterName="SubscribeReturn" ReturnTypeDescriptorPath="SubscribeReturnRootTd" Default="true" Name="SubscribeCustomer" DefaultDispla
<AccessControlList>
<AccessControlEntry Principal="NT Authority\\Authenticated Users">
<Right BdcRight="Edit" />
<Right BdcRight="Execute" />
<Right BdcRight="SetPermissions" />
<Right BdcRight="SelectableInClients" />
</AccessControlEntry>
</AccessControlList>
</MethodInstance>
</MethodInstances>
</Method>

You will now add client code to allow your list to subscribe to event notifications.

To add code to the App.js file to initiate the subscription


In the Scripts folder of your SharePoint Add-in project, open the App.js file. Paste the following method into the file.

function SubscribeEntity()
{
var notificationCallback = new SP.BusinessData.Runtime.NotificationCallback(context, "http://[MACHINE NAME]:8585");
var url = myweb.get_url();
notificationCallback.set_notificationContext(url);
context.load(notificationCallback);
var subscription = entity.subscribe(1, notificationCallback, "", "SubscribeCustomer", lobSystemInstance);
context.load(subscription);
context.executeQueryAsync(OnSubscribeSuccess, failmethod);
}

To register the event receiver with this script, you have to create a button on the Default.aspx page in your project and call the SubscribeEntity() from the onclick() method.
Open the Default.aspx page, and add the following HTML.

<input type="button" value="Subscribe" onclick="SubscribeEntity();"/>

For eventing to work, you must also enable the SharePoint list to accept external events. This is done by turning on the External Events feature.
The following is a script that will turn on the feature using client code.

function EnableEventing_Clicked()
{
var clientContext = SP.ClientContext.get_current();
var web = clientContext.get_web();
var features = web.get_features();

clientContext.load(features);

// The GUID provided here is the feature that allows external events and alerts.
var eventingFeatureId = new SP.Guid('5B10D113-2D0D-43BD-A2FD-F8BC879F5ABD');

var eventingFeature = features.add(eventingFeatureId, true, SP.FeatureDefinitionScope.farm);

clientContext.load(eventingFeature);
var onEventingFeatureActivated = function () {
alert("eventing feature activated");
};
clientContext.executeQueryAsync(Function.createDelegate(this,
onEventingFeatureActivated));
}

Just like with Subscribe, you will add a button to the page that will turn on the feature.
Add the following HTML to the Default.aspx page, right below the Subscribe button.

<input type="button" value="EnableEventing" onclick="EnableEventing_Clicked();"" />

Next, for this scenario you must add a notifications list that will show the notifications sent by the external system.

To add the notifications list


1. In Solution Explorer, open the shortcut menu for the project name, and choose Add.
2. Choose the List template, and name the listNotificationList.
To mimic an event receiver that is registered with SharePoint in the global assembly cache, the sample provides a console application that will start listening for changes. When it receives a
notification, it adds a list item to the NotificationList.

To start the command-line event receiver


1. Open the RemoteEventReceiverConsoleApp.
2. Open the Program.cs file, and change the name of your local computer (or the computer where the event receiver will be running).
3. Click the Start button in Visual Studio to run the console application.
A command window opens, which indicates that the application has compiled correctly, and it is listening for change notifications from the external system. Leave this window open
during this test.

To deploy the app to SharePoint


Press F5 with Visual Studio open to build and deploy the app.

Test the app


Now you can see the app in action.
1. Browse around the app to see the different lists that represent the data in the external system.
2. Click the Customers list.
3. Add a new customer.
4. View the new list item you just created.
5. Go to the notifications list to see that the external system has notified SharePoint of a change to the Customers table.
Keep in mind that the timer is set to send notifications every one minute. While testing, you might have to wait for a short period before you see the notifications posted.

See also
External events and alerts in SharePoint
How to: Create an add-in-scoped external content type in SharePoint
Get started using the client object model with external data in SharePoint
Business Connectivity Services in SharePoint
What's new in Business Connectivity Services in SharePoint
Get started with Business Connectivity Services in SharePoint
Get started using the client object model with external data in SharePoint
3/26/2018 • 4 minutes to read Edit Online

Learn how to use the SharePoint client object model to work with Business Connectivity Services (BCS) in SharePoint.

What is the SharePoint client object model?


The client object model for SharePoint is a set of client-based libraries that represent the server object model. They are packaged in three different DLLs to accommodate a variety of
development types. The client object model includes most of the major functions of the server API. This allows access to the same types of functionality from browser scripting and also .NET
web applications and Silverlight applications.
To enhance and expand the capabilities for working with external data, Business Connectivity Services (BCS) has expanded the client object model to include additional functionality.

Get started using the SharePoint client object model with external data
To develop solutions using the SharePoint client object model (CSOM), you will need the following:
SharePoint
Visual Studio 2012
Office Developer Tools for Visual Studio 2012
For information about how to set up your development environment, see Setting up a development environment for BCS in SharePoint.
To access the capabilities provided by the client object model, you need only to add references to the Microsoft.SharePoint.Client.Runtime.dll and Microsoft.SharePoint.Client.dll files
in their projects. You can also use the client object model by referencing the following DLLs in the global assembly cache:
\\Program Files\\Common Files\\Microsoft Shared\\Web Server Extensions\\15\\isapi\\Microsoft.SharePoint.Client.Runtime.dll

\\Program Files\\Common Files\\Microsoft Shared\\Web Server Extensions\\15\\isapi\\Microsoft.SharePoint.Client.dll

SharePoint client object model essentials


The following articles will help you understand more about the client object model in SharePoint.
Table 1. Core concepts for understanding the client object model

AR TICLE D ES CR IPTIO N

External content types in SharePoint Learn what you can do with external content types and what you need to start creating them in
SharePoint.

Using OData sources with Business Connectivity Services in SharePoint Provides information to help get started creating external content types based on OData sources and
using that data in SharePoint or Office 2013 components.

Choose the right API set in SharePoint Learn about the several sets of APIs that are provided in SharePoint, including the server object model,
the various client object models, and the REST/OData web service.

.NET client API reference for SharePoint Online Find information about the .NET client class libraries in SharePoint.

JavaScript API reference for SharePoint Find information about the JavaScript object libraries in SharePoint.

What can you do with the client object model?


You can use the SharePoint client object model to retrieve, update, and manage data that is contained in SharePoint. SharePoint offers the client libraries in different formats to accommodate
most developers. For web developers who are using scripting languages, the client library is offered in JavaScript. For .NET developers, it is offered as a .NET client managed DLL. For
developers of Silverlight applications, the client library is provided by a Silverlight DLL.
See the articles in Table 2 for more information about what you can do with the client object model in SharePoint.
Table 2. Basic tasks for using the client object model with external data

TAS K D ES CR IPTIO N

Complete basic operations using SharePoint client library code Learn how to write code to perform basic operations with the SharePoint client object model.

How to: Use the client code library to access external data in SharePoint Learn how to use the SharePoint client object model to work with SharePoint BCS objects using browser-
based scripting.

The following are some basic examples of tasks you can accomplish using CSOM.

Get a specific entity


This example shows how to get context from SharePoint, and then retrieve a specified data source entity.

ClientContext ctx = new ClientContext("http://sharepointservername");


Web web = ctx.Web;
ctx.Load(web);
Entity entity = ctx.Web.GetEntity("http://sharepointservername", "EntityName");
ctx.Load(entity);
ctx.ExecuteQuery();
Create a generic invoker
This example shows how to write a generic invoker so that you can create an entity object to work within your code.

ObjectCollection myObj;
entity.Execute("MethodInstanceName", lsi, myObj);
ctx.Load(myObj);
ctx.ExecuteQuery();

Retrieve paged result sets


The following example shows how to retrieve a filtered, paged dataset. In this case, the page value is 50.

// Find filters for given Method Name.


FilterCollection fCollection = entity.GetFilters("methodName");
ctx.Load(fCollection);
ctx.ExecuteQuery();
FilterCollection modifiedFCollection = new FilterCollection();
foreach( Filter filter in fCollection)
{
if( filter.FilterField.equals("X.Y.Z.Country"))
{
filter.FilterValue = "India";
modifiedFCollection.Add(Filter);
}
if(filter.FilterType == FilterType.Limit)
{
filter.FilterValue = 50;
modifiedFCollection.Add(Filter);
}
}
EntityInstanceCollection eCollection = entity.FindFiltered(modifiedFCollection,
"nameOfFinder", lsi);
ctx.ExecuteQuery();

Query for filtered information


The following example demonstrates how to return a filtered result set. In this case, the data column filtered is the X.Y.Z.Country field. The code looks for anything with the value of "India",
and then puts that into a collection.

// Find filters for given Method Name.


FilterCollection fCollection = entity.GetFilters("methodName");
ctx.Load(fCollection);
ctx.ExecuteQuery();
FilterCollection modifiedFCollection = new FilterCollection();
foreach( Filter filter in fCollection)
{
if( filter.FilterField.equals("X.Y.Z.Country"))
{
filter.FilterValue = "India";
modifiedFCollection.Add(Filter);
}
}
EntityInstanceCollection eCollection = entity.FindFiltered(modifiedFCollection,
"nameOfFinder", lsi);
ctx.ExecuteQuery();

Beyond the basics: Learn more about the client object model
For more information about using the client object model in SharePoint, see the information in Table 3.
Table 3. Advanced concepts for the client object model

AR TICLE D ES CR IPTIO N

BCS client object model reference for SharePoint Summarizes the objects available for creating client-side scripts using the SharePoint client object model
to access external data exposed by BCS.

See also
Business Connectivity Services in SharePoint
SharePoint Add-ins
How to: Use the client code library to access external data in SharePoint
Complete basic operations using SharePoint client library code
SharePoint: Access complex external content types with CSOM
Use the client code library to access external data in SharePoint
3/26/2018 • 4 minutes to read Edit Online

Learn how to use the SharePoint client object model to work with Business Connectivity Services (BCS) objects in SharePoint using browser-based scripting.
This article demonstrates how to set up an external list that retrieves data from an Open Data protocol (OData) source using the client object model in SharePoint.

Prerequisites for accessing external data using the SharePoint client object model
The following are requirements for being able to develop apps using the SharePoint client object model:
SharePoint
Visual Studio 2012
Office Developer Tools for Visual Studio 2012
A functioning SharePoint Add-ins development environment: Follow the instructions in Set up a general development environment for SharePoint.
Access to the public OData.org producers

Core concepts to know when accessing external data with the SharePoint client object model
The SharePoint client object model provides a way to access external data using client-side calls that mimic the server-side APIs. To understand how it works and how to use it, see the
articles in Table 1.
Table 1. Core concepts for using the client object model

AR TICLE D ES CR IPTIO N

Complete basic operations using SharePoint client library code Learn how to write code to peform basic operations with the SharePoint .NET Framework client object
model (CSOM).

Create an SharePoint Add-in to access external data using the client object model
The following procedures show how to set up an SharePoint Add-in and configure a webpage to make requests using client object model methods and objects to retrieve data from an
external data source.

To create an SharePoint Add-in


1. Open Visual Studio 2012.
2. Create an App for SharePoint project.
3. Specify the app settings, including app name, the site URL for debugging the app, and how you want to host the app (Autohosted, Provider-hosted, SharePoint-hosted). For more
information about hosting options, see Choose patterns for developing and hosting your SharePoint Add-in.
4. Click Finish to create the app.

To generate the external content type


1. In Solution Explorer, open the shortcut menu for the project, and choose Add, Content types for External Data source.
2. In the Specify OData Source wizard, enter the URL of the OData service that you want to connect to. In this case, you will use the Northwind OData source published at
http://www.odata.org/ecosystem. Set the URL for the OData service to http://services.odata.org/Northwind/Northwind.svc/
Specify a name for the data source, and choose Next.
3. A list of entities that are exposed by the OData Service will appear. Choose the Customers entity. Ensure that the Create list instances for the selected data entities (except
Service Operations) check box is selected.
4. Choose Finish.

Code example: Add scripts and HTML to the Default.aspx page


At this point, you have the external content type and an external list that displays the data from the Netflix OData source.
The next objective is to modify the default.aspx page that you created when you created your app. You add a container that will hold the results of the query that is executed with the page
loads. By executing the scripts on the page load event, you ensure that the script will be executed every time the page is browsed, and the resulting client object model calls will be made to
the Netflix OData source to add records to the page.

To add the container to the Default.aspx page


1. In Solution Explorer, open the Default.aspx page located in the Pages module.
2. Add the following div element to the page:

<div id="displayDiv"></div>

1. Save the page.


Finally, you add code to the App.js file that executes when the page loads.

To modify the App.js file to make client object model calls


1. Open the App.js file in the Scripts module of your SharePoint project.
2. Paste the following code at the end of the file.
$(document).ready(function () {

// Namespace
window.AppLevelECT = window.AppLevelECT || {};

// Constructor
AppLevelECT.Grid = function (hostElement, surlWeb) {
this.hostElement = hostElement;
if (surlWeb.length > 0 &amp;&amp; surlWeb.substring(surlWeb.length - 1, surlWeb.length) != "/")
surlWeb += "/";
this.surlWeb = surlWeb;
}

// Prototype
AppLevelECT.Grid.prototype = {

init: function () {

$.ajax({
url: this.surlWeb + "_api/lists/getbytitle('Customer')/items?$select=BdcIdentity,CustomerID,ContactName",
headers: {
"accept": "application/json",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: this.showItems
});
},

showItems: function (data) {


var items = [];

items.push("<table>");
items.push('<tr><td>Customer ID</td><td>Customer Name</td></tr>');

$.each(data.d.results, function (key, val) {


items.push('<tr id="' + val.BdcIdentity + '"><td>' +
val.CustomerID + '</td><td>' +
val.ContactName + '</td></tr>');
});

items.push("</table>");

$("#displayDiv").html(items.join(''));
}
}

ExecuteOrDelayUntilScriptLoaded(getCustomers, "sp.js");
});

function getCustomers() {
var grid = new AppLevelECT.Grid($("#displayDiv"), _spPageContextInfo.webServerRelativeUrl);
grid.init();
}

Press F5 to deploy the app to SharePoint. Browse to the Default.aspx page in the app, and a list of customers appears on the page.

See also
Business Connectivity Services in SharePoint
Get started using the client object model with external data in SharePoint
SharePoint Add-ins
Choose patterns for developing and hosting your SharePoint Add-in
BCS client object model reference for SharePoint
What's new in Business Connectivity Services in SharePoint
Complete basic operations using SharePoint client library code
Business Connectivity Services programmers reference for SharePoint
3/26/2018 • 2 minutes to read Edit Online

Find reference information to help you create solutions using Business Connectivity Services (BCS) in SharePoint. This section provides information for working with BCS programmatically
using a number of advanced programming APIs and technologies.

In this section
BCS REST API reference for SharePoint
BCS client object model reference for SharePoint
Changes in the BDC model schema for SharePoint
BDC model schema reference for SharePoint

See also
Business Connectivity Services in SharePoint
What's new in Business Connectivity Services in SharePoint
Get started with Business Connectivity Services in SharePoint
.NET client API reference for SharePoint Online
BCS REST API reference for SharePoint
3/26/2018 • 2 minutes to read Edit Online

Contains reference information for constructing Representational State Transfer (REST) URLs to access and manipulate external data sources using Business Connectivity Services (BCS) in
SharePoint.

Using RESTful APIs to access external data in SharePoint


The REST interface provided by SharePoint enables you to access most SharePoint resources through specially constructed URLs. Business Connectivity Services (BCS) uses this
architecture to provide access to external data.
You can access external data by constructing URLs just as you would to access standard list items.
NOTE

Access to entities through the BDC directly is not provided. To work with external data, you must create an external list and use the REST URLs to access the list items contained in the
external list.
The supported HTTP verbs for working with external lists are GET, PUT, POST, and DELETE.
Unlike with normal lists, you can't create an external list using REST. You must do that by creating a BDC model and an external list using Visual Studio 2012.
The information in Table 1 shows how to construct RESTful URLs and the corresponding client object model calls to access and manipulate data from external data sources.
Table 1. RESTful URL formats for accessing external data

URL D ES CR IPTIO N HT TP ME THO D

http://[sharepointsite]/_api The base of any REST request. The _api virtual directory is mapped GET
to call into client.svc, where the client object model can be used.

http://[sharepointsite]/_api/web/title Retrieves the title of the current web. GET

http://[sharepointsite]/_api/lists Retrieves all lists on a site. GET

http://[sharepointsite]/_api/lists/getbytitle('listname') Retrieves the metadata for a specified list. GET

http://[sharepointsite]/_api/lists/getbytitle('listname')/itemsRetrieves the list items in a specified list. GET

http://[sharepointsite]/_api/lists/getbytitle('listname')? Retrieves the title of a specific list. GET


select=Title

Constructing query strings for filtering data


In order to limit the amount of data returned, or make it more relevant to the user, you can use the filter operations found in Table 2.
Table 2. Operators for filtering data

O PER ATO R D ES CR IPTIO N

EQ Equals
Note: When you use EQ to filter, the filter criteria are passed to the external system where the filtering
happens on the server.

GT Greater Than
Note: When you use the GT operator, only client-side filtering is executed.> For example:
web/lists/getByTitle('ListName')/Items?$select=Title&amp;$filter=AverageRating gt 3
returns all titles with an average rating over 3.
NOTE

To retrieve columns that are part of an association, you must explicitly include the column in the URL using $select in the query string.

See also
Business Connectivity Services in SharePoint
Complete basic operations using SharePoint REST endpoints
Use OData query operations in SharePoint REST requests
SharePoint: Perform basic data access operations by using REST in apps
Choose the right API set in SharePoint
Complete basic operations using JavaScript library code in SharePoint
BCS client object model reference for SharePoint
3/26/2018 • 6 minutes to read Edit Online

Learn about the objects that are available for creating client-side scripts using the SharePoint client object model to access external data exposed by Business Connectivity Services (BCS).
The following objects are available for creating client-side scripts using the SharePoint client object model to access external data that is exposed by Business Connectivity Services (BCS).
The BCS object model components that are exposed to the client object model are located in Microsoft.SharePoint.Client.dll.

Entity object
The Entity object essentially represents a table in a database. The methods and properties presented here show the objects that can be manipulated through the use of the client code library.
Each of these calls maps directly to a server object model call. However, they are callable by a detached client, such as in a web browser using JavaScript.
Methods

ME THO D S ME THO D S IG NATU R E D ES CR IPTIO N

Create Identity Create(FieldValueDictionary fieldValues,


LobSystemInstance lobSystemInstanceName)

FindSpecificDefault EntityInstance FindSpecificDefault(Identity identity,


LobSystemInstance lobSystemInstanceName)

FindspecificByBdcIDDefault EntityInstance FindSpecific(Identity identity, string


specificFinderName, LobSystemInstance
lobSystemInstanceName)

FindSpecificByBdcID EntityInstance FindSpecificByBdcIDDefault(string


BdcIdentity, LobSystemInstance lobSystemInstanceName)

GetCreatorView EntityInstance FindSpecificByBdcID(string BdcIdentity,


string specificFinderName,LobSystemInstance
LobSystemInstanceName)

GetDefaultSpecificFinderView View GetCreatorView(string methodInstanceName)

GetSpecificFinderView_Client View GetDefaultSpecificFinderView()

GetUpdaterView_Client View GetSpecificFinderView_Client( string


specificFinderName)

GetIdentifiers View GetUpdaterView_Client(string updaterName)

GetIdentifiers()

Properties

PR O PER T Y D ES CR IPTIO N

long EstimatedInstanceCount { get; } Gets the number of expected external items of this external content type.

string Name { get; } Gets the name of the metadata object.

string Namespace { get; } Gets the namespace of the given data class.

int GetIdentifierCount()

EntityInstance method
Namespaces

MANAG ED JAV AS CR IPT

Microsoft.BusinessData.Runtime SP.BusinessData.Runtime

Methods

ME THO D R E TU R N T YPE D ES CR IPTIO N

Delete void Deletes the External Item.

FromXml void Sets the values in this dictionary from specified XML.
Method signature FromXml(string xml)

GetIdentity Identity Gets the identity of this External Item.

Delete void Deletes the External Item.

ToXml string Retrieves the values in XML format.


ME THO D R E TU R N T YPE D ES CR IPTIO N

Update void Submits the changes made to the External Item.

Properties

PR O PER T Y R E TU R N T YPE D ES CR IPTIO N

this[string fieldDotNotation] { get; set; } Object Gets or sets the value of the field referred to by the dot notation.

RelatedSpecificFinderName { get; } string

EntityView method
Specifies a customized view of the Entity data
Namespaces

MANAG ED JAV AS CR IPT

Microsoft.BusinessData.MetadataModel SP.BusinessData

Methods

ME THO D R E TU R N T YPE D ES CR IPTIO N

GetDefaultValues_Client() FieldValueDictionary Gets a field value dictionary that contains the default values for this
view.

GetXmlSchema() string Gets the XML Schema of the view.

GetType(string fieldDotNotation) string Gets the type of the specified field.

GetType(string fieldDotNotation) TypeDescriptor Gets the TypeDescriptor object that corresponds to the given dot
notation.

Properties

PR O PER T Y R E TU R N T YPE D ES CR IPTIO N

Fields { get; } FieldCollection Gets the collection of fields in the view.

Name { get; } string Gets the name of this View object

RelatedSpecificFinderName { get; } string Retrieves the name of the specific finder MethodInstance that this
view is tied to.

LobSystem method
Namespaces

MANAG ED JAV AS CR IPT

Microsoft.BusinessData.MetadataModel SP.BusinessData

Methods

ME THO D R E TU R N T YPE D ES CR IPTIO N

GetLobSystemInstances() void Gives the list of LOB system instances.

Name void Gets the name of the LobSystem.

Properties

PR O PER T Y D ES CR IPTIO N

None.

LobSystemInstance method
Namespaces

MANAG ED JAV AS CR IPT

Microsoft.BusinessData.MetadataModel SP.BusinessData

Methods

ME THO D R E TU R N T YPE D ES CR IPTIO N

None. void

Properties
PR O PER T Y D ES CR IPTIO N

None.

Identifier method
Namespaces

MANAG ED JAV AS CR IPT

Microsoft.BusinessData.MetadataModel SP.BusinessData

Methods

ME THO D R E TU R N T YPE D ES CR IPTIO N

ContainsLocalizedDisplayName bool Determines whether the metadata object contains localized display
name.

GetDefaultDisplayName string Returns the default display name.

GetLocalizedDisplayName string Returns the localized display name.

Properties

PR O PER T Y R E TU R N T YPE D ES CR IPTIO N

IdentifierType {get;} string Returns the type of identifier.

Name {get;} string Gets the name of the identifier.

IdentifierCollection method
Namespaces

MANAG ED JAV AS CR IPT

Microsoft.BusinessData.MetadataModel.Collections SP.BusinessData.Collections

Methods

ME THO D R E TU R N T YPE D ES CR IPTIO N

None. void

Properties

PR O PER T Y D ES CR IPTIO N

None.

Identity method
Namespaces

MANAG ED JAV AS CR IPT

Microsoft.BusinessData.Runtime SP.BusinessData.Runtime

Constructor

CO NS TR U CTO R D ES CR IPTIO N

public Identity (Object[] identifierValues) Constructs a new instance of the class by using an array of identifier values.

Methods

ME THO D R E TU R N T YPE D ES CR IPTIO N

Serialize string Gets a string representation of the identity.

Properties

PR O PER T Y R E TU R N T YPE D ES CR IPTIO N

IdentifierCount { get; } int Returns the number of identifiers.

IsTemporary { get; } bool Checks whether the identity is temporary.

this[int identifierIndex] { get; } Object Retrieves the element at the given index. CSOM does not support
int-based indexing. String-based accessor implemented for the
same.
PR O PER T Y R E TU R N T YPE D ES CR IPTIO N

TemporaryId { get; } Guid Returns the temporary part of the identity.

FieldValueDictionary method
Namespaces

MANAG ED JAV AS CR IPT

Microsoft.BusinessData.Runtime SP.BusinessData.Runtime

Methods

ME THO D R E TU R N T YPE D ES CR IPTIO N

FromXml void Sets the values in this dictionary from specified XML.

GetCollectionSize int Returns the size of the collection that the dot notation refers to.

ToXml string Retrieves the values in XML format.

Properties

PR O PER T Y D ES CR IPTIO N

Object this[string fieldDotNotation] { get; set; } Gets or sets the value of the field referred to by the dot notation.

EntityFieldCollection method
Namespaces

MANAG ED JAV AS CR IPT

Microsoft.BusinessData.Runtime SP.BusinessData.Runtime

Methods

ME THO D R E TU R N T YPE D ES CR IPTIO N

None. void

Properties

PR O PER T Y D ES CR IPTIO N

None.

EntityField method
Namespaces

MANAG ED JAV AS CR IPT

Microsoft.BusinessData.Runtime SP.BusinessData.Runtime

Methods

ME THO D R E TU R N T YPE D ES CR IPTIO N

None. void

Properties

PR O PER T Y R E TU R N T YPE R E AD O NLY D ES CR IPTIO N

ContainsLocalizedDisplayName Boolean Yes Determines whether the field contains a localized


display name.

DefaultDisplayName string Yes Retrieves the default display name of the Field.

GetLocalizedDisplayName string Retrieves the localized display name of the Field.

Name string Yes Retrieves the name of the Field.

TypeDescriptor class
Namespaces

MANAG ED JAV AS CR IPT

Microsoft.BusinessData.MetadataModel SP.BusinessData
Methods

ME THO D R E TU R N T YPE R E AD O NLY D ES CR IPTIO N

ContainsLocalizedDisplayName() Boolean Yes Determines whether the type descriptor contains


a localized display name.

GetLocalizedDisplayName() string Yes Returns the localized display name.

GetDefaultDisplayName() string Returns the default display name.

Properties

PR O PER T Y R E TU R N T YPE D ES CR IPTIO N

Name string Retrieves the name of the Field.

TypeName string Retrieves the name of the data type represented by this type
descriptor.

IsReadOnly Boolean Determines whether this type descriptor represents a read-only


data structure.

ContainsReadOnly Boolean Determines whether this type descriptor or one of its children
represent a read-only data structure.

IsCollection Boolean Determines whether the described type represents a collection data
structure.

Interfaces
The namespace is Microsoft.BusinessData.MetadataModel.

INTER FACE D ES CR IPTIO N

IMetadataCatalog The entry point into the BDC object model. Use the DatabaseBasedMetadataCatalog on the server.

ILobSystem Contains the details about an external system.

IEntity An external content type in the BDC Metadata Store.

IMethod An operation that can be performed on the external content type.

IEntityInstance An entity instance (also known as external item) is a single item returned from an external system in
BDC.
The IEntityInstance interface abstracts the underlying data sources and insulates the clients from having
to learn application-specific coding paradigms; it enables them to access all business data in a single,
simplified way. By using the IEntityInstance interface, you can work with a row of data from a database
in just the same way as working with a complex .NET Framework structure returned by a web service.
An entity instance in BDC has special semantics attached to it. For example, it has the ability to know
which field or fields in the row represent the identifier for the entity instance, and it enables you to call
methods, such as GetAssociated, GetIdentifierValues, and Execute, on that entity instance.

IEntityInstanceEnumerator Enumerators can be used to read the data in the external items collection, but they cannot be used to
modify the underlying collection. IEntityInstanceEnumerator supports streaming and is therefore very
useful when the back-end application returns large amounts of data.

Client Object model FAQ


Does the tag need to be included in a CAML query when querying an external list
No.
Do all fields in the external list need to be specified in the CAML query?
Using the ViewXML tag in the BDC model, the developer can specify only those fields that are required and the CSOM APIs for Lists will return only those fields.

See also
Business Connectivity Services programmers reference for SharePoint
.NET client API reference for SharePoint Online
Get started using the client object model with external data in SharePoint
How to: Use the client code library to access external data in SharePoint
What's new in Business Connectivity Services in SharePoint
Get started with Business Connectivity Services in SharePoint
Changes in the BDC model schema for SharePoint
3/26/2018 • 2 minutes to read Edit Online

Learn what has changed in SharePoint for the BDC model schema. The number of changes in the schema (BDCMetadata.xsd) for creating BDC models in SharePoint is relatively small. But
these changes have significant impact on the feature set offerings of Business Connectivity Services (BCS).
For more information about the BDCMetadata schema, see BDC model schema reference for SharePoint.

Changes to complex type elements in BDCMetadata.xsd


The following table shows what changes have been made to the top-level elements in the BDCMetadata schema.
Table 1. New complex types

ELEMENT D ES CR IPTIO N

IndividuallySecurableMetadataObject Used to designate that the specified MetadataObject is able to be secured explicitly and not by
association to its parent.

MetadataObject Used to store additional metadata about the connection to the external data source.

Changes to simple type elements in BDCMetadata.xsd


The following table lists the changes that have been made to the attributes of each element.
Table 2. Changes to simple types

ELEMENT D ES CR IPTIO N

No changes

Changes to attributes in BDCMetadata.xsd


The following table lists the changes to the attributes of each element.
Table 3. Changes to attributes

AT TR IB U TE PAR ENT D ES CR IPTIO N

No changes

See also
Business Connectivity Services in SharePoint
What's new in Business Connectivity Services in SharePoint
Get started with Business Connectivity Services in SharePoint
Business Connectivity Services programmers reference for SharePoint
BDC model schema reference for SharePoint
BDC model schema reference for SharePoint
5/3/2018 • 44 minutes to read Edit Online

Contains reference documentation for the BDC model schema (BDCMetadata.xsd), which you can use to create external content types in SharePoint. BDCMetadata.xsd

AccessControlEntry element
Contains an access control entry (ACE) that specifies access rights for the parent element.
See Business Connectivity Services security overview to learn more about the Business Connectivity Services and security.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<AccessControlEntry Principal = "String"> </AccessControlEntry>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Principal Required.
The name of the security principal that has this ACE.
Attribute type: String

Child elements

ELEMENT D ES CR IPTIO N

Right Element in AccessControlEntry (BDCMetadata Schema) A Right element that specifies the permissions available to the security principal.

Parent element

ELEMENT D ES CR IPTIO N

AccessControlList Element (BDCMetadata Schema) The access control list (ACL) that contains this ACE.

AccessControlList element
Specifies an access control list (ACL) for the parent element.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<AccessControlList></AccessControlList>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

AccessControlEntry Element in AccessControlList (BDCMetadata Schema) An access control entry (ACE).

Parent element

ELEMENT D ES CR IPTIO N

Model Element (BDCMetadata Schema) A model that contains external content types in a business application.

LobSystem Element in LobSystems (BDCMetadata Schema) The LobSystems contained inside the model.

Entity Element in Entities (BDCMetadata Schema) An external content type.

Method Element in Methods (BDCMetadata Schema) A method of an external content type.

Association Element in MethodInstances (BDCMetadata Schema) An association.

MethodInstance Element in MethodInstances (BDCMetadata Schema) A method instance of an external content type.

Action element
Specifies an action supported by an external content type.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog
Schema: BDCMetadata
Actions bridge the gap between SharePoint and Office 2013 and an external system's user interface by providing a link back to the external system.
By default, the Business Data Connectivity (BDC) service provides actions such as View Item, Edit Item, and Delete Item after you model these operations in the BDC model. In addition
to these default actions, you can create actions for other functionality you want to attach to your external content type. For example, you can use actions to perform simple actions, such as
sending email messages to a customer from the Customer external content type or opening a customer's home page in a browser.
Actions travel with an external content type. That is, after you define an action for an external content type, the action appears everywhere you display that external content type—whether in
an external list or Business Data web part or in an External Data column.

<Action Position = "Integer" IsOpenedInNewWindow = "Boolean" Url = "String" ImageUrl = "String" Name = "String" DefaultDisplayName = "String" IsCached = "Boolean"> </Action>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Position Required.
The suggested position of this action among the other actions of this external content type.
Attribute type: Integer

IsOpenedInNewWindow Optional.
Specifies whether the results of executing an action are presented in a new user interface window.
Default value: false
Attribute type: Boolean

Url Required.
The URL to go to when the action is invoked. The URL string is a .NET Framework format string. Each
format specifier (for example, {0}) corresponds to an Action parameter.
Attribute type: String

ImageUrl Optional.
The absolute or relative path to the icon image for the action. The icon image should be 16 x 16 pixels.
Attribute type: String

Name Required.
The name of this action.
Attribute type: String

DefaultDisplayName Optional.
The default display name for this action.
Attribute type: String

IsCached Optional.
Specifies whether this action is used frequently. This is used by the BDC client runtime to cache this
action.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized names of the action.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of the action.

ActionParameters Element in Action (BDCMetadata Schema) The parameters of the action.

Parent element

ELEMENT D ES CR IPTIO N

Actions Element in Entity (BDCMetadata Schema) The list of actions of an external content type.

ActionParameter element
Specifies the parameters of a URL-based action. It defines how to parameterize the URL of an action with EntityInstance-specific data.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata
The URL attribute of a URL-based action can receive parameters by using the ActionParameter element.

Important: ActionParameters can either represent identifier values, or values that correspond to TypeDescriptors in a SpecificFinder of the Entity. The ActionParameter
represents an identifier value when the IdOrdinal property is present. The value of the property specifies the index of the identifier whose value this ActionParameter represents. If the
IdOrdinal property is not specified, the ActionParameter represents a TypeDescriptor, and the Name attribute specifies which type descriptor is being represented. The Name
attribute is specified as a Dotted Path.

The ActionParameter element accepts the following property.

Important: Properties are case-sensitive.

Properties
PR O PER T Y T YPE D ES CR IPTIO N R EQ U IR ED . D EFAU LT V ALU E LIMITS /ACCEPTED V ALU ES

IdOrdinal System.Int32 Specifies if the Optional


ActionParameter represents
an identifier instead of a field.

<ActionParameter Index = "Integer" Name = "String" DefaultDisplayName = "String" IsCached = "Boolean"> </ActionParameter>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Index Required.
An ordinal attribute that specifies the position of this ActionParameter among other
ActionParameters in the URL.
Attribute type: Integer

Name Required.
The name of the ActionParameter.
Attribute type: String

DefaultDisplayName Optional.
The default display name for the ActionParameter.
Attribute type: String

IsCached Optional.
Specifies whether this ActionParameter is used frequently. This attribute is used by the BDC client
runtime to cache this Action.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized display names for the ActionParameter.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of the ActionParameter.

Parent element

ELEMENT D ES CR IPTIO N

ActionParameters Element in Action (BDCMetadata Schema) The ActionParameters element that contains this ActionParameter.

ActionParameters element
Specifies a list of ActionParameters for an action.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<ActionParameters></ActionParameters>

The following sections describe attributes, child elements, and parent elements.
Attributes
None.
Child elements

ELEMENT D ES CR IPTIO N

ActionParameter Element in ActionParameters (BDCMetadata Schema) An ActionParameter.

Parent element

ELEMENT D ES CR IPTIO N

Action Element in Actions (BDCMetadata Schema) The Action that these ActionParameters belong to.

Actions element
Specifies a list of actions of an external content type.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Actions></Actions>
The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

Action Element in Actions (BDCMetadata Schema) An action of an external content type.

Parent element

ELEMENT D ES CR IPTIO N

Entity Element in Entities (BDCMetadata Schema) The external content type that these actions belong to.

Association element
The Association element links related external content types within a system. For example, a customer is associated with a sales order in the AdventureWorks system: a customer makes sales
orders. An Association holds pointers to the source and destination external content types and a pointer to the business logic (a MethodInstance object) that allows a client to get the
destination external content type from the source external content type. The traversal of an Association is a method call on the external system.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog
Schema: BDCMetadata

Important: Properties are case-sensitive.

Properties

PR O PER T Y T YPE D ES CR IPTIO N R EQ U IR ED D EFAU LT V ALU E LIMITS /ACCEPTED V ALU ES

HideOnProfilePage System.Boolean Specifies whether the related Optional


external content type should be
added to the profile page of the
master external content type.

<Association Type = "String" Default = "Boolean" ReturnParameterName = "String" ReturnTypeDescriptorName = "String" ReturnTypeDescriptorLevel = "Integer" Name = "String" DefaultDisplayName = "Str

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Type Required.
The MethodInstanceType that specifies the type of the Association.
The following table lists the possible values for this attribute.
V ALUE D E S C R IP T IO N

AssociationNavigator The MethodInstance is an


AssociationNavigator.

Associator The MethodInstance is an Associator.

Disassociator The MethodInstance is a Disassociator.

BulkAssociatedIdEnumerator The MethodInstance is a


BulkAssociatedIdEnumerator.

BulkAssociationNavigator The MethodInstance is a


BulkAssociationNavigator.

Default Optional.
Specifies whether the Association is the default among all Associations sharing its type within the
containing external content type. If set to true, the Association is the default among all Associations
sharing its type within the containing external content type. If set to false, the Association is not the
default among all Associations sharing its type within the containing external content type.
Default value: false
Attribute type: Boolean

ReturnParameterName Optional.
The name of the parameter that contains the ReturnTypeDescriptor of the Association. The Direction
attribute of the parameter must contain a value of either "Out", "InOut", or "Return".
Attribute type: String

ReturnTypeDescriptorName Optional.
This has been deprecated. Use the ReturnTypeDescriptorPath instead.
Attribute type: String
AT TR IB U TE D ES CR IPTIO N

ReturnTypeDescriptorLevel Optional.
This has been deprecated. Use the ReturnTypeDescriptorPath instead.
Attribute type: Integer

ReturnTypeDescriptorPath Optional.
The dotted path of the TypeDescriptor of the Association.
Attribute type: String

Name Required.
The name of the Association.
Attribute type: String

DefaultDisplayName Optional.
The default display name for the Association.
Attribute type: String

IsCached Optional.
Specifies whether this Association is frequently used.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The LocalizedDisplayNames element specifies a list of localized names for the Association.

Properties Element in MetadataObject (BDCMetadata Schema) The Properties element specifies the properties of the Association.

AccessControlList Element (BDCMetadata Schema) The AccessControlList element specifies a set of access rights for the Association.

SourceEntity Element in Association (BDCMetadata Schema) The SourceEntity element specifies the source external content type in the association.

DestinationEntity Element in Association (BDCMetadata Schema) The DestinationEntity element specifies the destination external content type in the Association.

Parent element

ELEMENT D ES CR IPTIO N

MethodInstances Element in Method (BDCMetadata Schema) The MethodInstances element that contains the Association.

AssociationGroup element
Specifies an AssociationGroup. AssociationGroup is a construct that ties the related AssociationMethods together. For example, GetOrdersForCustomer, GetCustomerForOrder, and
AssociateCustomerToOrder are all association methods that work on the same relationship between Customer and Order.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata
AssociationGroup must be defined on the Entity element that is the Destination of the AssociationReferences that are not marked as Reverse, or the Source of the
AssociationReferences that are marked as Reverse.

<AssociationGroup Name = "String" DefaultDisplayName = "String" IsCached = "Boolean"> </AssociationGroup>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Name Required.
The name of the AssociationGroup.
Attribute type: String

DefaultDisplayName Optional.
The default display name of the AssociationGroup.
Attribute type: String

IsCached Optional.
Specifies whether the AssociationGroup is used frequently.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized names of the AssociationGroup.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of the AssociationGroup.

AssociationReference Element in AssociationGroup (BDCMetadata Schema) An AssociationReference of an AssociationGroup.

Parent element
ELEMENT D ES CR IPTIO N

AssociationGroups Element in Entity (BDCMetadata Schema) The AssociationGroups element that contains this AssociationGroup.

AssociationGroups element
Specifies a list of AssociationGroup elements.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<AssociationGroups></AssociationGroups>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

AssociationGroup Element in AssociationGroups (BDCMetadata Schema) An AssociationGroup.

Parent element

ELEMENT D ES CR IPTIO N

Entity Element in Entities (BDCMetadata Schema) The external content type that this AssociationGroups element is associated with.

AssociationReference element
Specifies an AssociationReference in an AssociationGroup.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<AssociationReference EntityNamespace = "String" EntityName = "String" AssociationName = "String" Reverse = "Boolean"> </AssociationReference>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

EntityNamespace Optional.
The namespace of the external content type where the Association is defined. If EntityName is
specified, EntityNamespace is required.
Attribute type: String

EntityName Optional.
The name of the external content type where the Association is defined. If EntityNamespace is
specified, EntityName is required.
Attribute type: String

AssociationName Required.
The name of the Association.
Attribute type: String

Reverse Optional.
Specifies that the referenced Association has its source and destination reversed. This would indicate
the Association is working in the opposite direction compared to other associations in the same
AssociationGroup. For example, if the AssociationGroup references an Association
"GetOrdersForCustomer", returning Order items for the given Customer item, then the
AssociationGroup is in the direction of Customer to Order. The other AssociationReference,
referencing another association "GetCustomerForOrder", must be marked as reverse, because this
association is in the direction of Order to Customer.
Default value: false
Attribute type: Boolean

Child elements
None
Parent element

ELEMENT D ES CR IPTIO N

AssociationGroup Element in AssociationGroups (BDCMetadata Schema) The AssociationGroup that this AssociationReference belongs to.

ConvertType element
Specifies the rule to convert the data type of a data value into another data type.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata
The Convert element specifies the rule to convert the data type of a data value into another data type. When the rules are applied in order, this rule specifies the data type of the data value to
be converted to the data type specified by the BDCType attribute. When the rules are applied in reverse order, this rule specifies the data type of the data value to be converted to the data
type specified by the LOBType attribute. For example, this rule can specify converting a date value obtained from an external system, into a culture and locale sensitive string which will
eventually be displayed to the user, and converting the updated value for that string back into the date that is compatible with the external system.

Caution: ConvertType does not support non-Gregorian calendars for conversions between System.String and System.DateTime.

<ConvertType LOBType = "String" BDCType = "String"> </ConvertType>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

LOBType Required.
The data type to convert the data value into when the rules are applied in reverse order.
Attribute type: String

BDCType Required.
The data type to convert the data value into when the rules are applied in order.
Attribute type: String

LOBLocale Optional.
The locale of the data that is received from the external system.

Child elements
None
Parent element

ELEMENT D ES CR IPTIO N

Interpretation Element in TypeDescriptor (BDCMetadata Schema) The rules to apply to the data stored in the data structures that are represented by a TypeDescriptor

DefaultValue element
Represents a default value.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<DefaultValue MethodInstanceName = "String" Type = "String"> </DefaultValue>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

MethodInstanceName Required.
The name of the MethodInstance to which this DefaultValue applies.
Attribute type: String

Type Required.
The data type of the default value.
The following are the acceptable values for this attribute.
System.Int16
System.Int32
System.Int64
System.Single
System.Double
System.Decimal
System.Boolean
System.Byte
System.UInt16
System.UInt32
System.UInt64
System.Guid
System.String
System.DateTime
Any other serializable type (such as where Type.IsSerializable == true )
Attribute type: String

Child elements
None
Parent element

ELEMENT D ES CR IPTIO N

DefaultValues Element in TypeDescriptor (BDCMetadata Schema)


DefaultValues element
Specifies a list of DefaultValues of a TypeDescriptor.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<DefaultValues></DefaultValues>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

DefaultValue Element in DefaultValues (BDCMetadata Schema) The default value of a TypeDescriptor for a MethodInstance.

Parent element

ELEMENT D ES CR IPTIO N

TypeDescriptor Element (BDCMetadata Schema) The TypeDescriptor that these DefaultValues belong to.

DestinationEntity element
Specifies the destination external content type in the Association.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<DestinationEntity Namespace = "String" Name = "String"> </DestinationEntity>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Namespace Required.
The name of the entity namespace.
Attribute type: String

Name Required.
The name of the destination entity.
Attribute type: String

Child elements
None
Parent element

ELEMENT D ES CR IPTIO N

Association Element in MethodInstances (BDCMetadata Schema)

Entities element
Specifies a list of external content types in an external system.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Entities></Entities>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

Entity Element in Entities (BDCMetadata Schema) An external content type in an external system.

Parent element
ELEMENT D ES CR IPTIO N

LobSystem Element in LobSystems (BDCMetadata Schema) An external system.

Entity element
Specifies an external content type.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Entity Namespace = "String" Version = "String" EstimatedInstanceCount = "Integer" DefaultOperationMode = "String" Name = "String" DefaultDisplayName = "String" IsCached = "Boolean"> </Entity>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Namespace Required.
The namespace that this external content type belongs to.
Attribute type: String
Note: The namespace should not contain the asterisk special character " \*".

Version Required.
The version number of this external content type.
Attribute type: String
Caution: When the BDC model changes, you must increase the version number of the external content
type. If the structure of an external content type changes, you should increase the major number.
Examples of structural changes include adding a field to a SpecificFinder or changing an identifier field.
If the change does not affect the structure of the external content type, for example, when adding a
creator method, changing connection information, or when changing names of LobSystems and type
descriptors, you should change the build number and revision number.

EstimatedInstanceCount Optional.
The estimated number of external items contained by the external system.
Default value: 10000
Attribute type: Integer

DefaultOperationMode Optional.
Specifies the default behavior when interacting with the external system while creating, deleting,
updating, or reading external items.
Default value: Default
The following table lists the possible values for this attribute.
V ALUE D E S C R IP T IO N

Online Bypass the cached external items for all


operations and interact with the external
system directly.

Cached Perform Create, Read, Update, and Delete


operations directly against the cached
external items. For Read operations, if the
requested external items are available in the
cache, use the external items in the cache.
Otherwise, bypass the cache to obtain the
external items from the external system, and
put it in the cache for later use.

Offline Perform Create, Read, Update, and Delete


operations against only the cached external
items.

Default Use the System default behavior. This uses


Cached mode if the environment supports
caching external items.

Name Required.
The name of the external content type.
Attribute type: String
Note: The name of an external content type should not contain the asterisk special character " \*".

DefaultDisplayName Optional.
The default display name of the external content type.
Attribute type: String

IsCached Optional.
Specifies whether this external content type will be frequently used. If set to true, Business Data
Connectivity (BDC) service will cache this external content type in memory.
Default value: true
Attribute type: Boolean

Child elements
ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized display names of this external content type.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of this external content type.

AccessControlList Element (BDCMetadata Schema) The access control list (ACL) of this external content type.

Identifiers Element in Entity (BDCMetadata Schema) The identifiers of the external content type.

Methods Element in Entity (BDCMetadata Schema) The methods of the external content type.

AssociationGroups Element in Entity (BDCMetadata Schema) The association groups of the external content type.

Actions Element in Entity (BDCMetadata Schema) The actions of the external content type.

Parent element

ELEMENT D ES CR IPTIO N

Entities Element in LobSystem (BDCMetadata Schema) The list of external content types in this external system.

FilterDescriptor element
Specifies a filter descriptor of a method.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<FilterDescriptor Type = "String" FilterField = "String" Name = "String" DefaultDisplayName = "String" IsCached = "Boolean"> </FilterDescriptor>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Type Required.
The type of the filter descriptor.
The following table lists the possible values for this attribute.
V ALUE D E S C R IP T IO N

Limit Used while querying an external system and


the value of which can be interpreted as a
limit on the number of external items
EntityInstances that are returned when the
method that it belongs to is called.

PageNumber

Wildcard Used while querying an external system. Its


value represents a pattern of regular and
wildcard characters that is matched against
the value of a particular field of the set of
EntityInstances. The external system returns
only those EntityInstances whose field values
match the specified pattern.

UserContext Used while querying an external system. Its


value can be set automatically by any client
application to the identity of the user who is
calling the external system. This value can then
be used by the external system to authorize
and then filter the results returned.

UserCulture

Username

Password

LastId

SsoTicket

UserProfile Used while querying an external system. Its


value can be obtained by examining the
current user's profile. The external system can
use its value to filter the results returned.
AT TR IB U TE D ES CR IPTIO N

Comparison Used while querying an external system. An


external system can compare a
ComparisonFilter value with the value of a
particular field of a set of EntityInstances and
only those EntityInstances where the field
values pass the comparison test can be
returned.

Timestamp

Input Used while calling an operation in an external


system. An external system can use the value
of an InputFilter as additional arguments for
the operation.

Output Used while calling an operation in an external


system. Additional results of an operation that
cannot be captured by ReturnTypeDescriptor
can be retrieved as a value of the
InputOutputFilter.

InputOutput Used while calling an operation in an external


system. An external system can use the value
of an InputOutputFilter as additional
arguments for the operation, and additional
results of an operation that cannot be
captured by ReturnTypeDescriptor can be
retrieved as a value of the InputOutputFilter.

Batching

BatchingTermination

ActivityId ActivityId is used when calling an operation


on the external system. Its value is set to a
GUID that represents the current operation
context. If no such value is available, this filter
generates a random GUID. On SharePoint
Foundation 2010, this filter uses the
CorrelationID.

FilterField Optional.
Attribute type: String

Name Required.
The name of the filter descriptor.
Attribute type: String

DefaultDisplayName Optional.
The default display name of the filter descriptor.
Attribute type: String

IsCached Optional.
Specifies whether this filter descriptor is used frequently. If set to true, Business Data Connectivity (BDC)
service caches this filter descriptor in memory.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized display names of this filter descriptor.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of this filter descriptor.

Parent element

ELEMENT D ES CR IPTIO N

FilterDescriptors Element in Method (BDCMetadata Schema) A list of filter descriptors of a method.

FilterDescriptors element
Specifies a list of filter descriptors of a method.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<FilterDescriptors></FilterDescriptors>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

FilterDescriptor Element in FilterDescriptors (BDCMetadata Schema) A filter descriptor.

Parent element

ELEMENT D ES CR IPTIO N

Method Element in Methods (BDCMetadata Schema) The method this list of filter descriptors belongs to.

Identifier element
Specifies an identifier of an external content type.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata
NOTE

Business Data Connectivity (BDC) service enables the mapping of identifiers to fields with nullable data types. However, for primary identifiers, BDC will cause an error when the value of
these identifiers are null.

<Identifier TypeName = "String" Name = "String" DefaultDisplayName = "String" IsCached = "Boolean"> </Identifier>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N
AT TR IB U TE D ES CR IPTIO N

TypeName Required.
The data type of the value that corresponds to the identifier.
The following table lists the possible values for this attribute.
V ALUE D E S C R IP T IO N

System.Boolean A bit.

System.Byte A number ranging from 0 to 255 inclusive.

System.Char A Unicode character.

System.DateTime A date and time ranging from 12:00:00


midnight, January 1, 1 Anno Domini (Common
Era) to 11:59:59 P.M. December 31, 9999 Anno
Domini (Common Era) inclusive, in resolution
of 100 nanoseconds.

System.Decimal A number ranging from negative


79,228,162,514,264,337,593,543,950,335 to
positive
79,228,162,514,264,337,593,543,950,335
inclusive.

System.Double A double precision number ranging from


negative 1.79769313486232e308 to positive
1.79769313486232e308 inclusive, and positive
zero, negative zero, positive infinity, negative
infinity, and not-a-number (NaN).

System.Guid A GUID.

System.Int16 A number ranging from negative 32768 to


positive 32767 inclusive.

System.Int32 A number ranging from 0 to 4,294,967,295


inclusive.

System.Int64 A number ranging from 0 to


18,446,744,073,709,551,615 inclusive.

System.SByte A number ranging from negative 128 to


positive 127 inclusive.

System.Single A single precision number ranging from


negative 3.402823e38 to positive 3.402823e38
inclusive.

System.String A string of Unicode text.

System.TimeSpan A duration ranging from negative 10675199


days 2 hours 48 minutes 5 seconds 477
milliseconds 580 microseconds 800
nanoseconds to positive 10675199 days 2
hours 48 minutes 5 seconds 477 milliseconds
580 microseconds 800 nanoseconds inclusive,
in resolution of 100 nanoseconds.

System.UInt16 A number ranging from 0 to 65535 inclusive.

System.UInt32 A number ranging from 0 to 4,294,967,295


inclusive.

System.UInt64 A number ranging from 0 to


18,446,744,709,551,615 inclusive.

Name Required.
The name of the identifier.
Attribute type: String

DefaultDisplayName Optional.
The default display name of the identifier.
Attribute type: String
AT TR IB U TE D ES CR IPTIO N

IsCached Optional.
Specifies whether this identifier is used frequently. If set to true, Business Data Connectivity (BDC)
service caches the identifier in memory.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized display names of the identifier.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of the identifier.

Parent element

ELEMENT D ES CR IPTIO N

Identifiers Element in Entity (BDCMetadata Schema) A list of identifiers of an external content type.

Identifiers element
Specifies a list of identifiers of an external content type.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Identifiers></Identifiers>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

Identifier Element in Identifiers (BDCMetadata Schema) Specifies an identifier.

Parent element

ELEMENT D ES CR IPTIO N

Entity Element in Entities (BDCMetadata Schema) The external content type that contains this list of identifiers.

Interpretation element
Specifies the rules to apply to the data stored in the data structures represented by a TypeDescriptor. These rules are typically specified to change the data values returned by an external
system to make it easier to represent them in the user interface. When the data value is obtained from the external system, the specified rules must be applied in the order they are specified
in the Interpretation element. The first rule must be applied to the data value received from the external system; the consecutive rules apply to the data value that result from the application
of the previous rule. When the data value is sent to external system, the specified rules must be applied in the reverse order they are specified in the Interpretation element. The first rule
must be applied to the data value received from the user; the consecutive rules apply to the data value that result from the application of the previous rule.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Interpretation></Interpretation>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

ConvertType Element in Interpretation (BDCMetadata Schema) A ConvertType element that specifies the conversion of a data type to another data type.

NormalizeDateTime Element in Interpretation (BDCMetadata Schema) A NormalizeDateTime element that specifies the conversion of the date and time representation of a
value obtained from an external system into another representation.

NormalizeString A NormalizeString element that specifies the conversion of the string representation of a value
obtained from an external system into another representation.

Parent element
ELEMENT D ES CR IPTIO N

TypeDescriptor Element (BDCMetadata Schema) The TypeDescriptor element.

LobSystem element
Represents an external data source.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<LobSystem Type = "String" Name = "String" DefaultDisplayName = "String" IsCached = "Boolean"> </LobSystem>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Type The type of the LobSystem.


Required.
The following table lists the possible values for this attribute.
V ALUE D E S C R IP T IO N

Database The represented external data source is a


database.

DotNetAssembly The represented external data source is a set


of .NET Framework classes.

Wcf The represented external data source is a


WCF Service endpoint.

WebService The represented external data source is a


Web service. This has been deprecated, use
WCF instead.

Custom The represented external data source has a


custom connector implemented to manage
the connection and data transfer.

Name The name of the LobSystem.


Required.
Attribute type: String

DefaultDisplayName The default display name of the LobSystem.


Optional.
Attribute type: String

IsCached Specifies whether the LobSystem is frequently used. If frequently used, Business Data Connectivity
(BDC) service caches the LobSystem.
Optional.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized names of the LobSystem.

Properties Element in MetadataObject (BDCMetadata Schema) Specifies the properties of an LobSystem.

AccessControlList Element (BDCMetadata Schema) Specifies the access control list (ACL) of an LobSystem.

Proxy Element in LobSystem (BDCMetadata Schema) Specifies a user-provided proxy that is identical to the one that would be generated if this element was
not present.

LobSystemInstances Element in LobSystem (BDCMetadata Schema) Specifies the external system instances for this external system.

Entities Element in LobSystem (BDCMetadata Schema) Specifies the external content types in this external system.

Parent element

ELEMENT D ES CR IPTIO N

LobSystems Element in Model (BDCMetadata Schema) Specifies a list of external systems in this model.

LobSystemInstance element
Specifies an external system instance.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<LobSystemInstance Name = "String" DefaultDisplayName = "String" IsCached = "Boolean"> </LobSystemInstance>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Name Required.
The name of the external system instance.
Attribute type: String

DefaultDisplayName Optional.
The default display name of the external system instance.
Attribute type: String

IsCached Optional.
Specifies whether this external system instance is used frequently. If set to true, Business Data
Connectivity (BDC) service caches the external system instance.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized names of this external system instance.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of this external system instance.

Parent element

ELEMENT D ES CR IPTIO N

LobSystemInstances Element in LobSystem (BDCMetadata Schema) A list of external system instances.

LobSystemInstances element
Specifies a list of external system instances.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<LobSystemInstances></LobSystemInstances>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

LobSystemInstance Element in LobSystemInstances (BDCMetadata Schema) An external system instance.

Parent element

ELEMENT D ES CR IPTIO N

LobSystem Element in LobSystems (BDCMetadata Schema) An external system.

LobSystems element
Specifies a list of LobSystem elements of a model.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<LobSystems></LobSystems>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements
ELEMENT D ES CR IPTIO N

LobSystem Element in LobSystems (BDCMetadata Schema) A LobSystem element that specifies a external system.

Parent element

ELEMENT D ES CR IPTIO N

Model Element (BDCMetadata Schema) An application definition (BDC model).

LocalizedDisplayName element
Specifies a localized name.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<LocalizedDisplayName LCID = "Integer"> </LocalizedDisplayName>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

LCID Required.
The language code identifier (LCID).
Attribute type: Integer

Child elements
None
Parent element

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The LocalizedDisplayNames element that contains this LocalizedDisplayName.

LocalizedDisplayNames element
Specifies a list of localized names of a MetadataObject.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<LocalizedDisplayNames></LocalizedDisplayNames>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayName Element in LocalizedDisplayNames (BDCMetadata Schema) A localized name.

Parent element

ELEMENT D ES CR IPTIO N

Model Element (BDCMetadata Schema)

LobSystem Element in LobSystems (BDCMetadata Schema)

LobSystemInstance Element in LobSystemInstances (BDCMetadata Schema)

Entity Element in Entities (BDCMetadata Schema)

Identifier Element in Identifiers (BDCMetadata Schema)

Method Element in Methods (BDCMetadata Schema)

FilterDescriptor Element in FilterDescriptors (BDCMetadata Schema)

Parameter Element in Parameters (BDCMetadata Schema)

TypeDescriptor Element (BDCMetadata Schema)

Association Element in MethodInstances (BDCMetadata Schema)


ELEMENT D ES CR IPTIO N

MethodInstance Element in MethodInstances (BDCMetadata Schema)

AssociationGroup Element in AssociationGroups (BDCMetadata Schema)

Action Element in Actions (BDCMetadata Schema)

ActionParameter Element in ActionParameters (BDCMetadata Schema)

MetadataObject element
Namespace:
Schema:

The following sections describe attributes, child elements, and parent elements.
Attributes
Child elements
Parent element

Method element
Specifies a method of an external content type.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Method IsStatic = "Boolean" LobName = "String" Name = "String" DefaultDisplayName = "String" IsCached = "Boolean"> </Method>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

IsStatic Optional.
Specifies whether the execution of this method requires an external item ( EntityInstance) to serve as a
context for execution. If set to true, the method represents a static method and does not require a
specific EntityInstance to provide context for execution. If set to false, the method represents an
instance method and requires an EntityInstance to provide the context for execution.
Default value: true
Attribute type: Boolean

LobName Optional.
The name of the operation defined in the external system that is represented by this method.
Attribute type: String

Name Required.
The name of this method.
Attribute type: String

DefaultDisplayName Optional.
The default display name of the method.
Attribute type: String

IsCached Optional.
Specifies whether this method is used frequently. If set to true, Business Data Connectivity (BDC) service
caches this method in memory.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized display names of the method.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of the method.

AccessControlList Element (BDCMetadata Schema) The access control list (ACL) of this method.

FilterDescriptors Element in Method (BDCMetadata Schema) The filter descriptors of the method.

Parameters Element in Method (BDCMetadata Schema) The parameters of the method. A method cannot have more than one return parameter.

MethodInstances Element in Method (BDCMetadata Schema) The method instances of the method.

Parent element
ELEMENT D ES CR IPTIO N

Methods Element in Entity (BDCMetadata Schema) A list of methods of an external content type.

MethodInstance element
Specifies a MethodInstance.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata
The following two cases in a BDC model result in an InvalidOperationException at run time:
Two SpecificFinder method instances that return the same set of fields.
Two SpecificFinder method instances that have the same number of fields and that share the same number of fields with another method instance, such as a Finder.

<MethodInstance Type = "Strig" Default = "Boolean" ReturnParameterName = "String" ReturnTypeDescriptorName = "String" ReturnTypeDescriptorLevel = "Integer" Name = "String" DefaultDisplayName = "S

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Type Required.
Specifies the type of the MethodInstance.
The following table lists the possible values for this attribute.
V ALUE D E S C R IP T IO N

Finder A type of MethodInstance that can be called


to return a collection of zero or more
EntityInstances of a particular Entity. Finder
input is defined by the FilterDescriptors that
are contained in the Method that contains the
Finder.

SpecificFinder A type of MethodInstance that can be called


to return a specific EntityInstance of a
specific Entity given its EntityInstanceId.
SpecificFinder input is defined and ordered
by the Identifiers that are associated with the
Entity.

GenericInvoker A type of MethodInstance that can be called


to perform a specific task in an external
system. GenericInvoker input and output is
specific to the Method.

IdEnumerator A type of MethodInstance that can be called


to return the Field values that represent the
identity of EntityInstances of a specific
Entity. The IdEnumerator input is defined by
the FilterDescriptors that are contained in the
method that contains the IdEnumerator to
get the list of IDs, which are the unique keys
for each entity that should be searchable. This
method instance enables external data search
in SharePoint Server.

ChangedIdEnumerator A type of MethodInstance that can be called


to retrieve EntityInstanceIds of
EntityInstances that were modified in an
external system after a specified time.

DeletedIdEnumerator A type of MethodInstance that can be called


to retrieve EntityInstanceIds of
EntityInstances that were deleted from an
external system after the specified time.

Scalar A MethodInstance that returns a single value


that you can invoke in the external system. For
example, you can use a scalar method
instance to get the total sales made to date
from the external system. Entities have zero
or more scalar method instances.

AccessChecker A type of MethodInstance that can be called


to retrieve the permissions that the calling
security principal has for each of a collection
of EntityInstances that are identified by the
specified EntityInstanceIds.

Creator A type of MethodInstance that can be called


to create an EntityInstance. The set of fields
that are required to create the EntityInstance
is referred to as the Creator View.
AT TR IB U TE D ES CR IPTIO N

Deleter A type of MethodInstance that can be called


to delete an EntityInstance with a specified
EntityInstanceId.

Updater A type of MethodInstance that can be called


to update an EntityInstance identified by a
specified EntityInstanceId. The set of fields
that is required to update the EntityInstance
is known as the Updater View. The set of fields
whose values should be passed before they
are changed is known as the PreUpdater View.

StreamAccessor A type of MethodInstance that can be called


to retrieve a field of an EntityInstance in the
form of a data stream of bytes.

BinarySecurityDescriptorAccessor A type of MethodInstance that can be called


to retrieve a sequence of bytes from an
external system. The system-specific byte
sequence describes a set of security principals
and the associated permissions that each
security principal has for the EntityInstance
identified by a specified EntityInstanceId.

BulkSpecificFinder A type of MethodInstance that can be called


to return a set of specific EntityInstances of
an Entity, given a set of corresponding
EntityInstanceIds.

BulkIdEnumerator A type of MethodInstance that can be called


to retrieve minimal information about the
external items corresponding to the given
identities. This method instance can be used
to optimize synchronization of cached data.
This method should return only the identities
and version information of the external items
that correspond to given Identities, which the
calling application can compare with the local
version to identify if anything has changed,
and if so, request the changed external items
to update the cached data.

Default Optional.
Specifies whether the MethodInstance is the default among all MethodInstances that share its type
within the containing external content type ( Entity).
Default value: false
Attribute type: Boolean

ReturnParameterName Optional.
The name of the Parameter that contains the ReturnTypeDescriptor of the MethodInstance. The
Direction attribute of the Parameter must be a ParameterDirection attribute with a value of Out,
InOut, or Return.
This attribute must be specified for all types of MethodInstances except GenericInvoker, Creator,
Deleter, and Updater.
Attribute type: String

ReturnTypeDescriptorLevel Optional.
This has been deprecated. Use the ReturnTypeDescriptorPath instead.
Attribute type: Integer

ReturnTypeDescriptorPath Optional.
The dotted path of the TypeDescriptor of the Association.
Attribute type: String

Name Required.
Specifies the name of the MethodInstance.
Attribute type: String

DefaultDisplayName Optional.
Specifies the default display name for the MethodInstance.
Attribute type: String

IsCached Optional.
Specifies whether the MethodInstance is used frequently.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized display names of the MethodInstance.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of the MethodInstance.

AccessControlList Element (BDCMetadata Schema) The access control lists (ACLs) of the MethodInstance.

Parent element
ELEMENT D ES CR IPTIO N

MethodInstances Element in Method (BDCMetadata Schema) The MethodInstances element that contains this MethodInstance.

MethodInstances element
Specifies a list of associations and method instances of a method.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<MethodInstances></MethodInstances>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

Association Element in MethodInstances (BDCMetadata Schema) An association.

MethodInstance Element in MethodInstances (BDCMetadata Schema) A method instance.

Parent element

ELEMENT D ES CR IPTIO N

Method Element in Methods (BDCMetadata Schema) The method that this method instance belongs to.

Methods element
Specifies a list of methods of an external content type.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Methods></Methods>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

Method Element in Methods (BDCMetadata Schema) Specifies a method.

Parent element

ELEMENT D ES CR IPTIO N

Entity Element in Entities (BDCMetadata Schema) The external content type that this list of methods belongs to.

Model element
Specifies the root element that represents an application definition. Models define external content types that are contained by external applications.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Model Name = "String" DefaultDisplayName = "String" IsCached = "Boolean"> </Model>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Name The name of the Model.


Required.
Attribute type: String

DefaultDisplayName The default display name of the Model.


Optional.
Attribute type: String
AT TR IB U TE D ES CR IPTIO N

IsCached Specifies whether the Model is used frequently. If this is set to true, then the Model is cached by the
Business Data Connectivity (BDC) service.
Optional.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized names of the Model.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of the Model.

AccessControlList Element (BDCMetadata Schema) The access control list (ACL) of the Model.

LobSystems Element in Model (BDCMetadata Schema) The LobSystems contained inside this Model.

Parent element
None

NormalizeDateTime element
Specifies the rule used to convert the representation of a date and time value to another representation. For example, this rule can specify converting a value represented in Coordinated
Universal Time (UTC) into a local time zone.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<NormalizeDateTime LobDateTimeMode = "String"> </NormalizeDateTime>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

LobDateTimeMode Required.
Specifies the conversion to apply.
The following table lists the possible values for this attribute.
V ALUE D E S C R IP T IO N

UTC The value that is received from the external


system is UTC (Coordinated Universal Time). If
the value received is Local, it is converted to
UTC. BDC sends UTC to the external system.

Local The value received from the external system is


Local. If the value received from the external
system is Local, then it will be converted to
UTC. BDC sends Local to the external system.

Unspecified The value sent by the external system has


Unspecified kind. BDC assumes the value is in
UTC by overwriting the kind to be UTC. BDC
sends UTC values as Unspecified kind to the
external system.

Child elements
None
Parent element

ELEMENT D ES CR IPTIO N

Interpretation Element in TypeDescriptor (BDCMetadata Schema) An Interpretation element that specifies the rules to apply to the data that is stored in the data
structures represented by a TypeDescriptor.

NormalizeString element
Specifies a parameter of a method.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

The following sections describe attributes, child elements, and parent elements.
Attributes
Child elements
Parent element

Parameter element
Specifies a parameter of a method.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Parameter Direction = "String" Name = "String" DefaultDisplayName = "String" IsCached = "Boolean"> </Parameter>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Direction Required.
The direction of the parameter.
The following table lists the possible values for this attribute.
V ALUE D E S C R IP T IO N

In The represented Parameter is an input


parameter.

Out The represented parameter is an output


parameter.

InOut The represented parameter is an input and


output parameter. In C#, these correspond to
"ref".

Return The represented parameter is a return


parameter.

Name Required.
The name of the parameter.
Attribute type: String

DefaultDisplayName Optional.
The default display name of the parameter.
Attribute type: String

IsCached Optional.
Specifies whether the Parameter is used frequently.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized names of the parameter.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of the parameter.

TypeDescriptor The root type descriptor of the parameter.

Parent element

ELEMENT D ES CR IPTIO N

Parameters Element in Method (BDCMetadata Schema) The Parameters element that contains this parameter.

Parameters element
Specifies a list of parameters of a method.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Parameters></Parameters>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements
ELEMENT D ES CR IPTIO N

Parameter Element in Parameters (BDCMetadata Schema) A parameter.

Parent element

ELEMENT D ES CR IPTIO N

Method Element in Methods (BDCMetadata Schema) The method these parameters belong to.

Properties element
Specifies a list of properties of a metadata object.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Properties></Properties>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

Property Element in Properties (BDCMetadata Schema) Specifies a property.

Parent element

ELEMENT D ES CR IPTIO N

Model Element (BDCMetadata Schema)

LobSystem Element in LobSystems (BDCMetadata Schema)

LobSystemInstance Element in LobSystemInstances (BDCMetadata Schema)

Entity Element in Entities (BDCMetadata Schema)

Identifier Element in Identifiers (BDCMetadata Schema)

Method Element in Methods (BDCMetadata Schema)

FilterDescriptor Element in FilterDescriptors (BDCMetadata Schema)

Parameter Element in Parameters (BDCMetadata Schema)

TypeDescriptor

TypeDescriptor Element (BDCMetadata Schema)

Association Element in MethodInstances (BDCMetadata Schema)

MethodInstance Element in MethodInstances (BDCMetadata Schema)

AssociationGroup Element in AssociationGroups (BDCMetadata Schema)

Action Element in Actions (BDCMetadata Schema)

ActionParameter Element in ActionParameters (BDCMetadata Schema)

Property element
Specifies the name and type of a property of a metadata object.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Property Name = "String" Type = "String"> </Property>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N
AT TR IB U TE D ES CR IPTIO N

Name Required.
Specifies the name of the property.
Attribute type: String

Type Required.
Specifies data type of the property.
Attribute type: String

Child elements
None
Parent element

ELEMENT D ES CR IPTIO N

Properties Element in MetadataObject (BDCMetadata Schema) The Properties element that contains this property.

Proxy element
Specifies a user-provided proxy that is identical to the one that would be generated if this element was not present. This is used to improve performance by removing the proxy generation
overhead. To specify custom business logic that connects to an external system, .NET Connectivity Assembly type external systems must be used.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Proxy></Proxy>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements
None
Parent element

ELEMENT D ES CR IPTIO N

LobSystem Element in LobSystems (BDCMetadata Schema) The LobSystem element that this proxy applies to.

Right element
Specifies a single access permission for an access control entry (ACE).
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<Right BdcRight = "String"> </Right>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N
AT TR IB U TE D ES CR IPTIO N

BdcRight Required.
The permission available to the security principal holding the right.
The following table lists the possible values for this attribute.
V ALUE D E S C R IP T IO N

None No permissions.

Execute The represented security principal has the


permission to invoke a MethodInstance.

Edit The represented security principal has


permission to change the attributes of a
metadata object or its relationship to other
metadata objects.

SetPermissions The represented security principal has


permission to change the set of permissions
for a metadata object.

SelectableInClients The represented security principal has


permission to select the metadata object this
right refers to. If a user does not have this
permission, the metadata object should not
be selectable.

Child elements
None
Parent element

ELEMENT D ES CR IPTIO N

AccessControlEntry Element in AccessControlList (BDCMetadata Schema) The AccessControlEntry element that contains this right.

SourceEntity element
Specifies a source external content type of an Association.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<SourceEntity Namespace = "String" Name = "String"> </SourceEntity>

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

Namespace Required.
The namespace of the external content type that is the source of the Association that contains this
element.
Attribute type: String

Name Required.
The name of the external content type that is the source of the Association that contains this element.
Attribute type: String

Child elements
None
Parent element

ELEMENT D ES CR IPTIO N

Association Element in MethodInstances (BDCMetadata Schema) The Association that contains this element.

TypeDescriptor element
Specifies a TypeDescriptor.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog
Schema: BDCMetadata

<TypeDescriptor TypeName = "String" LobName = "String" IdentifierEntityNamespace = "String" IdentifierEntityName = "String" IdentifierName = "String" ForeignIdentifierAssociationName = "String" F

The following sections describe attributes, child elements, and parent elements.
Attributes

AT TR IB U TE D ES CR IPTIO N

TypeName Required.
The identifier of the data type of the data structure that is represented by the TypeDescriptor.
Attribute type: String

LobName Optional.
The data structure that is represented by the TypeDescriptor. The default value of this attribute is the
name of the TypeDescriptor. For example, a line-of-business (LOB) system data structure named
"CN1A" can be represented by a TypeDescriptor with Name attribute equal to "Customer Name", if the
LobName attribute of this TypeDescriptor is equal to "CN1A".
Attribute type: String

IdentifierEntityNamespace Optional.
The namespace of the external content type that contains the identifier that the TypeDescriptor
references. If the TypeDescriptor does not reference an Identifier, this attribute must not be present.
When this attribute is present, the IdentifierEntityName and IdentifierName attributes must also be
present. The default value of this attribute is the namespace of the external content type that contains
the method containing the parameter that contains the TypeDescriptor.
Attribute type: String

IdentifierEntityName Optional.
The name of the Entity that contains the Identifier that the c TypeDescriptor references. If the
TypeDescriptor does not reference an Identifier, this attribute must not be present. When this
attribute is present, the IdentifierEntityNamespace and IdentifierName attributes must also be
present. The default value of this attribute is the name of the Entity that contains the Method
containing the Parameter that contains the TypeDescriptor.
Attribute type: String

IdentifierName Optional.
The name of the Identifier referenced by the TypeDescriptor. If the TypeDescriptor does not
reference an Identifier, this attribute must not be present.
Attribute type: String

ForeignIdentifierAssociationName Optional.
The name of the Association referenced by the TypeDescriptor. If the TypeDescriptor does not
reference an Association, this attribute must not be present. When this attribute is present, the
IdentifierName attribute must also be present. The ForeignIdentifierAssociationName attribute
must be specified when the Identifier referenced by this TypeDescriptor is related to an Association
and the Identifier is contained by a source Entity of the Association.
Attribute type: String

ForeignIdentifierAssociationEntityName Optional.
The name of the Entity that contains the Association referenced by the TypeDescriptor. If the
TypeDescriptor does not reference an Association, this attribute must not be present. When this
attribute is present, the ForeignIdentifierAssociationEntityNamespace and
ForeignIdentifierAssociationName attributes must also be present. The default value of this attribute
is the name of the Entity that contains the Method containing the Parameter that contains the
TypeDescriptor.
Attribute type: String

ForeignIdentifierAssociationEntityNamespace Optional.
The namespace of the Entity that contains the Association referenced by the TypeDescriptor. If the
TypeDescriptor does not reference an Association, this attribute must not be present. When this
attribute is present, the ForeignIdentifierAssociationEntityName and
ForeignIdentifierAssociationName attributes must also be present. The default value of this attribute
is the namespace of the Entity that contains the Method containing the Parameter that contains the
TypeDescriptor.
Attribute type: String

AssociatedFilter Optional.
The name of a FilterDescriptor that is associated with the TypeDescriptor. If the TypeDescriptor is
not associated with a FilterDescriptor this attribute must not be present.
Attribute type: String

IsCollection Optional.
Specifies whether the TypeDescriptor represents a single data structure or a collection of data
structures.
Default value: false
Attribute type: Boolean

ReadOnly Optional.
Specifies whether the data stored by the data structure represented by the TypeDescriptor can be
modified. This attribute must not be specified if the value of the Direction attribute of the Parameter
that contains the TypeDescriptor is "In".
Default value: false
Attribute type: Boolean

CreatorField Optional.
Specifies whether the TypeDescriptor represents a field for MethodInstances of type Creator that are
contained by the Method that contains the Parameter containing the TypeDescriptor.
Default value: false
Attribute type: Boolean
AT TR IB U TE D ES CR IPTIO N

UpdaterField Optional.
Specifies whether the TypeDescriptor represents a field for MethodInstances of type Updater that are
contained by the Method that contains the Parameter containing the TypeDescriptor. When this
attribute is specified, a PreUpdaterField attribute must not be specified.
Default value: false
Attribute type: Boolean

PreUpdaterField Optional.
Specifies whether data structure represented by the TypeDescriptor stores the latest data value
received from the external system of a field for MethodInstances of type Updater. When this attribute
is specified, a UpdaterField attribute must not be specified.
Default value: false
Attribute type: Boolean

Significant Optional.
Specifies whether values stored by the data structure represented by this TypeDescriptor are included
in calculating a hash code or comparing values stored in the data structures. For example, a
TypeDescriptor representing a customer's last name is taken into account when determining whether a
record has been modified, and so it is significant, whereas the TypeDescriptor representing the date on
which the customer record is last modified typically is not taken into account to determine whether a
record has been modified, and so it is not significant.
Default value: true
Attribute type: Boolean

Name Required.
The name of the TypeDescriptor.
Attribute type: String
Note: The name of a TypeDescriptor should not contain the special characters for forward slash ("/"),
period ("."), or opening bracket ("[").

DefaultDisplayName Optional.
The display name of the TypeDescriptor.
Attribute type: String

IsCached Optional.
Specifies whether the TypeDescriptor is used frequently.
Default value: true
Attribute type: Boolean

Child elements

ELEMENT D ES CR IPTIO N

LocalizedDisplayNames Element in MetadataObject (BDCMetadata Schema) The localized names of the TypeDescriptor.

Properties Element in MetadataObject (BDCMetadata Schema) The properties of the TypeDescriptor.


When the TypeDescriptor is of type System.String, the Properties element can contain a Property
of type System.Int32 with the Name attribute set to Size. The value of the Property specifies the
expected maximum string length of the value of the data structure described by this TypeDescriptor

Interpretation Element in TypeDescriptor (BDCMetadata Schema) The rules for the data stored by the data structure represented by the TypeDescriptor.

DefaultValues Element in TypeDescriptor (BDCMetadata Schema) The default values of the TypeDescriptor.

TypeDescriptors Element in TypeDescriptor (BDCMetadata Schema) The child TypeDescriptors of the TypeDescriptor.

Parent element

ELEMENT D ES CR IPTIO N

TypeDescriptors Element in TypeDescriptor (BDCMetadata Schema)

TypeDescriptors element
Specifies a list of TypeDescriptors of a parent TypeDescriptor.
Namespace: http://schemas.microsoft.com/windows/2007/BusinessDataCatalog

Schema: BDCMetadata

<TypeDescriptors></TypeDescriptors>

The following sections describe attributes, child elements, and parent elements.
Attributes
None
Child elements

ELEMENT D ES CR IPTIO N

TypeDescriptor Element (BDCMetadata Schema) A TypeDescriptor.

Parent element
ELEMENT D ES CR IPTIO N

TypeDescriptor Element (BDCMetadata Schema)

TypeDescriptor

See also
Changes in the BDC model schema for SharePoint
External content types in SharePoint
Get started using the client object model with external data in SharePoint
Business Connectivity Services in SharePoint
What's new in Business Connectivity Services in SharePoint
Get started with Business Connectivity Services in SharePoint
Business Connectivity Services programmers reference for SharePoint
Create hybrid connectivity apps for SharePoint
3/26/2018 • 6 minutes to read Edit Online

Learn about the process of developing and deploying apps for SharePoint hybrid connectivity solutions.

Hybrid connectivity in SharePoint and SharePoint Online


As businesses move to using SharePoint Online, they need a way to expose large amounts of proprietary data safely and securely. To help solve this challenge, SharePoint introduced hybrid
connectivity.
The Business Connectivity Services (BCS) hybrid connectivity capability lets SharePoint consume data housed on-premises, inside corporate firewalls, and secured by various forms of
authentication. With hybrid connectivity functionality, SharePoint Online can access this data securely over the web as if it was on the same internal network. Once hybrid connectivity is
configured, users can work with data that is secured within the business' infrastructure. They can access and manipulate the data according to the permissions that they have been granted in
SharePoint.
For a complete description of how to configure a working hybrid solution, see Hybrid for SharePoint. This series of articles walks you through all the requirements of configuring data
sources, reverse proxies, search, security, networking, and everything else needed to set up the end-to-end scenario.

Caution: To configure a hybrid SharePoint environment, you need a combination of expert skills and significant hands-on experience with SharePoint, SharePoint Online, and related
products and technologies. We recommend that you engage Microsoft Consulting Services to provide technical guidance and support during the design and deployment of your hybrid
environment. > For more information, see Microsoft Services.

For you to be able to create an app that consumes data from an internal data source through BCS and the hybrid connection, this article assumes that you have already followed the
procedures to configure your hybrid environment.

Create hybrid connectivity apps


Creating a hybrid SharePoint Add-in is essentially the same as creating any SharePoint Add-in.
Follow these steps to create a hybrid app:
Prepare the data source
Create an SharePoint Add-in
Create an external content type
Deploy the hybrid app

Prepare the data source


Most of the time, the data source is already in place and is servicing any number of business applications. However, that data may only be available from inside the corporate security
infrastructure. If your data does exist on a server located on the inside of a corporate firewall, or is secured by some other means, the next step is to expose that data to BCS, which is also
housed inside the firewall. A network device is configured to translate calls from SharePoint Online to the internal SharePoint farm. This device is referred to as a "reverse proxy" and allows
the SharePoint Add-in located in the cloud to call into BCS located inside the firewall. BCS handles all the data connectivity from there.
To make this data available to BCS, you should expose it as an OData source. You do this by creating an Internet Information Services (IIS) website that will host the service and allow BCS to
talk to the data source through OData and Representational State Transfer (REST) endpoints.
To create an OData endpoint, you will need to follow these steps for creating a Windows Communication Foundation (WCF) data service.

To create a WCF data service


1. Create an IIS website running at least Microsoft .NET Framework 4. Secure the site using basic authentication.
NOTE

It's not necessary for SharePoint to be installed on this server. In fact, for the sake of simplicity and performance, it's better if SharePoint is not installed on the server that hosts the
WCF data service.
2. Create a new project in Visual Studio 2012 using the ASP.NET Empty Web Application template.
3. In Solution Explorer add a new ADO.NET Entity Data Model.
4. Choose the Generate from database option in the Entity Data Model Wizard.
5. Select an existing connection, or create a new one.
6. Provide the URL and connection security information.
7. Select the items that you want to include in the model, and choose Finish.
8. Again in Solution Explorer, add a new WCF Data Service using the Visual Studio template.
9. Name the data service, and choose Next.
At this point, the entity model will be created and the resulting classes will be included in your project.
10. Set the security to the entities created by replacing the /* TODO: put your data source class name here */ with the class name of the entity model you just created and specifying
which entities you want to grant permissions to.
For a complete tutorial of how to set this up, see the following:
Getting Started With OData Part 1: Building an OData Service
Quickstart (WCF Data Services)

Create an SharePoint Add-in


One of the assumptions we are making here is that you are developing your app inside the corporate firewall. This represents a scenario where a developer working for a company would
have a computer located behind the protection of the security infrastructure, developing and testing the app until it is ready to be deployed. This simplifies the process of connecting to the
data source from Visual Studio, and uses Office Developer Tools for Visual Studio 2013 to automatically generate the external content type in the next step.

To create a new app


1. Open Visual Studio 2012 on your development computer that has Office Developer Tools for Visual Studio 2013 and SharePoint installed.
2. Create a new app for SharePoint.
3. Specify the name of the app, the local SharePoint URL that will host your site for testing, and how you want the app to be hosted. Choose Finish.

Create an external content type


To add a BDC model or external content type to your project, do the following.

To add an external content type


1. With your new project still open, open the shortcut menu for the solution, and choose Add, Content types for an External Data source.
2. The first page of the wizard is used to specify the URL of the data service. On the Specify OData Source page, enter the URL of the OData service that you want to connect to. The
URL should resemble the following: http://services.odata.org/Northwind/Northwind.svc/.
3. Choose a name for your OData source, and then choose Next.
4. A list of data entities that are being exposed by the OData service appears. Make sure that the Create list instances for the selected data entities check box is selected.
5. Select one or more of the entities, and choose Finish.
6. The last thing you have to do before deployment is modify the URL in your newly created external content type file.
Open the .ect file in an XML editor.
7. Modify the ODataServiceMetadataUrl property to point to the URL that allows access through the reverse proxy.
8. Modify the ODataServiceUrl property with the URL that allows access through the reverse proxy.

For information about how to add an OData-based external content type, see How to: Create an external content type from an OData source in SharePoint.

Deploy the hybrid app


When it is time to deploy your app, you have a couple of choices. You can deploy it directly to a tenancy using F5 deployment, or you can package it using the publishing features of Visual
Studio to create an .app file. This file can then be given to the SharePoint Online tenant administrator and uploaded.
For information about deploying SharePoint Add-ins, see the following:
Deploying and installing SharePoint Add-ins: methods and options
Publish SharePoint Add-ins by using Visual Studio
You can also take the BDCM file created for the external content type and extract that to be used at any level above the app. This is demonstrated in How to: Convert an add-in-scoped
external content type to tenant-scoped.

See also
Hybrid for SharePoint
Business Connectivity Services in SharePoint
How to: Create an external content type from an OData source in SharePoint
Publish SharePoint Add-ins by using Visual Studio
Developing with Duet Enterprise 2.0
3/26/2018 • 2 minutes to read Edit Online

Overview
Duet Enterprise 2.0 is the latest version of a collaborative effort between Microsoft and SAP to give SharePoint users the ability to work with data from SAP systems.It combines
components from SAP as well as SharePoint and SharePoint Online. It gives a developer the ability to create components that will allow users to bring data from SAP systems into the
familiar SharePoint environment.

Features of Duet Enterprise 2.0


When properly installed and configured, Duet Enterprise 2.0 will provide the following features:
You can work with data in SAP systems within SharePoint using Business Data Web parts, External lists and custom components.
Use SAP data in SharePoint without code by using built-in components.
Use SAP reporting systems inside of an app.
Use special web parts installed with Duet Enterprise 2.0 to add SAP information to SharePoint pages
Use SAP workflow in an app.
Developers can use client-side JavaScript to interact with SAP external data.
Secure data using OAuth for authentication.

Setting up the development environment


Developing SharePoint Add-ins using Duet Enterprise 2.0, for the most part, is exactly the same as creating standard SharePoint Add-ins. You can use Visual Studio to extend your apps and
work within the robust framework of the Visual Studio integrated development environment.

Adding external content types


In order to access the external data housed on the SAP system, you will have to add an external content type. Since SAP data is exposed through OData endpoints, the auto-generation tools
installed in Visual Studio can be used to How to: Create an external content type from an OData source in SharePoint that is scoped at the app level.
Follow these steps to create an external content type:

Creating an external content type from an SAP OData endpoint


1. In Solution Explorer, open the shortcut menu for the project, and choose Add, Content types for External Data source.
2. On the Specify OData Source page, enter the URL of the Duet Enterprise Workflow Service.
3. Choose a name for your OData source.
4. Select the entities that are needed.
5. Choose Finish.
Visual Studio will create a new folder named External Content Types where you will find the newly created BDC model.

Configuring the BDC model


The most important thing to make the project work, is to add the ODataExtensionProvider property to the BDC model. This property defines the extension provider that provides BCS
with the SAP extensions needed for creating app code.
This sample shows the properties added to the BDC model:

<LobSystem Type="OData" Name="LOB_SYSTEM_NAME">


<Properties>
<Property Name="ODataServiceMetadataUrl" Type="System.String">
https://<DUET_METADATA_URL>:443/sap/opu/odata/sap/
ZANDY_PO_HEADER_SRV/$metadata</Property>
<Property Name="ODataServicesVersion" Type="System.String">2.0</Property>
<Property Name="ODataExtensionProvider" Type="System.String">
OBA.Server.Canary.ObaOdataServerExtensionProvider,
OBA.Server.SSOProvider,
Version=15.0.0.0,
Culture=neutral,
PublicKeyToken=71e9bce111e9429c</Property>
<Property Name="TraceHeader" Type="System.String">SAP-PASSPORT</Property>
</Properties>

Using Duet starter services to develop custom apps


Duet Enterprise 2.0 installs several starter services to the file system on the SharePoint server. In a default installation, the files are found at C:\Program Files\Duet
Enterprise\2.0\Solutions\Starter Services. Among these are:
OBACustomerWorkspace
OBAOrderToCash
OBAPortal
OBAProductCenter
Each of these solutions contains WSP files, solution and other supporting files needed to implement them.
These solutions can be used to see what can be done with Duet Enterprise 2.0 and what the development patterns are, but they are not supported for use in SharePoint Add-ins.

See also
Duet Enterprise for Microsoft SharePoint and SAP Server 2.0
How to: Create an external content type from an OData source in SharePoint
Visual Studio Developer Center
Office Development with Visual Studio
Use SAP workflow with Duet Enterprise 2.0
3/26/2018 • 11 minutes to read Edit Online

Introduction
SAP Business Workflow provides a way to automate business processes, and with Duet Enterprise 2.0, those workflows can be integrated within an SharePoint Add-in.
The following steps show how to create an app, configure it, and then how to display the information retrieved from the SAP workflows.

Create an app for SharePoint and Duet Enterprise 2.0


The first step is to create an SharePoint Add-in that will contain the connection information using an external content type for Business Connectivity Services (BCS), external lists and any
customizations you might want to use to present the data.

To create an app for SharePoint:


1. Start Visual Studio 2012 as an administrator.
2. Choose File, New, New Project.
3. In the New Project dialog box, expand the Visual C# node, expand the Office/SharePoint node, and then choose the Apps node.
4. Choose App for SharePoint.
5. Name the project and click OK.
6. In the first Specify the App for SharePoint Settings dialog box, name your app and choose SharePoint-hosted under How do you want to host your app for SharePoint. Also
specify the URL of the Duet Workflow site you want to debug against under What SharePoint site do you want to use for debugging your app and choose Finish.
7. On the Build menu, choose Deploy <your app name> .
After the app is deployed, Visual Studio will launch the default page for the app.

Add the external content type and external lists to the app
BCS must be made aware of the external data source. This is done using an external content type.

To add an external content type:


1. In the Solution Explorer, open the shortcut menu for the project, and choose Add, Content types for External Data source.
2. On the Specify OData Source page, enter the URL of the Duet Enterprise Workflow Service. The following is an example of a Duet service URL:
https://<<DUETGATEWAY>>:<<PORT>>/sap/opu/odata/IWWRK/DUET_WORKFLOW_CORE;mo;c=SHAREPOINT_DE
3. Choose a name for your ODATA source, for example, SAPWorkflows, and then choose Next.
4. Specify the SAP username and password to connect to the service metadata.
5. A list of data entities that are being exposed by the OData Service appears. Select the entities you wish to include in the external content type. In this example, using the SAP workflow
services, select from the following:
AttachmentCollection
CommentCollection
DecisionOptionCollection
ExtensibleElementCollection
ParticipantCollection
ServiceOperations
TaskDescriptionCollection
WorkflowTaskCollection
1. Select the Create list instances for the selected data entities (except Service Operations) check box.
2. Choose Finish.
NOTE

Make sure SAP workflow service allows basic authentication as the BDC auto-generation tools in Visual Studio.

Add a custom action feature to a Duet Enterprise 2.0 workflow list


In order to provide a way for the user to work with the new functionality added to a SharePoint list, the following steps will add an item to the Site Actions menu.

To add a custom action:


1. Right-click the SharePoint Add-in project, and add a new UI Custom Action item.
2. Open the Elements.xml file of the custom action host web feature. By replacing the code in the file with the following XML, the custom action will:
Declare an ECB custom action and its attributes.
Declare a Ribbon custom action and its attributes.
Declare the app webpage target and the values that are passed to it through the query string.
The UrlAction element uses several tokens. For more information, see URL strings and tokens in SharePoint Add-ins.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction Id="ViewDetailsECBCustomAction"
RegistrationType="List"
RegistrationId="107"
Location="EditControlBlock"
Sequence="1"
ImageUrl="_layouts/15/images/placeholder16x16.png"
Title="View Details">
<UrlAction Url="~appWebUrl/Pages/ViewDetails.aspx?
{StandardTokens}&amp;amp;ListId={ListId}&amp;amp;ItemId={ItemId}"/>
</CustomAction>

<CustomAction
Id="ViewDetailsRibbonAction"
RegistrationId="107"
RegistrationType="List"
Location="CommandUI.Ribbon"
Title="View Details"
HostWebDialog="false"
HostWebDialogHeight="500"
HostWebDialogWidth="500">
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition
Location="Ribbon.ListItem.Workflow.Controls._children">
<Button
Id="Ribbon.ListItem.Workflow.ViewDetails"
Alt="View Details"
Sequence="25"
Command="Invoke_ViewDetailsSAPWorkflow"
LabelText="View Details"
TemplateAlias="o1"
Image32by32="_layouts/15/images/placeholder32x32.png"
Image16by16="_layouts/15/images/placeholder16x16.png"/>
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler
Command="Invoke_ViewDetailsSAPWorkflow"
CommandAction="~appWebUrl/Pages/ViewDetails.aspx?
{StandardTokens}&amp;amp;ListId={ListId}&amp;amp;ItemId={SelectedItemId}"/>
</CommandUIHandlers>
</CommandUIExtension>
</CustomAction>
</Elements>

1. Add a new page, ViewDetails.aspx page to the project.


2. Press F5 to build and deploy the SharePoint app.
3. Go to the WorkItem list in the host web and choose View Details in the context menu. You will be redirected to ViewDetails.aspx.
NOTE

Make sure the SAP workflow service allows basic authentication. The BDC auto-generation tools in Visual Studio currently only support anonymous and basic authentication.
If you deploy the app and then navigate to Lists/WorkflowTaskCollection inside your app, you will see the following message:
"Message from External System: 'LobSystem (External System) returned authentication error.'".
To fix this, you will need to add single sign-on to the app to provide authentication credentials to BCS and the SAP backend.

Add single sign-on security to the app


Duet Enterprise Single Sign-On will allow users to be authenticated so that they can access resources on both the SharePoint and SAP sides with one sign in.

To add single sign-on:


1. Create an OData connection by executing the following command on the SharePoint Management Shell.

New-SPODataConnectionSetting -Name SAPWorkflow


-ServiceContext "http://localhost" -ExtensionProvider
"OBA.Server.Canary.ObaOdataServerExtensionProvider, OBA.Server.SSOProvider,
Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
-AuthenticationMode passthrough -ServiceAddressURL
"https://<<DUETGATEWAY>>:<<PORT>>/sap/opu/odata/IWWRK/
DUET_WORKFLOW_CORE;mo;c=SHAREPOINT_DE"

1. Double click on WorkflowTaskCollection.ect.


2. In the Properties window, update the value of ODataConnectionSettingId to SAPWorkflow .
3. Allow the App to use the Connection.
4. Open the AppManifest.xml.
5. In Permission Requests, select Scope, BCS then Permission = Read.
6. Press F5 to deploy the app.
7. On the Permissions page for the app, select the OData connection this app will use.
8. Choose the Trust It button.
9. Navigate to ../Lists/WorkflowTaskCollection. You should see the SAP tasks assigned to you coming directly from the SAP system.
Access workflow tasks and associated items using JSOM
Since SharePoint Add-ins must use client code to communicate with SharePoint, the following will demonstrate how to interact with the SAP workflow tasks using the JavaScript object
model.

To create the code:


1. Right-click the Pages folder in the Solution Explorer, add a .NET page and name it ViewDetails.aspx
2. Paste the following HTML in the PlaceHolderAdditionalPageHead section. This will set the style sheet reference, load the script and then return the related workflow tasks from SAP.

<link
rel="Stylesheet"
type="text/css"
href="../Content/App.css"/>

<script
src="//ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"
type="text/javascript">
</script>
<script
src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js"
type="text/javascript">
</script>
<script
src="../Scripts/ViewDetails.js"
type="text/javascript">
</script>

1. Right-click the Scripts folder and add a JavaScript file. Name it ViewDetails.js.
2. This markup will do the following:
Retrieves the ClientContext for the parent web.
Retrieves the TaskInstanceParentId for the selected workflow task using the Duet workflow list GUID and the selected item ID.
Parses the TaskInstanceParentId to get SAP Origin and the ID for the workflow in SAP.
Loads the entities for the external content types.
Reads the specific workflow task from SAP using specific finder by passing SAP Origin and the workflow task ID for SAP as parameters.
Reads the associated elements for the workflow task from SAP.
1. The following is the complete HTML and JavaScript for the page.

// This code runs when the DOM is ready. It ensures the SharePoint
// script files are loaded and then executes execOperation().
$(document).ready(function () {
SP.SOD.executeFunc("sp.js", "SP.ClientContext", execOperation);
});

function execOperation() {
retrieveTaskFromList();
}

function retrieveTaskFromList() {
// Retrieves the ClientContext of the parent web.
var clientContext =
new SP.ClientContext.get_current();
var appContextSite =
new SP.AppContextSite(clientContext,
decodeURIComponent(getQueryStringParameter("SPHostUrl")));
var web = appContextSite.get_web();
// Loads the selected workflow task from the duet workflow list.
var listGuid = decodeURIComponent(getQueryStringParameter("ListId"));
var itemId = decodeURIComponent(getQueryStringParameter("ItemId"))
this.workflowItem = web.get_lists().getById(
listGuid.substring(1, listGuid.length - 1)).getItemById(itemId);
clientContext.load(workflowItem);

clientContext.executeQueryAsync(
Function.createDelegate(this, this.onLoadingTaskSucceeded),
Function.createDelegate(this, this.onError)
);
}

function onLoadingTaskSucceeded() {
var sapParameters = parseParentTaskId(workflowItem.
get_item("TaskInstanceParentId"));
getDataFromSAP(sapParameters);
}

// Parses the TaskInstanceParentId


// to get SAP Origin and the id for the workflow in SAP.
function parseParentTaskId(parentTaskId) {
var idlength = parseInt(parentTaskId.substring(0, 2));
var sapParameters = new Object();
if (parentTaskId.length > (17 + idlength)) {
sapParameters.workitemId = parentTaskId.substring(5, 5 + idlength);
sapParameters.sapOrigin = parentTaskId.substring(17 + idlength);
}
return sapParameters;
}

// Retrieves the workflow task and associated elements from SAP.


function getDataFromSAP(sapParameters) {
context = new SP.ClientContext.get_current();
//Loads the entities for the external content types.
wfEntity = context.get_web().getAppBdcCatalog().
getEntity("DUET_WORKFLOW_CORE", "WorkflowTaskCollection");
context.load(wfEntity);
wfExtensibleElementEntity = context.get_web().getAppBdcCatalog().
getEntity("DUET_WORKFLOW_CORE", "ExtensibleElementCollection");
context.load(wfExtensibleElementEntity);
wfCommentsEntity = context.get_web().getAppBdcCatalog().
getEntity("DUET_WORKFLOW_CORE", "CommentCollection");
context.load(wfCommentsEntity);
wfDecisionsEntity = context.get_web().getAppBdcCatalog().
getEntity("DUET_WORKFLOW_CORE", "DecisionOptionCollection");
context.load(wfDecisionsEntity);
wfParticipantEntity = context.get_web().getAppBdcCatalog().
getEntity("DUET_WORKFLOW_CORE", "ParticipantCollection");
context.load(wfParticipantEntity);
wfDescriptionEntity = context.get_web().getAppBdcCatalog().
getEntity("DUET_WORKFLOW_CORE", "TaskDescriptionCollection");
context.load(wfDescriptionEntity);
wfAttachmentEntity = context.get_web().getAppBdcCatalog().
getEntity("DUET_WORKFLOW_CORE", "AttachmentCollection");
context.load(wfAttachmentEntity);

// Loads a LOB system instances.


lobSystem = wfEntity.getLobSystem();
lobSystemInstanceCollection = lobSystem.getLobSystemInstances();
context.load(lobSystemInstanceCollection);

context.executeQueryAsync(onLoadingLOBInstanceSucceeded, onError);

function onLoadingLOBInstanceSucceeded() {
lobSystemInstance = lobSystemInstanceCollection.get_item(0);
// Reads the workflow task from SAP using specific finder.
var identifierValues = [sapParameters.sapOrigin, sapParameters.workitemId];
var entityIdentity = SP.BusinessData.Runtime.EntityIdentity.
newObject(context, identifierValues);
wfEntityInstance = wfEntity.findSpecific(entityIdentity,
"ReadSpecificWorkflowTask", lobSystemInstance);
context.load(wfEntityInstance);

context.executeQueryAsync(onLoadingWorkflowSucceeded, onError);
}

function onLoadingWorkflowSucceeded() {
// Reads the associated elements for the workflow task.
var exFilterCollection = wfExtensibleElementEntity.getFilters(
"GetExtensibleElementsFromWorkflowTaskCollection");
context.load(exFilterCollection);
exElementsCollection = wfExtensibleElementEntity.findAssociated(
wfEntityInstance, "GetExtensibleElementsFromWorkflowTaskCollection",
exFilterCollection, lobSystemInstance);
context.load(exElementsCollection);

var comFilterCollection = wfCommentsEntity.getFilters(


"GetCommentsFromWorkflowTaskCollection");
context.load(comFilterCollection);
commentsCollection = wfCommentsEntity.findAssociated(
wfEntityInstance, "GetCommentsFromWorkflowTaskCollection",
comFilterCollection, lobSystemInstance);
context.load(commentsCollection);

var decFilterCollection = wfDecisionsEntity.getFilters(


"GetDecisionOptionsFromWorkflowTaskCollection");
context.load(decFilterCollection);
decisionsCollection = wfDecisionsEntity.findAssociated(
wfEntityInstance, "GetDecisionOptionsFromWorkflowTaskCollection",
decFilterCollection, lobSystemInstance);
context.load(decisionsCollection);

var partFilterCollection = wfParticipantEntity.getFilters(


"GetParticipantsFromWorkflowTaskCollection");
context.load(partFilterCollection);
participantsCollection = wfParticipantEntity.findAssociated(
wfEntityInstance, "GetParticipantsFromWorkflowTaskCollection",
partFilterCollection, lobSystemInstance);
context.load(participantsCollection);

var descFilterCollection = wfDescriptionEntity.getFilters(


"GetDescriptionFromWorkflowTaskCollection");
context.load(descFilterCollection);
descriptionCollection = wfDescriptionEntity.findAssociated(
wfEntityInstance, "GetDescriptionFromWorkflowTaskCollection",
descFilterCollection, lobSystemInstance);
context.load(descriptionCollection);

var attaFilterCollection = wfAttachmentEntity.getFilters(


"GetAttachmentsFromWorkflowTaskCollection");
context.load(attaFilterCollection);
attachmentCollection = wfAttachmentEntity.findAssociated(
wfEntityInstance, "GetAttachmentsFromWorkflowTaskCollection",
attaFilterCollection, lobSystemInstance);
context.load(attachmentCollection);

context.executeQueryAsync(getUpdatedDataSucceeded, onError);
}

function getUpdatedDataSucceeded() {
alert("# of extensible elements: " + exElementsCollection.get_count() +
"\\n# of comments: " + commentsCollection.get_count() +
"\\n# of decision options: " + decisionsCollection.get_count() +
"\\n# of attachments: " + attachmentCollection.get_count() +
"\\n# of participants: " + participantsCollection.get_count());
}

function onError(sender, e) {
alert("Request failed. " + e.get_message() +
alert("Request failed. " + e.get_message() +
"\\n" + e.get_stackTrace());
}
}

// Retrieves a query string value.


function getQueryStringParameter(paramToRetrieve) {
var params = document.URL.split("")[1].split("&amp;");
var strParams = "";
for (var i = 0; i < params.length; i = i + 1) {
var singleParam = params[i].split("=");
if (singleParam[0] == paramToRetrieve)
return singleParam[1];
}
}

1. Open the AppManifest.xml file.


2. In Permission Requests, select Scope, Web and Permission and set the value to Read .
3. Press F5 to deploy the solution to the duet workflow site.
4. Go to My Workflow Tasks. Select View Details in the ECB menu or select a task and press View Details in the ribbon. You will be redirected to ViewDetails.aspx where you will
see an alert containing the count for some of the elements associated to the workflow.

Using HTML and JavaScript to render Custom UI


In ViewDetails.aspx, replace the following code with your own HTML and JavaScript to render your own custom UI.

alert("# of extensible elements: " + exElementsCollection.get_count() +


"\\n# of comments: " + commentsCollection.get_count() +
"\\n# of decision options: " + decisionsCollection.get_count() +
"\\n# of attachments: " + attachmentCollection.get_count() +
"\\n# of participants: " + participantsCollection.get_count());

Adding Lync Control to your details page


Here is one option for your custom user interface. Adding a Lync control will give you the ability to communicate with your Lync contacts from the custom page.

To add a Lync control:


1. Right-click the Scripts folder in solution explorer, add a JavaScript file and name it People.js.
2. The following markup will:
Add presence control for the participants of the task.
Lync integration in callout for participants for one-click collaboration for the task.

Paste the following code into the **People.js** page.

var presenceControlCount = 0;
var appWebURL = '';

function AddPeopleControl(userName) {
var id = "pc_participants_" + presenceControlCount++;
var prevId = null;

return "<div id='" + id + "' ></div>" +


"<script>" +
"LoadPeopleControl('" +id+ "', '" +prevId+ "', '" +userName+ "');" +
"</script>";
}

function LoadPeopleControl(elemId, prevId, user) {


var prevElement = null;
var element = $("#" + elemId);
user = "fareast\\\\" + user.toLowerCase();

GetUsersInfo(user, element, prevElement);


}

function GetUsersInfo(accountName, htmlElement, waitforElement) {


var clientContext = SP.ClientContext.get_current();
var website = clientContext.get_web();

clientContext.load(website);
clientContext.executeQueryAsync(onRequestSucceeded, onRequestFailed);

function onRequestSucceeded() {
appWebURL = website.get_url();
var queryURL = appWebURL +
"/_api/SP.UserProfiles.PeopleManager/GetPropertiesFor(accountName=@v)?@v='"
+ accountName + "'";

jQuery.ajax({
url: queryURL,
type: "GET",
headers: {
"ACCEPT": "application/json;odata=verbose"
},
success: function (data) {
var html = [];
var i = 0;

var id = htmlElement[0].id + "_";


var about_info;

if (data.d.UserProfileProperties != null) {
for (i = 0; i < data.d.UserProfileProperties.results.length; i++) {
if (data.d.UserProfileProperties.results[i].Key == "AboutMe") {
about_info = data.d.UserProfileProperties.results[i].Value;
}
}
}

var email = data.d.Email;


var profileUrl = data.d.UserUrl;
var pictureUrl = data.d.PictureUrl;
var name = data.d.DisplayName;

if (name == null) {
name = accountName;
}

var isFollowed = data.d.IsFollowed;

var html = [
"<table>",
"<tr>",
"<td>",
"<span class='ms-spimn-presenceWrapper ms-spimn-imgSize-5x48'> ",
"<img id='imn_" + id + "_" + i++ + ",type=smtp'" ,
"onload=\\"IMNRC('", email, "')\\" ",
"class='ms-spimn-img ms-spimn-presence-offline-5x48x32 '",
"title='' name='imnmark' alt='Offline' ",
"src='/_layouts/15/images/spimn.png' ",
"sip='" + email + "' showofflinepawn='1'>",
"</span>",
"</td>",
"<td>",
"<span class='ms-imnSpan'>",
"<a class='ms-imnlink' tabindex='-1'",
"onclick='IMNImageOnClick(event);return false;' href='#'>",
"<img id='imn_" + id + "_" + i++ + ",type=smtp'",
"onload=\\"IMNRC('", email, "')\\"",
"class=' ms-hide' title='' name='imnmark' alt='Away' ",
"src='/_layouts/15/images/spimn.png' ",
"sip='" + email + "' showofflinepawn='1'>",
"</a>",
"<a class='ms-subtleLink ms-peopleux-imgUserLink' ",
"onclick='GoToLinkOrDialogNewWindow(this);return false;' ",
"href='" + profileUrl + "'>",
"<span style='width: 48px; height: 48px;'" ,
"class='ms-peopleux-userImgWrapper'>",
"<img style='cliptop: 0px; clipright: 48px;" ,
"clipbottom: 48px; clipleft: 0px; ",
"min-height: 48px; min-width: 48px; max-width: 48px;' ",
"class='ms-peopleux-userImg' alt='' src='" +pictureUrl+ "'>",
"</span>",
"</a>",
"</span>",
"</td>",
"<td>",
"<span class='ms-spimn-presenceWrapper ms-spimn-imgSize-5x48'>",
"<img id='imn_" + id + "_" + i++ + ",type=smtp' ",
"onload=\\"IMNRC('", email, "')\\" ",
"class='ms-spimn-img ms-spimn-presence-offline-5x48x32' ",
"title='' name='imnmark' alt='Offline' ",
"src='/_layouts/15/images/spimn.png' ",
"sip='" + email + "' showofflinepawn='1'>",
"</span>",
"</td>",
"<td>",
"<span class='ms-microfeed-userName ms-textLarge' ",
"style='font-size: medium;'>" + name + "<br/>",
"<div id='people_callout_" + id + "_" + i + "' ",
"class='ms-microfeed-button ms-textSmall" +
"ms-secondaryCommandLink ms-microfeed-footerButton' ",
"align='center' ",
"style='cursor:pointer; font-size:small;' > more... </div>",
"<script>",
"RegisterCallOut(\\"people_callout_" + id + "_" + i +
"\\",\\"" + name + "\\",\\"" + encodeURI(about_info) +
"\\",\\"" + profileUrl + "\\",\\"" + isFollowed + "\\");",
"</script>",
"</span>",
"</td>",
"</tr>",
"</table>",
];

htmlElement.html(html.join(''));
}

});
}
function onRequestFailed(sender, args) {
alert('Error: ' + args.get_message());
}

function RegisterCallOut(divId, displayName, aboutme, userUrl, isFollowed) {


if (typeof CalloutManager !== "object" || typeof Callout !== "function" || typeof CalloutAction !== "function")
return;

var launchdiv = document.getElementById(divId);


var calloutId = divId + "_callout";
var html = [];
html.push("<br/>");

if (aboutme == "") {
html.push("No Information Found about this person.");
}
else {
html.push(decodeURI(aboutme));
}

html.push("<hr/>");

if (isFollowed == true) {
html.push("<div>You are <b>following</b> this person</div>");
}
else {
html.push("<div >You are <b>not following</b> this person</div>");
}

var callout = CalloutManager.createNew({


launchPoint: launchdiv,
openOptions: {
closeCalloutOnBlur: true,
event: "click",
showCloseButton: true
},
ID: calloutId,
title: displayName,
content: html.join("")
});

callout.addAction(new CalloutAction({
text: "View Profile", onClickCallback:
function (calloutActionClickEvent, calloutAction) {
window.open(userUrl);
}
}));
}

NOTE

The user name of the participant in company's network is same as that in SAP.
1. Open the AppManifest.xml page.
2. In Permission Requests, select Scope, User Profiles and Permission and set its value to Read .
3. Copy the following markup and paste it in the PlaceHolderAdditionalPageHead section in ViewDetails.aspx.

<script src="../Scripts/People.js" type="text/javascript"></script>

1. To add the presence control for a participant, call the following:

AddPeopleControl(userName);

See also
SharePoint Add-ins
Complete basic operations using SharePoint client library code
An introduction to SAP Business Workflow
Use SAP Reporting with Duet Enterprise 2.0
3/26/2018 • 2 minutes to read Edit Online

Introduction
Duet Enterprise 2.0 gives you the ability to integrate the Duet reporting features within your SharePoint Add-in by doing a little customization.
The secret to enabling reporting for your app is by using a hidden feature installed by Duet. You will need to staple this feature to custom features, so that when the app is instantiated, the
SAP reporting features will be made available to the app.

Enabling the features


To enable the Duet reporting features, the sequence of activation must be carefully followed.

To create a feature to add the app-scoped external content type:


1. Inside your Duet reporting app, in the Solution Explorer, right click the project name. Choose Add, Content Types for an External Data Source. Click Next.
2. Enter the URL for the SAP Reporting endpoint as the OData Source.
3. Select the Entities, and choose Finish.
4. Open the newly created external content type to view the LSI properties. You will notice that they are the same as for the farm-scoped external content type except for the
ODataconnectionSettingsId.

To create a feature to enable the hidden Duet features:


1. Add another new feature to your project. Name the title AddDuetReporting.
This feature will have a dependency on the AddReportingModel and the DuetReportingForApps features.
2. Add the following code to the Elements file.

<?xml version="1.0" encoding="utf-8"?>


<Feature xmlns="http://schemas.microsoft.com/sharepoint/" Title="AddDuetReporting" Id="6a55705c-af12-455a-914b-8cf3a31c820e" Scope="Web">
<ActivationDependencies>
<ActivationDependency FeatureId="e1fe41d3-7fc3-458f-9a66-6ecf6a39bb2c" FeatureTitle="AddReportingModel" />
<ActivationDependency FeatureId="9b60ccba-ebfd-4e38-87c8-3dea9cc2680a" FeatureTitle="SAPReportingForApps" />
</ActivationDependencies>
</Feature>

Please note that the sequence in activation dependency is important. First, you must create the external content type and then activate the SAPReportingForApps feature. Also, note that
the second feature (ID: 9b60ccba-ebfd-4e38-87c8-3dea9cc2680a) is shipped with Duet Enterprise 2.0, but it is marked as hidden. With this approach, a developer can make use of this
feature and can bring in Duet Reporting capabilities to an app.
Once the DuetReportingForApps feature is activated, it will bring all the artifacts (Report List, Lib, forms, etc.) and customization on the apps site but as the app site template does not have
standard navigation links, the app developer needs to add custom page elements to bring out the Duet features (e.g. Report Settings, library list view, and forms). The developer should
consult standard Duet documentation for Reporting feature to learn more about the feature and its UI elements. A developer may choose to build up a custom UI for feature entry points
which may suit better with the general theme of the app.

Viewing the results


To see the default report settings page, navigate to: ~/Lists/ReportSetting/AllReportTemplate.aspx.
To see the default view for the report document library, navigate to: ~/ReportsLib/Forms/AllItems.aspx.

Customizing the reports


Inside an app, a developer can also create his own custom UI (using HTML/JavaScript/Jquery etc.) and make use of BCS CSOM to build a richer user experience. Following screenshots
shows a similar app where custom HTML based UI is built with the help of OOB artifacts and client side BCS APIs.

See also
Developing with Duet Enterprise 2.0
How to: Create an external content type from an OData source in SharePoint
Using OData sources with Business Connectivity Services in SharePoint
Office 2013 and SharePoint application services
3/26/2018 • 2 minutes to read Edit Online

Learn about Access Services, Excel Services, Machine Translation Service, PerformancePoint Services, PowerPoint Automation Services, Visio Services, and Word Automation Services.

Overview and usage scenarios for Office and SharePoint services in SharePoint
Office and SharePoint services run on individual application servers in the farm and provide a wide range of functionality. The services that are described in this section provide functionality
across the following scenarios:
Business intelligence (BI) and Insights enable people to find, analyze, and share information about their work or business.
Simple apps let users create basic apps that contain a reliable backing store.
File conversion converts Word and PowerPoint files and streams to other formats.
Translation translates sites, documents, and streams for multilingual support.
The following table shows high-level scenarios that apply to the services described in this section.
Table 1. Scenarios for Office and SharePoint services in SharePoint

B I/INS IG HTS S IMPLE APPS FILE CO NV ER S IO N TR ANS L ATIO N

Access Services X X

Excel Services X

Machine Translation Service X

PerformancePoint Services X

PowerPoint Automation Services X

Visio Services X

Word Automation Services X


NOTE

Not all services and scenarios are represented in this section. For links to developer documentation for other services, see Additional resources.

In this section
Use the links in Table 2 to learn more about developing with the Office and SharePoint services described in this section: Access Services, Excel Services, Machine Translation Service,
PerformancePoint Services, PowerPoint Automation Services, Visio Services, and Word Automation Services.
Table 2. Overview of Office and SharePoint services in this section

S ER V ICE D ES CR IPTIO N

Access Services Enables users to create, deploy, and manage collaborative web-based Access applications.
See Develop Access web apps

Excel Services Enables users to load, calculate, and display Excel workbooks on SharePoint sites.
See Excel Services in SharePoint

Machine Translation Service Provides automatic machine translation of sites, documents, and sites.
See Machine Translation Services in SharePoint

PerformancePoint Services Creates and publishes dashboards that contain interactive data visualizations (such as scorecards and
See PerformancePoint Services in SharePoint reports.md) that enable people to monitor and analyze their business performance.

PowerPoint Automation Services Provides unattended, server-side conversion of PowerPoint presentations into other formats.
PowerPoint Automation Services in SharePoint

Visio Services Enables users to view and interact with Visio drawings stored on SharePoint sites.
See Visio Services in SharePoint

Word Automation Services Provides unattended, server-side conversion of documents that are supported by Word.
See What's new in Word Automation Services for developers

Not all services and scenarios are represented in this section. For links to developer documentation for other services, see Additional resources.

See also
Add SharePoint capabilities
Business Connectivity Services in SharePoint
Search in SharePoint
Install SQL Server BI Features with SharePoint (PowerPivot and Reporting Services)
Excel Services in SharePoint
5/3/2018 • 2 minutes to read Edit Online

Learn about the new capabilities in Excel Services in SharePoint and how you can use them in your own development efforts.

What's new in Excel Services for developers


SharePoint brings new technologies to Excel Services─such as ECMAScript (JavaScript, JScript) UDFs and Excel Interactive View ─and new enhancements to existing technologies, such as
ODATA for REST, and updates to the ECMAScript (JavaScript, JScript) Object Model (JSOM) API.

JavaScript UDFs
Excel Services already lets you create user-defined functions (UDFs) using managed code. Excel Services in SharePoint introduces a new kind of UDF—ECMAScript (JavaScript, JScript)
UDFs. JavaScript UDFs run in the context of the browser: either in a Excel workbook that is hosted in an Excel Web Access web part on SharePoint, or in a workbook that is embedded on a
host webpage.

OData in Excel Services


SharePoint Server 2010 introduced the REST API for use in getting and setting information in Excel Workbooks stored in SharePoint document libraries. SharePoint adds a new way to
request data from Excel Services that uses the Open Data Protocol (OData) which you can use to get information about Excel Services resources. This new service relies heavily on the
existing Excel Services REST API.
NOTE

he Excel Interactive View feature has been disabled. For information about removing this feature from your website, see Removing Excel Interactive View from a webpage.

In this section
Getting Started with Excel Services
Excel Web Services
Excel Services User-Defined Functions
Excel Web Access
Excel Services ECMAScript (JavaScript, JScript)
Excel Services REST API
General Guidelines
Removing Excel Interactive View from a webpage

See also
Add SharePoint capabilities
Office 2013 and SharePoint application services
Getting Started with Excel Services
5/3/2018 • 2 minutes to read Edit Online

This section introduces Excel Services — a server technology first introduced in Microsoft Office SharePoint Server 2007 — and its architecture. It also maps out the types of development
you can do using Excel Services, discusses unsupported features, and gives an overview of business intelligence in Excel Services.

In this section
Excel Services Overview

Learn about this new technology that enables you to load, calculate, and display Excel workbooks on SharePoint Server

Excel Services Architecture

Learn how the three components of Excel Services communicate and work together.

Excel Services Development Roadmap

Learn about types of development you can do and the most common scenarios for using Excel Web Services.

Supported and Unsupported Features

Find out which features of Excel are not supported in this first version of Excel Services.

Excel Services Blogs, Forums, and Resources

Get links to blogs that are written about Excel Services.

Reference
Microsoft.Office.Excel.Server.Udf

Excel Services UDF (user-defined function) attributes.

Microsoft.Office.Excel.Server.WebServices

The Excel Web Services API.

Microsoft.Office.Excel.WebUI

The Excel Web Access web part object model.


Excel Services Overview
5/3/2018 • 9 minutes to read Edit Online

Excel Services is a service application that enables you to load, calculate, and display Microsoft Excel workbooks on Microsoft SharePoint. Excel Services was first introduced in Microsoft
Office SharePoint Server 2007.
By using Excel Services, you can reuse and share Excel workbooks on SharePoint portals and dashboards. For example, financial analysts, business planners, or engineers can create content
in Excel and share it with others by using an SharePoint portal and dashboard—without writing custom code. You can control what data is displayed, and you can maintain a single version of
your Excel workbook. There are four primary interfaces for Excel Services:
An Excel Web Access web part, which enables you to view and interact with a live workbook by using a browser
Excel Web Services for programmatic access
An ECMAScript (JavaScript, JScript) object model for automating and customizing, and to drive the Excel Web Access control and help build more compelling, integrated solutions as
well as the ability to user user-defined functions to extend the ECMAScript (JavaScript, JScript) object model
A Representational State Transfer (REST) API for accessing workbook parts directly through a URL
NOTE

The Excel Interactive View feature has been disabled. For information about removing this feature from your website, see Removing Excel Interactive View from a webpage.
You can also extend Excel Calculation Services by using user-defined functions (UDFs).
NOTE

For more information about Excel Calculation Services, see Excel Services Architecture.
By using Excel Services, you can view live, interactive workbooks by using only a browser. This means that you can save Excel workbooks and interact with them from within portal sites.You
can also interact with Excel-based data by sorting, filtering, expanding, or collapsing PivotTables, and by passing in parameters; this provides the ability to perform analysis on published
workbooks. You can interact with a workbook without changing the published workbook—which is valuable for report authors and report consumers.Excel Services supports workbooks that
are connected to external data sources. You can embed connection strings to external data sources in the workbook or save them centrally in a data connection library file.You can also make
selected cells in worksheets editable by making them named ranges (parameters). Items that you choose to make viewable, when you save to Excel Services, appear in the Parameters pane
in Excel Web Access. You can change the values of these named ranges in the Parameters pane and refresh the workbook. You can also use the portal's filter web part to filter several web
parts (Excel Web Access and other types of web parts) together.However, you cannot use Excel Services to create new workbooks or to edit existing workbooks. To author a workbook for use
with Excel Services, you can use Microsoft Excel 2013.
NOTE

Microsoft Excel Online, part of Office Online, also supports Excel workbooks in the browser. For more information about Excel Online, see Get started with the new Office.
Excel Services also has a Web service. You can use Excel Web Services to load workbooks, set values in cells and ranges, refresh external data connections, calculate worksheets, and extract
calculated results (including cell values, the entire calculated workbook, or a snapshot of the workbook). In SharePoint, you can also save, save a copy, and participate in collaborative editing
sessions by using Excel Web Services.
NOTE

or more information about snapshots, see How to: Get an Entire Workbook or a Snapshot.
Excel Services supports UDFs, which you can use to extend the capabilities of Excel Calculation Services—for example, to implement custom calculation libraries or to read data from Web
services and data sources that are not natively supported by Excel Services.Excel Services is designed to be a scalable, robust, enterprise-class server that provides feature and calculation
fidelity with Excel.

Scenarios and Features


Excel Services supports many different scenarios and features, some of which are described in this section.

Business Intelligence Portal and Workbook Analysis


A business intelligence portal displays scorecards and reports, and enables users to explore data by using only a browser. The BI Center feature in SharePoint Server includes a business
intelligence portal and dashboard functionalities. Figure 1 shows a report center dashboard with a library of reports, a chart, and Key Performance Indicators (KPIs) already set up.
Excel Services also enables you to calculate data on the server. Excel Services participates in the BI Center by providing the ability to calculate and expose Excel-based content on integrated
BI dashboards.You can display an Excel workbook by using the Excel Web Access web part, connect to external data sources, and further interact with the data in the workbook.
Figure 1 shows a dashboard with a filter web part, and Excel workbooks displayed by using Excel Web Access web parts.
Figure 1. Dashboard with filtering and Excel content
In addition to participating in integrated dashboards, Excel Services can also be used to display all or part of Excel workbooks to enable users to interact with that content in the familiar Excel
user interface. Figure 2 shows a range being displayed, and cells being exposed for user input through parameters. Designating specific cells as parameters enables users to change values in
those cells in a worksheet by using the edit boxes in the right pane. Excel Services then recalculates the worksheet based on the new values.
If you want to use certain functionalities in Excel or if you want to analyze a workbook by using all Excel functionalities, you can open a workbook in Excel by clicking Open in Excel. You can
also open a workbook in Excel to print it and to work offline.
NOTE

To open a workbook by using the Open in Excel command, you must have "open" rights. For more information, see the next section, Managing Workbooks, and User Permissions and
Permission Levels on TechNet. Users who do not have "open" rights can still open a snapshot in Excel.
Figure 2. Using the Parameters pane

You can also analyze, pivot, and interact with data by using Excel Web Access.
For more information about Excel Services and business intelligence capability in SharePoint, see the business intelligence documentation in SharePoint Server Help.

Managing Workbooks
The workbook management and lockdown capabilities of Excel Services enable you to:
Maintain only one copy of a workbook, that is created and changed by a trusted author in a central, secure place, instead of maintaining multiple copies on each user's computer. The
correct version of the worksheet is easier to find, share, and use from within Excel, SharePoint, and other applications.
Secure and protect workbook models and back-end data. You can give users view-only rights to limit access to the workbook. For example, you can prevent users from opening a
workbook by using Excel or you can control what they are allowed to view in a workbook. Users can have browser-based access to the content in a workbook that the author wants to
share, but no ability to open the workbook in the Excel client, view formulas, or view supporting content or other intellectual property that may be in the workbook.
Create snapshots of a workbook.
Excel Services is optimized for many users and many workbooks. It can also help load-balance calculation across the server farm.
For more information about managing workbooks by using Excel Services, see the SharePoint Server documentation on TechNet or SharePoint Server Help.

Programmatic Access through Custom .NET Applications


You can create custom applications—for example, ASP.NET applications—that:
Call Excel Web Services to access, parameterize, and calculate workbooks.
Open, refresh external data, set cells or ranges, recalculate, participate in collaborative editing sessions with other applications or people, save, and save as.
Use custom workflows to schedule calculation operations or send e-mail notifications. (This uses SharePoint capabilities and is not a native part of Excel Services.)

User-Defined Functions (UDFs)


You can also use Excel Services UDFs, which enable you to use formulas in a cell to call custom functions that are written in managed code and deployed to SharePoint Server.
For more information about UDFs in Excel Services, see Understanding Excel Services UDFs.

ECMAScript (JavaScript, JScript)


You can also use the JavaScript object model in Excel Services to automate, customize, and drive the Excel Web Access web part control. You can use the JavaScript object model to build
more compelling and integrated solutions.

JavaScript user-defined functions (UDFs)


New in Microsoft Excel Services and Microsoft SharePoint, ECMAScript (JavaScript, JScript) UDFs enable you to add custom functions to Excel when you are using an embedded Excel
workbook with OneDrive or an Excel Web AccessExcel Web Access web part in SharePoint. Besides the built-in functions that you use in Excel, you can add your own, custom functions using
JavaScript UDFs that you can call from inside formulas in .
JavaScript UDFs are similar to UDFs that you can create for Microsoft Excel. The difference is that JavaScript UDFs are only used in workbooks embedded in a webpage and only exist on
that webpage.

JavaScript Object Model


The Excel Services JSOM API now includes the following:
The ability to reload the embedded workbook. Now you can reset the embedded workbook to the data in the underlying workbook file.
User-created floating objects. The EwaControl object has new methods that let you add/remove floating objects that you create.
More control over viewable area of the Ewa control.
SheetChanged Event. This event raises when something changes on a sheet, such as updating cells, deleting or clearing cells, copying, cutting or pasting ranges, and undo/redo
actions.
Enabling data validation. You can now validate data that is entered by a user.

REST API
You can use the REST API in Excel Services to access workbook parts or elements directly through a URL. The discovery mechanisms built into the Excel Services REST API enable
developers and users to explore the content of the workbook manually or programmatically.
For more information about the REST API in Excel Services, see Excel Services REST API.

REST ODATA
New in Microsoft Excel Services and Microsoft SharePoint, by using the new OData functionality in the Excel Services REST API, you can request the tables inside an Excel workbook as
OData. For example, to request Excel metadata about available resources in the SampleWorkbook.xlsx workbook using a REST call, you use the following syntax.
http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/SampleWorkbook.xlsx/model For more information about the REST API, see the
Excel Services 2010 REST API documentation in the SharePoint SDK documentation.
To request metadata about available resources in the SampleWorkbook.xlsx workbook using OData, use the same REST syntax, except replace /Model with /Odata as in the following
request.
http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/OData
From there you can use OData system query options to get specific information about tables inside the workbook.

See also
Excel Services Development Roadmap
Excel Services Architecture
JavaScript user-defined functions overview
Using OData with Excel Services REST in SharePoint
Walkthrough: Developing a Custom Application Using Excel Web Services
Frequently Asked Questions About Excel Services UDFs
Unsupported Features in Excel Services
Excel Services Blogs, Forums, and Resources
Excel Services Architecture
5/3/2018 • 5 minutes to read Edit Online

Excel Services is part of Microsoft SharePoint Server 2010. Excel Services is built on ASP.NET and SharePoint Foundation technologies. Following are the core components in Excel Services:
Excel Web Access
Excel Web Services
User-defined functions (UDFs)
ECMAScript (JavaScript, JScript)
Representational State Transfer (REST) service
Excel Calculation Services
NOTE

Microsoft Excel Online, part of Office Online, also supports Excel workbooks in the browser. For more information about Excel Online, see documentation about Office Web Apps.
The Excel Web Access, Excel Web Services, UDFs, JavaScript, the REST service, and Excel Calculation Services components can be divided into two major groups: the components on a
front-end server (also known as the "Web front end") and the component on a back-end application server. Components of a Web front end and a back-end application server

Web Front-End Servers and Back-End Application Servers


The Excel Web Access, Excel Web Services, UDFs, JavaScript, the REST service, and Excel Calculation Services components can be divided into components on the Web front-end server and
components that live on a back-end application server. The Web front end includes Excel Web Access, JavaScript, the REST service, and Excel Web Services. The Excel Calculation Services
component resides on the back-end application server, alongside any UDF assemblies that an administrator has added.
In the simplest configuration in SharePoint Server 2010—that is, a single computer running SharePoint Server 2010 as a stand-alone installation—all five components are installed on the
same computer. However, in a typical enterprise environment with a large number of users, the components on the Web front-end server and the components on the back-end application
server are on different computers in a farm configuration. It is possible to scale out the Web front-end server independently from the back-end application server. For example, you can have
more Web front-end servers or more back-end application servers, depending on your organizational needs.
For information about Excel Services topology, scalability, performance, and security, see the SharePoint Server 2010 documentation on TechNet.

Excel Web Access


Excel Web Access is a viewer page and an Excel Services web part that you can add to any web parts page in SharePoint Server 2010. Excel Web Access renders (in other words, creates the
HTML for) live Excel workbooks on a webpage, and enables the user to interact with those workbooks and explore them. Excel Web Access is the visible Excel Services component for the
user. You can use Excel Web Access like any other web part in SharePoint Server 2010. Excel Web Access does not require the user to install anything on the client computer.
The Excel Web Access web part properties are also customizable. For more information, see the Microsoft.Office.Excel.Server.WebUI namespace reference documentation.

Excel Web Services


Excel Web Services is the Excel Services component that provides programmatic access to its Web service. You can develop applications that call Excel Web Services to calculate, set, and
extract values from workbooks, and to refresh external data connections. By using Excel Web Services, you can incorporate server-side workbook logic into an application, automate the
updating of Excel workbooks, and create application-specific user interfaces around server-side Excel calculation.
NOTE

When you make changes to a workbook—for example, by setting values to a range by using Excel Web Services—the changes to the workbook are preserved only for that session. The
changes are not saved or persisted back to the original workbook. When the current workbook session ends (for example, when you call the CloseWorkbook method, or when the session
times out), the changes that you made are lost.> If you want to save changes that you make to a workbook, you can use the GetWorkbook method, and then save the workbook. For more
information, see Microsoft.Office.Excel.Server.WebServices . You can also open the workbook in edit mode and save the changes.
For more information about Excel Web Services, see Excel Services Development Roadmap.

User-Defined Functions (UDFs)


Excel Services UDFs enable you to use formulas in a cell to call custom functions that are written in managed code and deployed to SharePoint Server 2010. For more information about
UDFs in Excel Services, see Understanding Excel Services UDFs.

ECMAScript (JavaScript, JScript)


The JavaScript object model in Excel Services enables developers to customize, automate, and drive the Excel Web Access web part control on a page. By using the JavaScript object model,
you can build mashups and other integrated solutions that interact with one or more Excel Web Access web part controls on a page or an iframe with script on the page. It also enables you
to add more capabilities to your workbooks and code around them.
For more information about the JavaScript object model in Excel Services, see the Ewa namespace reference documentation.
REST API
The REST API in Excel Services enables you to access workbook parts or elements directly through a URL. The URL contains a "marker" path, which is the entry point to an .aspx page, to the
workbook file location, and to the path to the requested element inside the workbook.
The discovery mechanisms built into the Excel Services REST API enables developers and users to explore the content of a workbook manually or programmatically.
For more information about the REST API in Excel Services, see Excel Services REST API.

Excel Calculation Services


The role of Excel Calculation Services is to load workbooks, calculate workbooks, call custom code (UDFs), and refresh external data. It also maintains the session state for interactivity. Excel
Calculation Services maintains a session for the duration of interactions with the same workbook by a user or caller. A session is closed when the caller explicitly closes it or when the session
times out on the server. Excel Services caches the opened Excel workbooks, calculation states, and external data query results, for improved performance when multiple users access the
same set of workbooks.

Load-Balancing
In multiple-server configurations, Excel Services load-balances requests across multiple Excel Calculation Services occurrences in a farm configuration. If your installation includes multiple
application servers, Excel Services will balance the load in an attempt to help ensure that no single application server is overloaded by requests.
Administrators can configure the load-balancing behavior.

See also
Concepts
Excel Services Overview
Excel Services Development Roadmap
Supported and Unsupported Features
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Excel Services Development Roadmap
5/3/2018 • 6 minutes to read Edit Online

An important aspect of Excel Services is that solution developers can use its power programmatically from their applications. These applications can be line-of-business (LOB) products or
custom enterprise solutions that an organization develops internally.
Following are examples of these applications:
Multitiered applications, with the presentation layer implemented as a Web application (for example, an ASP.NET application) that calls Excel Web Services.
Applications within Microsoft SharePoint Server 2010, or integrated with LOB products.
There are five types of development that you can do by using Excel Services:
Develop solutions by using Excel Web Services
Extend the Microsoft Excel function library in Excel Services by using user-defined functions (UDFs)
Customize the Excel Web Access web part
Develop solutions by using ECMAScript (JavaScript, JScript)
Use the REST API to perform operations against Excel workbooks

Excel Web Service


Following are the main scenarios for Excel Web Services:
Server-side Excel calculation
This scenario is application-centric. In this scenario, you use models defined in Excel workbooks and calculated on the server as part of application logic.
Automating workbook updates on the server
This scenario is file-centric. In this scenario, Excel Web Services processes a workbook, and saves copies of the workbook or snapshots.
Opening workbooks in edit sessions
Excel Web Services supports opening workbooks in edit sessions in SharePoint Server 2010. In this scenario, you can use code to edit a workbook.

Server-Side Excel Calculation


For server-side Excel calculation, a custom application typically uses an Excel model as part of its logic. Instead of having to re-code Excel workbook business logic in a programming
language, the business user can maintain the model in Excel in a server location. The developer never needs to change a line of code in the application that uses the model created by the
business user.
In this scenario, the custom application repeatedly calls Excel Web Services, which sends the calls to a back-end calculation service. Excel Calculation Services does the following:
Loads the specified Excel workbook
Receives inputs
Processes the workbook (for example, refreshes data or performs calculations)
Sends the results to the custom application

Automating Workbook Updates on the Server


When developers automate the updating of Excel workbooks on the server, they often have two objectives:
Generate Excel files or modify Excel templates by using the Open XML File Formats, and then calculate the generated Excel file.
Periodically open an Excel file to refresh external data (once, or maybe multiple times per user), and then calculate the resulting workbooks and save them or send them in e-mail
messages to various users.
In this scenario, a custom application uses Excel Web Services to do the following:
Load the specified Excel workbook
Input parameters
Process the workbook (for example, refresh data or perform calculations)
The custom application retrieves the live version of the workbook or snapshot and then saves the workbook or snapshot by using Excel Web Services.
NOTE

When you make changes to a workbook—for example, by setting values to a range by using Excel Web Services—the changes to the workbook are preserved only for that particular session.
The changes are not saved or persisted back to the original workbook. When the current workbook session ends (for example, when you call the CloseWorkbook method, or when the
session times out), changes that you made are lost.> If you want to save changes that you make to a workbook, you can use the GetWorkbook method and then save the workbook by
using the SaveWorkbook method or the SaveWorkbookCopy method. For more information about the Excel Web Services API, see Microsoft.Office.Excel.Server.WebServices .

Using Excel Web Services


You can use Excel Web Services as:
A regular Web service, by calling the Web methods through SOAP over HTTP.
A local assembly, by linking directly to Microsoft.Office.Excel.Server.Webservices.dll.
For more information about when you should link directly to Microsoft.Office.Excel.Server.Webservices.dll, see Loop-Back SOAP Calls and Direct Linking.
For information about the Excel Web Services API, see the Microsoft.Office.Excel.Server.Webservices namespace reference documentation. For an example of how to develop a custom
application by using Excel Web Services, see Walkthrough: Developing a Custom Application Using Excel Web Services.
User-Defined Functions (UDFs)
Excel Services supports managed-code UDFs. Excel Services UDFs give you the ability to use formulas in cells to call custom functions written in managed code and deployed to SharePoint
Server 2010. You can create UDFs to:
Call custom mathematical functions.
Get data from custom data sources into worksheets.
Call Web services from the UDFs.
Wrap calls to existing native code library functions—for example, existing Excel UDFs.
For more information about Excel Services UDFs, see Understanding Excel Services UDFs.

Using UDFs
For information about Excel Services UDF definitions, see the Microsoft.Office.Excel.Server.Udf namespace reference documentation.
For an example of how to create managed-code UDFs, see Walkthrough: Developing a Managed-Code UDF.

Excel Web Access


You can use the extensible properties of the Excel Web Access web part to:
Configure Excel Web Access programmatically.
Change Excel Web Access properties programmatically.
Apply a theme or brand a web part page by using cascading style sheets (CSS).

Using Excel Web Access web part Extensibility


For information about:
Excel Web Access extensible properties, see the Microsoft.Office.Excel.Server.WebUI namespace reference documentation.
Excel Web Access CSS, see the CSS reference documentation.
How to programmatically configure a web part, see the SharePoint Foundation SDK.

ECMAScript (JavaScript, JScript)


In SharePoint Server 2010, Excel Services added support for JavaScript. The JavaScript object model in Excel Services enables developers to automate, customize, and interact with the Excel
Web Access web part control on a page. By using the JavaScript object model, you can build mashups and other integrated solutions that interact with one or more Excel Web Access web
part controls on a page. It also enables you to add more capabilities to your workbooks and code around them.
For more information about the JavaScript object model in Excel Services, see the Ewa namespace reference documentation.

Using ECMAScript (JavaScript, JScript)


For more information about JavaScript, see the following links:
For more information about the JavaScript object model in Excel Services, see the Ewa namespace reference documentation.
For an example of how to interact with the JavaScript object model in Excel Services by using the Content Editor web part, see Walkthrough: Developing Using the Content Editor
web part.

REST API
The REST API in Excel Services is new in SharePoint Server 2010. By using the REST API, you can access workbook parts or elements directly through a URL.
The discovery mechanisms built into the Excel Services REST API also enable developers and users to explore the content of a workbook manually or programmatically, by supplying Atom
feeds that contain information about the elements that reside in a specific workbook. The resources that you can access through the REST API are ranges, charts, tables, and PivotTables.
Using the Atom feed provided by the REST API enables an easier way to get to the data that you care about. The feed contains traversable elements that allow any piece of code to discover
what elements exist in a workbook.
For more information, see Excel Services REST API.

Using the REST API


For information about:
Accessing the REST service, and to view sample URIs for the REST service in Excel Services, see Accessing Excel Services REST API.
Accessing a schema for the REST service in Excel Services, see Accessing a Schema.

See also
Tasks
How to: Programmatically Add an Excel Web Access web part to a Page
Concepts
Excel Services Overview
Excel Services Architecture
Supported and Unsupported Features
Excel Services Blogs, Forums, and Resources
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Supported and Unsupported Features
5/3/2018 • 3 minutes to read Edit Online

Microsoft Excel is feature-rich. With every release, the functionality gap between Excel and Excel Services gets narrower, and the number of unsupported features is reduced. But is not
possible to support every Excel feature in the second version of Excel Services, in Microsoft SharePoint Server 2010. When deciding which feature to support, priorities are given to features
that are needed in key Excel Services scenarios, and to ensuring that Excel Services is a server-grade service that meets customers' expectations for reliability, scalability, and security.
NOTE

This topic assumes that you are familiar with what is supported and unsupported in Microsoft Office SharePoint Server 2007. You can find more information about the unsupported features
in Office SharePoint Server 2007 in Unsupported Features in Excel Services.

Support for New Excel Features


Most of the new features in Microsoft Excel 2010 work in some way in Excel Services. Some features display as they do in Excel. Others can be displayed and are also interactive.
Following are new features that can be viewed:
Sparklines
Icon set and data bar improvements
PivotTable named sets
PivotTable improvements
Following are new features that can be viewed and interacted with:
Slicers
PowerPivot files
The new functions in Excel are also supported. Embedded images, a long-time feature of Excel, are now supported and can be viewed in Excel Services.

Features that Previously Prevented Excel Files from Loading


In Office SharePoint Server 2007, Excel workbooks that contain unsupported features like VBA macros, form controls, and so on are not loaded in Excel Services.
In SharePoint Server 2010, to help users work with this limitation, Excel Services ignores certain unsupported features. In other words, rather than blocking the entire file from loading, Excel
Services loads the file but you do not see the features that Excel Services does not support.
Following are features that do not prevent Excel Services from loading a file:
Cell comments.
Formula references to external books.
Query tables (also known as external data ranges).
Microsoft Visual Basic for Applications (VBA).
Any OfficeArt technology. For example, Shapes, WordArt, SmartArt, organization chart, diagrams, signature lines, ink annotations, and so on.
Note that these features continue to be unsupported. This means that they do not render, execute, or work in any way as they do on the client. Most of the features in the list do not render in
Excel Services. For example, if there is a Shape near cell A1 when viewed in the client, you see no Shape when viewed on the server. Other features, like formula references and query tables,
show values that were last refreshed on the client. In other words, the values in the cells are still there, but you cannot update them.
Lastly, VBA code does not execute on the server. In Office SharePoint Server 2007, Excel Services did not support loading *.xlsm files. In SharePoint Server 2010, Excel Services ignores VBA
macros. Therefore, *.xlsm files can now be loaded in Excel Services.

Viewing a File with Ignored Features


If Excel Services is able to load files and not render certain unsupported features, how can you know the file that you are viewing is missing some features? You know that you are viewing a
file with some missing features because Excel Services displays a notification above the worksheet to alert you. The following screenshot shows the notification.
Unsupported Features notification on top of workbook
This notification is the first indication that the file is rendering differently than it would in the Excel client.
In the following figure, clicking Learn more about unsupported features provides information about which unsupported features are in the file.
Unsupported feature error message for VBA

Cropped images are not displayed (that is, missing features).


NOTE

For workbooks that contain ignored or missing unsupported features that loaded in view mode with a notification bar, attempting to save a copy of the workbook involves removing the
unsupported features. A dialog box alerts the user of this.
Other Unsupported Features
All other unsupported features continue to behave as they do in Office SharePoint Server 2007 for Excel Services. That is, Excel Services blocks loading of a file if it detects the existence of
one or more of these unsupported features. Users are informed that the file cannot be loaded, as shown in the following screen shot.
NOTE

The Unsupported Features in Excel Services topic contains more details about these unsupported features.
W A R N IN G

The information bar with the list of unsupported features is not displayed if the file is loaded from a web part.
Unsupported feature error message for XML maps

Unlike workbooks with external links, charts with external links are blocked from loading.

See also
Concepts
Excel Services Overview
Excel Services Architecture
Excel Services Blogs, Forums, and Resources
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Excel Services Blogs, Forums, and Resources
3/26/2018 • 2 minutes to read Edit Online

The following are links to blogs, forums, and additional resources related to Excel Services and SharePoint:

B LO G NAME LINK S

Cum Grano Salis Home page


Excel Services page

Microsoft Excel 2010: The official blog of the Microsoft Excel product team Home page
Excel Online page

Microsoft Office Web Apps: The official blog of the Microsoft Office Online team Home page

FO R U M NAME LINK S

SharePoint - Excel Services Excel Services forum home page

SharePoint Products and Technologies List of SharePoint Products and Technologies forums

AD D ITIO NAL R ES O U R CES LINK S

Excel Services Resource Center Excel Services Resource Center on MSDN

IT Pro \ Administration Documentation TechNet

Microsoft Excel Online, part of Office Online, also supports Excel workbooks in the browser. For more information about Excel Online, see the documentation on Technet.

See also
Concepts
Excel Services Overview
Excel Services Development Roadmap
Excel Services Architecture
Excel Services Best Practices
Excel Services Alerts
Excel Services Known Issues and Tips
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Unsupported Features in Excel Services
Excel Web Services
3/26/2018 • 2 minutes to read Edit Online

This section contains information about Excel Web Services and explains how to use it to develop custom applications.

In this section
What's New in Excel Web Services

Learn about the new types and members added to Excel Web Services in Microsoft SharePoint Server 2010.

Accessing the SOAP API

Learn how to call the Web service by referencing the Excel Web Services Web Services Description Language (WSDL).

Loop-Back SOAP Calls and Direct Linking

Learn when to link to Microsoft.Office.Excel.Server.WebServices.dll locally.

Walkthrough: Developing a Custom Application Using Excel Web Services

Get step-by-step instructions about how to create a Web service client application that accesses Excel Web Services.

Excel Services Error Codes

Read about the error codes for Excel Web Services alerts and the associated messages, explanations, and resolutions.

How to: Set Credentials

Learn how to set credentials for your users so that they can call Excel Web Services by using your custom applications.

How to: Get an Entire Workbook or a Snapshot

Learn how to get an entire workbook, a snapshot of the file, or a snapshot of the viewable sheets or objects in the file by using Excel Web Services.

How to: Save a Workbook

Learn about using the various libraries in the Microsoft .NET Framework to save a workbook.

How to: Get Values from Ranges

See examples of the four methods for getting values from an Excel workbook.

How to: Set Values of Ranges

Learn how to use the four methods for setting values in an Excel workbook.

How to: Specify a Range Address and Sheet Name

Learn how to specify range addresses by using range coordinates, named ranges, rows, and columns. Also learn how to specify a sheet name, and about the relationship between a sheet
name and a range address.

How to: Use the CloseWorkbook Method Call Asynchronously

Find out how to close a workbook asynchronously to save some operation time.

How to: Refresh Data

Learn how you can use the Refresh method to retrieve updated data from external data sources for an open workbook.

How to: Use the SubCode Property to Capture Error Codes

Get examples that show how to capture Excel Services error codes when using SOAP and when using direct linking.

Reference
Microsoft.Office.Excel.Server.WebServices

The Excel Web Services API.

See also
Other resources
Excel Services Class Library and Web Service Reference
What's New in Excel Web Services
3/26/2018 • 2 minutes to read Edit Online

This topic lists the new types and members added to Excel Web Services.

Excel Web Services Enhancements


Excel Web Services is expanded and enhanced in Microsoft SharePoint Server 2010. In SharePoint Server 2010, you can edit and save a workbook programmatically. In addition, the Excel
Web Services now supports opening workbooks in edit sessions in SharePoint Server 2010. In this scenario, you can use code to edit a workbook at the same time that other users are co-
authoring the workbook.
For more information about the Excel Web Services API and more detailed remarks about the new methods, enumerations, and types, see Microsoft.Office.Excel.Server.WebServices.

New Methods
The following are new methods added to Excel Web Services, in alphabetical order:
GetChartImageUrl Gets a URL value to the chart or PivotChart image file in a workbook.
GetPublishedItemNames Gets a list of published items in a workbook.
GetSheetNames Gets a list of all of the sheet names present in a workbook.
OpenWorkbookForEditing Opens a workbook for editing.
SaveWorkbook Saves a workbook in the original format (.xlsx, .xlsb, .xlsm).
SaveWorkbookCopy Saves a workbook by using a different file name and/or saves a workbook to a different SharePoint document library.
SetCalculationOptions Changes the calculation mode setting for workbooks.
SetParameters Sets multiple published parameters with a single Web Service call.
In addition:
You can now set formulas by using the set value methods.
Dynamic ranges are supported in Excel Web Services in SharePoint Server 2010.

New Enumerations
The following are new enumerations added to Excel Web Services, in alphabetical order:
ItemType Indicates the types of the returned items.
SheetType Indicates the types of the returned sheets.
SheetVisibility Indicates whether the returned sheets are visible.
SaveOptions Specifies whether to overwrite an existing, unlocked file.
WorkbookCalculation Defines the calculation mode setting for a workbook.

New Types
The following are new types added to Excel Web Services, in alphabetical order:
ParameterInfo Gets or sets the name and values of a parameter.
SheetInfo Contains information about a sheet in a workbook.
Size Defines the width and height of the chart image
WorkbookItem Represents named items in the workbook.

See also
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Accessing the SOAP API
3/26/2018 • 2 minutes to read Edit Online

Excel Web Services uses Simple Object Access Protocol (SOAP) over HTTP and acts as a communications interface between client programs and Excel Services. The Web service consists of
methods and a set of complex type objects that you can use to access the complete functionality of Excel Web Services. To call the service, you must reference the Excel Web Services Web
Services Description Language (WSDL).

Referencing the WSDL


To call a Web service successfully, you must know how to access the service, what operations the service supports, what parameters the service expects, and what the service returns. WSDL
provides this information in an XML document that can be read or processed by a computer.
The WSDL for the Excel Web Services endpoint is accessed through ExcelServices.asmx?wsdl . WSDL can be consumed by development kits that support SOAP and Web services, such as
the Microsoft .NET Framework SDK.
The following example shows the format of the URL to the Excel Web Services WSDL file:
http://<server>/<customsite>/_vti_bin/excelservice.asmx?WSDL

If you do not have a custom site, you can use the following URL temporarily:
http://<server>/_vti_bin/excelservice.asmx?WSDL

It is recommended that you create a custom site, and then use the URL that includes the custom site in the URL format.
The following table describes each element in the URL.

U R L ELEMENT D ES CR IPTIO N

server The name of the server on which Microsoft SharePoint Server 2010 is deployed.

customsite A custom SharePoint Server 2010 site that the server administrator creates.

.asmx The name of the Web service endpoint. For Excel Web Services, it is ExcelService.asmx .

For more information about the WSDL format, see the World Wide Web Consortium (W3C) WSDL specification at http://www.w3.org/TR/wsdl.

See also
Other resources
Step 1: Creating the Web Service Client Project
Step 2: Adding a Web Reference
Step 3: Accessing the Web Service
Step 4: Building and Testing the Application
Walkthrough: Developing a Custom Application Using Excel Web Services
Loop-Back SOAP Calls and Direct Linking
5/3/2018 • 2 minutes to read Edit Online

If you are writing code within Microsoft SharePoint Foundation, for example, a custom web part, custom aspx page, and so on, you should make direct calls to
Microsoft.Office.Excel.Server.WebServices.dll. You do this by linking directly to Microsoft.Office.Excel.Server.WebServices.dll.
Using Simple Object Access Protocol (SOAP) from a Web server to communicate with the same Web server is also known as using loop-back SOAP calls. It is strongly recommended that
you do not attempt to use loop-back SOAP calls. If you are writing code within SharePoint Foundation, you should not use SOAP to call the Excel Web Services. You should instead link to
Microsoft.Office.Excel.Server.WebServices.dll locally and make calls to it as you would any local assembly.

Location of Microsoft.Office.Excel.Server.WebServices.dll
You can find Microsoft.Office.Excel.Server.WebServices.dll in one of the following locations:
[drive:]\Program Files\Common Files\Microsoft Shared\web server extensions\14\ISAPI
Global assembly cache

Adding a Reference to Microsoft.Office.Excel.Server.WebServices.dll


To link directly to Microsoft.Office.Excel.Server.WebServices.dll in your project and call it from your code, you add a reference to it. On the computer where you have installed Microsoft
SharePoint Server 2010, using the Add Reference dialog box in Microsoft Visual Studio, you can do one of the following:
Select Excel Web Services from the Component Name list in the .NET tab.
Browse to Microsoft.Office.Excel.Server.WebServices.dll located in:
[drive:]\Program Files\Common Files\Microsoft Shared\web server extensions\14\ISAPI

See also
Concepts
Accessing the SOAP API
Excel Services Known Issues and Tips
Excel Services Alerts
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Walkthrough: Developing a Custom Application Using Excel Web Services
3/26/2018 • 2 minutes to read Edit Online

The walkthrough in this section describes the process for accessing Excel Web Services from an application created with Microsoft Visual C#.
During this walkthrough, you will learn how to:
Create a client application using the Visual Studio Console Application project template.
Add a Web reference for Excel Web Services.
Write code to access the Web service. You will learn how to open a workbook, get the session ID, pass in the default credentials, get Web service version information, define the range
coordinate object, get the range that uses the range coordinate object, close the workbook, and catch the SOAP exception.
Test and run the console application in debug mode.
A client console application is just one way to access the Web service. A more common way would be to use server applications, such as Microsoft ASP.NET applications. This walkthrough
uses a console application example for simplicity, to focus on the Excel Web Services API aspects.

Prerequisites
In order to complete this walkthrough, you will need:
Microsoft SharePoint Server 2010.
Visual Studio or a similar Microsoft .NET Framework-compatible development tool.
Sufficient permissions (at the very least, "view" permissions) to be able to access Excel Web Services on the computer where SharePoint Server 2010 is located.
NOTE

For more information about workbook permissions, see the following section, "Workbook Permissions."
A sample workbook installed on a local drive or local SharePoint document library.
A trusted location to store the workbooks that you want to access using Excel Web Services. If the workbooks are not stored in a trusted location, the Excel Web Services calls to open
the workbook will fail. This walkthrough assumes the workbook is present on the local computer.
NOTE

For information about how to trust a location, see How to: Trust a Location and How to: Trust Workbook Locations Using Script.
To create the workbook using Excel.
To save the workbook as .xlsx or .xlsb files.
The workbook used in this example has a worksheet named "Sheet1". The worksheet has 11 columns and 19 rows. Each cell from A1 to K19 contains a numeric value—for example,
4245.955, 6960.673, and so on.

Workbook Permissions
To get the entire workbook (for example, by calling the GetWorkbook method), the caller needs "open" permission fr the workbook.
To call the GetApiVersion method, no permission is necessary.
For the rest of the Excel Web Services methods, the caller needs "view" permission (in Microsoft SharePoint Foundation) or "read" permission (on a file share) for the workbook.
NOTE

For more information about setting permissions, see the SharePoint Foundation documentation.

See also
Accessing the SOAP API
Excel Services Alerts
Excel Services Known Issues and Tips
Loop-Back SOAP Calls and Direct Linking
Step 1: Creating the Web Service Client Project
Step 2: Adding a Web Reference
Step 3: Accessing the Web Service
Step 4: Building and Testing the Application
Step 1: Creating the Web Service Client Project
3/26/2018 • 2 minutes to read Edit Online

For this walkthrough, you will create a new project and a simple console application that accesses Excel Web Services. This walkthrough assumes you are developing in Visual Studio.

Creating the Project


The following project uses Microsoft Visual Studio 2003.
NOTE

If you are using Microsoft Visual Studio 2005 or Microsoft Visual Studio 2008, the process to create a new project is slightly different depending on which settings you use in the Visual
Studio integrated development environment (IDE).

To create a new project


1. Start Visual Studio.
2. On the File menu, point to New, and then click Project. The New Project dialog box appears.
3. In the Project Type pane, select Visual C# Projects.
4. In the Templates pane, click Console Application.
5. In the Name box, type SampleApplication.
6. In the Location box, enter the path where you want to save your project, or click Browse to navigate to the folder.
7. Click OK. Your newly created project appears in Solution Explorer.
In Solution Explorer, a file with the default name of Class1.cs has been added to your project.

See also
Concepts
Accessing the SOAP API
Excel Services Alerts
Excel Services Known Issues and Tips
Other resources
Step 2: Adding a Web Reference
Step 3: Accessing the Web Service
Step 4: Building and Testing the Application
Walkthrough: Developing a Custom Application Using Excel Web Services
Step 2: Adding a Web Reference
4/20/2018 • 2 minutes to read Edit Online

Web service discovery is the process by which a client locates a Web service and obtains its service description. The process of Web service discovery in Visual Studio involves interrogating
a website following a predetermined algorithm. The goal of the process is to locate the service description, which is an XML document that uses the Web Services Description Language
(WSDL).
The service description describes what services are available and how to interact with those services. Without a service description, it is impossible to programmatically interact with a Web
service. Your application must have a means to communicate with the Web service and to locate it at run time. Adding a Web reference to your project for the Web service does this by
generating a proxy class that interfaces with the Web service and provides a local representation of the Web service. For more information, see "Web References and Generating an XML
Web Service Proxy" in the Microsoft Visual Studio 2005 documentation.

To add a Web Reference


1. On the Project menu, click Add Web Reference.
2. In the URL box of the Add Web Reference dialog box, type the URL to obtain the service description of the Excel Web Services, such as
http://<server>/<customsite>/_vti_bin/excelservice.asmx or http://<server>/_vti_bin/excelservice.asmx . Then click Go to retrieve information about the Web service.

NOTE

You can also open the Add Web Reference dialog box in the Solution Explorer pane by right-clicking References and selecting Add Web Reference.
3. In the Web reference name box, rename the Web reference toExcelWebService.
4. Click Add Reference to add a Web reference for the target Web service.
5. Visual Studio downloads the service description and generates a proxy class to interface between your application and Excel Web Services.
6. For more information, see Accessing the SOAP API.

See also
Concepts
Loop-Back SOAP Calls and Direct Linking
Other resources
Step 1: Creating the Web Service Client Project
Step 3: Accessing the Web Service
Step 4: Building and Testing the Application
Walkthrough: Developing a Custom Application Using Excel Web Services
Step 3: Accessing the Web Service
3/26/2018 • 6 minutes to read Edit Online

After you have added a reference to Excel Web Services to your project, the next step is to create an instance of the Web service's proxy class. You can then access the methods of the Web
service by calling the methods in the proxy class. When your application calls these methods, the proxy class code generated by Visual Studio handles the communications between your
application and the Web service.
First you create an instance of the Web service's proxy class, ExcelWebService. Next you call several of the Web service's methods and properties using the proxy class. You use the calls to
open a workbook, get the session ID, pass in the default credentials, define the range coordinate object, get the range that uses the range coordinate object, close the workbook, and catch the
SOAP exceptions.

Accessing the Web Service


To add directives
1. When you added the Web reference earlier, it created an object named ExcelService in a namespace called .. In this example, the object is named SampleApplication.ExcelWebService. This
walkthrough also shows how to catch SOAP exceptions. To do so, you use the System.Web.Services.Protocols object. The System.Web.Services.Protocols namespace consists of the
classes that define the protocols used to transmit data across the wire during the communication between XML Web service clients and XML Web services created using ASP.NET.
To facilitate using these objects, you must first add the namespaces as directives to the Class1.cs file. This way, if you use these directives, you do not need to fully qualify the types in the
namespace.
1. To add these directives, add the following code to the beginning of your code in the Class1.cs file, after using System:

using SampleApplication.ExcelWebService;
using System.Web.Services.Protocols;

Imports SampleApplication.ExcelWebService
Imports System.Web.Services.Protocols

To call the Web service


1. Instantiate and initialize the Web service proxy object by adding the following code after the opening bracket in static void Main(string[] args) :

ExcelService es = new ExcelService();

Dim es As New ExcelService()

1. Add the following code to create a status array and range coordinate objects:

Status[] outStatus;
RangeCoordinates rangeCoordinates = new RangeCoordinates();

Dim outStatus() As Status


Dim rangeCoordinates As New RangeCoordinates()

1. Add the code to point to the worksheet you want to access. In this example, the worksheet is called "Sheet1". Add the following to your code:

string sheetName = "Sheet1";

```VB.net
Dim sheetName As String = "Sheet1"
```
> [!NOTE]
> Make sure the workbook you want to open has a worksheet called "Sheet1" that contains values. Alternatively, you can change "Sheet1" in the code to the name of your worksheet.

1. Add the following code to point to the workbook you want to open :

```cs
string targetWorkbookPath = "http://myserver02/example/Shared%20Documents/Book1.xlsx";
```

```VB.net
Dim targetWorkbookPath As String = "http://myserver02/example/Shared%20Documents/Book1.xlsx"
```

> [!IMPORTANT]
> Change the workbook path to match the location of the workbook you are using for this walkthrough. Make sure the workbook exists and that the location where the workbook is saved is a trusted l

> [!NOTE]
> You can get the path to a workbook in Microsoft SharePoint Server 2010 by right-clicking the workbook and selecting **Copy Shortcut**. Alternatively, you can select **Properties** and copy the

1. Add the following code to set the credentials for the request.
NOTE
You have to explicitly set the credentials even if you intend to use the default credentials.

es.Credentials = System.Net.CredentialCache.DefaultCredentials;

es.Credentials = System.Net.CredentialCache.DefaultCredentials

1. Add the following code to open the workbook and point to the trusted location where the workbook is located. Place the code in a try block:

try
{
string sessionId = es.OpenWorkbook(targetWorkbookPath, "en-US",
"en-US", out outStatus);

Try
Dim sessionId As String = es.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", outStatus)

1. Add the following code to prepare an object to define range coordinates, and call the GetRange method. The code will also print the total number of rows in the range and the value in a
particular range.

rangeCoordinates.Column = 3;
rangeCoordinates.Row = 9;
rangeCoordinates.Height = 18;
rangeCoordinates.Width = 12;

object[] rangeResult1 = es.GetRange(sessionId, sheetName,


rangeCoordinates, false, out outStatus);
Console.WriteLine("Total rows in range: " + rangeResult1.Length);
Console.WriteLine("Value in range is: " + ((object[])rangeResult1[5])[2]);

rangeCoordinates.Column = 3
rangeCoordinates.Row = 9
rangeCoordinates.Height = 18
rangeCoordinates.Width = 12

Dim rangeResult1() As Object = es.GetRange(sessionId, sheetName, rangeCoordinates, False, outStatus)


Console.WriteLine("Total rows in range: " &amp; rangeResult1.Length)
Console.WriteLine("Value in range is: " &amp; (CType(rangeResult1(5), Object()))(2))

1. Add code to close the workbook and close the current session. Also add a close bracket to end the try block.

Important: It is good practice to close the workbook if you are done using the session. This will close the session and free resources.

es.CloseWorkbook(sessionId);
}

es.CloseWorkbook(sessionId)

1. Add a catch block to catch the SOAP exception and print the exception message:

catch (SoapException e)
{
Console.WriteLine("SOAP Exception Message: {0}", e.Message);
}

Catch e As SoapException
Console.WriteLine("SOAP Exception Message: {0}", e.Message)
End Try

Complete Code
The following code sample is the complete code in the Class1.cs example file described in the previous procedures.

Important: Make changes to the workbook path, sheet name, and so on, as appropriate.
using System;
using SampleApplication.ExcelWebService;
using System.Web.Services.Protocols;

namespace SampleApplication
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
// Instantiate the Web service and create a status array object and range coordinate object
ExcelService es = new ExcelService();
Status[] outStatus;
RangeCoordinates rangeCoordinates = new RangeCoordinates();

string sheetName = "Sheet1";


// Using workbookPath this way will allow
// you to call the workbook remotely.
// TODO: change the workbook path to
// point to workbook in a trusted location
// that you have access to
string targetWorkbookPath = "http://myserver02/example/Shared%20Documents/Book1.xlsx";
//you can also use .xlsb files, for example, //"http://myserver02/example/Shared%20Documents/Book1.xlsb";

// Set credentials for requests


es.Credentials = System.Net.CredentialCache.DefaultCredentials;
//Console.WriteLine("Cred: {0}", es.Credentials);
try
{
// Call open workbook, and point to the trusted
// location of the workbook to open.
string sessionId = es.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", out outStatus);
// Console.WriteLine("sessionID : {0}", sessionId);

// Prepare object to define range coordinates


// and the GetRange method.
rangeCoordinates.Column = 3;
rangeCoordinates.Row = 9;
rangeCoordinates.Height = 18;
rangeCoordinates.Width = 12;

object[] rangeResult1 = es.GetRange(sessionId, sheetName, rangeCoordinates, false, out outStatus);


Console.WriteLine("Total Rows in Range: " + rangeResult1.Length);
Console.WriteLine("Value in range is: " + ((object[])rangeResult1[5])[3]);

// Close workbook. This also closes session.


es.CloseWorkbook(sessionId);
}
catch (SoapException e)
{
Console.WriteLine("SOAP Exception Message: {0}", e.Message);
}
// catch (Exception e)
// {
// Console.WriteLine("Exception Message: {0}", e.Message);
// }
// Console.ReadLine();
}
}
}
Imports System
Imports SampleApplication.ExcelWebService
Imports System.Web.Services.Protocols

Namespace SampleApplication
Friend Class Class1
<STAThread> _
Shared Sub Main(ByVal args() As String)
' Instantiate the Web service and create a status array object and range coordinate object
Dim es As New ExcelService()
Dim outStatus() As Status
Dim rangeCoordinates As New RangeCoordinates()

Dim sheetName As String = "Sheet1"


' Using workbookPath this way will allow
' you to call the workbook remotely.
' TODO: change the workbook path to
' point to workbook in a trusted location
' that you have access to
Dim targetWorkbookPath As String = "http://myserver02/example/Shared%20Documents/Book1.xlsx"
'you can also use .xlsb files, for example, //"http://myserver02/example/Shared%20Documents/Book1.xlsb";

' Set credentials for requests


es.Credentials = System.Net.CredentialCache.DefaultCredentials
'Console.WriteLine("Cred: {0}", es.Credentials);
Try
' Call open workbook, and point to the trusted
' location of the workbook to open.
Dim sessionId As String = es.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", outStatus)
' Console.WriteLine("sessionID : {0}", sessionId)

' Prepare object to define range coordinates


' and the GetRange method.
rangeCoordinates.Column = 3
rangeCoordinates.Row = 9
rangeCoordinates.Height = 18
rangeCoordinates.Width = 12

Dim rangeResult1() As Object = es.GetRange(sessionId, sheetName, rangeCoordinates, False, outStatus)


Console.WriteLine("Total Rows in Range: " &amp; rangeResult1.Length)
Console.WriteLine("Value in range is: " &amp; (CType(rangeResult1(5), Object()))(3))

' Close workbook. This also closes session.


es.CloseWorkbook(sessionId)
Catch e As SoapException
Console.WriteLine("SOAP Exception Message: {0}", e.Message)
' Catch e As Exception
' Console.WriteLine("Exception Message: {0}", e.Message)
End Try
'Console.ReadLine()
End Sub
End Class
End Namespace

See also
Concepts
Accessing the SOAP API
Other resources
Step 1: Creating the Web Service Client Project
Step 2: Adding a Web Reference
Step 4: Building and Testing the Application
Walkthrough: Developing a Custom Application Using Excel Web Services
How to: Trust Workbook Locations Using Script
Step 4: Building and Testing the Application
3/26/2018 • 2 minutes to read Edit Online

In this step, you will build and test your application. Visual Studio offers several methods to build and run a console application from the IDE, such as:
Start Without Debugging ( CTRL + F5)
Start ( F5)

Build, Run, and Debug the Application


To build and run the application
1. On the Debug menu, click Start Without Debugging or press CTRL + F5. This ensures that the console window remains open after the program has finished executing.
2. The application prints the following output to the console.
NOTE

These values vary depending on the values you have in your workbook, session ID, and so on.

The Credential is: System.Net.SystemNetworkCredential


Total rows in range: 18
Value in range is: 4245.955129

3. Press any key to close SampleApplication.exe.

File Not Found Exception


1. If the path to the workbook you provided is wrong, you will get a "file not found" exception, which is caught by the following code:

catch (SoapException e)
{
Console.WriteLine("SOAP Exception Message: {0}", e.Message);
}

Catch e As SoapException
Console.WriteLine("SOAP Exception Message: {0}", e.Message)
End Try

1. The application prints the following SOAP exception output to the console:

SOAP Exception Message: The file you selected could not be found. Check the spelling of the file name and verify that the location is correct.

Index Out Of Range Exception


1. If you try to get a value from outside the range, you will get a System.IndexOutOfRangeException exception. The application prints the following output to the console:

The Credential is: System.Net.SystemNetworkCredential


The sessionID is : 64.28e58e90-b757-4658-b1c4-890ad68ef6cbRmqR4IINXfkMeOJRG8Iq0Y
27tVk=110.33d3R6fqv7tr2jPyYiPwRu|!@en-US|en-US|+0480#0000-10-00-05T02:00:00:0000
#+0000#0000-04-00-01T02:00:00:0000#-0060
Total rows in range: 18

1. Then you will get an unhandled exception that says:

An unhandled exception of type 'System.IndexOutOfRangeException' occurred in SampleApplication.exe


Additional information: Index was outside the bounds of the array.

1. You can handle the above unhandled exception by adding another catch block to catch the exception after the SOAP exception catch block as shown here:

catch (Exception e)
{
Console.WriteLine("Exception Message: {0}", e.Message);
}

Catch e As Exception
Console.WriteLine("Exception Message: {0}", e.Message)
End Try

To run the application using F5


1. You can run your application by clicking Start on the Debug menu, or by pressing F5. To ensure that the console window remains open after the program has finished executing, you
could add the following line of code at the end of your code (after the catch block):

Console.ReadLine();
Console.ReadLine()

1. Press any key to close SampleApplication.exe.

See also
Concepts
Accessing the SOAP API
Other resources
Step 1: Creating the Web Service Client Project
Step 2: Adding a Web Reference
Step 3: Accessing the Web Service
Walkthrough: Developing a Custom Application Using Excel Web Services
How to: Trust Workbook Locations Using Script
Excel Services Error Codes
3/26/2018 • 7 minutes to read Edit Online

Excel Services generates errors and error messages in the SOAP exception based on errors that occur in Excel Services. The following table shows the errors that are accessible when calls to
the Excel Web Services methods throw a SOAP exception.
You use the SubCode property of the SoapException class to capture the error codes. For more information about using the SubCode property to capture error codes, see How to: Use the
SubCode Property to Capture Error Codes For more information about Excel Services alerts, see Excel Services Alerts.

Error Codes
The following table lists the error codes for Excel Web Services alerts and the associated messages, explanation, and resolutions.

ER R O R CO D E MES S AG E E X PL ANATIO N R ES O LU TIO N

ApiInvalidArgument Invalid value to argument: {0} An invalid value for an argument was passed into Use a valid value for the argument.
the API call.
0 = name of the argument. Its value is invalid.

ApiInvalidCoordinate The {0} coordinate of {1} is invalid. 0 = coordinate name (row, column, height, width). Use valid coordinate values for the argument.
1 = name of the argument, which holds the
coordinate structure.
The contents of the RangeCoordinates class or
the row\column\height\width parameters on a
get or set call are invalid.

DimensionAndArrayMismatch The size of the provided array does not match the The caller tried to set a range into a workbook Make sure the size of the provided array matches
size and shape of the destination range. but the parameter that contains the array values the dimensions of the destination range (for
does not match the target range. example, 2 columns wide by 3 rows high).

DiscontiguousRangeNotSupported The request for the range does not refer to a The caller supplied a noncontiguous range when Enter a contiguous range such as "A1:B7" or "A1"
contiguous range. Excel Services supports trying to set or get a range of cells. Excel Services or "MyTable[#Data]" instead of a noncontiguous
contiguous ranges only. does not support noncontiguous ranges. It only range such as "A1:B7, B12" or "A1,A3".
supports contiguous ranges.

ExternalDataRefreshFailed Unable to retrieve external data for the following Attempts to refresh a data source inside a Make sure the data source is available and that
connections: workbook failed. you have permission to access it.
{0} 0 is a \n separated list of connection names.
The data source may be unreachable, may not be
responding, or has denied access.

FileOpenAccessDenied You do not have permissions to open this file on A call to the OpenWorkbook method failed Contact your administrator.
Excel Services. because the user does not have access to the file.

FileCorrupt The file you selected cannot be opened because it A call to the OpenWorkbook method failed Try to open the file again, or use Excel to open the
is corrupt, protected by Information Rights because the file is corrupted. file.
Management, or in a file format not supported by
Excel Services. Excel may be able to open this file.

FileOpenNotFound The file you selected could not be found. Check A call to the OpenWorkbook method failed Make sure that the file has not been renamed,
the spelling of the file name and verify that the because the file does not exist. moved, or deleted, that the file is in a trusted
location is correct. location, and that you have access to the file. If
the problem persists, contact your administrator.

FileOpenSecuritySettings The file you selected cannot be opened at this A call to the OpenWorkbook method failed Contact your administrator.
time due to security settings for Excel Services. because the administrator's security settings
prevented it from opening for various reasons.
For example, the file is too big, that is, its size
exceeded the limit set by the administrator.

FormulaEditingNotEnabled Editing Formulas is not enabled in this release of The caller tried to write a formula into the Do not try to write a formula because it is not
Excel Services. workbook. supported in this release of Excel Services.

GenericFileOpenError An error occurred while opening the file you Excel Services is unable to open the file for an Wait a few minutes and try to open the file again.
selected. unknown reason. If the problem persists, contact your
administrator.

InvalidSheetName The worksheet that you requested does not exist The sheet name was not found or was invalid. Use a valid value for the name of the sheet.
in the workbook.

InvalidOrTimedOutSession The operation you performed cannot be The call sessionId value is either invalid or has Reload the workbook in a new session.
completed at this time because the session is no since timed out.
longer available on the server. You can reload the
workbook and create a new session, but any
changes you have made have been lost.

IRMedWorkbook The requested workbook is IRM protected. Excel A call to the OpenWorkbook method failed Only pass in workbooks that are not IRM
Services cannot load IRM protected workbooks. because the workbook is protected by protected.
Information Rights Management (IRM).

MaxSessionsPerUserExceeded The maximum number of allowed sessions per The maximum number of sessions a user can Do not exceed the limit or contact your
user has been exceeded. The operation cannot be have opened at any given time has been administrator.
completed. exceeded. This limit is set by the administrator.

MultipleRequestsOnSession An operation is already being processed in this Multiple requests have been issued on the same Try performing the operation again.
session. Only one operation can be processed in a session. A session can only process one request at
session at a time. a time (with a few exceptions).
ER R O R CO D E MES S AG E E X PL ANATIO N R ES O LU TIO N

NotMemberOfRole Access denied. You do not have permission to The caller does not have permission to access the Contact your administrator.
perform this action or access this resource. server.

ObjectTypeNotSupported One or more object types provided are not The caller tried to write unsupported object type Try the operation again using one of the
supported by Excel Services. The operation was values into a range. supported object types.
rolled back.

OperationCanceled The operation has been canceled. The operation that is currently taking place is Call the CancelRequest method only if you want
canceled because the user calls the to cancel the current operation.
CancelRequest method.

RangeParseError Excel Services was unable to parse the range The range that was passed into a method with Enter a range reference using A1 notation such as
request. the A1 suffix ( SetCellA1, SetRangeA1, "Sheet1!Range("A6:A15")" or a valid structured
GetCellA1, and GetRangeA1) could not be reference such as "[ShipCity].[#Headers]".
parsed.

RangeRequestAreaExceeded The area of the requested range exceeds The requested range exceeds the 1,000,000 cell To return ranges that contain more than
1,000,000 cells. limit. 1,000,000 cells, use multiple calls.

RetryError Excel Services is unable to process the request. Excel Services might at times reach a state where Wait a few minutes and try to perform this
its resources are low. When this happens, it might operation again.
start denying requests.

SaveFailed An error occurred while saving the file. A call to the GetWorkbook method failed. Try to save the file again.

SetRangeFailure The requested operation attempted to overwrite The caller tried to write values into a range that Only empty cells or cells that contain values can
the contents of cells that cannot be edited. has protected cells. For example, the cell contains be edited by Excel Services.
a formula.

SheetRangeMismatch The sheet provided as the sheet argument is not The name of the sheet passed in for a sheetName When specifying a sheet in both the range and
the same as the sheet specified in the range parameter does not match the sheet location sheet arguments, ensure that the sheet names
argument. specified in the rangeName parameter. are the same. For example,
Calculate(Sheet1, Sheet1!Range("A1")) .

SpecifiedRangeNotFound The requested range does not exist in the sheet. The range that was passed into a method with Make sure the range specified exists in the sheet.
the A1 suffix ( SetCellA1, SetRangeA1,
GetCellA1, and GetRangeA1) could not be
found.

WorkbookNotSupported The file you selected cannot be opened because it The workbook contains unsupported features. Make sure the workbook does not contain
contains feature(s) that are not supported by 0 = a \n separated list of unsupported feature features that are not supported by Excel Services.
Excel Services. One or more of the following names.
unsupported features were detected in the
workbook:
{0}

See also
Tasks
How to: Use the SubCode Property to Capture Error Codes
Concepts
Excel Services Alerts
Excel Services Known Issues and Tips
Excel Services Best Practices
Get values from ranges
3/26/2018 • 6 minutes to read Edit Online

Excel Web Services exposes four methods for getting values from an Excel workbook: GetCell, GetCellA1, GetRange, and GetRangeA1.
The GetCell and GetCellA1 methods return the value of a single cell. If you try to request more than a single cell—for example, by passing in a range reference such as "B1:E2" or a named
range that is larger than a single cell, and so on—your method call will fail. If you want to retrieve values from a range of cells, use the GetRange and GetRangeA1 methods instead.
Methods that have the A1 suffix ( GetCellA1 and GetRangeA1) use a different coordinate system than those that do not ( GetCell and GetRange). If you want to use Excel-style references
to cells, such as range references (for example, H8, A3:D5, Sheet2!A12:G18) or named ranges, you should use the methods with the A1 suffix. Those methods allow you to pass in the name
of a sheet and the range address you want. In most cases, it is a good idea to use named ranges rather than Excel-style references, for abstraction reasons.
If you want to access an Excel range by using a numeric coordinate system, you should use the methods that do not have the A1 suffix. It is easier to use range coordinates when you have
code that iterates through a set of cells in a loop, or when the range coordinates are calculated dynamically as part of the algorithm.The row and column coordinates of a cell are 0-based.
Therefore, "0,0" will return cell A1, as in this example:

// Call the GetCell method to retrieve a value from a cell.


// The cell is in the first row and first column; that is, cell A1
object[] rangeResult2 = xlservice.GetCell(sessionId, sheetName, 0, 0, true, out outStatus);

' Call the GetCell method to retrieve a value from a cell.


' The cell is in the first row and first column; that is, cell A1
Dim rangeResult2() As Object = xlservice.GetCell(sessionId, sheetName, 0, 0, True, outStatus)

If you are getting values from multiple adjacent cells, you may want to consider using the GetRange method instead of making multiple calls to the GetCell method. This results in a single
roundtrip to the server instead of multiple roundtrips. Therefore, in some cases, you may gain a noticeable performance improvement by using the GetRange method instead of the GetCell
method.When getting a range of cells using the GetRange and GetRangeA1 methods, you get back an object array ( object[] in C# and Object () in Visual Basic .NET). The object array is
actually a jagged array. Each entry in the array you get back will be another array of objects representing the cells. For more information about jagged arrays, see Jagged Arrays (C#
Programming Guide) (http://msdn.microsoft.com/en-us/library/2s05feca.aspx).

To get values using the GetCell and GetRange methods


1. Use the GetCell method to get a value from a cell in the open workbook by using numeric range coordinates; for example:

// Instantiate the Web service and make a status array object.


ExcelService xlservice = new ExcelService();
Status[] outStatus;
string sheetName = "Sheet2";

// Set the path to a workbook.


// The workbook must be in a trusted location.
string targetWorkbookPath = "http://myserver02/example/Shared%20Documents/Book1.xlsx";

// Set credentials for requests.


xlservice.Credentials = System.Net.CredentialCache.DefaultCredentials;

// Call the open workbook, and point to the trusted


// location of the workbook to open.
string sessionId = xlservice.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", out outStatus);

// Call the GetCell method to retrieve a value from a cell.


// The cell is in the first row and ninth column.
object[] rangeResult2 = xlservice.GetCell(sessionId, sheetName, 0, 8, false, out outStatus);

' Instantiate the Web service and make a status array object.
Dim xlservice As New ExcelService()
Dim outStatus() As Status
Dim sheetName As String = "Sheet2"

' Set the path to a workbook.


' The workbook must be in a trusted location.
Dim targetWorkbookPath As String = "http://myserver02/example/Shared%20Documents/Book1.xlsx"

' Set credentials for requests.


xlservice.Credentials = System.Net.CredentialCache.DefaultCredentials

' Call the open workbook, and point to the trusted


' location of the workbook to open.
Dim sessionId As String = xlservice.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", outStatus)

' Call the GetCell method to retrieve a value from a cell.


' The cell is in the first row and ninth column.
Dim rangeResult2() As Object = xlservice.GetCell(sessionId, sheetName, 0, 8, False, outStatus)

1. Use the GetRange method to get values from a range in the open workbook by using numeric range coordinates.
// Instantiate the Web service and make a status array object.
ExcelService xlservice = new ExcelService();
Status[] outStatus;
RangeCoordinates rangeCoordinates = new RangeCoordinates();
string sheetName = "Sheet1";
...
// Prepare object to define range coordinates
// and call the GetRange method.
// startCol, startRow, startHeight, and startWidth
// get their value from user input.
rangeCoordinates.Column = (int)startCol.Value;
rangeCoordinates.Row = (int)startRow.Value;
rangeCoordinates.Height = (int)startHeight.Value;
rangeCoordinates.Width = (int)startWidth.Value;
...
object[] rangeResult1s = xlservice.GetRange(sessionId, sheetName, rangeCoordinates, false, out outStatus);
foreach (object[] x in rangeResult1s)
{
foreach (object y in x)
{
Console.WriteLine(String.Format("{0}", y));
}
}

' Instantiate the Web service and make a status array object.
Dim xlservice As New ExcelService()
Dim outStatus() As Status
Dim rangeCoordinates As New RangeCoordinates()
Dim sheetName As String = "Sheet1"
...
' Prepare object to define range coordinates
' and call the GetRange method.
' startCol, startRow, startHeight, and startWidth
' get their value from user input.
rangeCoordinates.Column = CInt(Fix(startCol.Value))
rangeCoordinates.Row = CInt(Fix(startRow.Value))
rangeCoordinates.Height = CInt(Fix(startHeight.Value))
rangeCoordinates.Width = CInt(Fix(startWidth.Value))
...
Dim rangeResult1s() As Object = xlservice.GetRange(sessionId, sheetName, rangeCoordinates, False, outStatus)
For Each x As Object() In rangeResult1s
For Each y As Object In x
Console.WriteLine(String.Format("{0}", y))
Next y
Next x

To get values using the GetCellA1 and GetRangeA1 methods


1. Use the GetCellA1 method to get a value from a cell in the open workbook, using the Excel "A1" range specification; for example:

// Instantiate the Web service and make a status array object.


ExcelService xlservice = new ExcelService();
Status[] outStatus;
string sheetName = "Sheet2";

object[] rangeResult = xlservice.GetCellA1(sessionId, sheetName, "MonthlyPayment", true, out outStatus);

' Instantiate the Web service and make a status array object.
Dim xlservice As New ExcelService()
Dim outStatus() As Status
Dim sheetName As String = "Sheet2"

Dim rangeResult() As Object = xlservice.GetCellA1(sessionId, sheetName, "MonthlyPayment", True, outStatus)

1. Use the GetRangeA1 method to get a value from a range in the open workbook, using the Excel "A1" range specification. The following code example asks for a 2x3 range, that is,
two rows by three columns. The code then loops through each row that is returned and retrieves the three cells each row contains. That is, in the first iteration:
rangeResult [0] returns the value in cell B2
rangeResult [1] returns the value in cell C2
rangeResult [2] returns the value in cell D2
In the second iteration:
rangeResult [0] returns the value in cell B3
rangeResult [1] returns the value in cell C3
rangeResult [2] returns the value in cell D3

object[] rangeResults = xlservice.GetRangeA1(sessionId, "Sheet1", "B2:D3", true, out outStatus);


foreach (object[] rangeResult in rangeResults)
{
Console.WriteLine(String.Format("{0} | {1} | {2}",
rangeResult[0], rangeResult[1], rangeResult[2]));
}
Dim rangeResults() As Object = xlservice.GetRangeA1(sessionId, "Sheet1", "B2:D3", True, outStatus)
For Each rangeResult As Object() In rangeResults
Console.WriteLine(String.Format("{0} | {1} | {2}", rangeResult(0), rangeResult(1), rangeResult(2)))
Next rangeResult

See also
Tasks
How to: Specify a Range Address and Sheet Name
How to: Set Values of Ranges
Concepts
Accessing the SOAP API
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Set values of ranges
3/26/2018 • 8 minutes to read Edit Online

Excel Web Services exposes four methods for setting values into an Excel workbook: SetCell, SetCellA1, SetRange, and SetRangeA1.
NOTE

When you make changes to a workbook—for example, by setting values to a range using Excel Web Services—the changes to the workbook are preserved only for that particular session.
The changes are not saved or persisted back to the original workbook. When the current workbook session ends (for example, when you call the CloseWorkbook method, or the session
times out), changes you made will be lost.> If you want to save changes you make to a workbook, you can use the GetWorkbook method and then save the workbook using the API of the
destination file store. For more information, see How to: Get an Entire Workbook or a Snapshot and How to: Save a Workbook.
Use the SetCell and SetCellA1 methods to set values in a single cell. If you try to set values in a range of cells—for example, by passing in a range reference such as "D3:G5" or a named
range that is larger than a single cell, and so on—your method call will fail. If you want to set values in a range of cells, use the SetRange and SetRangeA1 methods instead.
Methods that have the A1 suffix ( SetCellA1 and SetRangeA1) use a different coordinate system than those that do not ( SetCell and SetRange). If you want to use Excel-style references
to cells, such as range references (for example, H8, A3:D5, Sheet2!A12:G18) or named ranges, you should use the methods with the A1 suffix. Those methods allow you to pass in the name
of a sheet and range.If you want to access an Excel range by using a numeric coordinate system, you should use the methods that do not have the A1 suffix. It is easier to use range
coordinates when you have code that iterates through a set of cells in a loop, or when the range coordinates are calculated dynamically as part of the algorithm.The row and column
coordinates of a cell are 0-based. Therefore, "0,0" will return cell A1, as in this example:

// Call the SetCell method to set a value, 8, into a cell.


// The cell is in the first row and first column; that is, cell A1.
xlservice.SetCell(sessionId, sheetName, 0, 0, 8);

' Call the SetCell method to set a value, 8, into a cell.


' The cell is in the first row and first column; that is, cell A1.
xlservice.SetCell(sessionId, sheetName, 0, 0, 8)

If you are getting values from multiple adjacent cells, you may want to consider using the SetRange method instead of making multiple calls to the SetCell method. This results in a single
round trip to the server instead of multiple round trips. Therefore, in some cases, you may gain a noticeable performance improvement by using the SetRange method instead of the
SetCell method.When setting values into a range of cells using the SetRange and SetRangeA1 methods, you use an object array ( object[] in C# and Object () in Visual Basic .NET). The
object array is actually a jagged array; each entry in the array is another array of objects representing the cells. For more information about jagged arrays, see Jagged Arrays (C#
Programming Guide) (http://msdn.microsoft.com/en-us/library/2s05feca.aspx).

To set values by using the SetCell and SetRange methods


1. Use the SetCell method to set a value in a cell in the open workbook by using numeric range coordinates:

// Instantiate the Web service and make a status array object.


ExcelService xlservice = new ExcelService();
Status[] outStatus;
RangeCoordinates rangeCoordinates = new RangeCoordinates();
string sheetName = "Sheet2";

// Set the path to a workbook.


// The workbook must be in a trusted location.
string targetWorkbookPath = "http://myserver02/example/Shared%20Documents/Book1.xlsx";

// Set credentials for requests.


xlservice.Credentials = System.Net.CredentialCache.DefaultCredentials;

// Call the open workbook, and point to the trusted


// location of the workbook to open.
string sessionId = xlservice.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", out outStatus);

// Call the SetCell method to set the cell's value to 28.


// The cell is in the ninth row and second column, which is cell B9.
xlservice.SetCell(sessionId, sheetName, 8, 1, 28);

' Instantiate the Web service and make a status array object.
Dim xlservice As New ExcelService()
Dim outStatus() As Status
Dim rangeCoordinates As New RangeCoordinates()
Dim sheetName As String = "Sheet2"

' Set the path to a workbook.


' The workbook must be in a trusted location.
Dim targetWorkbookPath As String = "http://myserver02/example/Shared%20Documents/Book1.xlsx"

' Set credentials for requests.


xlservice.Credentials = System.Net.CredentialCache.DefaultCredentials

' Call the open workbook, and point to the trusted


' location of the workbook to open.
Dim sessionId As String = xlservice.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", outStatus)

' Call the SetCell method to set the cell's value to 28.
' The cell is in the ninth row and second column, which is cell B9.
xlservice.SetCell(sessionId, sheetName, 8, 1, 28)

1. Use the SetRange method to set values in a range in the open workbook by using numeric range coordinates:
// Instantiate the Web service and make a status array object.
ExcelService xlservice = new ExcelService();
Status[] outStatus;
RangeCoordinates rangeCoordinates = new RangeCoordinates();

...
private void Form1_Load(object sender, EventArgs e)
{
...
...
//Prepare object to define range coordinates
//and call the GetRange method.
//startCol, startRow, startHeight, and startWidth
//get their values from user input.
rangeCoordinates.Column = (int)startCol.Value;
rangeCoordinates.Row = (int)startRow.Value;
rangeCoordinates.Height = (int)startHeight.Value;
rangeCoordinates.Width = (int)startWidth.Value;
...
...
}
private void SetRangeButton_Click(object sender, EventArgs e)
{
object[] values = new object[rangeCoordinates.Height];
string[] fieldValues =
SetRangeTextBox.Text.Split((",").ToCharArray());

if (fieldValues.Length != rangeCoordinates.Height *
rangeCoordinate.Width)
{
throw new Exception("The number of inputs (" +
fieldValues.Length + ") does not match" +
" the product of Height (" + rangeCoordinates.Height + ") and Width (" +
rangeCoordinates.Width + ")");
}

for (int i = 0; i < rangeCoordinates.Height; i++)


{
object[] currentRow =
new object[rangeCoordinates.Width];
for (int j = 0; j < rangeCoordinates.Width; j++)
{
currentRow[j] = fieldValues[i * rangeCoordinates.Width + j];
}
values[i] = currentRow;
}

SetStatusText("Waiting for SetRange...");


outStatus = xlservice.SetRange(
sessionID, SheetNameTextBox.Text,
rangeCoordinates, values);
}
catch (SoapException exc)
{
StopTimer("SetRange");
GenerateErrorMessage("SetRange", exc);
}
catch (Exception exc)
{
StopTimer("SetRange");
GenerateToolErrorMessage("While calling SetRange", exc);
}
}
' Instantiate the Web service and make a status array object.
Private xlservice As New ExcelService()
Private outStatus() As Status
Private rangeCoordinates As New RangeCoordinates()

...
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
...
...
'Prepare object to define range coordinates
'and call the GetRange method.
'startCol, startRow, startHeight, and startWidth
'get their values from user input.
rangeCoordinates.Column = CInt(Fix(startCol.Value))
rangeCoordinates.Row = CInt(Fix(startRow.Value))
rangeCoordinates.Height = CInt(Fix(startHeight.Value))
rangeCoordinates.Width = CInt(Fix(startWidth.Value))
...
...
End Sub
Private Sub SetRangeButton_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim values(rangeCoordinates.Height - 1) As Object
Dim fieldValues() As String = SetRangeTextBox.Text.Split((",").ToCharArray())

If fieldValues.Length <> rangeCoordinates.Height * rangeCoordinate.Width Then


Throw New Exception("The number of inputs (" &amp; fieldValues.Length &amp; ") does not match" &amp; " the product of Height (" &amp; rangeCoordinates.Height &amp; ") and Width (" &amp; r
End If

For i As Integer = 0 To rangeCoordinates.Height - 1


Dim currentRow(rangeCoordinates.Width - 1) As Object
For j As Integer = 0 To rangeCoordinates.Width - 1
currentRow(j) = fieldValues(i * rangeCoordinates.Width + j)
Next j
values(i) = currentRow
Next i
Try
SetStatusText("Waiting for SetRange...")
outStatus = xlservice.SetRange(sessionID, SheetNameTextBox.Text, rangeCoordinates, values)
Catch exc As SoapException
StopTimer("SetRange")
GenerateErrorMessage("SetRange", exc)
Catch exc As Exception
StopTimer("SetRange")
GenerateToolErrorMessage("While calling SetRange", exc)
End Try
End Sub

To set values by using the SetCellA1 and SetRangeA1 methods


1. Use the SetCellA1 method to set a value in a cell in the open workbook, using the Excel "A1" range specification:

// Instantiate the Web service and make a status array object.


ExcelService xlservice = new ExcelService();
Status[] outStatus;

xlservice.SetCellA1(sessionId, String.Empty, "InterestRateParam", 8);

' Instantiate the Web service and make a status array object.
Dim xlservice As New ExcelService()
Dim outStatus() As Status

xlservice.SetCellA1(sessionId, String.Empty, "InterestRateParam", 8)

1. Use the SetRangeA1 method to get a value from a range in the open workbook, using the Excel "A1" range specification:
// Instantiate the Web service and make a status array object.
ExcelService xlservice = new ExcelService();
Status[] outStatus;
...

void SetRangeA1Button_ServerClick(object sender, EventArgs e)


{
int height, width;
CalculateHeightAndWidth(RangeNameTextBox5.Value.Trim(),
out height, out width);

object[] values = new object[height];


string[] fieldValues =
RangeValuesTextBox1.Value.Split((",").ToCharArray());
if (fieldValues.Length != height * width)
{
throw new Exception("The number of inputs (" +
fieldValues.Length + ") does not match" +
" the product of Height (" + height + ") and
Width (" + width + ")");
}

for (int i = 0; i < height; i++)


{
object[] currentRow = new object[width];
for (int j = 0; j < width; j++)
{
currentRow[j] = fieldValues[i * width + j];
}
values[i] = currentRow;
}
try
{
xlservice.SetRangeA1(SessionIDTextBox.Value,
SheetNameTextBox1.Value,RangeNameTextBox5.Value,
values, out outStatus);
}
catch (SoapException exc)
{
ExceptionTextBox1.Value = exc.Message;
}

' Instantiate the Web service and make a status array object.
Private xlservice As New ExcelService()
Private outStatus() As Status
...

Private Sub SetRangeA1Button_ServerClick(ByVal sender As Object, ByVal e As EventArgs)


Dim height, width As Integer
CalculateHeightAndWidth(RangeNameTextBox5.Value.Trim(), height, width)

Dim values(height - 1) As Object


Dim fieldValues() As String = RangeValuesTextBox1.Value.Split((",").ToCharArray())
If fieldValues.Length <> height * width Then
Throw New Exception("The number of inputs (" &amp; fieldValues.Length &amp; ") does not match" &amp; " the product of Height (" &amp; height &amp; ") and Width (" &amp; width &amp; ")")
End If

For i As Integer = 0 To height - 1


Dim currentRow(width - 1) As Object
For j As Integer = 0 To width - 1
currentRow(j) = fieldValues(i * width + j)
Next j
values(i) = currentRow
Next i
Try
xlservice.SetRangeA1(SessionIDTextBox.Value, SheetNameTextBox1.Value,RangeNameTextBox5.Value, values, outStatus)
Catch exc As SoapException
ExceptionTextBox1.Value = exc.Message
End Try

End Sub

See also
Tasks
How to: Specify a Range Address and Sheet Name
How to: Get Values from Ranges
Concepts
Accessing the SOAP API
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Specify a range address and sheet name
3/26/2018 • 5 minutes to read Edit Online

This example shows how to specify range addresses by using range coordinates, named ranges, rows, and columns. It also shows how to specify a sheet name and the relationship between a
sheet name and a range address.
Range coordinates are the four integer coordinates used to select a contiguous range. Range coordinates enable you to specify Excel ranges by using direct integer indexing as an alternative
to "A1" expressions. The coordinates you can specify are the top row, left column, height, and width. It is easier to use range coordinates when you have code that iterates through a set of
cells in a loop, or when the range coordinates are calculated dynamically as part of the algorithm. A range specification must contain a sheet name; Excel Web Services does not recognize
the "current sheet." There are a few ways to specify the sheet name:
As part of the range address—for example, "Sheet3!B12:D18"—in which case the sheet name argument can be empty:

object[] rangeResult1 = xlservice.GetRangeA1(sessionId, String.Empty, "Sheet2!A12:G18", true, out outStatus);

Dim rangeResult1() As Object = xlservice.GetRangeA1(sessionId, String.Empty, "Sheet2!A12:G18", True, outStatus)

In a separate sheet name argument, in which case the range address argument does not have to include the sheet name:

xlservice.SetCell(sessionId, "Sheet3", 0, 11, 1000);

xlservice.SetCell(sessionId, "Sheet3", 0, 11, 1000)

In both the sheet name and range address, in which case the name of the sheet must match:

object[] rangeResult = xlservice.GetCellA1(sessionId, "Sheet3", "Sheet3!G18", true, out outStatus);

Dim rangeResult() As Object = xlservice.GetCellA1(sessionId, "Sheet3", "Sheet3!G18", True, outStatus)

The only case that does not require a sheet name is a named range, because some named ranges have a workbook scope. For example, you can refer to named ranges without specifying the
sheet name argument:

xlServices.SetCellA1(sessionId, String.Empty, "MyNamedRange", 8);

xlServices.SetCellA1(sessionId, String.Empty, "MyNamedRange", 8)

If you specify a sheet name, the ranges you reference must exist on the sheet you specify. If you specify a sheet that does not exist, the call will fail and you will get a Simple Object Access
Protocol (SOAP) exception, saying that the sheet does not exist.

Example
NOTE

It is assumed that you have already created a SharePoint document library and made it a trusted location. For more information about this, see How to: Trust a Location and How to: Trust
Workbook Locations Using Script.
using System;
using System.Text;
using System.Web.Services.Protocols;
using ExcelWebService.myserver02;
namespace ExcelWebService
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class MyExcelWebService
{
[STAThread]
static void Main(string[] args)
{
// Instantiate the Web service
// and range coordinate array object.
ExcelService xlservice = new ExcelService();
Status[] outStatus;
RangeCoordinates rangeCoordinates = new RangeCoordinates();
string sheetName = "MySheet1";

// TODO: Change the path to the workbook


// to point to a workbook you have access to.
// The workbook must be in a trusted location.
// Using the workbook path this way will allow
// you to call the workbook remotely.
string targetWorkbookPath =
"http://myserver02/example/Shared%20Documents/MyWorkbook1.xlsx";

// Set Credentials for requests


xlservice.Credentials =
System.Net.CredentialCache.DefaultCredentials;

try
{
// Call the open workbook, and point to
// the workbook to open.
string sessionId =
xlservice.OpenWorkbook(targetWorkbookPath,
String.Empty, String.Empty, out outStatus);
// Prepare object to define range coordinates
// and call the GetRange method.
// startCol, startRow, startHeight, and startWidth
// get their values from user input.
rangeCoordinates.Column = (int)startCol.Value;
rangeCoordinates.Row = (int)startRow.Value;
rangeCoordinates.Height = (int)startHeight.Value;
rangeCoordinates.Width = (int)startWidth.Value;

object[] rangeResult1 = xlservice.GetRange(sessionId,


sheetName, rangeCoordinates, false, out outStatus);
Console.WriteLine("Total rows in range: " +
rangeResult1.Length);
Console.WriteLine("Sum in last column is: " +
((object[])rangeResult1[18])[11]);

// Call the SetCell method, which invokes


// the Calculate method.
// Set first row in last column cell to 1000.
xlservice.SetCell(sessionId, sheetName, 0, 11, 1000);

// Call the GetRange method again to see if


// the Sum total in the last column changed.
object[] rangeResult2 = xlservice.GetRange(sessionId,
sheetName, rangeCoordinates, false, out outStatus);
Console.WriteLine("Sum in the last column after SetCell
is: " + ((object[])rangeResult2[18])[11]);

// Close workbook. This also closes the session.


xlservice.CloseWorkbook(sessionId);
}

catch (SoapException e)
{
Console.WriteLine("Exception Message: {0}", e.Message);
}
catch (Exception e)
{
Console.WriteLine("Exception Message: {0}", e.Message);
}
Console.ReadLine();
}
}
}
Imports System
Imports System.Text
Imports System.Web.Services.Protocols
Imports ExcelWebService.myserver02
Namespace ExcelWebService
''' <summary>
''' Summary description for Class1.
''' </summary>
Friend Class MyExcelWebService
<STAThread> _
Shared Sub Main(ByVal args() As String)
' Instantiate the Web service
' and range coordinate array object.
Dim xlservice As New ExcelService()
Dim outStatus() As Status
Dim rangeCoordinates As New RangeCoordinates()
Dim sheetName As String = "MySheet1"

' TODO: Change the path to the workbook


' to point to a workbook you have access to.
' The workbook must be in a trusted location.
' Using the workbook path this way will allow
' you to call the workbook remotely.
Dim targetWorkbookPath As String = "http://myserver02/example/Shared%20Documents/MyWorkbook1.xlsx"

' Set Credentials for requests


xlservice.Credentials = System.Net.CredentialCache.DefaultCredentials

Try
' Call the open workbook, and point to
' the workbook to open.
Dim sessionId As String = xlservice.OpenWorkbook(targetWorkbookPath, String.Empty, String.Empty, outStatus)
' Prepare object to define range coordinates
' and call the GetRange method.
' startCol, startRow, startHeight, and startWidth
' get their values from user input.
rangeCoordinates.Column = CInt(Fix(startCol.Value))
rangeCoordinates.Row = CInt(Fix(startRow.Value))
rangeCoordinates.Height = CInt(Fix(startHeight.Value))
rangeCoordinates.Width = CInt(Fix(startWidth.Value))

Dim rangeResult1() As Object = xlservice.GetRange(sessionId, sheetName, rangeCoordinates, False, outStatus)


Console.WriteLine("Total rows in range: " &amp; rangeResult1.Length)
Console.WriteLine("Sum in last column is: " &amp; (CType(rangeResult1(18), Object()))(11))

' Call the SetCell method, which invokes


' the Calculate method.
' Set first row in last column cell to 1000.
xlservice.SetCell(sessionId, sheetName, 0, 11, 1000)

' Call the GetRange method again to see if


' the Sum total in the last column changed.
Dim rangeResult2() As Object = xlservice.GetRange(sessionId, sheetName, rangeCoordinates, False, outStatus)
Console.WriteLine("Sum in the last column after SetCell is: " &amp; (CType(rangeResult2(18), Object()))(11))

' Close workbook. This also closes the session.


xlservice.CloseWorkbook(sessionId)

Catch e As SoapException
Console.WriteLine("Exception Message: {0}", e.Message)
Catch e As Exception
Console.WriteLine("Exception Message: {0}", e.Message)
End Try
Console.ReadLine()
End Sub
End Class
End Namespace

Robust programming
Make sure you add a Web reference to an Excel Web Services site to which you have access. Change the following:
Change the using ExcelWebService.myserver02; statement to point to the Web service site you are referencing.
Change string targetWorkbookPath = "http://myserver02/example/Shared%20Documents/Book1.xlsx"; to point to a workbook to which you have access. The workbook must be in a trusted
location.

See also
Tasks
How to: Get Values from Ranges
How to: Set Values of Ranges
Concepts
Accessing the SOAP API
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Get an entire workbook or a snapshot
3/26/2018 • 5 minutes to read Edit Online

This example shows how to get an entire workbook, a snapshot of the entire file, or just a snapshot of the viewable sheets or objects in the file by using Excel Web Services. Getting the
workbook or a snapshot is useful if you want to save a copy of the up-to-date workbook, store it somewhere, send it to someone, and so on.
A snapshot is a workbook generated by Excel Calculation Services, and it represents the current state of the workbook in the Excel Services session. Some snapshots (known as "published
item snapshots") contain only those portions of the Excel file that an author selects as viewable when saving the file to the server. Snapshots contain the layout and formats of the original file,
and up-to-date values calculated by Excel Calculation Services, but they do not contain Excel formulas or external data connections. Excel Services opens the Excel file on the server, refreshes
data sources, and calculates all Excel formulas. When a user or application requests a snapshot, Excel Services then generates and sends a snapshot back through the Web service API. You
can acquire a snapshot of a workbook you already saved to the server, even if you do not have the rights to access the actual file on the server.
You use the Web service's GetWorkbook method to get either the entire workbook or one of the snapshot types. For example, the following code returns a snapshot of the entire Excel
workbook. It uses the WorkbookType.FullSnapshot enumeration as the second argument in the GetWorkbook method.

byte[] workbook = xlService.GetWorkbook(sessionId, WorkbookType.FullSnapshot, out status);

Dim workbook() As Byte = xlService.GetWorkbook(sessionId, WorkbookType.FullSnapshot, status)

The GetWorkbook method returns a byte array, in the same Excel file format as the one loaded into the session.To get a snapshot of the items that the Excel workbook author selected as
viewable when saving the workbook from Excel to the server, use the WorkbookType.PublishedItemsSnapshot enumeration as shown here:

byte[] workbook = xlService.GetWorkbook(sessionId, WorkbookType.PublishedItemsSnapshot, out status);

Dim workbook() As Byte = xlService.GetWorkbook(sessionId, WorkbookType.FullSnapshot, status)

To get a snapshot of the entire workbook in its current session state, use the WorkbookType.FullWorkbook enumeration:

byte[] workbook = xlService.GetWorkbook(sessionId, WorkbookType.FullWorkbook, out status);

Dim workbook() As Byte = xlService.GetWorkbook(sessionId, WorkbookType.FullWorkbook, status)

The WorkbookType.FullWorkbook option works only if the user has open rights to the file; if the user has view-only rights, the call will fail.In some cases, your code would need to save the
result of a GetWorkbook call. For a discussion about how to save a workbook, see the How to: Save a Workbook example.For more information about the GetWorkbook method and the
WorkbookType enumeration, see the Excel Web Services reference documentation.

Example
The following program (a console application) receives one command-line argument, which is the path to the workbook on the server. The program calls the Web service to open the
workbook on the server and get a snapshot. It then writes it to standard output so that you can redirect it to a new snapshot file.
using System;
using System.IO;
using System.Text;
using System.Web.Services.Protocols;
// TODO: Change the using GetSnapshot.myServer02 statement
// to point to the Web service you are referencing.
using GetSnapshot.myServer02;

namespace GetSnapshot
{
class ExcelServicesSnapshot
{
static void Main(string[] args)
{
try
{
if (args.Length < 1)
{
Console.Error.WriteLine("Command line arguments should be: GetSnapshot [workbook_path] > [snapshot_filename]");
return;
}
// Instantiate the Web service and
// create a status array object.
ExcelService xlService = new ExcelService();
Status[] status;

xlService.Timeout = 600000;
// Set credentials for requests.
// Use the current user's logon credentials.
xlService.Credentials =
System.Net.CredentialCache.DefaultCredentials;

// Open the workbook, then call GetWorkbook


// and close the session.
string sessionId = xlService.OpenWorkbook(args[0], "en-US", "en-US", out status);
byte[] workbook = xlService.GetWorkbook(sessionId, WorkbookType.PublishedItemsSnapshot, out status);
// byte[] workbook = xlService.GetWorkbook(sessionId, WorkbookType.FullWorkbook, out status);
// byte[] workbook = xlService.GetWorkbook(sessionId, WorkbookType.FullSnapshot, out status);

// Close the workbook. This also closes the session.


status = xlService.CloseWorkbook(sessionId);

// Write the resulting Excel file to stdout


// as a binary stream.
BinaryWriter binaryWriter = new BinaryWriter(Console.OpenStandardOutput());
binaryWriter.Write(workbook);
binaryWriter.Close();
}

catch (SoapException e)
{
Console.WriteLine("SOAP Exception Message: {0}", e.Message);
}

catch (Exception e)
{
Console.WriteLine("Exception Message: {0}", e.Message);
}
}
}
}
Imports System
Imports System.IO
Imports System.Text
Imports System.Web.Services.Protocols
' TODO: Change the using GetSnapshot.myServer02 statement
' to point to the Web service you are referencing.
Imports GetSnapshot.myServer02

Namespace GetSnapshot
Friend Class ExcelServicesSnapshot
Shared Sub Main(ByVal args() As String)
Try
If args.Length < 1 Then
Console.Error.WriteLine("Command line arguments should be: GetSnapshot [workbook_path] > [snapshot_filename]")
Return
End If
' Instantiate the Web service and
' create a status array object.
Dim xlService As New ExcelService()
Dim status() As Status

xlService.Timeout = 600000
' Set credentials for requests.
' Use the current user's logon credentials.
xlService.Credentials = System.Net.CredentialCache.DefaultCredentials

' Open the workbook, then call GetWorkbook


' and close the session.
Dim sessionId As String = xlService.OpenWorkbook(args(0), "en-US", "en-US", status)
Dim workbook() As Byte = xlService.GetWorkbook(sessionId, WorkbookType.PublishedItemsSnapshot, status)
' byte[] workbook = xlService.GetWorkbook(sessionId, WorkbookType.FullWorkbook, out status);
' byte[] workbook = xlService.GetWorkbook(sessionId, WorkbookType.FullSnapshot, out status);

' Close the workbook. This also closes the session.


status = xlService.CloseWorkbook(sessionId)

' Write the resulting Excel file to stdout


' as a binary stream.
Dim binaryWriter As New BinaryWriter(Console.OpenStandardOutput())
binaryWriter.Write(workbook)
binaryWriter.Close()

Catch e As SoapException
Console.WriteLine("SOAP Exception Message: {0}", e.Message)

Catch e As Exception
Console.WriteLine("Exception Message: {0}", e.Message)
End Try
End Sub
End Class
End Namespace

Use the following command line and arguments to run the GetSnapshot application:

GetSnapshot.exe [workbook_path] > [snapshot_filename]

For example:

C:\\>GetSnapshot.exe http://myServer02/reports/reports/OriginalWorkbook.xlsx > SnapshotCopy.xlsx

If you use the previous command-line example, the GetSnapshot tool places a new file in the "C:\" directory.
NOTE

he workbook that you want to get a snapshot of must be in a trusted location.

Robust programming
Make sure you add a Web reference to an Excel Web Services site you have access to. Change the using GetSnapshot.myServer02; statement to point to the Web service site you are
referencing.

See also
Tasks
How to: Trust a Location
Concepts
Accessing the SOAP API
Other resources
Step 1: Creating the Web Service Client Project
Step 2: Adding a Web Reference
Step 3: Accessing the Web Service
Step 4: Building and Testing the Application
Walkthrough: Developing a Custom Application Using Excel Web Services
Use the CloseWorkbook method call asynchronously
3/26/2018 • 4 minutes to read Edit Online

When you are using Excel Web Services, it is good practice to close the workbook by calling the CloseWorkbook method if you are finished using the session. This closes the session and
allows Excel Services to free resources in a predictable manner. This could potentially improve your server performance and robustness.
However, any Web service call takes time. Depending on the way your server is installed, the way that you access it, and how much stress the server is under, the call can take anywhere
between 50 milliseconds to 500 milliseconds. It can also take longer, but only if your server is under severe stress. Because a failed CloseWorkbook method call is not actionable, you do not
need to wait for it to finish to see whether it succeeds. Because of this, you can usually make the call asynchronously and save some operation time.
NOTE

If your application makes some calls to Excel Services and then exits, you may want to close a workbook synchronously instead of asynchronously. In this case, you call the CloseWorkbook
method instead of the CloseWorkbookAsync method. The reason is if you immediately exit the process after issuing an asynchronous call, there is a good chance the call might not get
through.
To close the workbook asynchronously, you must do two things:
Make sure you do not dispose the Excel Web Services proxy class—if you do, non-Excel Services exceptions may occur.
Call the CloseWorkbookAsync method instead of the CloseWorkbook method. The signature for the CloseWorkbookAsync method is:

public void CloseWorkbookAsync(string sessionId)

Public Sub CloseWorkbookAsync(ByVal sessionId As String)


End Sub

You don't have to implement the event that is called when the CloseWorkbookAsync method is called.You can find the signature in the "Reference.cs" file in your project "Web References"
directory.
NOTE

You can find the CloseWorkbookAsync method in the proxy class that is generated when you add a Web reference using Microsoft Visual Studio 2005. If you are using Visual Studio 2003,
you call the BeginCloseWorkbook method to close a workbook asynchronously instead.
Calling the CloseWorkbookAsync method or BeginCloseWorkbook method means the call to close a workbook will be executed asynchronously and not cost your application any
significant amount of time.

Example
The following example shows how to close a workbook asynchronously using Visual Studio 2005.
using System;
using SampleApplication.ExcelWebService;
using System.Web.Services.Protocols;
namespace SampleApplication
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
// Instantiate the Web service
// and create a status array object.
ExcelService es = new ExcelService();
Status[] outStatus;

string sheetName = "Sheet1";


// TODO: change the workbook path to
// point to workbook in a trusted location
// that you have access to.
string targetWorkbookPath =
"http://myserver02/example/Shared%20Documents/Book1.xlsx";

// Set credentials for requests.


es.Credentials =
System.Net.CredentialCache.DefaultCredentials;

try
{
// Call open workbook, and point to the trusted
// location of the workbook to open.
string sessionId = es.OpenWorkbook(targetWorkbookPath,
"en-US", "en-US", out outStatus);
// Call the GetCell method
// to retrieve a value from a cell.
// The cell is in the first row and ninth column.
object[] rangeResult2 = xlservice.GetCell(sessionId,
sheetName, 0, 8, false, out outStatus);

// Close the workbook asynchronously.


// This also closes session.
es.CloseWorkbookAsync(sessionId);
}
catch (SoapException e)
{
Console.WriteLine("SOAP Exception Message: {0}",
e.Message);
Console.WriteLine("SOAP Exception Error Code: {0}",
e.SubCode.Code.Name);
}
catch (Exception e)
{
Console.WriteLine("Exception Message: {0}", e.Message);
}
// Console.ReadLine();
}
}
}
Imports System
Imports SampleApplication.ExcelWebService
Imports System.Web.Services.Protocols
Namespace SampleApplication
Friend Class Class1
<STAThread> _
Shared Sub Main(ByVal args() As String)
' Instantiate the Web service
' and create a status array object.
Dim es As New ExcelService()
Dim outStatus() As Status

Dim sheetName As String = "Sheet1"


' TODO: change the workbook path to
' point to workbook in a trusted location
' that you have access to.
Dim targetWorkbookPath As String = "http://myserver02/example/Shared%20Documents/Book1.xlsx"

' Set credentials for requests.


es.Credentials = System.Net.CredentialCache.DefaultCredentials

Try
' Call open workbook, and point to the trusted
' location of the workbook to open.
Dim sessionId As String = es.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", outStatus)
' Call the GetCell method
' to retrieve a value from a cell.
' The cell is in the first row and ninth column.
Dim rangeResult2() As Object = xlservice.GetCell(sessionId, sheetName, 0, 8, False, outStatus)

' Close the workbook asynchronously.


' This also closes session.
es.CloseWorkbookAsync(sessionId)
Catch e As SoapException
Console.WriteLine("SOAP Exception Message: {0}", e.Message)
Console.WriteLine("SOAP Exception Error Code: {0}", e.SubCode.Code.Name)
Catch e As Exception
Console.WriteLine("Exception Message: {0}", e.Message)
End Try
' Console.ReadLine();
End Sub
End Class
End Namespace

Robust programming
Make sure that you add a Web reference to an Excel Web Services site that you have access to. Change the using SampleApplication.ExcelWebService; statement to point to the Web service
site that you are referencing.
In addition, make changes to the workbook path, sheet name, and so on, as appropriate.

See also
Tasks
How to: Catch Exceptions
How to: Trust a Location
How to: Save from Excel Client to the Server
How to: Use the SubCode Property to Capture Error Codes
Concepts
Accessing the SOAP API
Excel Services Alerts
Excel Services Known Issues and Tips
Loop-Back SOAP Calls and Direct Linking
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Set various credentials
3/26/2018 • 3 minutes to read Edit Online

You must set credentials for your users before they can call Excel Web Services by using your custom application. You must explicitly set credentials even if you intend to use the default
credentials. Excel Web Services uses the authentication schemes that Microsoft SharePoint Foundation supports. For more information about SharePoint Foundation authentication
schemes, see the SharePoint Foundation documentation in this SDK and Incoming claims: Signing into SharePoint.
The following examples show how to set credentials.

To use the current user's credentials


The following code uses the current user's logon credentials to make a request to the Web service.

//Instantiate the Web service.


ExcelService xlService = new ExcelService();
//Set credentials for requests.
xlService.Credentials = System.Net.CredentialCache.DefaultCredentials;

'Instantiate the Web service.


Dim xlService As New ExcelService()
'Set credentials for requests.
xlService.Credentials = System.Net.CredentialCache.DefaultCredentials

To use various sets of credentials


The following code uses the current user's logon credentials to make a request to the Web service.
Sample code provided by: Saif Ullah Baig, Microsoft Corporation.

protected string farmURL, docLibPath, workbookPath, uiCulture, dataCulture, localTempFolder, authenticationType;


protected Cookie authCookie;

protected API.ExcelService api;


protected Constants.XLS_VER version;

public VariousAuthScheme(Constants.XLS_VER ver, string farmurl, string docLib, string fileName,


string uic, string datac,
string userName, string password, string domain,
string localTemp, string authType)
{
api = new API.ExcelService();

farmURL = farmurl;

if (!farmURL.EndsWith("/"))
{
farmURL += "/";
}

api.Url = farmURL + "_vti_bin/ExcelService.asmx";

version = ver;

if (!docLib.EndsWith("/"))
{
docLib += "/";
}

workbookPath = farmURL + docLib + fileName;


docLibPath = farmURL + docLib;
uiCulture = uic;
dataCulture = datac;
localTempFolder = localTemp;
authenticationType = authType;

switch (authType)
{
case "Windows-Classic":
authenticationType = "Windows-Classic";
AuthenticateWindowsClassic(domain, userName, password);
break;

case "Windows-Claims":
authenticationType = "Windows-Claims";
AuthenticateWindowsClaims();
break;

case "FBA-Claims":
authenticationType = "FBA-Claims";
if (!AuthenticateFBAClaims(userName, password))
throw new Exception("FBA-Claims authentication failed");
break;

case "Anonymous":
authenticationType = "Anonymous";
break;

default:
throw new Exception ("Undefined authentication type specified: " + authType);
break;
}
}
}

protected void AuthenticateWindowsClassic(string domain, string userName, string password)


{
if (userName != null &amp;&amp; userName.Length > 0)
{
api.Credentials = new System.Net.NetworkCredential(userName, password, domain);
}
else
{
api.Credentials = System.Net.CredentialCache.DefaultCredentials;
}

// Verify set credentials.


System.Net.NetworkCredential cred = (System.Net.NetworkCredential) api.Credentials;
Console.WriteLine(@"Credentials set to: {0}\\{1}", cred.Domain, cred.UserName);
}

protected void AuthenticateWindowsClaims()


{
throw new Exception ("Windows-Claims Authentication method not implemented");
}

protected bool AuthenticateFBAClaims(string userName, string password)


{
FBA.Authentication spAuthentication = new FBA.Authentication();
spAuthentication.Url = farmURL + "_vti_bin/Authentication.asmx";

spAuthentication.CookieContainer = new CookieContainer();

FBA.LoginResult loginResult = spAuthentication.Login(userName, password);


authCookie = new Cookie();

// Determines if login is successful.


if (loginResult.ErrorCode == FBA.LoginErrorCode.NoError)
{
// Get the cookie collection from the authenticating Web service.
CookieCollection cookies = spAuthentication.CookieContainer.GetCookies(new Uri(spAuthentication.Url));

// Get the specific cookie that contains the security token.


authCookie = cookies[loginResult.CookieName];

// Initialize the cookie container of Excel Web Services.


api.CookieContainer = new CookieContainer();
api.CookieContainer.Add(authCookie);

return true;
}
else
{
return false;
}

To use a different set of credentials


The following code uses the current user's logon credentials to make a request to the Web service.

//Instantiate the Web service.


ExcelService xlService = new ExcelService();

public void VerifyCredentials()


{
//Check whether the default credentials
//should be used instead.
if (DefaultCredentialsCheckBox.Checked)
{
xlService.Credentials =
System.Net.CredentialCache.DefaultCredentials;
}
else
{
//Check whether user-defined credentials
//should be used instead.
System.Net.NetworkCredential userDefined = new
System.Net.NetworkCredential(
LoginNameTextBox.Text,
LoginPWDTextBox.Text,
LoginDomainTextBox.Text);

xlService.Credentials = userDefined;
}
}
'Instantiate the Web service.
Private xlService As New ExcelService()

Public Sub VerifyCredentials()


'Check whether the default credentials
'should be used instead.
If DefaultCredentialsCheckBox.Checked Then
xlService.Credentials = System.Net.CredentialCache.DefaultCredentials
Else
'Check whether user-defined credentials
'should be used instead.
Dim userDefined As New System.Net.NetworkCredential(LoginNameTextBox.Text, LoginPWDTextBox.Text, LoginDomainTextBox.Text)

xlService.Credentials = userDefined
End If
End Sub

In this example, LoginNameTextBox, LoginPWDTextBox, and LoginDomainTextBox are the Name property values of the logon text boxes.
For more information about how to use the CredentialCache class and the NetworkCredential class, and how to use them securely, see the Microsoft Visual Studio documentation, or
NetworkCredential Class.

See also
Concepts
Accessing the SOAP API
Other resources
Step 1: Creating the Web Service Client Project
Step 2: Adding a Web Reference
Step 3: Accessing the Web Service
Step 4: Building and Testing the Application
Walkthrough: Developing a Custom Application Using Excel Web Services
Refresh data
3/26/2018 • 4 minutes to read Edit Online

This example shows how to retrieve updated data from external data sources for the open workbook by using the Refresh method. The Excel Web Services signature for the Refresh
method is as follows:

public Status[] Refresh (string sessionId, string connectionName)

Public Function Refresh(ByVal sessionId As String, ByVal connectionName As String) As Status()


End Function

If you link directly to Microsoft.Office.Excel.Server.WebServices.dll, the signature for the Refresh method is:

public void Refresh (string sessionId, string connectionName,


out Status[] status)

Public Sub Refresh(ByVal sessionId As String, ByVal connectionName As String, <System.Runtime.InteropServices.Out()> ByRef status() As Status)
End Sub

The connectionName argument refers to the connection name in a Microsoft Office Excel 2007 workbook.You can use the Refresh method to refresh a single data connection in the
workbook, or to refresh all connections. This is useful particularly when the connections are created without refresh-on-open functionality.When you refresh a connection, the data and all
objects using the connection will be refreshed. To refresh all available connections in the workbook, you pass in an empty connection string or null for the connection name argument.The
refresh operations will be attempted regardless of the type of authentication used, without any further confirmation or prompt.For more information about the Refresh method, see the Excel
Web Services reference documentation.

Example
The following code sample shows how to call the Refresh method using Excel Web Services. The connection name in this example is "MyInventoryConnection":

// Instantiate the Web service.


ExcelService xlservice = new ExcelService();
Status[] outStatus;
RangeCoordinates rangeCoordinates = new RangeCoordinates();
string sheetName = "Sheet3";

// Set the path to the workbook to open.


// TODO: Change the path to the workbook
// to point to a workbook you have access to.
// The workbook must be in a trusted location.
string targetWorkbookPath =
http://myserver02/example/Shared%20Documents/Book1.xlsx";

// Set credentials for requests.


xlservice.Credentials = System.Net.CredentialCache.DefaultCredentials;

// Call open workbook, and point to the trusted


// location of the workbook to open.
string sessionId = xlservice.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", out outStatus);

// Prepare object to define range coordinates.


rangeCoordinates.Column = 0;
rangeCoordinates.Row = 0;
rangeCoordinates.Height = 8;
rangeCoordinates.Width = 10;

// Set the cell located in the first row and


// ninth column to 300.
xlservice.SetCell(sessionId, sheetName, 0, 8, 300);
xlservice.Refresh(sessionId, "MyInventoryConnection");
' Instantiate the Web service.
Dim xlservice As New ExcelService()
Dim outStatus() As Status
Dim rangeCoordinates As New RangeCoordinates()
Dim sheetName As String = "Sheet3"

' Set the path to the workbook to open.


' TODO: Change the path to the workbook
' to point to a workbook you have access to.
' The workbook must be in a trusted location.
' Set credentials for requests.
Dim targetWorkbookPath As String = http: xlservice.Credentials = System.Net.CredentialCache.DefaultCredentials 'myserver02/example/Shared%20Documents/Book1.xlsx";

' Call open workbook, and point to the trusted


' location of the workbook to open.
Dim sessionId As String = xlservice.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", outStatus)

' Prepare object to define range coordinates.


rangeCoordinates.Column = 0
rangeCoordinates.Row = 0
rangeCoordinates.Height = 8
rangeCoordinates.Width = 10

' Set the cell located in the first row and


' ninth column to 300.
xlservice.SetCell(sessionId, sheetName, 0, 8, 300)
xlservice.Refresh(sessionId, "MyInventoryConnection")

If you link directly to Microsoft.Office.Excel.Server.WebServices.dll, the equivalent code is:

// Instantiate the ExcelService class.


ExcelService xlservice = new ExcelService();
Status[] outStatus;
RangeCoordinates rangeCoordinates = new RangeCoordinates();
string sheetName = "Sheet3";

// Set the path to the workbook to open.


// TODO: Change the path to the workbook
// to point to a workbook you have access to.
// The workbook must be in a trusted location.
string targetWorkbookPath =
http://myserver02/example/Shared%20Documents/Book1.xlsx";

// Call the open workbook, and point to the trusted


// location of the workbook to open.
string sessionId = xlservice.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", out outStatus);

// Set the cell located in the first row and


// ninth column to 300.
xlservice.SetCell(sessionId, sheetName, 0, 8, 300, out outStatus);
xlservice.Refresh(sessionId, "MyInventoryConnection", out outStatus);

byte[] workbook = xlService.GetWorkbook(sessionId, WorkbookType.FullWorkbook, out status);

// Write the resulting Excel file to stdout


// as a binary stream.
BinaryWriter binaryWriter =
new BinaryWriter(Console.OpenStandardOutput());
binaryWriter.Write(workbook);
binaryWriter.Close();
...
...

' Instantiate the ExcelService class.


Dim xlservice As New ExcelService()
Dim outStatus() As Status
Dim rangeCoordinates As New RangeCoordinates()
Dim sheetName As String = "Sheet3"

' Set the path to the workbook to open.


' TODO: Change the path to the workbook
' to point to a workbook you have access to.
' The workbook must be in a trusted location.
' Call the open workbook, and point to the trusted
' location of the workbook to open.
Dim targetWorkbookPath As String = http: String sessionId = xlservice.OpenWorkbook(targetWorkbookPath, "en-US", "en-US", outStatus) 'myserver02/example/Shared%20Documents/Book1.xlsx";

' Set the cell located in the first row and


' ninth column to 300.
xlservice.SetCell(sessionId, sheetName, 0, 8, 300, outStatus)
xlservice.Refresh(sessionId, "MyInventoryConnection", outStatus)

Dim workbook() As Byte = xlService.GetWorkbook(sessionId, WorkbookType.FullWorkbook, status)

' Write the resulting Excel file to stdout


' as a binary stream.
Dim binaryWriter As New BinaryWriter(Console.OpenStandardOutput())
binaryWriter.Write(workbook)
binaryWriter.Close()
...
...

See also
Tasks
How to: Trust a Location
How to: Save from Excel Client to the Server
How to: Get an Entire Workbook or a Snapshot
Concepts
Accessing the SOAP API
Excel Services Alerts
Excel Services Known Issues and Tips
Loop-Back SOAP Calls and Direct Linking
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Use the SubCode property to capture error codes
3/26/2018 • 5 minutes to read Edit Online

Excel Services generates errors in the SOAP exception based on errors that occur in Excel Services. To make it easier for the developer to catch specific error conditions, an Excel Calculation
Services alert has an associated error code. The Excel Web Services then returns the error using properties from the SoapException class.
The following examples show how to capture the error codes using the SubCode property (http://msdn.microsoft.com/en-
us/library/system.web.services.protocols.soapexception.subcode.aspx) of the SoapException class.
[!NOTE]

To be able to use the SubCode property, you must use Microsoft Visual Studio 2005. The SubCode property does not exist in earlier versions of Visual Studio.

For a list of error codes, see Excel Services Error Codes.

To capture error codes when using SOAP


1. After adding a Web reference to the Excel Web Services, add the following using directive so that you can use the SoapException class without having to qualify it with a full namespace:

using System.Web.Services.Protocols;

Imports System.Web.Services.Protocols

1. To capture the Excel Services error codes using the SubCode property, you must use the SOAP12 protocol version. After instantiating the Excel Web Services proxy class, set the SOAP
protocol version as follows:

// Instantiate the Web service.


ExcelService xlservice = new ExcelService();

// Set the SOAP protocol version.


xlservice.SoapVersion = SoapProtocolVersion.Soap12;

' Instantiate the Web service.


Dim xlservice As New ExcelService()

' Set the SOAP protocol version.


xlservice.SoapVersion = SoapProtocolVersion.Soap12

1. To catch the error codes using the SubCode property, add a SOAP exception catch block to your code, for example:

catch (SoapException e)
{
Console.WriteLine("SOAP Exception Message: {0}", e.Message);
Console.WriteLine("SOAP Exception Error Code: {0}",
e.SubCode.Code.Name);
}

Catch e As SoapException
Console.WriteLine("SOAP Exception Message: {0}", e.Message)
Console.WriteLine("SOAP Exception Error Code: {0}", e.SubCode.Code.Name)
End Try

To capture error codes when using direct linking


1. In the direct linking scenario, you won't need to add a Web reference to the Excel Web Services. However, you will need to add a reference to System.Web.Services namespace.
2. After you add a reference, add the following using directive to your code so that you can use the SoapException class without having to qualify it with a full namespace:

using System.Web.Services.Protocols;

Imports System.Web.Services.Protocols

1. Unlike using SOAP over HTTP, in the direct linking scenario, you won't need to set the SOAP protocol version.
2. To catch the error codes using the SubCode property, add a SOAP exception catch block to your code, for example:

catch (SoapException e)
{
Console.WriteLine("SOAP Exception Message: {0}", e.Message);
Console.WriteLine("SOAP Exception Error Code: {0}",
e.SubCode.Code.Name);
}

Catch e As SoapException
Console.WriteLine("SOAP Exception Message: {0}", e.Message)
Console.WriteLine("SOAP Exception Error Code: {0}", e.SubCode.Code.Name)
End Try
Example
The following program (a console application) uses the SubCode property to capture the error codes. The program takes different actions based on the error code that is caught. You can, for
example, intentionally pass in a nonexistent sheet name to trigger a SOAP exception. In this case, the following SOAP exception message is returned:

The sheet that was requested could not be found. Please try a different one.

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Services.Protocols;
using System.Threading;
using SubCodeExample;

namespace SubCodeExample
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 3)
{
Console.WriteLine("This program requires 3 parameters -
workbook, sheet and cell");
}
string workbookUrl = args[0];
string sheetName = args[1];
string cellRange = args[2];

const string DataRefreshError =


"ExternalDataRefreshFailed";
const string InvalidSheetNameError = "InvalidSheetName";
const string FileOpenNotFound = "FileOpenNotFound";

string sessionId = null;


MyXlServices.ExcelService service = null;
try
{
MyXlServices.Status[] status;
service = new
SubCodeExample.MyXlServices.ExcelService();
service.SoapVersion = SoapProtocolVersion.Soap12;
service.Credentials =
System.Net.CredentialCache.DefaultCredentials;
sessionId = service.OpenWorkbook(workbookUrl, "", "",
out status);

object result = service.GetCellA1(sessionId, sheetName,


cellRange, true, out status);
Console.WriteLine("GetCell result was:{0}", result);

int retries = 3;
while (retries > 0)
{
try
{
service.Refresh(sessionId, "");
}
catch (SoapException soapException)
{
bool rethrow = true;
if (soapException.SubCode.Code.Name ==
DataRefreshError)
{
if (retries > 1)
{
Console.WriteLine("Error when
refreshing. Retrying...");
Thread.Sleep(5000);
rethrow = false;
}
}
if (rethrow) throw;
}
retries--;
}

}
catch (SoapException exception)
{
string subCode = exception.SubCode.Code.Name;
if (subCode == FileOpenNotFound)
{
Console.WriteLine("The workbook could not be found.
Change the first argument to be
a valid file name.");
}
else if (subCode == DataRefreshError)
{
Console.WriteLine("Could not refresh
the workbook.");
}
else if (subCode == InvalidSheetNameError)
{
Console.WriteLine("The sheet that was requested
could not be found. Please try
a different one.");
}
else
{
Console.WriteLine("Unknown error code returned from
Excel Services:{0}", subCode);
Excel Services:{0}", subCode);
}
}

catch (Exception)
{
Console.WriteLine("Unknown exception was raised.");
}
finally
{
if (service != null &amp;&amp;
!String.IsNullOrEmpty(sessionId))
{
try
{
service.CloseWorkbook(sessionId);
}
catch
{
}
}
}
}
}
}
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Web.Services.Protocols
Imports System.Threading
Imports SubCodeExample

Namespace SubCodeExample
Friend Class Program
Shared Sub Main(ByVal args() As String)
If args.Length <> 3 Then
Console.WriteLine("This program requires 3 parameters - workbook, sheet and cell")
End If
Dim workbookUrl As String = args(0)
Dim sheetName As String = args(1)
Dim cellRange As String = args(2)

Const DataRefreshError As String = "ExternalDataRefreshFailed"


Const InvalidSheetNameError As String = "InvalidSheetName"
Const FileOpenNotFound As String = "FileOpenNotFound"

Dim sessionId As String = Nothing


Dim service As MyXlServices.ExcelService = Nothing
Try
Dim status() As MyXlServices.Status
service = New SubCodeExample.MyXlServices.ExcelService()
service.SoapVersion = SoapProtocolVersion.Soap12
service.Credentials = System.Net.CredentialCache.DefaultCredentials
sessionId = service.OpenWorkbook(workbookUrl, "", "", status)

Dim result As Object = service.GetCellA1(sessionId, sheetName, cellRange, True, status)


Console.WriteLine("GetCell result was:{0}", result)

Dim retries As Integer = 3


Do While retries > 0
Try
service.Refresh(sessionId, "")
Catch soapException As SoapException
Dim rethrow As Boolean = True
If soapException.SubCode.Code.Name = DataRefreshError Then
If retries > 1 Then
Console.WriteLine("Error when refreshing. Retrying...")
Thread.Sleep(5000)
rethrow = False
End If
End If
If rethrow Then
Throw
End If
End Try
retries -= 1
Loop

Catch exception As SoapException


Dim subCode As String = exception.SubCode.Code.Name
If subCode = FileOpenNotFound Then
Console.WriteLine("The workbook could not be found. Change the first argument to be a valid file name.")
ElseIf subCode = DataRefreshError Then
Console.WriteLine("Could not refresh the workbook.")
ElseIf subCode = InvalidSheetNameError Then
Console.WriteLine("The sheet that was requested could not be found. Please try a different one.")
Else
Console.WriteLine("Unknown error code returned from Excel Services:{0}", subCode)
End If

Catch e1 As Exception
Console.WriteLine("Unknown exception was raised.")
Finally
If service IsNot Nothing AndAlso (Not String.IsNullOrEmpty(sessionId)) Then
Try
service.CloseWorkbook(sessionId)
Catch
End Try
End If
End Try
End Sub
End Class
End Namespace

Robust programming
Make sure that you add a Web reference to an Excel Web Services site that you have access to. Change the using SubCodeExample; statement to point to the Web service site that you are
referencing.
In addition, make changes to the workbook path, sheet name, and so on, as appropriate.

See also
Tasks
How to: Catch Exceptions
How to: Trust a Location
How to: Save from Excel Client to the Server
Concepts
Accessing the SOAP API
Excel Services Alerts
Excel Services Known Issues and Tips
Loop-Back SOAP Calls and Direct Linking
Other resources
Walkthrough: Developing a Custom Application Using Excel Web Services
Excel Services User-Defined Functions
3/26/2018 • 2 minutes to read Edit Online

This section contains information about user-defined functions (UDFs) and how to use UDF attributes in your code.

In this section
Understanding Excel Services UDFs

Learn about managed-code UDFs, including required attributes, deployment, and security.

Walkthrough: Developing a Managed-Code UDF

Get step-by-step instructions about developing Excel Services UDFs by using Microsoft Visual C#.

Frequently Asked Questions About Excel Services UDFs

Find answers to the most common questions about Excel Services UDFs.

How to: Enable UDFs

Learn how to enable UDFs and allow them to be called from an Excel workbook.

How to: Create a UDF That Calls a Web Service

Learn how to call an external Web service from a UDF.

How to: Access an External Data Source from a UDF

Get an example showing how to access an external database from a UDF.

How to: Deploy UDFs Using SharePoint Foundation Solutions

Learn how to deploy a UDF by using the s solution framework.

How to: Restrict UDF Code Access Security Permissions

Learn how to create a custom code group and restrict permission for a UDF assembly by using the .NET Framework Configuration tool.

Reference
[Microsoft.Office.Excel.Server.Udf]

Excel Services UDF attributes.


Understanding Excel Services UDFs
3/26/2018 • 4 minutes to read Edit Online

User-defined functions (UDFs) are custom functions that extend the calculation and data-import capabilities of Excel. Developers create custom calculation packages to provide:
Functions that are not built into Excel.
Custom implementations to built-in functions.
Custom data feeds for legacy or unsupported data sources, and application-specific data flows.
Users who create workbooks can call UDFs from a cell through formulas—for example, "=MyUdf(A1*3.42)"—just like they call built-in functions.
Excel Services UDFs give you the ability to use formulas in cells to call custom functions written in managed code and deployed to Microsoft SharePoint Server 2010. You can create UDFs
to:
Call custom mathematical functions.
Get data from custom data sources into worksheets.
Call Web services from the UDFs.

Creating Managed-Code UDFs


An easy way to create an Excel Services managed-code UDF is to use the Microsoft Visual Studio 2005 class library template. You will need to reference the Excel Services UDF dynamic link
library (DLL), named Microsoft.Office.Excel.Server.Udf.dll, in your managed-code UDF project.
Microsoft.Office.Excel.Server.Udf.dll has been compiled using Microsoft .NET Framework 2.0. If you use Visual Studio 2003 to create your managed-code UDF, you will not be able to
reference Microsoft.Office.Excel.Server.Udf.dll. It is not possible for an assembly created with an older version of the .NET Framework to reference an assembly created with .NET Framework
2.0.

Required Attributes
To use custom functions in a class as an Excel Services UDF class, you must mark your UDF class with the Microsoft.Office.Excel.Server.Udf.UdfClass attribute. Any classes that are not
marked with this attribute in the UDF assembly will be ignored by Excel Calculation Services. They are not considered to be Excel Services UDF classes.
To use custom functions in a class as Excel Services UDF methods, you must mark your UDF methods with the Microsoft.Office.Excel.Server.Udf.UdfMethod attribute. Any methods
that are not marked with this attribute in the UDF assembly will be ignored because they are not considered to be Excel Services UDF methods.
The Microsoft.Office.Excel.Server.Udf.UdfMethodattribute has an IsVolatile property. You use the IsVolatile property to specify a UDF method as volatile or nonvolatile. The
IsVolatile property takes a Boolean value. The default value is false, which means that particular UDF method is nonvolatile.

Location of Microsoft.Office.Excel.Server.Udf.dll
On the computer where you have installed SharePoint Server 2010, you can find a copy of Microsoft.Office.Excel.Server.Udf.dll at:
[drive:]\\Program Files\\Common Files\\Microsoft Shared\\web server extensions\\14\\ISAPI

Deployment and Security


Deployment Location Type
UDF assemblies can reside in a local directory, global assembly cache, or network share. In a farm scenario, the local directory path must be identical across the farm.

Identification of UDF Assemblies


You can expose the identity of a UDF assembly by using the full path or strong name of the assembly for Excel Calculation Services to call.
For example, you can use:
C:\UDFs\MySampleUdf.dll
\\MyNetworkServer\UDFs\MySampleUdf.dll
CompanyName.Hierarchichal.MyUdfNamespace.MyUdfClassName.dll, Version=1.1.0.0, Culture=en, PublicKeyToken=e8123117d7ba9ae38

Enabling UDF Assemblies


UDF assemblies are disabled by default.
Each Excel Services trusted location has an AllowUdfs flag.
NOTE

The AllowUdfs flag is denoted by the User-defined functions allowed option on the Excel Services Trusted File Locations page. To learn how to navigate to the Trusted File Locations
page, see Step 3: Deploying and Enabling UDFs.
The default AllowUdfs value is false. If the AllowUdfs value is set to false in a particular trusted location, the workbooks in that trusted location are not allowed to call UDFs.
In order to allow UDFs to be called from a specific trusted location, you set the AllowUdfs value to true.
If the AllowUdfs value is false when a session is started on a workbook that has UDF calls in this trusted location, the UDF calls will fail. If you change the AllowUdfs value to true after a
session has started, the UDF calls will also fail. This is because changes in the AllowUdfs flag take effect on the next session, after the configuration database has been updated.

Allowing UDF Assemblies to Run


If administrators want to allow UDF assemblies to run, they have to register all UDF assemblies, and enable workbooks to call UDFs by setting the AllowUdfs flag to true in the trusted
locations.

Reloading a UDF Assembly


To reload a UDF assembly, you can run iisreset or restart the Excel Calculation Services application domain.

Caution: Resetting IIS will end all current sessions. > For more information, see How to: Enable UDFs.
For more information, see Unloading an Application from Memory (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csvr2002/htm/cs_mmc_administering_myhj.asp).

Default Code Access Security Permission for UDF Assemblies


By default, UDF assemblies run with full trust.

Restricting Code Access Security Permission for UDF Assemblies


If you do not want a particular UDF assembly to run with full trust, you must explicitly restrict code access security permission for that UDF assembly. You can configure the code groups and
restrict permission by using the .NET Framework 2.0 Configuration tool.
Developers can also use the RequestMinimum and RequestOptional methods in their code to ensure that their UDF assemblies don't get more permission than they require.
For more information about configuring code groups, as well as the RequestMinimum and RequestOptional methods, see the following articles on MSDN:
Configuring Code Groups Using the .NET Framework Configuration Tool (http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconUsingNETConfigurationToolToWorkWithCodeGroups.asp?frame=true)
Code Access Security in Practice (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/thcmch08.asp)

See also
Tasks
How to: Create a UDF That Calls a Web Service
How to: Trust a Location
How to: Catch Exceptions
How to: Enable UDFs
Concepts
Walkthrough: Developing a Managed-Code UDF
Frequently Asked Questions About Excel Services UDFs
Excel Services Architecture
Excel Services Alerts
Excel Services Known Issues and Tips
Excel Services Best Practices
Walkthrough: Developing a Managed-Code UDF
3/26/2018 • 2 minutes to read Edit Online

This walkthrough describes the process for developing Excel Services user-defined functions (UDFs) using Microsoft Visual C#.
During this walkthrough, you will learn how to:
Create a project using the Microsoft Visual Studio 2005 class library project template.
Add a reference to Microsoft.Office.Excel.Server.Udf.dll.
Write UDFs for use in Excel Services.
Create a workbook to call custom functions from cells.
Test and run UDFs in Excel Services.

Prerequisites
In order to complete this walkthrough, you will need:
Microsoft SharePoint Server 2010
NOTE

The easiest way to get all you need on the server is to do a basic, stand-alone install. All you need to add on top of that is a trusted location.
Excel
Visual Studio or a similar Microsoft .NET Framework-compatible development tool
To enable running the UDF assembly
A trusted SharePoint document library in which to store a workbook, and to allow the workbook to call UDFs by setting the AllowUdfs value to true
A sample workbook that calls the UDF stored in a trusted SharePoint document library
Permissions to view and publish a workbook to a SharePoint document library
NOTE

For more information about setting permissions, see the Windows SharePoint Services 3.0 documentation.
To create the workbook using Excel
To save the workbook as an .xlsx or .xlsb file
NOTE

For more information about how to trust a location, how to enable UDFs, and how to set the AllowUdfs flag, see Step 3: Deploying and Enabling UDFs.

See also
Step 1: Creating a Project and Adding a UDF Reference
Step 2: Creating a Managed-Code UDF
Step 3: Deploying and Enabling UDFs
Step 4: Testing and Calling UDFs from Cells
How to: Create a UDF That Calls a Web Service
Understanding Excel Services UDFs
Walkthrough: Developing a Custom Application Using Excel Web Services
Step 1: Creating a Project and Adding a UDF Reference
3/26/2018 • 2 minutes to read Edit Online

In this step, you will create a project and add a reference to Microsoft.Office.Excel.Server.Udf.dll.

Creating the Project


The following project uses Microsoft Visual Studio 2005.
NOTE

Depending on which settings you use in the Visual Studio integrated development environment (IDE), the process to create a project could be slightly different.

To create a project
1. Start Visual Studio.
2. On the File menu, point to New, and then click Project. The New Project dialog box appears.
3. In the Project Type pane, select Visual C# Projects.
4. In the Templates pane, click Class Library.
5. In the Name box, type SampleUdf.
6. In the Location box, type the path where you want to save your project, or click Browse to navigate to the folder.
7. Click OK. Your new project appears in Solution Explorer. You also will see that a file with the default name of Class1.cs has been added to your project.
8. You should see the following code in the Class1.cs file:

using System;
using System.Collections.Generic;
using System.Text;

namespace SampleUdf
{
public class Class1
{
}
}

Imports System
Imports System.Collections.Generic
Imports System.Text

Namespace SampleUdf
Public Class Class1
End Class
End Namespace

Adding a Reference
The following steps show how to locate Microsoft.Office.Excel.Server.Udf.dll and how to add a reference to it.

To add a reference
1. On the Project menu, click Add Reference.
2. In the Add Reference dialog box, on the .NET tab, select Excel Services UDF Framework.
NOTE

You can also open the Add Reference dialog box in Solution Explorer by right-clicking References and selecting Add Reference.
3. Click OK.
NOTE

The previous steps assume that you are building the project on a computer that has Microsoft SharePoint Server 2010 installed. On the computer where you have installed
SharePoint Server 2010, you can find a copy of Microsoft.Office.Excel.Server.Udf.dll at: > [drive:]\Program Files\Common Files\Microsoft Shared\web server extensions\14\ISAPI

See also
Step 2: Creating a Managed-Code UDF
Step 3: Deploying and Enabling UDFs
Step 4: Testing and Calling UDFs from Cells
How to: Create a UDF That Calls a Web Service
Walkthrough: Developing a Managed-Code UDF
Understanding Excel Services UDFs
Step 2: Creating a Managed-Code UDF
3/26/2018 • 2 minutes to read Edit Online

After you have added a reference to Microsoft.Office.Excel.Server.Udf.dll to your project, the next step is to create some custom functions and mark them with the Excel Services user-defined
function (UDF) attributes.
You must mark your UDF class with the Microsoft.Office.Excel.Server.Udf.UdfClass attribute, and mark the UDF methods with the Microsoft.Office.Excel.Server.Udf.UdfMethod
attribute. Any methods that are not marked with the Microsoft.Office.Excel.Server.Udf.UdfMethod attribute in the UDF assembly will be ignored, because they will not be considered
UDF methods.
The Microsoft.Office.Excel.Server.Udf.UdfMethod attribute has an IsVolatile property. You use the IsVolatile property to specify a UDF method as volatile or nonvolatile. The
IsVolatile property takes a Boolean value. The default value is false, which means that particular UDF method is nonvolatile.

Creating UDFs
To add directives
The types to use are defined in the Microsoft.Office.Excel.Server.Udf namespace. Adding a using (or Imports) directive at the top of the Class1.cs file will allow you to use the
types in Microsoft.Office.Excel.Server.Udf without having to fully qualify the types in the namespace.
To add this directive, add the following code to the beginning of your code in the Class1.cs file, after using System.Text:

using Microsoft.Office.Excel.Server.Udf;

Imports Microsoft.Office.Excel.Server.Udf

To mark a UDF class and methods


1. Mark Class1 as a UDF class by adding the following attribute just above public class Class1 :

[UdfClass]

<UdfClass>_

1. Create a function that takes a number (of type double), and in the function, multiply the number by 9. The function is a UDF method that is nonvolatile. Add the following code to Class1
:

[UdfMethod]
public double MyDouble(double d)
{
return d * 9;
}

<UdfMethod> _
Public Function MyDouble(ByVal d As Double) As Double
Return d * 9
End Function

> [!NOTE]
> The default value for the **IsVolatile** property is **false**, which means that particular UDF method is nonvolatile. Therefore, it is sufficient to mark a nonvolatile UDF method as `[UdfMeth

1. Create another function that returns the current date using the System.DateTime.Today property. The function is a UDF method that is volatile. Add the following code to Class1 :

[UdfMethod(IsVolatile = true)]
public DateTime ReturnDateTimeToday()
{
return (DateTime.Today);
}

<UdfMethod(IsVolatile := True)> _
Public Function ReturnDateTimeToday() As Date
Return (Date.Today)
End Function

To build the project


1. On the Build menu, click Build Solution.
2. You should find SampleUdf.dll assembly in the directory where you have saved your project.

Complete Code
The following code sample is the complete code in the Class1.cs example file described in the previous procedures.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Office.Excel.Server.Udf;

namespace SampleUdf
{
[UdfClass]
public class Class1
{
[UdfMethod]
public double MyDouble(double d)
{
return d * 9;
}

[UdfMethod(IsVolatile = true)]
public DateTime ReturnDateTimeToday()
{
return (DateTime.Today);
}
}
}

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports Microsoft.Office.Excel.Server.Udf

Namespace SampleUdf
<UdfClass> _
Public Class Class1
<UdfMethod> _
Public Function MyDouble(ByVal d As Double) As Double
Return d * 9
End Function

<UdfMethod(IsVolatile := True)> _
Public Function ReturnDateTimeToday() As Date
Return (Date.Today)
End Function
End Class
End Namespace

See also
Tasks
Step 1: Creating a Project and Adding a UDF Reference
Step 3: Deploying and Enabling UDFs
Step 4: Testing and Calling UDFs from Cells
How to: Create a UDF That Calls a Web Service
Concepts
Walkthrough: Developing a Managed-Code UDF
Understanding Excel Services UDFs
Step 3: Deploying and Enabling UDFs
3/26/2018 • 2 minutes to read Edit Online

In this step, you will:


1. Deploy SampleUdf.dll, which you created in Step 2: Creating a Managed-Code UDF, to a folder on a computer that has Microsoft SharePoint Server 2010 installed.
2. Allow user-defined functions (UDFs) to be called from a specific trusted location, for example, trusted Shared Documents location.
3. Enable SampleUdf.dll.

Deploying UDFs
To deploy UDFs
1. Create a folder named "UDFs" on the local drive of the computer to which you want to deploy UDFs. For example, "C:\UDFs".
2. Copy the SampleUdf.dll assembly.
3. Save SampleUdf.dll in "C:\UDFs".

Trusting a Location
To trust a location
1. On the Start menu, click All Programs.
2. Point to Microsoft SharePoint 2010 Products and click SharePoint Central Administration.
3. Under Application Management click Manage service applications.
4. On the Manage Service Applications page, click Excel Services Application.
5. On the Excel Services Application page, click Trusted File Locations.
6. On the Trusted File Locations page, click Add Trusted File Location.
7. On the Add Trusted File Location page, in the Address box, type the location where you will save your workbook—for example, http://MyServer002/Shared%20Documents.
8. Under Location type, click the appropriate location type. In this example, select Microsoft SharePoint Foundation.
9. Under Trust Children, select Children trusted to trust child libraries or directories.
10. Under Allow User-Defined Functions, select User-defined functions allowed to allow UDFs to be called from workbooks stored in this trusted location.
11. Click OK.

Enabling UDFs
To do the following steps, you need a computer that has SharePoint Server 2010 installed.

To enable UDFs
1. Follow steps 1 through 3 in the previous procedure ("To trust a location") to display the Shared Services home page for an SSP.
2. Under Excel Services Settings, click User-defined function assemblies.
3. On the Excel Services User-Defined Functions page, click Add User-Defined Function to open the ExcelServices Add User-Defined Function Assembly page.
4. In the Assembly box, type the path to the SampleUdf.dll assembly. In this example, it would be C:\UDFs\SampleUdf.dll.
5. Under Assembly Location, click File path.
6. Under Enable Assembly, the Assembly enabled check box should be selected by default.
7. Click OK.

Robust programming
If the AllowUdfs value is false when a session is started on a workbook that has UDF calls, the UDF calls will fail.
NOTE

The AllowUdfs flag is denoted by the User-defined functions allowed option (see step 9 in the "Trusting a Location" section).
If you change the AllowUdfs value to true after a session has started, the UDF calls will also fail. This is because changes in the AllowUdfs flag take effect on the next session. You can get
around this by resetting Microsoft Internet Information Services (IIS). Resetting IIS will reload UDFs.
For more information about resetting IIS, see How to: Enable UDFs.

See also
Step 1: Creating a Project and Adding a UDF Reference
Step 2: Creating a Managed-Code UDF
Step 4: Testing and Calling UDFs from Cells
How to: Enable UDFs
Walkthrough: Developing a Managed-Code UDF
Understanding Excel Services UDFs
Step 4: Testing and Calling UDFs from Cells
3/26/2018 • 3 minutes to read Edit Online

In this step, you will test the SampleUdf.dll assembly you created, deployed, and enabled in the previous steps. To test the user-defined function (UDF), you will:
1. Create a workbook with a named range and formulas that call the functions in SampleUdf.dll.
2. Save the workbook to a SharePoint document library that is a trusted location.
NOTE

It is assumed that you have already created a SharePoint document library and made it a trusted location. For information about how to trust a location, see the "Trusting a Location"
section in Step 3: Deploying and Enabling UDFs.
3. Change parameters to recalculate the workbook.

Testing UDFs
To call UDFs from cells
1. Start Microsoft Office Excel 2007.
2. In cell A1, type the formula to call the MyDouble function in SampleUdf.dll. The MyDouble function takes an argument of type double. In this example, you will take the argument from
cell B1. In cell A1, type =MyDouble(B1).
NOTE

The formula will evaluate to "#NAME?" in Excel. The formula will be evaluated only when the workbook is displayed in Excel Services.
NOTE

You can run UDFs on both the client and server. A future article published on MSDN will explain the details. They are omitted here for the sake of simplicity.
3. In cell B1, type the number 8.
4. Make cell B1 a named range. First click the Formulas tab. Then click cell B1 to select it. On the Formulas tab, in the Named Cells group, click Name a Range. In the New Name
dialog box, in the Name box, type MyDoubleParam.
5. In cell A2, type the formula to call the ReturnDateTimeToday function. Type=ReturnDateTimeToday().
6. In cell A3, type the formula to call the ReturnDateTimeToday function. Type=ReturnDateTimeToday(). Next, right-click cell A3 to display the menu. Click Format Cells.
7. In the Format Cells dialog box, on the Number tab, select Date. Select a date format type from the Type list—for example, *3/4/2001.
8. Click OK.
9. Save the workbook to a location of your choice on the local drive. Name the workbook "TestSampleUdf.xlsx".

To save to Excel Services


1. Click the Microsoft Office Button, point to Save As, and click Save for Excel Services.
2. In the Save As dialog box, click Excel Services Options.
3. In the Excel Services Options dialog box, on the Show tab, make sure that Entire Workbook is selected.
4. Click Parameters.
5. In the Add Parameters list, select the MyDoubleParam check box.
6. Click OK. You should now see "MyDoubleParam" listed in the Parameters list.
7. Click OK.
8. In the Save As dialog box, make sure that the Open this workbook in my browser after I save check box is selected.
9. In the File name box, type the path to the trusted SharePoint document library where you want to store this workbook. For example,
http://MyServer002/Shared%20Documents/TestSampleUdf.xlsx.
10. Click Save. You should see TestSampleUdf.xlsx in Excel Web Access. In cell A1, you should see the number "72" because cell B1 * 9 = 8 * 9, which is 72. In cell A2 you should see a
number. In cell A3, you should see the current date.
NOTE

In cell A2, the number represents the number of days since 1/1/1900 (or 1/1/1904 if you have "Use 1904 Date System" turned on). It's how Excel represents dates internally.

To change parameters to test the UDF


1. In the Parameters pane, you should see the named range for cell B1, that is, "MyDoubleParam".
2. You can change the value in cell B1 by typing a number in the box next to "MyDoubleParam". For example, if you type 3 and then click Apply, Excel Services will recalculate the
workbook. Cell A1 will contain "27" instead of "72".

See also
Tasks
Step 1: Creating a Project and Adding a UDF Reference
Step 2: Creating a Managed-Code UDF
Step 3: Deploying and Enabling UDFs
How to: Create a UDF That Calls a Web Service
Concepts
Walkthrough: Developing a Managed-Code UDF
Understanding Excel Services UDFs
Frequently Asked Questions About Excel Services UDFs
3/26/2018 • 2 minutes to read Edit Online

Here are some frequently asked questions about Excel Services user-defined functions (UDFs).

Creating Managed-Code UDFs


What is a supported UDF class?
The UDF class in a UDF assembly must be public. It can be sealed. It cannot be abstract, internal, or private. It must have a parameterless, public constructor. For languages that automatically
generate a parameterless, public constructor (for example, C#), you can have no constructor at all.

What is a supported UDF method?


The UDF method in a UDF assembly must be public. The UDF method must be thread-safe.
A UDF method cannot have:
ref or out parameters
retval attributes
Optional arguments
unsupported data types
The UDF method must also have a supported return type. For a list of supported data types, see the "Data Types" section of this topic.

Can I call a Web service from a UDF assembly?


Yes. For an example, see the following UDF sample code. Also see How to: Create a UDF That Calls a Web Service.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Office.Excel.Server.Udf;
using UdfWS.dk.iter.webservices;

namespace UdfWS
{
[UdfClass]
public class MyUdfClass
{
// Instantiate the Web service. The Web service used is at
// http://webservices.iter.dk/calculator.asmx
Calculator calc = new Calculator();

[UdfMethod]
public int MyFunction()
{
int i;
i = (i + 88) * 2;
return i;
}

[UdfMethod(IsVolatile = true)]
public double MyDouble(double d)
{
return d * 9;
}

[UdfMethod]
public int AddMe(int a, int b)
{
int c;
// Call the Web service Add method
c = calc.Add(a, b);
return c;
}
}
}
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports Microsoft.Office.Excel.Server.Udf
Imports UdfWS.dk.iter.webservices

Namespace UdfWS
<UdfClass> _
Public Class MyUdfClass
' Instantiate the Web service. The Web service used is at
' http://webservices.iter.dk/calculator.asmx
Private calc As New Calculator()

<UdfMethod> _
Public Function MyFunction() As Integer
Dim i As Integer
i = (i + 88) * 2
Return i
End Function

<UdfMethod(IsVolatile := True)> _
Public Function MyDouble(ByVal d As Double) As Double
Return d * 9
End Function

<UdfMethod> _
Public Function AddMe(ByVal a As Integer, ByVal b As Integer) As Integer
Dim c As Integer
' Call the Web service Add method
c = calc.Add(a, b)
Return c
End Function
End Class
End Namespace

Data Types
What are the data types that can be used as UDF parameters?
The supported data types are as follows:
Numeric types: Double, Single, Int32, UInt32, Int16, UInt16, Byte, Sbyte
String
Boolean
Object arrays: one- or two- dimensional arrays, that is, object [] and object [,]
DateTime

What are the supported return value types?


The supported return value types are as follows:
Numeric types: Double, Single, Int32, UInt32, Int16, UInt16, Byte, Sbyte
String
Boolean
Object arrays: one- or two-dimensional arrays, that is, object [], object [,], int[] and int[,])
DateTime
Object

XLLs
Are XLLs supported?
Not directly. Excel Services will load and call only managed-code UDFs. However, you can write a managed-code wrapper to call the XLLs and deploy the XLLs to the server, together with
the managed-code wrapper assembly.

See also
Tasks
How to: Create a UDF That Calls a Web Service
How to: Trust a Location
How to: Catch Exceptions
Concepts
Understanding Excel Services UDFs
Walkthrough: Developing a Managed-Code UDF
Excel Services Architecture
Excel Services Alerts
Excel Services Known Issues and Tips
Excel Services Best Practices
Enable UDFs
3/26/2018 • 2 minutes to read Edit Online

Each Excel Services trusted location in the Shared Services Provider (SSP) has an AllowUdfs flag.
NOTE

The AllowUdfs flag is denoted by the User-defined functions allowed option on the Excel Services Trusted File Locations page.
The default AllowUdfs value is false. If the AllowUdfs value is set to false in a particular trusted location, the workbooks in that trusted location are not allowed to call UDFs.
In order to allow UDFs to be called from a specific trusted location, you set the AllowUdfs value to true.If the AllowUdfs value is false when a session is started on a workbook that has
UDF calls in this trusted location, the UDF calls will fail. If you change the AllowUdfs value to true after a session has started, the UDF calls will also fail. This is because changes in the
AllowUdfs flag take effect on the next session, after the configuration database has been updated.You can get around this by restarting the session—for example, by selecting Reload
Workbook in Excel Web Access.

Caution: If you choose to reset Microsoft Internet Information Services (IIS) instead, it will end all current sessions.

Enabling UDFs
To do the following steps, you need a computer that has Microsoft SharePoint Server 2010 installed.

To enable UDFs
1. On the Start menu, click All Programs.
2. Point to Microsoft Office Server and click SharePoint Central Administration.
3. On the Quick Launch, click your Shared Services Provider (SSP) link—for example, "SharedServices1"—to view the Shared Services home page for that particular SSP.
4. Under Excel Services Settings, click User-defined functions.
5. On the Excel Services User-Defined Functions page, click Add User-Defined Function to open the Excel Services Add User-Defined Function Assembly page.
6. In the Assembly box, type the path to the UDF assembly. For example,C:\MyUdfFolder\MyUdf.dll.
7. Under Assembly Location, click Local file.
NOTE

The Local file option will be replaced with File path in future releases of Excel Services. If you see File path, select that instead.
8. Under Enable Assembly, the Assembly enabled check box should be selected by default.
9. Click OK.

Allowing UDF Calls


To allow UDFs to be called from a workbook
1. Open the Excel Services Add Trusted File Location page (if you are adding a new trusted location) or Excel Services Edit Trusted File Location page (if you are editing an existing
trusted location).
NOTE

For more information about trusting a location, see How to: Trust a Location.
2. Under Allow User-Defined Functions, select User-defined functions allowed to allow UDFs to be called from workbooks stored in this trusted location.
3. Click OK.

See also
Step 3: Deploying and Enabling UDFs
How to: Create a UDF That Calls a Web Service
How to: Trust a Location
Walkthrough: Developing a Managed-Code UDF
Frequently Asked Questions About Excel Services UDFs
Understanding Excel Services UDFs
Excel Services Alerts
Excel Services Known Issues and Tips
Excel Services Best Practices
Create a UDF that calls a web service
5/3/2018 • 4 minutes to read Edit Online

This example shows how to call an external Web service from a user-defined function (UDF). The Web service used in this example is:
http://webservices.imacination.com/distance/Distance.jws?wsdl You must use Microsoft Visual Studio 2005 or a similar Microsoft .NET Framework 2.0-compatible development tool to
create this sample.
NOTE

Before testing the code, make sure that the Web service you are calling is available. The Web service server could be down or the Web service discontinued. If the Web service is unavailable,
the calls you make to the Web service from your code will fail. > You can check if a Web service is available by visiting its site. In this example, the URL is: >
http://webservices.imacination.com/distance/Distance.jws?wsdl > If the Web service is available, you will be able to see the Web Services Description Language (WSDL). If it is not available,
you will get the usual "webpage not found" error.

Example
You can learn more about the Web service used in this example by examining its WSDL.
One service it provides is to return geographical coordinates in decimal form. In this sample, the ToDegreeNotation function has been added to show how you can convert coordinates to
degrees/minutes/seconds, which is more appropriate for displaying coordinates.

[UdfMethod]
public string ToDegreeNotation(double angle)
{
int deg = (int)angle;
double minutesAndSeconds = Math.Abs(angle - deg) * 60;
int minutes = (int)minutesAndSeconds;
int seconds = (int)(Math.Abs(minutesAndSeconds - minutes) * 60);

return deg.ToString() + "°" + minutes.ToString() + "\\'" +


seconds.ToString() + "\\"";
}

<UdfMethod> _
Public Function ToDegreeNotation(ByVal angle As Double) As String
Dim deg As Integer = CInt(Fix(angle))
Dim minutesAndSeconds As Double = Math.Abs(angle - deg) * 60
Dim minutes As Integer = CInt(Fix(minutesAndSeconds))
Dim seconds As Integer = CInt(Fix(Math.Abs(minutesAndSeconds - minutes) * 60))

Return deg.ToString() &amp; "°" &amp; minutes.ToString() &amp; "'" &amp; seconds.ToString() &amp; """"
End Function

If your Internet Explorer L AN setting is configured to use a proxy server, your code must explicitly make a call to set the proxy server. Otherwise, your Web service calls will fail. You can set
the proxy server in the constructor as follows:

namespace ZipCodeUdfSample
{
[UdfClass]
public class ZipCodeUdfs
{
DistanceService distanceService = null;
public ZipCodeUdfs()
{
this.distanceService = new DistanceService();
this.distanceService.Proxy =
new WebProxy("http://myproxy:80", true);
}

Namespace ZipCodeUdfSample
<UdfClass> _
Public Class ZipCodeUdfs
Private distanceService As DistanceService = Nothing

Public Sub New()


Me.distanceService = New DistanceService()
'this.distanceService.Proxy = new WebProxy("http://myproxy:80", true);
End Sub

For more information about how to test and call UDFs from cells, see Walkthrough: Developing a Managed-Code UDF.
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using Microsoft.Office.Excel.Server.Udf;
using ZipCodes.com.imacination.webservices;

namespace ZipCodeUdfSample
{
[UdfClass]
public class ZipCodeUdfs
{
DistanceService distanceService = null;

public ZipCodeUdfs()
{
this.distanceService = new DistanceService();
//this.distanceService.Proxy = new WebProxy("http://myproxy:80", true);
}

[UdfMethod]
public double GetDistanceBetweenTwoZipCodes(int zip1, int zip2)
{
string zip1String = Convert.ToString(zip1);
string zip2String = Convert.ToString(zip2);

return (distanceService.getDistance(zip1String, zip2String));


}

[UdfMethod]
public string GetCityFromZip(int zip)
{
string zipString = Convert.ToString(zip);

return (distanceService.getCity(zipString));
}

[UdfMethod]
public string GetStateFromZip(int zip)
{
string zipString = Convert.ToString(zip);

return (distanceService.getState(zipString));
}

[UdfMethod]
public string GetLocationFromZip(int zip)
{
string zipString = Convert.ToString(zip);

return (distanceService.getLocation(zipString));
}

[UdfMethod]
public double GetLatitudeFromZip(int zip)
{
string zipString = Convert.ToString(zip);

return (distanceService.getLatitude(zipString));
}

[UdfMethod]
public double GetLongitudeFromZip(int zip)
{
string zipString = Convert.ToString(zip);

return (distanceService.getLongitude(zipString));
}

[UdfMethod]
public string ToDegreeNotation(double angle)
{
int deg = (int)angle;
double minutesAndSeconds = Math.Abs(angle - deg) * 60;
int minutes = (int)minutesAndSeconds;
int seconds = (int)(Math.Abs(minutesAndSeconds - minutes) * 60);

return deg.ToString() + "°" + minutes.ToString() + "\\'" + seconds.ToString() + "\"";


}
}
}
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Net
Imports Microsoft.Office.Excel.Server.Udf
Imports ZipCodes.com.imacination.webservices

Namespace ZipCodeUdfSample
<UdfClass> _
Public Class ZipCodeUdfs
Private distanceService As DistanceService = Nothing

Public Sub New()


Me.distanceService = New DistanceService()
'this.distanceService.Proxy = new WebProxy("http://myproxy:80", true);
End Sub

<UdfMethod> _
Public Function GetDistanceBetweenTwoZipCodes(ByVal zip1 As Integer, ByVal zip2 As Integer) As Double
Dim zip1String As String = Convert.ToString(zip1)
Dim zip2String As String = Convert.ToString(zip2)

Return (distanceService.getDistance(zip1String, zip2String))


End Function

<UdfMethod> _
Public Function GetCityFromZip(ByVal zip As Integer) As String
Dim zipString As String = Convert.ToString(zip)

Return (distanceService.getCity(zipString))
End Function

<UdfMethod> _
Public Function GetStateFromZip(ByVal zip As Integer) As String
Dim zipString As String = Convert.ToString(zip)

Return (distanceService.getState(zipString))
End Function

<UdfMethod> _
Public Function GetLocationFromZip(ByVal zip As Integer) As String
Dim zipString As String = Convert.ToString(zip)

Return (distanceService.getLocation(zipString))
End Function

<UdfMethod> _
Public Function GetLatitudeFromZip(ByVal zip As Integer) As Double
Dim zipString As String = Convert.ToString(zip)

Return (distanceService.getLatitude(zipString))
End Function

<UdfMethod> _
Public Function GetLongitudeFromZip(ByVal zip As Integer) As Double
Dim zipString As String = Convert.ToString(zip)

Return (distanceService.getLongitude(zipString))
End Function

<UdfMethod> _
Public Function ToDegreeNotation(ByVal angle As Double) As String
Dim deg As Integer = CInt(Fix(angle))
Dim minutesAndSeconds As Double = Math.Abs(angle - deg) * 60
Dim minutes As Integer = CInt(Fix(minutesAndSeconds))
Dim seconds As Integer = CInt(Fix(Math.Abs(minutesAndSeconds - minutes) * 60))

Return deg.ToString() &amp; "°" &amp; minutes.ToString() &amp; "'" &amp; seconds.ToString() &amp; """"
End Function
End Class
End Namespace

See also
Tasks
Step 1: Creating a Project and Adding a UDF Reference
Step 2: Creating a Managed-Code UDF
Step 3: Deploying and Enabling UDFs
Step 4: Testing and Calling UDFs from Cells
Concepts
Accessing the SOAP API
Other resources
Step 2: Adding a Web Reference
Step 3: Accessing the Web Service
Walkthrough: Developing a Custom Application Using Excel Web Services
Access an external data source from a UDF
3/26/2018 • 2 minutes to read Edit Online

This example shows how to access an external database from a user-defined function (UDF).

Example
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Office.Excel.Server.Udf;
using System.Data.SqlClient;
using System.Web;
using System.Security.Principal;

namespace DatabaseAccessUdfTest1
{
[UdfClass]
public class
{
[UdfMethod(IsVolatile=true)]
public string GetRowCount()
{
try
{
SqlConnection sqlConnection = new SqlConnection
("Data Source=myDatabaseServer002;Initial
Catalog=northwind;Integrated Security=SSPI;");
SqlCommand sqlCommand = new SqlCommand("SELECT COUNT(*)
FROM Customers", sqlConnection);
sqlConnection.Open();
string rowCount = (string)sqlCommand.ExecuteScalar();
sqlConnection.Close();
return (rowCount);
}
catch (Exception e)
{
return (e.ToString());
}
}

[UdfMethod(IsVolatile=true)]
public string GetSqlUserName()
{
try
{
SqlConnection sqlConnection = new SqlConnection("Data
Source= myDatabaseServer003;Initial
Catalog=northwind;Integrated Security=SSPI;");
SqlCommand sqlCommand = new SqlCommand("SELECT
CURRENT_USER", sqlConnection);

sqlConnection.Open();
string userName = (string)sqlCommand.ExecuteScalar();
sqlConnection.Close();
return (userName);
}
catch (Exception e)
{
return (e.ToString());
}
}

[UdfMethod(ReturnsPersonalInformation=true)]
public string GetUserName()
{
return
(System.Threading.Thread.CurrentPrincipal.Identity.Name);
}

[UdfMethod(ReturnsPersonalInformation=true)]
public string GetUserAuthenticationType()
{
return
(System.Threading.Thread.CurrentPrincipal.Identity.AuthenticationType);
}
}
}
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports Microsoft.Office.Excel.Server.Udf
Imports System.Data.SqlClient
Imports System.Web
Imports System.Security.Principal

Namespace DatabaseAccessUdfTest1
<UdfClass> _
Public Class
<UdfMethod(IsVolatile:=True)> _
Public Function GetRowCount() As String
Try
Dim sqlConnection As New SqlConnection("Data Source=myDatabaseServer002;Initial Catalog=northwind;Integrated Security=SSPI;")
Dim sqlCommand As New SqlCommand("SELECT COUNT(*) FROM Customers", sqlConnection)
sqlConnection.Open()
Dim rowCount As String = CStr(sqlCommand.ExecuteScalar())
sqlConnection.Close()
Return (rowCount)
Catch e As Exception
Return (e.ToString())
End Try
End Function

<UdfMethod(IsVolatile:=True)> _
Public Function GetSqlUserName() As String
Try
Dim sqlConnection As New SqlConnection("Data Source= myDatabaseServer003;Initial Catalog=northwind;Integrated Security=SSPI;")
Dim sqlCommand As New SqlCommand("SELECT CURRENT_USER", sqlConnection)

sqlConnection.Open()
Dim userName As String = CStr(sqlCommand.ExecuteScalar())
sqlConnection.Close()
Return (userName)
Catch e As Exception
Return (e.ToString())
End Try
End Function

<UdfMethod(ReturnsPersonalInformation:=True)> _
Public Function GetUserName() As String
Return (System.Threading.Thread.CurrentPrincipal.Identity.Name)
End Function

<UdfMethod(ReturnsPersonalInformation:=True)> _
Public Function GetUserAuthenticationType() As String
Return (System.Threading.Thread.CurrentPrincipal.Identity.AuthenticationType)
End Function
End Class
End Namespace

See also
Tasks
How to: Create a UDF That Calls a Web Service
How to: Trust a Location
How to: Catch Exceptions
How to: Enable UDFs
Concepts
Walkthrough: Developing a Managed-Code UDF
Frequently Asked Questions About Excel Services UDFs
Excel Services Architecture
Excel Services Alerts
Excel Services Known Issues and Tips
Excel Services Best Practices
Deploy UDFs using SharePoint Foundation solutions
5/3/2018 • 3 minutes to read Edit Online

This example shows how to deploy a user-defined function (UDF) DLL by using the Microsoft SharePoint Foundation solution framework.
The SharePoint Foundation solution framework lets you bundle all the components to extend SharePoint Foundation in a new file called a solution file (a CAB-based format with a .wsp
extension). A solution is a deployable, reusable package that can contain a set of features, site definitions, and assemblies that you can apply to a site, and individually enable or disable.
Additionally, you can use the solution file to deploy the contents of a web part package, including assemblies, class resources, .dwp files, and other package components. For more
information about the SharePoint Foundation solution framework, see the SharePoint Foundation node in the Getting Started with Development for SharePoint Foundation 2010
(http://msdn.microsoft.com/en-us/library/ee539432(office.14).aspx). The procedure for creating and deploying a UDF assembly by using SharePoint Foundation solution framework is as
follows:
1. Create the solution manifest file, Manifest.xml.
The solution manifest (always called Manifest.xml) is stored at the root of a solution file. This file defines the list of features, site definitions, resource files, web part files, and
assemblies to be processed. It does not define the file structure; if files are included in a solution but not listed in the manifest XML file, they are not processed in any way.
NOTE

For more information about the structure of the manifest XML file, see the SharePoint Foundation documentation.
2. Package the UDF assembly and Manifest.xml into a CAB file.
3. Make sure that the SharePoint Foundation Administration service is running on the server.
4. Add the solution to the server by using stsadm.exe.
5. Deploy the solution by using stsadm.exe.
Each Excel Services trusted location has an AllowUdfs flag.
NOTE

The AllowUdfs flag is denoted by the User-defined functions allowed option on the Excel Services Trusted File Locations page. To learn how to navigate to the Trusted File Locations
page, see Step 3: Deploying and Enabling UDFs.
In order to allow UDFs to be called from a specific trusted location, you must:
Set the AllowUdfs value to true. The default value is false.
Add the UDF assembly to the trusted UDF list to allow the UDF to be called from a workbook.
For more information on how to enable UDFs and add UDFs to the trusted UDF list, see How to: Enable UDFs.
NOTE

To avoid name collision, give your UDF assemblies and their dependencies strong names, and name them as uniquely as possible. For more information, see Excel Services Best Practices
and Excel Services Known Issues and Tips.

Procedure
To create the Manifest.xml file
1. Right-click your project in Solution Explorer, point to Add, and then click New Item.
2. Select XML File, and name the file Manifest.xml.
3. Click Add.
4. Add the following content to the file:

<?xml version="1.0" encoding="utf-8" ?>


<Solution xmlns="http://schemas.microsoft.com/sharepoint/" SolutionId="{57568687-2CC0-45bf-B66A-2D50D57108CA}" DeploymentServerType="ApplicationServer">
<Assemblies>
<Assembly DeploymentTarget="GlobalAssemblyCache" Location="EcsUdfsCommonSet.dll"/>
</Assemblies>
</Solution>

> [!NOTE]
> You should generate a unique GUID for each solution. For more information about **Solution** element, see the SharePoint Foundation [Solutions and web part Packages](http://msdn.microsoft.com/l

To create a solution package


For information about how to create the solution file, see the "Creating a Solution" topic under the "Solutions and web part Packages" node in the SharePoint Foundation SDK.

To verify whether SharePoint Foundation Administration is running


1. Click Start, point to Administrative Tools, and then double-click Services.
The Services dialog box appears.
2. Make sure that the status of SharePoint Foundation Administration service shows Started. If it does not, right-click SharePoint Foundation Administration, and then select Start.

To add the solution


1. Click Start, click Run, and then typecmd.
The command prompt console appears.
2. Run the following script to add the solution to SharePoint server:
stsadm.exe -o addsolution -filename
NOTE

You can find the Stsadm.exe at: > C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN.
NOTE

For more information about Stsadm.exe command options, see the Stsadm to Windows PowerShell Mapping (SharePoint Foundation 2010) (http://technet.microsoft.com/en-
us/library/ff621081.aspx).

To deploy the solution


1. Click Start, click Run, and then typecmd.
The command prompt console appears.
2. Run the following script to deploy the solution to SharePoint server.
stsadm.exe -o deploysolution -name -immediate -allowGacDeployment
You should now see your UDF DLL in the global assembly cache.

See also
Tasks
How to: Create a UDF That Calls a Web Service
How to: Enable UDFs
How to: Restrict UDF Code Access Security Permissions
Concepts
Walkthrough: Developing a Managed-Code UDF
Frequently Asked Questions About Excel Services UDFs
Understanding Excel Services UDFs
Restrict UDF code access security permissions
3/26/2018 • 3 minutes to read Edit Online

If you do not want a particular user-defined function (UDF) assembly to run with full trust, you must explicitly restrict code access security permissions for it. You can configure code groups
and restrict permissions by using the .NET Framework 2.0 Configuration tool.
For example, imagine a scenario where you have a UDF assembly that contains multiple methods. One of the UDF methods performs a custom calculation, and another UDF method in the
same assembly calls a Web service to obtain stock quotes. Because your users only use Excel workbooks that call the first (calculation) method, you might want to disable the assembly from
having Web access, for increased security. You have the UDF assembly installed in a folder on the server at C:\UdfAssemblies\CalcAndWebAccessUdf.dll. Because the assembly is on the
same computer as Microsoft SharePoint Server 2010, when Excel Calculation Services loads the UDF assembly, it is loaded in the MyComputer zone. By default, the MyComputer zone is
fully trusted. This means that the UDF assembly is granted full trust permission.
To lock down the UDF assembly so that it cannot have Web access, you must explicitly restrict the permission set that it is granted by following these steps:
1. Create a new URL-based code group under My_Computer_Zone at the Machine level. Scope the code group to that specific assembly and create a custom permission set.
2. Configure the custom code group properties so that your policy level has only the permissions from the permission set that is associated with the custom code group. When Excel
Calculation Services loads a UDF assembly that resides on the same computer, the assembly is loaded in the MyComputer zone. This means that by default, the UDF assembly is
granted full trust. When the custom permission set intersects with the full trust permission set, the result is full trust. To make it so that the a policy has only the permission from the
permission set that is associated with your custom code group, you must enable the This policy level will only have the permissions from the permission set associated with
this code group property.
For more information about configuring code groups, see the following articles on MSDN:
Configuring Code Groups Using the .NET Framework Configuration Tool (http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/cpguide/html/cpconUsingNETConfigurationToolToWorkWithCodeGroups.asp?frame=true)
Code Access Security in Practice (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/thcmch08.asp)

To create a new code group


1. Click Start, point to All Programs, point to Administrative Tools, and then click Microsoft .NET Framework 2.0 Configuration.
This starts the .NET 2.0 Framework Configuration tool.
2. In the left pane, expand the My Computer node, and then expand the Runtime Security Policy node.
3. Expand the Machine node.
4. Expand the Code Groups node.
5. Expand the All_Code node.
6. Expand the My_Computer_Zone node.Right-click My_Computer_Zone and then select New to display the Identify the new Code Group dialog box.
7. Select Create a new code group.
8. In the Name field, type a name for the new code group, for example,RestrictWebAccessUdf.
9. Click Next.
10. To scope the code group to your specific UDF assembly, select URL from the Choose the condition type for this code group.
This displays the URL field.
11. In the URL field, type the path to the UDF assembly for which you want to restrict access to the Web, for example,C:\UdfAssemblies\CalcAndWebAccessUdf.dll.
12. Click Next.
13. Select Create a new permission set, and then click Next.
14. In the Name field, type a name for your permission set, for example,AssemblyExecutionCustomPermissionSet.
15. Click Next.
16. To give your UDF assembly "assembly execution" permission, select Security from the Assembly Permissions list, and then click Add.
This displays the Permission Settings dialog box.
17. Select assemblies the following security permissions.
18. Select Enable assembly execution.
19. Click OK, and then click Next.
20. Click Finish.
You should see your new custom code group under the My_Computer_Zone node (in this example, RestrictWebAccessUdf).

To make sure that the permission sets are executed


1. Under the My_Computer_Zone node, right-click the new custom code group (in this example, RestrictWebAccessUdf), and then select Properties.
2. On the General tab, select the This policy level will only have the permissions from the permission set associated with this code group check box.
3. Click Apply, and then click OK.
NOTE

If the UDF method throws an exception because it cannot make the Web service call, you should receive a #VALUE! error in the Excel formula that called the UDF.
NOTE

If you want to enable Web access for your UDF assembly for testing, you must add the appropriate permission to your custom permission set. To do this, in Step 11 of the "To create a
new code group" procedure, select Web Access.
See also
How to: Create a UDF That Calls a Web Service
How to: Enable UDFs
How to: Access an External Data Source from a UDF
How to: Deploy UDFs Using SharePoint Foundation Solutions
Walkthrough: Developing a Managed-Code UDF
Frequently Asked Questions About Excel Services UDFs
Understanding Excel Services UDFs
Excel Web Access
5/3/2018 • 2 minutes to read Edit Online

This section describes the Excel Web Access web part and explains how to use it.

In this section
How to: Programmatically Add an Excel Web Access web part to a Page

Learn how to programmatically add an Excel Web Access web part to a SharePoint page, and how to programmatically display a workbook in an Excel Web Access web part.

How to: Locate and Copy Microsoft.Office.Excel.WebUI.dll and Microsoft.Office.Excel.WebUI.Internal.dll

Learn how to locate and copy this DLL, so that you can programmatically add an Excel Web Access web part to a SharePoint page.

Reference
[Microsoft.Office.Excel.WebUI]

The Excel Web Access web part object model.

See also
Concepts
Excel Services Development Roadmap
Programmatically add an Excel Web Access web part to a page
5/3/2018 • 7 minutes to read Edit Online

This example shows how to programmatically add an Excel Web Access web part to a SharePoint page. It also shows you how to display an Excel workbook programmatically in an Excel
Web Access web part.
The following project uses Microsoft Visual Studio.
NOTE

Depending on the Visual Studio version and the Visual Studio integrated development environment (IDE) settings that you are using, the process and steps to create a Visual Studio project
could be slightly different from the procedures shown in this topic.
NOTE

It is assumed that you have already created a SharePoint document library and made it a trusted location. For more information, see How to: Trust a Location.

Adding a Reference
The following steps show how to locate Microsoft.Office.Excel.WebUI.dll and how to add a reference to it. Repeat for Microsoft.Office.Excel.WebUI.Internal.dll and Microsoft.SharePoint.dll.
NOTE

It is assumed that you have already copied Microsoft.Office.Excel.WebUI.dll and Microsoft.Office.Excel.WebUI.Internal.dll from the global assembly cache to a folder of your choice. For more
information about how to locate and copy Microsoft.Office.Excel.WebUI.dll and Microsoft.Office.Excel.WebUI.Internal.dll, see How to: Locate and Copy Microsoft.Office.Excel.WebUI.dll and
Microsoft.Office.Excel.WebUI.Internal.dll.

To add a reference to Microsoft.Office.Excel.WebUI.dll


1. On the Project menu, click Add Reference.
2. In the Add Reference dialog box, click Browse.
NOTE

You can also open the Add Reference dialog box in the Solution Explorer pane by right-clicking References and selecting Add Reference.
3. Browse to the location of Microsoft.Office.Excel.WebUI.dll.
4. Select Microsoft.Office.Excel.WebUI.dll, and then click OK.
5. Click Add Reference. A reference to Microsoft.Office.Excel.WebUI.dll is added to your project.

Instantiating a web part


To instantiate the Excel Web Access web part
1. Add the Microsoft.Office.Excel.WebUI namespace as a directive to your code, so that when you use the types in this namespace, you do not need to fully qualify them:

using Microsoft.Office.Excel.WebUI;

Imports Microsoft.Office.Excel.WebUI

1. Instantiate and initialize the Excel Web Access web part, as follows:

ExcelWebRenderer ewaWebPart = new ExcelWebRenderer();

Dim ewaWebPart As New ExcelWebRenderer()

To display a workbook programmatically


1. In this example, the AddWebPart method takes in the path to an Excel workbook location as an argument. The user provides the path by typing in a Windows Forms text box and
clicking a button.
Sample code provided by: Daniel Mullowney, Microsoft Corporation

public bool AddWebPart(string sitename, string book)


{
...
}
private void AddEWAButton_Click(object sender,
EventArgs e)
{
siteurl = textBox1.Text;
bookuri = textBox2.Text;
succeeded = AddWebPart(siteurl, bookuri);
if (succeeded)
{
MessageBox.Show(
success,
appname,
MessageBoxButtons.OK,
MessageBoxIcon.Information);
progressBar1.Value = 1;
}
}
Public Function AddWebPart(ByVal sitename As String, ByVal book As String) As Boolean
...
End Function
Private Sub AddEWAButton_Click(ByVal sender As Object, ByVal e As EventArgs)
siteurl = textBox1.Text
bookuri = textBox2.Text
succeeded = AddWebPart(siteurl, bookuri)
If succeeded Then
MessageBox.Show(success, appname, MessageBoxButtons.OK, MessageBoxIcon.Information)
progressBar1.Value = 1
End If
End Sub

> **Important:**
> Ensure that the location where the workbook is saved is a trusted location.

1. You can display an Excel workbook programmatically by using the following code.
Sample code provided by: Daniel Mullowney, Microsoft Corporation

...
// Instantiate Excel Web Access web part.
// Add an Excel Web Access web part in a shared view.
ExcelWebRenderer ewaWebPart = new ExcelWebRenderer();
ewaWebPart.WorkbookUri = book;
progressBar1.PerformStep();

try
{
webPartManager.AddWebPart(ewaWebPart, "Left", 0);
}
catch (Exception exc)
{
MessageBox.Show(
addWebPartError + "\\n" + exc.Message,
appName,
MessageBoxButtons.OK,
MessageBoxIcon.Asterisk);
progressBar1.Value = 1;
return b;

'Instantiate Excel Web Access web part.


'Add an Excel Web Access web part in a shared view.
Dim ewaWebPart As New ExcelWebRenderer()
ewaWebPart.WorkbookUri = book
progressBar1.PerformStep()

Try
webPartManager.AddWebPart(ewaWebPart, "Left", 0)
Catch exc As Exception
MessageBox.Show(addWebPartError &amp; vbLf &amp; exc.Message, appName,
MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
progressBar1.Value = 1
Return b
End Try

Example
The following example is a Windows Forms application that enables a user to enter information on a SharePoint site and display an Excel workbook saved in a trusted location
programmatically. It programmatically creates an Excel Web Access web part on the default.aspx page of the specified site and displays the specified Excel workbook.
The code sample is the code from the Form1.cs and Form1.vb example files described in the previous procedures. The code sample uses two text boxes, a progress bar, and a button. The
code is only a portion of the Windows Forms project. For example, the code involving the layout of the form is not shown.
Sample code provided by: Daniel Mullowney, Microsoft Corporation

namespace AddEWATool
{
using System;
using System.Windows.Forms;
using Microsoft.Office.Excel.WebUI;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;

/// <summary>
/// Form1 class derived from System.Windows.Forms.
/// </summary>
public partial class Form1 : Form
{
private string appName = "AddEWATool";
private string specifyInputError = "Please add a site URL, for example: http://myserver/site/";
private string openSiteError = "There was a problem with the site name. Please check that the site exists.";
private string addWebPartError = "There was a problem adding the web part.";
private string successMessage = "web part successfully added.";

/// <summary>
/// Add the Excel Web Access web part to the Default.aspx page of the specified site.
/// </summary>
/// <param name="siteName">URL of the SharePoint site</param>
/// <param name="book">URI to the workbook</param>
/// <returns>Returns true if the WebPart was successfully added; otherwise, false.</returns>
public bool AddWebPart(string siteName, string book)
{
{
SPSite site = null;
SPWeb targetWeb = null;
SPLimitedWebPartManager webPartManager = null;

bool b = false;
progressBar1.Visible = true;
progressBar1.Minimum = 1;
progressBar1.Maximum = 4;
progressBar1.Value = 1;
progressBar1.Step = 1;

if (String.IsNullOrEmpty(siteName))
{
MessageBox.Show(
specifyInputError,
appName,
MessageBoxButtons.OK,
MessageBoxIcon.Asterisk);
return b;
}

try
{
try
{
site = new SPSite(siteName);
targetWeb = site.OpenWeb();
}
catch (Exception exc)
{
MessageBox.Show(
openSiteError + "\\n" + exc.Message,
appName,
MessageBoxButtons.OK,
MessageBoxIcon.Asterisk);
progressBar1.Value = 1;
return b;
}

progressBar1.PerformStep();

try
{
// Get the shared web part manager on the Default.aspx page.
webPartManager = targetWeb.GetLimitedWebPartManager(
"Default.aspx",
System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared);
}
catch (Exception exc)
{
MessageBox.Show(
openSiteError + "\\n" + exc.Message,
appName,
MessageBoxButtons.OK,
MessageBoxIcon.Asterisk);
progressBar1.Value = 1;
return b;
}

progressBar1.PerformStep();

// Instantiate Excel Web Access web part.


// Add an Excel Web Access web part in a shared view.
ExcelWebRenderer ewaWebPart = new ExcelWebRenderer();
ewaWebPart.WorkbookUri = book;
progressBar1.PerformStep();

try
{
webPartManager.AddWebPart(ewaWebPart, "Left", 0);
}
catch (Exception exc)
{
MessageBox.Show(
addWebPartError + "\\n" + exc.Message,
appName,
MessageBoxButtons.OK,
MessageBoxIcon.Asterisk);
progressBar1.Value = 1;
return b;
}
}
finally
{
if (site != null)
{
site.Dispose();
}

if (targetWeb != null)
{
targetWeb.Dispose();
}

if (webPartManager != null)
{
webPartManager.Dispose();
}
}

progressBar1.PerformStep();
b = true;
return b;
}
/// <summary>
/// AddEWAButton click handler.
/// </summary>
/// <param name="sender">caller</param>
/// <param name="e">event</param>
private void AddEWAButton_Click(object sender, EventArgs e)
{
string siteUrl = textBox1.Text;
string bookUri = textBox2.Text;
bool succeeded = AddWebPart(siteUrl, bookUri);
if (succeeded)
{
MessageBox.Show(
successMessage,
appName,
MessageBoxButtons.OK,
MessageBoxIcon.Information);
progressBar1.Value = 1;
}
}
}
}

Imports System
Imports System.Windows.Forms
Imports Microsoft.Office.Excel.WebUI
Imports Microsoft.SharePoint
Imports Microsoft.SharePoint.WebPartPages

Namespace AddEWATool
''' <summary>
''' Form1 class derived from System.Windows.Forms.
''' </summary>
Partial Public Class Form1
Inherits Form

Private appName As String = "AddEWATool"


Private specifyInputError As String = "Please add a site URL, for example, http://myserver/site/"
Private openSiteError As String = "There was a problem with the site name. Please check that the site exists."
Private addWebPartError As String = "There was a problem adding the web part."
Private successMessage As String = "web part successfully added."

''' <summary>
''' Add the Excel Web Access web part to the Default.aspx page of the specified site.
''' </summary>
''' <param name="siteName">URL of the SharePoint site</param>
''' <param name="book">URI to the workbook</param>
''' <returns>Returns true if the WebPart was successfully added; otherwise, false.</returns>
Public Function AddWebPart(ByVal siteName As String, ByVal book As String) As Boolean
Dim site As SPSite = Nothing
Dim targetWeb As SPWeb = Nothing
Dim webPartManager As SPLimitedWebPartManager = Nothing

Dim b As Boolean = False


progressBar1.Visible = True
progressBar1.Minimum = 1
progressBar1.Maximum = 4
progressBar1.Value = 1
progressBar1.Step = 1

If String.IsNullOrEmpty(siteName) Then
MessageBox.Show(specifyInputError, appName, MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
Return b
End If

Try
Try
site = New SPSite(siteName)
targetWeb = site.OpenWeb()
Catch exc As Exception
MessageBox.Show(openSiteError &amp; vbLf &amp; exc.Message, appName, MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
progressBar1.Value = 1
Return b
End Try

progressBar1.PerformStep()

Try
' Get the shared web part manager on the Default.aspx page.
webPartManager = targetWeb.GetLimitedWebPartManager( _
"Default.aspx", _
System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared)
Catch exc As Exception
MessageBox.Show(openSiteError &amp; vbLf &amp; exc.Message, appName, MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
progressBar1.Value = 1
Return b
End Try

progressBar1.PerformStep()

'Instantiate Excel Web Access web part.


'Add an Excel Web Access web part in a shared view.
Dim ewaWebPart As New ExcelWebRenderer()
ewaWebPart.WorkbookUri = book
progressBar1.PerformStep()

Try
webPartManager.AddWebPart(ewaWebPart, "Left", 0)
Catch exc As Exception
MessageBox.Show(addWebPartError &amp; vbLf &amp; exc.Message, appName, MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
progressBar1.Value = 1
Return b
End Try
End Try
Finally
If Not IsNothing(site) Then
site.Dispose()
End If

If Not IsNothing(targetWeb) Then


targetWeb.Dispose()
End If

If Not IsNothing(webPartManager) Then


webPartManager.Dispose()
End If
End Try

progressBar1.PerformStep()
b = True
Return b
End Function

''' <summary>
''' AddEWAButton click handler.
''' </summary>
''' <param name="sender">caller</param>
''' <param name="e">event</param>
Private Sub AddEWAButton_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim siteUrl As String = textBox1.Text
Dim bookUri As String = textBox2.Text
Dim succeeded As Boolean = AddWebPart(siteUrl, bookUri)
If succeeded Then
MessageBox.Show(successMessage, appName, MessageBoxButtons.OK, MessageBoxIcon.Information)
progressBar1.Value = 1
End If
End Sub
End Class
End Namespace

Robust programming
The Excel workbook that you are using must be in a trusted location.

See also
Tasks
How to: Locate and Copy Microsoft.Office.Excel.WebUI.dll and Microsoft.Office.Excel.WebUI.Internal.dll
Concepts
Excel Services Alerts
Excel Services Known Issues and Tips
Locate and copy Microsoft.Office.Excel.WebUI.dll and Microsoft.Office.Excel.WebUI.Internal.dll
5/3/2018 • 3 minutes to read Edit Online

If you want to programmatically add an Excel Web Access web part to a SharePoint page and programmatically change the Excel Web Access web part, you must add a reference to the
required SharePoint DLLs. For example:
Microsoft.Office.Excel.WebUI.dll
Microsoft.Office.Excel.WebUI.Internal.dll
Microsoft.SharePoint.dll
On the computer running Microsoft SharePoint Server 2010, you can find a copy of Microsoft.Office.Excel.WebUI.dll and Microsoft.Office.Excel.WebUI.Internal.dll in the global assembly
cache. Before you can add a reference to Microsoft.Office.Excel.WebUI.dll by using the Add Reference dialog box in Microsoft Visual Studio, you must first copy
Microsoft.Office.Excel.WebUI.dll and Microsoft.Office.Excel.WebUI.Internal.dll from the global assembly cache to a folder. Then, you can use the Browse tab in the Add Reference dialog box
to browse to the folder that contains the copy of Microsoft.Office.Excel.WebUI.dll and Microsoft.Office.Excel.WebUI.Internal.dll.
The following steps show how to:
Locate Microsoft.Office.Excel.WebUI.dll.
Copy Microsoft.Office.Excel.WebUI.dll from the global assembly cache to a folder of your choice.
NOTE

Repeat the steps to copy Microsoft.Office.Excel.WebUI.Internal.dll from the global assembly cache to a folder.

To locate Microsoft.Office.Excel.WebUI.dll
1. To start the command-prompt console, click Start, and then click Run.
2. In the Open field text box, typecmd.
The command-prompt console appears.
3. Use the cd command to navigate to the "C:\Windows\assembly" directory:
NOTE

The directory structure on your computer might be slightly different. This example uses a computer that has Windows Server 2008 installed.

```

cd C:\\Windows\\assembly
```

1. Use the dir command to display the contents of the "C:\Windows\assembly" directory:

C:\\Windows\\assembly>dir

You will see contents similar to the following:

Volume in drive C has no label.

Directory of C:\\Windows\\assembly

02/20/2010 09:22 AM <DIR> GAC


02/20/2010 09:39 AM <DIR> GAC_32
02/20/2010 09:32 AM <DIR> GAC_64
02/22/2010 05:05 PM <DIR> GAC_MSIL
02/22/2010 05:35 PM <DIR> NativeImages_v2.0.50727_32
02/22/2010 04:33 PM <DIR> NativeImages_v2.0.50727_64
02/20/2010 10:34 AM <DIR> NativeImages_v4.0.30219_32
02/20/2010 10:35 AM <DIR> NativeImages_v4.0.30219_64
02/22/2010 05:04 PM <DIR> temp
02/22/2010 05:05 PM <DIR> tmp
0 File(s) 0 bytes
10 Dir(s) 104,032,665,600 bytes free

1. Use the cd command again to change the directory and navigate to the gac_msil directory:

C:\\Windows\\assembly>cd gac_msil

1. Use the dir command to display the content of the "C:\Windows\assembly\GAC_MSIL" directory:

C:\\Windows\\assembly\\GAC_MSIL>dir

You will see contents similar to the following:


Volume in drive C has no label.
Directory of C:\\Windows\\assembly\\GAC_MSIL
...
02/20/2010 07:57 AM <DIR> Microsoft.Office.Excel.Server.Udf
02/20/2010 07:57 AM <DIR> Microsoft.Office.Excel.Server.WebServices

02/20/2010 07:57 AM <DIR> Microsoft.Office.Excel.WebUI


02/20/2010 07:57 AM <DIR> Microsoft.Office.Excel.WebUI.Internal
...
02/20/2010 07:57 AM <DIR> Microsoft.SharePoint
...
0 File(s) 0 bytes
739 Dir(s) 100,594,409,472 bytes free

1. Now that you have located Microsoft.Office.Excel.WebUI.dll and Microsoft.Office.Excel.WebUI.Internal.dll, you can copy them to a folder of your choice.

To copy Microsoft.Office.Excel.WebUI.dll
1. Use the cd command again to change the directory to "Microsoft.Office.Excel.WebUI":

C:\\Windows\\assembly\\GAC_MSIL>cd Microsoft.Office.Excel.WebUI

1. Use the dir command to display the contents:

C:\\Windows\\assembly\\GAC_MSIL\\Microsoft.Office.Excel.WebUI>dir

You will see contents similar to the following:

Volume in drive C has no label.


Directory of C:\\Windows\\assembly\\GAC_MSIL\Microsoft.Office.Excel.WebUI

02/20/2010 07:57 AM <DIR> .


02/20/2010 07:57 AM <DIR> ..
02/20/2010 07:57 AM <DIR> 14.0.0.0__71e9bce111e9429c
0 File(s) 0 bytes
3 Dir(s) 104,006,115,328 bytes free

1. Use the cd command again to change the directory:

C:\\Windows\\assembly\\GAC_MSIL\\Microsoft.Office.Excel.WebUI>cd 14.0.0.0__71e9bce111e9429c

1. Use the copy command to copy Microsoft.Office.Excel.WebUI.dll to a folder of your choice.


In the following example, Microsoft.Office.Excel.WebUI.dll is copied to "C:\WebUIAssembly", where "C:\WebUIAssembly" is a folder that you created previously:

C:\\Windows\\assembly\\GAC_MSIL\\Microsoft.Office.Excel.WebUI\\14.0.0.0__71e9bce111e9429c>copy Microsoft.Office.Excel.WebUI.dll c:\\WebUIAssembly


1 file(s) copied.

Example
The following is an example of the result of using the command prompt to locate and copy Microsoft.Office.Excel.WebUI.dll to a folder.
C:\\Windows\\assembly>dir
Volume in drive C has no label.
Directory of C:\\Windows\\assembly

02/20/2010 09:22 AM <DIR> GAC


02/20/2010 09:39 AM <DIR> GAC_32
02/20/2010 09:32 AM <DIR> GAC_64
02/22/2010 05:05 PM <DIR> GAC_MSIL
02/22/2010 05:35 PM <DIR> NativeImages_v2.0.50727_32
02/22/2010 04:33 PM <DIR> NativeImages_v2.0.50727_64
02/20/2010 10:34 AM <DIR> NativeImages_v4.0.30219_32
02/20/2010 10:35 AM <DIR> NativeImages_v4.0.30219_64
02/22/2010 05:04 PM <DIR> temp
02/22/2010 05:05 PM <DIR> tmp
0 File(s) 0 bytes
10 Dir(s) 104,032,665,600 bytes free
C:\\Windows\\assembly>cd gac_msil

C:\\Windows\\assembly\\GAC_MSIL>dir
Volume in drive C has no label.
Directory of C:\\Windows\\assembly\GAC_MSIL
...
02/20/2010 07:57 AM <DIR> Microsoft.Office.Excel.Server.Udf
02/20/2010 07:57 AM <DIR> Microsoft.Office.Excel.Server.WebServices

02/20/2010 07:57 AM <DIR> Microsoft.Office.Excel.WebUI


02/20/2010 07:57 AM <DIR> Microsoft.Office.Excel.WebUI.Internal
...

C:\\Windows\\assembly\\GAC_MSIL>cd Microsoft.Office.Excel.WebUI

C:\\Windows\\assembly\\GAC_MSIL\\Microsoft.Office.Excel.WebUI>dir
Volume in drive C has no label.
Directory of C:\\Windows\\assembly\\GAC_MSIL\Microsoft.Office.Excel.WebUI

02/20/2010 07:57 AM <DIR> .


02/20/2010 07:57 AM <DIR> ..
02/20/2010 07:57 AM <DIR> 14.0.0.0__71e9bce111e9429c
0 File(s) 0 bytes
3 Dir(s) 104,006,115,328 bytes free

C:\\Windows\\assembly\\GAC_MSIL\\Microsoft.Office.Excel.WebUI>cd 14.0.0.0__71e9bce111e9429c

C:\\Windows\\assembly\\GAC_MSIL\\Microsoft.Office.Excel.WebUI\\14.0.0.0__71e9bce111e9429c>copy Microsoft.Office.Excel.WebUI.dll c:\\WebUIAssembly


1 file(s) copied.

C:\\Windows\\assembly\\GAC_MSIL\\Microsoft.Office.Excel.WebUI\\14.0.0.0__71e9bce111e9429c>

See also
Tasks
How to: Programmatically Add an Excel Web Access web part to a Page
How to: Trust a Location
Concepts
Excel Services Alerts
Excel Services Known Issues and Tips
Excel Services ECMAScript (JavaScript, JScript)
5/3/2018 • 2 minutes to read Edit Online

This section contains information about ECMAScript (JavaScript, JScript) in Excel Services and explains how to use it.

Related sections
Excel Services ECMAScript Overview

Learn about the JavaScript object model in Excel Services.

Walkthrough: Developing Using the Content Editor web part

Learn how to call the JavaScript object model in Excel Services by using the Content Editor web part.

JavaScript user-defined functions overview

Learn about JavaScript user-defined functions in Excel Services.

See also
Concepts
Excel Services Development Roadmap
Walkthrough: Developing Using the Content Editor web part
5/3/2018 • 2 minutes to read Edit Online

The walkthrough in this section describes the process for interacting with the ECMAScript (JavaScript, JScript) object model in Excel Services by using the Content Editor web part.
During this walkthrough, you will learn how to:
Create a text file that contains JavaScript and save it as a text file to a trusted document library.
Add a Content Editor web part, and then feed the URL for the JavaScript text file to the Content Editor web part.
Display and interact with a workbook by using the Excel Services web part that will call the JavaScript in Excel Services that you scripted.
NOTE

For information about how to trust a location, see How to: Trust a Location.

See also
How to: Trust a Location
Excel Services Alerts
Excel Services Known Issues and Tips
How to: Trust Workbook Locations Using Script
Step 1: Creating a ECMAScript Text File
5/3/2018 • 2 minutes to read Edit Online

For this walkthrough, you will create an ECMAScript (JavaScript, JScript) text file. This walkthrough assumes that you are familiar with coding in JavaScript.

To create an ECMAScript text file


1. Create a text file and name it JSOM_FeedToContentEditor.txt.
2. Add the following script to the JSOM_FeedToContentEditor.txt file.
Sample code provided by: Vidya Joshi, Microsoft Corporation.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">


<html>
<head>Logging results:
</head>
<body>
<div id='resultdiv'></div>
<script type="text/javascript">

// Set the page event handlers for onload and unload.


if (window.attachEvent)
{
window.attachEvent("onload", Page_Load);
}
else
{
// For some browsers window.attachEvent does not exist.
window.addEventListener("DOMContentLoaded", Page_Load, false);
}

// Load the page.


function Page_Load()
{
Ewa.EwaControl.add_applicationReady(GetEwa);
}

function GetEwa()
{
om =Ewa.EwaControl.getInstances().getItem(0);
writelog('DomId:' + om.getDomElement().id,0);

om.add_activeCellChanged(cellchanged);
om.add_activeSelectionChanged(selChanged);
om.add_gridSynchronized(gridSynchronized);
om.add_workbookChanged(wbchanged);
om.add_enteredCellEditing(editing);
}

function cellchanged(rangeArgs)
{
writelog('Address:'+ rangeArgs.getRange().getAddressA1(),1);
writelog('Value:' + rangeArgs.getFormattedValues(),1);
writelog('Cell changed event triggered',0);
}

function selChanged(rangeArgs)
{
writelog('Address:'+ rangeArgs.getRange().getAddressA1(),1);
writelog('Value:' + rangeArgs.getFormattedValues(),1);
writelog('Selection changed event triggered',0);
}

function gridSynchronized(res)
{
writelog('WorkbookPath:' +om.getActiveWorkbook().getWorkbookPath(),1);
writelog('grid synchronized',0);
}

function wbchanged(r)
{
writelog('Workbook changed event triggered',0);
}

function editing(rangeArgs)
{
writelog('Address:'+ rangeArgs.getRange().getAddressA1(),1);
writelog('Value:' + rangeArgs.getFormattedValues(),1);
writelog('Entered cell editing event triggered',0);
}

function writelog(output, indentLevel)


{
output = output + "<br/>";
document.getElementById('resultdiv').innerHTML = output + document.getElementById('resultdiv').innerHTML ;
}
</script>
</body>
</html><html>

1. Save the text file.

To save the text file to a trusted document library


1. Upload the text file that you created in the previous procedure to a trusted SharePoint document library.
2. Note the URL to the text file. For example:
http:// myserver /Docs/Documents/JSOM_FeedToContentEditor.txt

In the next procedure, you will need this URL to feed to the Content Editor web part.
Step 2: Adding the Content Editor and Excel Services web parts
5/3/2018 • 2 minutes to read Edit Online

After you create an ECMAScript (JavaScript, JScript) text file and save the text file in a trusted location, the next step is to create a web parts Page and add the Content Editor web part and
the Excel Services web part to the page.
Next, display a workbook by using the Excel Services web part that you added to the page.

To add the Content Editor web part and the Excel Services web part
1. Create a new web parts Page.
2. Add a Content Editor web part to the web parts Page that you just created.
3. Feed the URL for the text file that you created in Step 1: Creating a ECMAScript Text File to the Content Editor web part. You do this by adding the URL for the text file that you
uploaded to a trusted document library in Step 1: Creating a ECMAScript Text File.
For example:
http:// myserver /Docs/Documents/JSOM_FeedToContentEditor.txt

4. Add an Excel Services web part to the page.

To run the ECMAScript sample


1. Upload a workbook to a trusted document library. Use the Modify Shared web part menu to display the Excel Services web part task pane. In the Workbook Display section, in the
Workbook field, type the URL to the workbook that you want the Excel Services web part to load and display. For example:
http:// myserver /Docs/Documents/WorkbookToDisplay.xlsx

2. Try clicking different cells and observe the cell value populated in the Content Editor div.
Excel Services ECMAScript Overview
5/3/2018 • 2 minutes to read Edit Online

In Microsoft SharePoint Server 2010, Excel Services added support for ECMAScript (JavaScript, JScript). JavaScript enables a new set of solutions by using Excel Services.
The JavaScript object model in Excel Services enables developers to automate, customize, and interact with the Excel Web Access web part control on a page. By using the JavaScript object
model, you can build mashups and other integrated solutions that interact with one or more Excel Web Access web part controls on a page. It also enables you to add more capabilities to
your workbooks and to code around them. By using the JavaScript object model, it is possible to detect and react to a user's interactions with an Excel Web Access web part and to
programmatically interact with one or multiple Excel Web Access web parts.

Using the ECMAScript Object Model


To use the JavaScript object model in Excel Services, you insert the JavaScript code on the page that contains the Excel Web Access web part. This can be done by adding the code to the web
part page by using the Content Editor web part or by directly editing the .aspx page.
The JavaScript object model in Excel Services enables developers to:
Access items in a workbook such as ranges, tables, PivotTables, charts, and sheets.
Set and retrieve values from cells by using ranges or named ranges.
Raise events when the user changes the active selection or active cell or when the user starts editing a cell.
Scroll to a different region and to switch the displayed sheet or named item.
For more information, see the following links:
For more information about the JavaScript object model in Excel Services, see the Ewa namespace reference documentation.
For an example of how to interact with the JavaScript object model in Excel Services by using the Content Editor web part, see Walkthrough: Developing Using the Content Editor
web part.

ECMAScript .js File Location


Minified .js files for the JavaScript object model are installed in the %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\TEMPL ATE\L AYOUTS directory. The name
of the file is EwaMoss.js.
For basic information about how to use the JavaScript object model within an .aspx page or .js file, see Setting Up an Application Page for JavaScript.
JavaScript user-defined functions overview
5/3/2018 • 2 minutes to read Edit Online

JavaScript user-defined functions (UDFs) are new in Excel Services in SharePoint. This article provides a high-level look at JavaScript UDFs, including basic information on how they work in
Excel Services.

What are UDFs?


A user-defined function (UDF) is a function that you can create yourself and then add to the list of available functions in Excel when Excel doesn't provide the type of function that you want
right out of the box.
Excel Services already allows you to create UDFs using managed code, so if you have worked with the existing Excel Services UDFs, JavaScript UDFs should look familiar to you. For more
information about creating UDFs using managed code, see Excel Services User-Defined Functions.

JavaScript UDFs
JavaScript UDFs are UDFs that run in the browser on a webpage that has an embedded Excel workbook. You use the JavaScript UDF inside of the embedded workbook. As long as you are
working with the workbook in the browser, you can use the JavaScript UDF just like you use the built-in Excel functions. When the webpage is closed, the JavaScript UDF is no longer
available.

How do JavaScript UDFs work?


To use a JavaScript UDF, you have to have the ability to modify the content of the webpage where you embed the workbook. After you reference the correct Excel Services JavaScript source
file, you add your JavaScript UDF code to the page. Additionally, before you use your JavaScript UDF, you first have to register the UDF with the Excel Calculation Services. The JavaScript
UDF API provides methods to both register and unregister your JavaScript UDF.
When the webpage with the Excel Web Access web part or embedded workbook renders, you can invoke the JavaScript UDF in the workbook just like any other Excel workbook.
For example, you may have a function that gets the current stock price for a specific stock. You could add a JavaScript UDF to the webpage that hosts your Excel workbook (assuming you
have authoring rights for the webpage) that uses JavaScript code as follows.

function StockInfo(symbol, measure) {


var req = new XMLHttpRequest();
req.open('GET', 'http://www.contoso-stock-quotes.com/quote/' + symbol + '/' + measure, false);
req.send(null);
if (req.status == 200) {
return req.responseText;
} else {
throw new Error(ExcelCalcError.Value);
}

ewa.BrowserUdfs.add("StockQuote",
StockInfo,
"Gets a stock quote given a security symbol and measure to return."
false,
false
);

You could then call the JavaScript UDF, StockInfo, in a formula from a cell inside the Excel Online.
Figure 1. JavaScript UDF invoked in Excel Online

Where can I use JavaScript UDFs?


You can create and use JavaScript UDFs either on workbooks displayed in SharePoint Excel Web Access web parts or on a host webpage that has an embedded workbook. The workbook
must be stored on Microsoft OneDrive. The main difference is that JavaScript UDFs added to Excel Web Access web parts require a SharePoint server. JavaScript UDFs added to host
webpages that have embedded workbooks require only that the workbook be stored on OneDrive.

Key points
JavaScript UDFs only live as long as the webpage they are on is being displayed. They do not persist beyond the lifetime of the webpage where they were created.
You can't make calls to the Excel Services JavaScript object model from within a JavaScript UDF.

See also
Excel Services in SharePoint
What's new in Excel Services for developers
Excel Services User-Defined Functions
Working with the Excel Services JavaScript object model
5/3/2018 • 3 minutes to read Edit Online

When you write code that uses the JavaScript object model (JSOM), there are two scenarios where the code can run: on a SharePoint page; or on a host webpage that contains an embedded
workbook that is stored on Microsoft OneDrive. This article discusses the main difference between the two scenarios that significantly affect how you write your code.

Using the Excel Services JSOM


Table 1 lists the difference between the two scenarios available when you write code that uses the JSOM.
Table 1. Scenarios for Excel Services JSOM

LO CATIO N D ES CR IPTIO N

OneDrive In this scenario, you embed a workbook that is stored on OneDrive into the host webpage using an
HTML
element. Then you include code in the page that interacts with the embedded workbook.

SharePoint In this scenario, you have a SharePoint page served by SharePoint. You insert an web part into the
SharePoint page that contains a workbook that is stored in an trusted location. Then you include code in
the SharePoint page that interacts with the web part.

The main difference between writing code for the two scenarios is how you get a reference to the Ewa.EwaControl object. Because the [Ewa.EwaControl] is the entry point to the JavaScript
object model, you must get a reference to it to work with the JSOM.

Getting a reference to the EwaControl object (SharePoint)


When writing code that interacts with an web part on a SharePoint page, you get a reference to the [Ewa.EwaControl] object by using the method,
Ewa.EwaControlCollection.getItem(index), as shown in the following code example.

<script type="text/javascript">
var ewa = null;

// Add event handler for onload event.


if (window.attachEvent)
{
window.attachEvent("onload", ewaOmPageLoad);
}
else
{
window.addEventListener("DOMContentLoaded", ewaOmPageLoad, false);
}
// Add event handler for applicationReady event.
function ewaOnPageLoad()
{
if (typeof (Ewa) != "undefined")
{
Ewa.EwaControl.add_applicationReady(ewaApplicationReady);
}
else
{
alert("Error - the EWA is not loaded.");
}
// Add additional page load code here.
}

function ewaApplicationReady()
{
// Get a reference to the Excel Services web part.
ewa = Ewa.EwaControl.getInstances().getItem(0);

// Add other initialization logic here.


}

// Add your code here.


</script>

Getting a reference to the EwaControl object (OneDrive)


When writing code that interacts with an embedded workbook that is stored on OneDrive, you get a reference to the [Ewa.EwaControl] object through the AsyncResult object. The
[AsyncResult] object is passed in as the single parameter to the callback method that you specify in the Ewa.EwaControl.loadEwaAsync static method. When the callback is invoked, a
reference to the [Ewa.EwaControl] object is included in the [AsyncResult] object. The following code example shows how you get a reference to the [Ewa.EwaControl] object through the
[AsyncResult] object.
<div id="myExcelDiv" style="width: 402px; height: 346px"></div>
<script type="text/javascript" src="http://r.office.microsoft.com/r/rlidExcelWLJS?v=1&amp;kip=1"></script>
<script type="text/javascript">
/*
* This code uses the Microsoft Office Excel JavaScript object model to programmatically insert the
* Excel Web App into a div with id=myExcelDiv. The full API is documented at
* http://msdn.microsoft.com/en-us/library/hh315812.aspx. There you can find out how to programmatically get
* values from your Excel file and how to use the rest of the object model.
*/

// Use this file token to reference Book1.xlsx in the Excel APIs


// Replace the the placeholder for the filetoken with your value
var fileToken = " XXXXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXX/";
var ewa = null;

// Run the Excel load handler on page load.


if (window.attachEvent)
{
window.attachEvent("onload", loadEwaOnPageLoad);
} else
{
window.addEventListener("DOMContentLoaded", loadEwaOnPageLoad, false);
}

function loadEwaOnPageLoad()
{
var props = {
uiOptions: {
showGridlines: false,
showRowColumnHeaders: false,
showParametersTaskPane: false
},
interactivityOptions: {
allowTypingAndFormulaEntry: false,
allowParameterModification: false,
allowSorting: false,
allowFiltering: false,
allowPivotTableInteractivity: false
}
};
// Embed workbook using loadEwaAsync
Ewa.EwaControl.loadEwaAsync(fileToken, "myExcelDiv", props, onEwaLoaded);
}

function onEwaLoaded(asyncResult)
{
if (asyncResult.getSucceeded())
{
// Use the AsyncResult.getEwaControl() method to get a reference to the EwaControl object
ewa = asyncResult.getEwaControl();

}
else
{
alert("Async operation failed!");
}
// ...
}
</script>

Conclusion
Writing a solution that uses the JavaScript object model is basically the same whether the solution runs on SharePoint or on a host webpage. The main difference is how you get a reference
to the [Ewa.EwaControl] object. Once you have a reference to the [Ewa.EwaControl] object, the rest of the code that you write will be almost the same for both scenarios.

See also
Using the Excel Services JavaScript API to Work with Embedded Excel Workbooks
Ewa.EwaControl.loadEwaAsync
Ewa.EwaControlCollection.getItem(index)
Create a mashup that uses an embedded workbook and Bing Maps
5/3/2018 • 7 minutes to read Edit Online

This article walks you through a powerful Web-based mashup that combines an embedded Excel workbook and Bing Maps.

About the "Destination Explorer"


The Destination Explorer is a mashup that lets the user choose a region, a destination type (city or park), a specific destination within the region, and then see weather information or number
of visitors to the destination by month.
When the user selects different options from the UI, JavaScript is used to process the events and pass the changes to the workbook on OneDrive. The workbook recalculates itself based on
the changes and notifies the Destination Explorer when it is finished using callback functions. Depending on what the user changed, the Destination Explorer may either get more data from
the Travel workbook, update the view of the Bing Map, hide the charts, or swap the chart that is currently showing.
The "Travel workbook"
The Destination Explorer depends heavily on an embedded workbook that contains all the destination names, statistics for weather and visitor numbers, and two charts for displaying
monthly weather data and monthly visitor data.
Excel Services JavaScript API
The mashup uses the Excel Services JavaScript API to embed the workbook and to interact with it. To use the Excel Services JavaScript API, you only have to reference the API source
location in your code. Once you have access to the Excel Services JavaScript API, you can programmatically embed and work with an Excel workbook.
Bing Maps JavaScript API
The mashup also uses the Bing Maps API to display the locations selected on the workbook inside a Bing Map. Just like any other JavaScript library, all you have to do is reference the API
library in your code in order to include a Bing Map in your mashup.

Creating the "Destination Explorer" Mashup


To create this mashup, we followed 3 basic steps:
1. Store the workbook on OneDrive. Find more information on the OneDrive page.
2. Embed the workbook on the page. Find more information on embedding workbooks from OneDrive here.
3. Mash it up with Bing Maps. This step is covered in more detail in the following sections.

Mashup Excel Services and Bing Maps


After storing the workbook in a public folder on OneDrive, and after embedding the workbook on the host webpage, the Bing Maps functionality is combined with interactions on the
embedded workbook to create the Destination Explorer Mashup.
The integration happens in the following 3 steps:
Create the page structure for the mashup
Initialize the embedded workbook charts and the Bing Map
Create the appropriate callback functions
1. Create the page structure for the mashup
An HTML select control on the webpage is populated with data from the Travel workbook when the page loads or whenever the user changes the current region or the destination
type. The definition for this select control ( destinations ) is shown in Snippet 1. Snippet 1 also shows the definition for the other key elements on the page: chartDiv, chartDiv2, and
mapDiv. The chart div elements are containers for the two charts defined in the Travel workbook. The map div is the container for the Bing Map control.
Snippet 1: Structuring the webpage

<!-- HTML omitted for brevity -->


<select id="destinations" style="width: 150px" name="destinations"
onchange="onDestinationChange()">
</select>
<!-- HTML omitted for brevity -->
<div id="chartDiv" style="width: 483px; height: 318px"></div>
<div id="chartDiv2" style="width: 483px; height: 318px; display: none"></div>
<!-- HTML omitted for brevity -->
<div id="mapDiv" style="position:relative; width:693px; height:400px;"></div>
<!-- HTML omitted for brevity -->

1. Initialize the embedded workbook charts and the Bing Map


The next step is to initialize the Excel components and the Bing Map when the page loads. In order to access an embedded Excel workbook programmatically, you need to refer to it by
a file token. See http://msdn.microsoft.com/en-us/library/hh315812.aspx for information on how to get the appropriate file token for your workbook.
The code in Snippet 2 completes three main tasks inside the Page_Load event handler. First, it establishes a reference to the Travel workbook to display the chart named Chart 1
inside the chartDiv element on the webpage. Second, it calls a simple function named GetMap to initialize the Bing Map. Third, it creates a second reference to the Travel workbook
to display the chart named Chart 2 inside the chartDiv2 element.
Snippet 2: Initializing the Page
// Use this file token to reference your OneDrive hosted workbook in Excel's APIs
var fileToken = "TOKEN TO YOUR WORKBOOK GOES HERE";
var map;
var ewaChart = null;
var ewaChart2 = null;

// Set the page event handlers for onload and unload.


if (window.attachEvent) {
window.attachEvent("onload", Page_Load);
}
else {
// For some browsers window.attachEvent does not exist.
window.addEventListener("DOMContentLoaded", Page_Load, false);
}

hideCharts();

// Page load event handler


function Page_Load() {

// Load Excel Chart


var props = {
item: "Chart 1",
uiOptions: {
showParametersTaskPane: false
},
interactivityOptions: {
allowTypingAndFormulaEntry: true,
allowParameterModification: false,
allowSorting: false,
allowFiltering: false,
allowPivotTableInteractivity: false
}
};
Ewa.EwaControl.loadEwaAsync(fileToken, "chartDiv", props, onEwaChartLoaded);

// Load the Bing map


GetMap();

// Load the 2nd Excel Chart


var props = {
item: "Chart 2",
uiOptions: {
showParametersTaskPane: false
},
interactivityOptions: {
allowTypingAndFormulaEntry: true,
allowParameterModification: false,
allowSorting: false,
allowFiltering: false,
allowPivotTableInteractivity: false
}
};
Ewa.EwaControl.loadEwaAsync(fileToken, "chartDiv2", props, onEwaChart2Loaded);
}

// Setup the Bing Map's initial view


function GetMap() {

map = new Microsoft.Maps.Map(document.getElementById("mapDiv"),


{ credentials: "YOUR CREDENTIALS",
center: new Microsoft.Maps.Location(37.2802459560, -112.738963),
mapTypeId: Microsoft.Maps.MapTypeId.road,
zoom: 3 });

1. Create the appropriate callback functions


All calls to functions in the Excel Services JavaScript API usually take a callback as a parameter to the function. The callback parameter is the name of the function in your JavaScript
that should be run when the call to the Excel Services JavaScript API completes. You can see a callback used in the EwaControl.loadEwaAsync function in Snippet 2:

Ewa.EwaControl.loadEwaAsync(fileToken, "chartDiv", props, onEwaChartLoaded);

The callback used here is **onEwaChartLoaded**. This launches the following chain of calls to the Excel Services JavaScript API and callbacks within the Destination Explorer. The callbacks used i

onEwaChartLoaded() - This function saves a reference to the Excel Web Access Control associated with the chart. After it has the control, it calls the method getRangeA1Async()
to get the range represented by the name OutputTopFiveDetails .
onGotDetailRange() - The call to getRangeA1Async() returns the range, not the values so this callback calls the method getValuesAsync() to get the values associated with the
range.
onGotDetailValues() - The values associated with the range are stored in a variable for later use and then this method calls the following methods defined within the Destination
Explorer:
loadDestinations() - Populates the select element with the destinations within the range OutputTopFiveDetails
updateMap() - Updates the map if necessary
updateChart() - Updates the chart if necessary

The purpose of the chain of callbacks shown in **Snippet 3** is to update the data shown on the HTML page. There is another chain of callback functions used to modify data within the Travel workb

**Snippet 3: The callback chain for modifying inputs in the Travel workbook**
// Event handler called when user selects a different region.
function onRegionChange() {
currentDestination = '';
var e = document.getElementById("regions");
currentRegion = e.options[e.selectedIndex].text;
updateExcel();
}

// Event handler called when user selects a different destination.


function onDestinationChange() {
var select = document.getElementById('destinations');
var i = select.selectedIndex;
currentDestination = select.options[i].text;
updateChart();
updateMap(false);
}
// Event handler called when user selects a different destination type.
function onTypeChange(type) {
currentDestination = '';
currentDestinationType = type;
updateExcel();
}

// Called from onTypeChange and onRegionChange when user selects a different destination type or region
function updateExcel() {
ewaChart.getActiveWorkbook().getRangeA1Async("Input!Inputs", onGotRange, 0);
ewaChart2.getActiveWorkbook().getRangeA1Async("Input!Inputs", onGotRange, 1);
}

// Callback - called from updateExcel - sets input values according to user selections
function onGotRange(result) {
var range = result.getReturnValue();
var values = new Array(2);
values[0] = new Array(1);
values[0][0] = currentRegion;
values[1] = new Array(1);
values[1][0] = currentDestinationType;
range.setValuesAsync(values, null, null);

// Initiate process of refreshing the script variable detailRangeValues


if (result.getUserContext() == 0)
ewaChart.getActiveWorkbook().getRangeA1Async("Output!OutputTopFiveDetails", onGotDetailRange, null);
}

Conclusion
This walkthrough gives an example of how web developers can create rich, interactive mashups using Excel Services and other technologies.
Excel Services REST API
3/26/2018 • 2 minutes to read Edit Online

This section contains information about the Representational State Transfer (REST) API in Excel Services and explains how to use it.
NOTE

The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For Office 365 Education, Business, and Enterprise accounts, use the Excel REST APIs that are part of
the Microsoft Graph endpoint.

Related sections
Excel Services REST API Overview

Learn about the REST API in Excel Services.

Basic URI Structure and Path

Learn how to construct the URI structure and path for the REST service commands in Excel Services.

Discovery in Excel Services REST API

Learn about the discovery mechanisms built into the REST API in Excel Services.

Resources URI for Excel Services REST API

Learn the entities that you can link directly to by using the REST API in Excel Services.

Getting Ranges Using Atom Feed and HTML Fragment

Learn to access ranges—Atom feeds and HTML fragments—by using the REST API in Excel Services.

Sample URI For Excel Services REST API

Provides a sample URI for the REST service commands in Excel Services.

Accessing a Schema

Learn how to access and look at a schema for the REST service in Excel Services.

Unsupported Features in Excel Services REST API

Lists some of the more important features that are currently not supported or working in the Excel Services REST API.

Advanced Scenarios and Additional Samples

Describes some advanced REST scenarios and provides links to additional samples.
Excel Services REST API Overview
3/26/2018 • 2 minutes to read Edit Online

The REST API in Excel Services is new in Microsoft SharePoint Server 2010. By using the REST API, you can access workbook parts or elements directly through a URL.
NOTE

The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For For Office 365 Education, Business, and Enterprise accounts,, use the Excel REST APIs that are
part of the Microsoft Graph endpoint.
REST services are based on two requirements:
An addressing scheme used to locate networked resources
A methodology for returning representations of these resources
REST services are resource-centric. With REST, data is divided into resources, each resource is given a URL, and standard operations are implemented on the resources, which enable
operations like creation, retrieval, update, and deletion.
NOTE

For more information about the difference between REST services and custom Web services, see Custom Service or RESTful Service.
A REST API for Excel Services enables operations against Excel workbooks by using operations specified in the HTTP standard. This allows for a flexible, secure, and simpler mechanism to
access and manipulate Excel Services content.The discovery mechanisms built into the Excel Services REST API also enable developers and users to explore the content of the workbook
manually or programmatically by supplying an Atom feed that contains information about the elements that reside in a specific workbook. Some examples of the resources that you can
access through the REST API are charts, PivotTables, and tables.Using the Atom feed provided by the REST API is an easier way of getting to the data that you care about. The feed contains
traversable elements that enable any piece of code to discover what elements exist in a workbook. For information about accessing the REST service and obtaining sample URIs for the
REST service in Excel Services, see Basic URI Structure and Path and Sample URI For Excel Services REST API.
Basic URI Structure and Path
3/26/2018 • 2 minutes to read Edit Online

This topic explains how to construct the URI structure and path for REST service commands in Excel Services.
NOTE

The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For Office 365 Education, Business, and Enterprise accounts, use the Excel REST APIs that are part of
the Microsoft Graph endpoint.

Basic URL Structure and Path


The REST API in Excel Services gives you the ability to access resources like charts, PivotTables, tables, and named ranges in a workbook directly through a URL. Each REST URL in Excel
Services is built of three parts. Following is the basic structure of the URL to access the resources in a workbook:
1. REST aspx Page URI The entry point to an .aspx page
2. Workbook Location The path to the workbook
3. Resource Location The path to the requested resource inside the workbook
Following is the construct for the REST URL to a specific element in a workbook:

http://<ServerName>/_vti_bin/ExcelRest.aspx/<DocumentLibrary>/<FileName>/<ResourceLocation>

Following is an example of how a REST URL in Excel Services looks with all three parts combined. In this example, the REST URL is accessing a workbook called "sampleWorkbook.xlsx" that
contains a chart called "SampleChart":

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('SampleChart')

The workbook is stored in a document library. The full path to the workbook is http:// /Docs/Documents/sampleWorkbook.xlsx .
The three parts of the REST URL are:
1. REST aspx Page URI: http:// /_vti_bin/ExcelRest.aspx

2. Workbook Location: /Docs/Documents/sampleWorkbook.xlsx

3. Resource Location: /model/Ranges('nameOfTheNamedRange')

Accessing by Using the Discovery User Interface


You can also access the chart by using the discovery user interface. To learn how access resources like charts, tables, PivotTables, and ranges by using the discovery mechanism shown in the
following screen shot, see Discovery in Excel Services REST API.

Marker Path
Following is the aspx page for the REST service in Excel Services:

http://<ServerName>/_vti_bin/ExcelRest.aspx

To access the REST service in Excel Services, you must preface the URL with http:// /_vti_bin/ExcelRest.aspx .
Workbook Location
The workbook location is the relative path to the workbook that has resources that you are interested in accessing. For example, assume that you have a workbook named
sampleWorkbook.xlsx, saved to a trusted SharePoint document library. In this example, following is the path to the location of sampleWorkbook.xlsx:

http://<ServerName>/Docs/Documents/sampleWorkbook.xlsx

You take the relative path to the workbook ( Docs/Documents/sampleWorkbook.xlsx ) and append it to the marker path. Following is the URL with the marker path and workbook location
appended:

http://<ServerName>/_vti_bin/ExcelRest.aspx

Resource Location
The resource location is the path inside the workbook to the element that you request. For example, if you want to get a chart, the resource location would be similar to
/model/Charts('Chart 1') .

For the full URL, you append this to the marker path and the relative path to the workbook. Following is the full example URL:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('Chart 1')

See also
Concepts
Resources URI for Excel Services REST API
Discovery in Excel Services REST API
Discovery in Excel Services REST API
5/3/2018 • 3 minutes to read Edit Online

This topic discusses the discovery mechanisms built into the Excel Services REST API.
NOTE

The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For Office 365 Education, Business, and Enterprise accounts, use the Excel REST APIs that are part of
the Microsoft Graph endpoint.

Discovery Base URL and Discovery Example


Discovery enables developers and users to discover information about and the content of a workbook manually or programmatically. The discovery mechanism supplies the Atom feed that
contains information about the resources in a workbook. By using discovery, you can explore and view the resources in the workbook. Resources that you can explore and access are ranges,
charts, tables, and PivotTables.
Following is the construct of the REST URL to a specific element in a workbook:

http://<ServerName>/_vti_bin/ExcelRest.aspx/<DocumentLibrary>/<FileName>/<ResourceLocation>

As described in the Basic URI Structure and Path topic, following is the REST URL to access a workbook named sampleWorkbook.xlsx and further view the chart called SampleChart:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('SampleChart')

To start and explore the resources in the workbook and view the resources by using discovery, go to the model page by using a URI that follows this example:

http://<ServerName>/_vti_bin/ExcelRest.aspx/<DocumentLibrary>/<FileName>/model

Using the "sampleWorkbook.xlsx" example, following is the URI:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model

Following is a screen shot of the model page.


Excel Services REST model URL

The URL to the model page is where you start the discovery. The model page displays four resource collections that the Excel Services REST API currently supports. The resource collections
are ranges, charts, tables, or PivotTables. You can explore those resources in a particular workbook by clicking Ranges, Charts, Tables, or PivotTables on the model page.
For example, to access the chart in the workbook by using discovery, do the following:
1. On the model page, click Charts. Clicking the Charts link brings another Atom feed—this resulting feed lists all the charts that are available in the sampleWorkbook.xlsx workbook.
The sampleWorkbook.xlsx workbook contains three charts named Chart 1, Chart 3, and SampleChart. Therefore, three chart names are listed, as seen in the following screen shot.
Excel Services REST discovery chart list
1. On the model page, click SampleChart. This displays the chart named SampleChart that resides in sampleWorkbook.xlsx, as shown in the following screen shot.
Viewing chart using REST

1. Similarly, clicking Chart 1 or Chart 3 displays the chart with the corresponding name. Clicking SampleChart navigates to the actual chart URL. Following is the URL to the
SampleChart image (as can be seen in the screen shot):

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('SampleChart%20')?$format=image

Atom Feed
Using the Atom feed provided by the REST API gives you an easier way of getting to the data that you are interested in. If you view the source of the webpage, you get the XML. An example
from the charts in sampleWorkbook.xlsx is shown below.
As can be seen in the XML, the feed contains traversable elements that enable code to discover what elements exist in the workbook. Each Atom entry corresponds to a chart that can be
accessed. This same mechanism applies to discovering ranges, tables, and PivotTables.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:x="http://schemas.microsoft.com/office/2008/07/excelservices/rest" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservice" xmlns:m="http://s
<title type="text">Charts</title>
<id>http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts</id>
<updated>2010-01-19T19:32:53Z</updated>
<author>
<name />
</author>
<link rel="self" href="http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts?$format=atom" title="Charts" />
<entry>
<category term="ExcelServices.Chart" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<title>Chart 1</title>
<id>http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('Chart%201')</id>
<updated>2010-01-19T19:32:53Z</updated>
<author>
<name />
</author>
<link rel="alternate" title="Chart 1" href="http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('Chart%201')?$format=image" />
<content type="image/png" src="http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('Chart%201')?$format=image" />
</entry>
<entry>
<category term="ExcelServices.Chart" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<title>Chart 3</title>
<id>http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('Chart%203')</id>
<updated>2010-01-19T19:32:53Z</updated>
<author>
<name />
</author>
<link rel="alternate" title="Chart 3" href="http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('Chart%203')?$format=image" />
<content type="image/png" src="http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('Chart%203')?$format=image" />
</entry>
<entry>
<category term="ExcelServices.Chart" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<title>SampleChart </title>
<id>http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('SampleChart%20')</id>
<updated>2010-01-19T19:32:53Z</updated>
<author>
<name />
</author>
<link rel="alternate" title="SampleChart" href="http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('SampleChart%20')?$format=image" />
<content type="image/png" src="http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Charts('SampleChart%20')?$format=image" />
</entry>
</feed>

See also
Concepts
Resources URI for Excel Services REST API
Resources URI for Excel Services REST API
3/26/2018 • 2 minutes to read Edit Online

You can link to entities directly by using the REST API in Excel Services.
NOTE

The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For Office 365 Education, Business, and Enterprise accounts, use the Excel REST APIs that are part of
the Microsoft Graph endpoint.

Base REST URL


The following is an example of a REST URL to a specific element in a workbook.

http://<ServerName>/_vti_bin/ExcelRest.aspx/<DocumentLibrary>/<FileName>/<ResourceLocation>

A relative REST URL is based off the base REST URL. The following is an example of a base REST URL to a specific workbook.

http://<ServerName>/_vti_bin/ExcelRest.aspx/<DocumentLibrary>/<FileName>

For example, if you have a workbook named "sampleWorkbook.xlsx" in the following document library:

http://<ServerName>/Docs/Documents/sampleWorkbook.xlsx

The base REST URL to the workbook is:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx

Resources URI
Table 1 shows all the accessible resources in the Excel Services REST API. To access a particular resource, append the resource location to the base REST URL to a workbook.
Table 1. Accessible resources in the Excel Services REST API

R ES O U R CE LO CATIO N FO R MAT E X AMPLE NO TES

/model Atom (default) /model Returns an Atom feed with the resources
supported by the Excel Services REST API. The
supported resources are ranges, charts, tables,
and PivotTables.

/model workbook /model?$format=workbook This is the workbook. Supported workbook


formats are xlsx, xlsb, and xlsm.

/model/Ranges Atom (default) /model/Ranges?$format=atom An Atom feed that listis all the named ranges in
the workbook.

/model/Ranges('[Name]') HTML (default) /model/Ranges('MyRange')?$format=html An HTML fragment for the requested range.

/model/Ranges('[Name]') Atom /model/Ranges('MyRange')?$format=atom An Atom entry that contains an XML


representation of the data within the range.

/model/Charts Atom (default) /model/Charts?$format=atom An Atom feed that lists all the charts in the
workbook.

/model/Charts('[Name]') Image (default) /model/Charts('MyChart')?$format=image An image of the chart. The image is in Portable
Network Graphics (PNG) format.

/model/Tables Atom (default) /model/Tables?$format=atom An Atom feed that lists all the available tables in
the workbook.

/model/Tables('[Name]') HTML (default) /model/Tables('MyTable')?$format=html An HTML fragment for the requested table.

/model/Tables('[Name]') Atom /model/Tables('MyTable')?$format=atom An Atom entry that contains an XML


representation of the data within the table.

/model/PivotTables Atom (default) /model/PivotTables?$format=atom An Atom feed that lists all the available
PivotTables in the workbook

/model/PivotTables('[Name]') HTML (default) /model/PivotTables('MyPivotTable)?$format=html An HTML fragment for the requested PivotTable.

/model/PivotTables('[Name]') Atom /model/PivotTables('MyPivotTable')?$format=atom An Atom entry that contains an XML


representation of the data within the PivotTables.
NOTE

Excel Services limits the number of ranges that you can include in a URL to 10. If you include more than 10 Ranges in a URL, you will get an error that indicates that the service is
unavailable.

See also
Basic URI Structure and Path
Getting Ranges Using Atom Feed and HTML Fragment
3/26/2018 • 3 minutes to read Edit Online

This topic describes two ways to access ranges—Atom feed and HTML fragment, by using the REST API in Excel Services.
NOTE

The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For Office 365 Education, Business, and Enterprise accounts, use the Excel REST APIs that are part of
the Microsoft Graph endpoint.

Accessing Ranges
The REST API in Excel Services supports two mechanisms for getting ranges. The first is used mainly to enable applications to get to the raw-data of a workbook, that is, the raw numbers or
values from a worksheet. The second is to get HTML fragments from inside a browser.
As described in the Discovery in Excel Services REST API topic, the REST URL to the model page using discovery is:

http://<ServerName>/_vti_bin/ExcelRest.aspx/<DocumentLibrary>/<FileName>/model

Therefore, for a workbook with the file name sampleWorkbook.xlsx that is saved to http://<ServerName>/Docs/Documents/sampleWorkbook.xlsx , following is the URI to the model page:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model

Using the discovery mechanism described in Discovery in Excel Services REST API, if you click on the Ranges Atom feed on the model page on the server, ( http://
/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model ), it displays a page that shows all the named ranges in the workbook. The sampleWorkbook.xlsx contains one named
range, SampleNamedRange, as shown in the following screen shot:
IM P O R T A N T

You can also specify arbitrary ranges, and not just the ranges returned by discovery. Colon ":" must be replaced with "|". For example use "A1|G5" instead of "A1:G5".
NOTE

Characters like "?" and "#" are unsupported. To correctly reference sheet names that contain special characters, the basic guideline is "see what the Excel client does" when referencing a
formula to a sheet with special characters and follow that example.
Excel Services REST named range discovery

Accessing Ranges by Using an Atom Feed


If you click SampleNamedRange in the range discovery page, you navigate to the following URL:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Ranges('SampleNamedRange')?$format=atom

Note that, in Internet Explorer, the resulting page looks like an error, as shown in the following screen shot.
Excel Services REST range discovery using Atom

Internet Explorer cannot show a single-entry Atom feed item. But viewing the source of the page shows the XML that the feed item contains:
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns:x="http://schemas.microsoft.com/office/2008/07/excelservices/rest" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservice" xmlns:m="http://schemas.microsoft.com/ado/2007/08/da
<title type="text">SampleNamedRange</title>
<id>http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Ranges('SampleNamedRange')</id>
<updated>2010-01-20T21:28:10Z</updated>
<author>
<name />
</author>
<link rel="self" href="http://ServerName/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Ranges('SampleNamedRange')?$format=atom" title="SampleNamedRange" />
<category term="ExcelServices.Range" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<x:range name="SampleNamedRange">
<x:row>
<x:c>
<x:fv>Performance</x:fv>
</x:c>
<x:c>
<x:v>26</x:v>
<x:fv>26</x:fv>
</x:c>
<x:c />
</x:row>
<x:row>
<x:c>
<x:fv>Employment</x:fv>
</x:c>
<x:c>
<x:v>42</x:v>
<x:fv>42</x:fv>
</x:c>
<x:c />
</x:row>
<x:row>
<x:c>
<x:fv>Earnings And Job Quality</x:fv>
</x:c>
<x:c>
<x:v>22</x:v>
<x:fv>22</x:fv>
</x:c>
<x:c />
</x:row>
... XML truncated for brevity.
<x:row>
<x:c>
<x:fv>Innovation Assets</x:fv>
</x:c>
<x:c>
<x:v>43</x:v>
<x:fv>43</x:fv>
</x:c>
<x:c />
</x:row>
<x:row>
<x:c />
<x:c>
<x:fv>State</x:fv>
</x:c>
<x:c />
</x:row>
</x:range>
</content>
</entry>

The feed item contains XML that represents the data inside the range. Following are the XML elements of interest:
The range element. Represents the container of the returned range.
The row element. Represents each row in the range.
The cell element. Represents each cell in a row.
The formatted value element. Represents the value as it is formatted by Excel. If the value is of type string in the workbook, the formatted value element is the only element under .
The value element. Represents a number value. If the value in the cell is a number instead of a string, the value element contains that information.
Using XML gives you an easier way to get data out of an Excel range so that you can use it in your application.

Accessing Ranges by Using HTML


If you look at the URL to access a named range by using Atom feed, note that the final part of the URL contains a parameter called $format , which is set to atom . This parameter can also
take the value of html . If you change the atom value to html , the URL returns an HTML fragment instead of an Atom feed. Following is an example of the URL:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Ranges('SampleNamedRange')?$format=html

In Internet Explorer, the page looks similar to the following figure.


NOTE

This HTML can be directly consumed in an IFRAME, or it can be used in JavaScript to create a more seamless experience.
See also
Concepts
Resources URI for Excel Services REST API
Sample URI For Excel Services REST API
3/26/2018 • 2 minutes to read Edit Online

This topic lists sample URIs for the representational state transfer (REST) service commands in Excel Services.
NOTE

The Excel Services REST API applies to SharePoint and SharePoint 2016 on-premises. For Office 365 Education, Business, and Enterprise accounts, use the Excel REST APIs that are part of
the Microsoft Graph endpoint.

Sample URI for REST Commands in Excel Services


In the following examples, each URI references a workbook named sampleWorkbook.xlsx .
The sampleWorkbook.xlsx file contains named ranges and charts.
The sampleWorkbook.xlsx file is saved to a trusted SharePoint document library. In this example, the path to the location of sampleWorkbook.xlsx is:

http://<ServerName>/Docs/Documents/sampleWorkbook.xlsx

Sample URI
The .aspx page for the REST service in Excel Services is:

http://<ServerName>/_vti_bin/ExcelRest.aspx

The following are example URIs to access the sampleWorkbook.xlsx workbook by using the REST service in Excel Services.
Top-level model for the workbook (only ranges and charts in the current build):

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model

Get the full workbook:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model?$format=workbook

Return a range (default html). The following two URI examples are equivalent:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Ranges('Sheet1!A1|G5')

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Ranges('Sheet1!A1|G5')?$format=html

Get a named range:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Ranges('nameOfTheNamedRange')

Return an Atom XML feed:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model?$format=atom

Set a cell and return it:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Ranges('Sheet1!A1|G5')?Ranges('Sheet1!C3')=demo

Get a chart:

http://<ServerName>/_vti_bin/ExcelRest.aspx/Docs/Documents/sampleWorkbook.xlsx/model/Cha

S-ar putea să vă placă și