This week I had the honor to present three sessions at the German SharePoint Conference in Erding. It was the first time that I ever had three sessions at just on the conference, which was pretty challenging but I enjoyed it.
My latest addition to Office 365 pattern and practices – Community Call June 2015
Recently I added the code of my blog post on “How to deploy binary files from SharePoint hosted App” to the Office 365 Pattern and Practices repository. During the monthly community call I was able to present my part of these additions.
I case you missed the monthly call you will find the screen recording on Channel 9.
Deploy binary files from SharePoint Hosted App to Host Web
SharePoint hosted Apps are limited to, use JavaScript or Jquery only. In some cases you like to copy a file directly from a SharePoint hosted app to the host web. This works as long as the file is a simple text file just like a master page or display template.
In case you like to copy an image to the host web, this is not possible trough jQuery. The reason for that is that jQuery has only been capable reading text files but not binary files.
The copy will succeed, but the file will be unusable and destroyed.
Lookup fields as site column declarative deployed
In this article I like to show you my way to deploy lookup fields to SharePoint declarative. I need to note that I won’t do this fully declarative but found a solution that works best. This will be used by SharePoint internally and is fully supported. The lookups I’m talking are lookup fields deployed as site column.
Whenever it comes to content types and site column in my opinion the best way is to create them declarative. The reason for this is that I can handle that all deployed fields have the same GUID that I defined and every Site Collection has the same fields with the same IDs. Simple field types such as text, number, Date and Time, User Fields, Yes/No Fields can be created easily using the declarative approach but with lookup fields this can be a little bit trickier. During the last weeks I did a couple of interviews with Becky Bertram, Doug Hemminger and made a poll on SPYAM. The result of this was that most people deploy or create lookup fields using code and not using the declarative approach. Here is the result of the poll.
But now let’s take a look how to create a lookup field.
Creating the Lookup Field
The basic declaration of a lookup field looks simple and you can reference the List by using the URL of the web where the site column will be deployed to. This can be done according to the documentation as long as the list will be deployed in the same feature as the lookup column.
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Field ID="{6C798145-A205-4FC4-8175-837B0F7744CC}" Type="Lookup" SourceID="http://schemas.microsoft.com/sharepoint/v3" DisplayName="Colors" Required="false" List="Lists/Colors" ShowField="LinkTitleNoMenu" UnlimitedLengthInDocumentLibrary="TRUE" Group="N8D Fields" StaticName="Colors" Name="Colors" /> </Elements>
In a second module I created a basic list instance with a custom list.
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <ListInstance Title="Colors" OnQuickLaunch="TRUE" TemplateType="100" FeatureId="00bfea71-de22-43b2-a848-c05709900100" Url="Lists/Colors" Description=""> </ListInstance> </Elements>
Both elements will be deployed in the same feature which means that the reference of the lookup should match the list and replace the token List URL with the value for “Lists/Colors” with the GUID. The problem is that after the deployment the lookup column looks like this.
If you go to the definition of the lookup column the list is empty and won’t be displayed correctly and the field won’t work with lists. The empty “Get information from” is one reason that people create lookup fields using code. As always in SharePoint many ways lead to a solution and a lot of people have created their own provisioning classes to create site column lookup fields, but here comes the good news. This problem can be fixed some simple modifications of the field configuration using code.
Fixing declarative Lookup Field
From my experience the problem is that SharePoint won’t replace the List URL token with the GUID of the list and the web. When you like to use site columns as lookup fields than you have to get those GUID somehow to the schema of the fields. The URL token in Site columns cannot be used because site columns need to have a reference to the GUID of a list and a web. Then SharePoint will be able to find the matching list and web where the lookup should reference to. A sub site cannot make use of a list with the value “List/Colors”.
A quick solution would be to create the list first and the web first and add the GUID in the field definition. Works great as long as you don’t like to reuse the lookup field in another site collection. In this case you have to change the GUID when you like to deploy the solution to another web application or sites. Not really a great option.
My solution is to add the GUIDs to the schema of the field definition and use the List URL as a token to find the proper list. This can be done with a simple feature receiver. The code for this looks like this.
public override void FeatureActivated(SPFeatureReceiverProperties properties) { SPSite targetSite = properties.Feature.Parent as SPSite; using (SPSite site = new SPSite(targetSite.ID)) { using (SPWeb web = site.OpenWeb()) { SPField lookupField = web.Fields.TryGetFieldByStaticName("Colors"); if (lookupField != null) { // Getting Schema of field XDocument fieldSchema = XDocument.Parse(lookupField.SchemaXml); // Get the root element of the field definition XElement root = fieldSchema.Root; // Check if list definition exits exists if (root.Attribute("List") != null) { // Getting value of list url string listurl = root.Attribute("List").Value; // Get the correct folder for the list SPFolder listFolder = web.GetFolder(listurl); if (listFolder != null && listFolder.Exists == true) { // Setting the list id of the schema XAttribute attrList = root.Attribute("List"); if (attrList != null) { // Replace the url wit the id attrList.Value = listFolder.ParentListId.ToString(); } // Setting the souce id of the schema XAttribute attrWeb = root.Attribute("SourceID"); if (attrWeb != null) { // Replace the sourceid with the correct webid attrWeb.Value = web.ID.ToString(); } // Update field with new schema lookupField.SchemaXml = fieldSchema.ToString(); } } } } } }
The code above does the following tasks:
- Get the Field
- Get the list that should be referenced by the lookup
- Change SourceID and List to the GUID of the web and list.
Without using the feature event receiver the field looked this:
<Field ID="{6C798145-A205-4FC4-8175-837B0F7744CC}" Type="Lookup" SourceID="http://schemas.microsoft.com/sharepoint/v3" DisplayName="Colors" Required="false" List="Lists/Colors" ShowField="LinkTitleNoMenu" UnlimitedLengthInDocumentLibrary="TRUE" Group="N8D Fields" StaticName="Colors" Name="Colors" />
After the deployment with the feature event receiver the field looked like this:
<Field ID="{6C798145-A205-4FC4-8175-837B0F7744CC}" Type="Lookup" SourceID="f22f83b7-8d4d-4111-a154-714ca309633a" DisplayName="Colors" Required="false" List="aaec4791-2991-4537-b19a-7106e5ffc9fd" ShowField="LinkTitleNoMenu" UnlimitedLengthInDocumentLibrary="TRUE" Group="N8D Fields" StaticName="Colors" Name="Colors" Version="1" />
SharePoint incremented the version number of the field after the changes have been applied to. The manipulation of the schema using the object model is fully supported by SharePoint but you need to take care that your modification are set with a proper xml that matches the field schema definitions. You will find this comment in the SPField.SchemaXML on the MSDN. There is not much difference in setting the schema of a field or create a field directly from XML using AddFieldAsXML.
A second look to the column settings shows that everything will be displayed correctly.
If you like to try this yourself you can download the solution N8D.Lookup.
Some other recommended Information on lookup fields I used previously was.
- Create lookup as a feature by Chris O’Brian
- Programmatically provision lookup field by Waldek Mastykarz
Deploy Content Type and Document Templates to Office 365 and SharePoint 2010
One of the best concepts in SharePoint are them hierarchical definition of content types that has been first introduces in SharePoint 2007. New content types could be defined by small variations made easily by developer or end users. All document based templates could be assigned with a specific document template that would be used in libraries. If someone has predefined Document Templates that could be assigned with the content type, they could be uploaded or deployed.
Xml Definition of content type with document template
The solution to deploy document templates and content type together in a solution consists of two parts:
- The content type definition
- A module for the template file
The first part of this solution is just a xml content type definition with the parent content type set to “Document”. A DocumentTemplate inside the content type definition was specified, which points to the defined template file. The content type looks as follows:
<!-- ContentType: Document (0x0101) --> <ContentType ID="0x01010064db413f63314bbbb9e4cd59d461beff" Name="MyNewContentType" Group="Developent Content Type" Description="My Content Type" Inherits="TRUE" Version="0"> <DocumentTemplate TargetName="MyNewContentTypeTemplate.docx"> <DocumentTemplate> <FieldRefs> </FieldRefs> <ContentType>
In SharePoint every content type has its own folder where templates will be stored, no matter if the content type is deployed through a solution or a template file has been uploaded via web the browser. These folders are located in the root of the site collection beneath the _cts folder. This folder can be found in the SharePoint Designer. Once the root of the site collection has been opened in SharePoint Designer and on the left side of the navigation “All Files” has been selected the _cts folder gets visible.
The second part of the solution is a module that has word document which will be deployed to the folder of the content type.
<Module Name="MyNewContentType"> <File Path="MyNewContentType\MyNewContentTypeTemplate.docx" Url="_cts/MyNewContentType/MyNewContentTypeTemplate.docx" Type="GhostableInLibrary" /> </Module>
On solution deployment, first of all the content type is created that reference the template file. Later the module will make sure that the template file could be located in the correct content type folder and make the template file accessible.
After the deployment the content type and the template can be accessed through SharePoint and used in any desired document library.
SharePoint Farm Solution, Sandboxed or SharePoint Online aka Office 365
This solution works in all the common deployment scenarios no matter where it should be deployed. This is because no custom code is required. The complete code for this only uses a couple of lines xml definition and looks like this:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <!-- Parent ContentType: Document (0x0101) --> <ContentType ID="0x01010064db413f63314bbbb9e4cd59d461beff" Name="MyNewContentType" Group="Developent Content Type" Description="My Content Type" Inherits="TRUE" Version="0"> <DocumentTemplate TargetName="MyNewContentTypeTemplate.docx"> </DocumentTemplate> <FieldRefs> </FieldRefs> </ContentType> <Module Name="MyNewContentType"> <File Path="MyNewContentType\MyNewContentTypeTemplate.docx" Url="_cts/MyNewContentType/MyNewContentTypeTemplate.docx" Type="GhostableInLibrary" /> </Module> </Elements>
For those who like to try the solution can download the VS Studio Solution or the WSP File.