<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-7384653670825187633</atom:id><lastBuildDate>Wed, 11 Mar 2026 09:26:21 +0000</lastBuildDate><title>Ivan on Software</title><description>Thoughts and ideas on web development</description><link>http://neganov.blogspot.com/</link><managingEditor>noreply@blogger.com (Ivan Neganov)</managingEditor><generator>Blogger</generator><openSearch:totalResults>49</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-4749228776759086755</guid><pubDate>Wed, 08 Dec 2021 03:42:00 +0000</pubDate><atom:updated>2021-12-07T20:34:09.566-08:00</atom:updated><title>Royalty-Free PDF Conversion and Manipulation Web Service</title><description>&lt;p&gt;PDF generation, anyone? There are tons of libraries to do all sorts of things with PDF. But time and again I witness the pain that PDF handling task causes organizations, even though it should long be totally mundane, one would think...&amp;nbsp;&lt;/p&gt;&lt;p&gt;Why is this so? You have to pay for a good PDF tool. Sometimes a lot. And the many free alternatives either focus on narrow things, or do not produce the best quality, or are hard to use, or are not for the platform of choice at the organization. The biggest obstacle is of course the licensing. If you cannot get a completely free license, then there is often a lot of friction&amp;nbsp; when trying to get a paid-for variant... Here is one example of how a conversation could evolve:&amp;nbsp;&lt;/p&gt;&lt;p&gt;- &quot;We already have a license for PDF converter X!&quot;.&amp;nbsp;&lt;/p&gt;&lt;p&gt;- &quot;But it does not do what we need/or it is too hard to use!&quot; etc., etc.&amp;nbsp;&lt;/p&gt;&lt;p&gt;And needless to say that this sort of complexity typically arises in the kind of organizations that do a lot of document management and depend on PDF generation.&lt;/p&gt;&lt;p&gt;Having been through this recently myself I have got inspired to try and help my customer, &lt;a href=&quot;https://tc.canada.ca/en&quot;&gt;Transport Canada&lt;/a&gt;, and other teams that may find themselves in a similar situation, and share a way to reliably generate high quality PDF documents and do some basic manipulations on them, absolutely free of charge.&lt;/p&gt;&lt;p&gt;Indeed, there has long been several useful PDF utilities made available on Linux, and there is the prominent&amp;nbsp;&lt;a href=&quot;https://www.libreoffice.org/&quot;&gt;LibreOffice suite&lt;/a&gt; that can generate great quality PDF documents free of charge. So I thought why not give it a try and put these applications inside of a Docker container and write a service that would accept HTTP requests and launch them?&amp;nbsp;&lt;/p&gt;&lt;p&gt;Such service would allow tapping into the richness of available open source tools, many of which have been out there for decades, and if you are a developer then it would let you easily adjust which specific tools would you want to run, or how would you want to scale the service. Pretty flexible.&amp;nbsp;&lt;/p&gt;&lt;p&gt;The service is now being adopted by Marine department at Transport Canada, and I hope it will evolve and serve them well. And since Transport Canada has a great policy of sharing the source code for some of their applications, I am happy to share &lt;a href=&quot;https://github.com/tc-ca/DSD-Marine-LibreOfficePdf&quot;&gt;&lt;b&gt;a link to its public Github repository&lt;/b&gt;&lt;/a&gt;, which also has a detailed description of how it works and how to handle it. I will just list its &quot;no frills&quot; but much sought-after basic&amp;nbsp; capabilities here:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;Conversion of popular office and image formats to PDF (thanks to &lt;a href=&quot;https://www.libreoffice.org/&quot;&gt;LibreOffice&lt;/a&gt;!)&lt;/li&gt;&lt;li&gt;Merging of office documents and images into a single PDF document (thanks to &lt;a href=&quot;https://www.ghostscript.com/&quot;&gt;GhostScript&lt;/a&gt;!)&lt;/li&gt;&lt;li&gt;Populating and &quot;flattening&quot; of fillable PDF forms (thanks to &lt;a href=&quot;https://gitlab.com/pdftk-java/pdftk&quot;&gt;pdftk-java&lt;/a&gt; and &lt;a href=&quot;https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/&quot;&gt;PDF Toolkit&lt;/a&gt;!)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Have fun converting to PDF for free!&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description><link>http://neganov.blogspot.com/2021/12/royalty-free-pdf-conversion-and.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-1323745561612914267</guid><pubDate>Fri, 21 May 2021 21:23:00 +0000</pubDate><atom:updated>2021-05-31T07:31:54.232-07:00</atom:updated><title>Migrate Data from a Cosmos DB Azure Table API</title><description>&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: Open Sans;&quot;&gt;&lt;span face=&quot;-apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif&quot; style=&quot;background-color: white; color: #172b4d; font-size: 15px; letter-spacing: -0.08px; line-height: 1.7; white-space: pre-wrap;&quot;&gt;If you need to migrate data from or into Azure Cosmos DB you can use Microsoft’s &lt;/span&gt;&lt;a class=&quot;sc-iyvyFf kJXhAi&quot; data-renderer-mark=&quot;true&quot; href=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/import-data&quot; style=&quot;background-color: white; color: #0052cc; font-size: 15px; letter-spacing: -0.08px; line-height: 1.7; text-decoration-line: none; white-space: pre-wrap;&quot; title=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/import-data&quot;&gt;data migration tool&lt;/a&gt;&lt;span face=&quot;-apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif&quot; style=&quot;background-color: white; color: #172b4d; font-size: 15px; letter-spacing: -0.08px; line-height: 1.7; white-space: pre-wrap;&quot;&gt; to do this. The tool is versatile but the documentation isn&#39;t providing all the answers. Specifically, in a scenario when you need to migrate data from Cosmos DB instance configured as an &lt;/span&gt;&lt;em data-renderer-mark=&quot;true&quot; style=&quot;background-color: white; color: #172b4d; font-size: 15px; letter-spacing: -0.08px; line-height: 1.7; white-space: pre-wrap;&quot;&gt;Azure Table &lt;/em&gt;&lt;span face=&quot;-apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif&quot; style=&quot;background-color: white; color: #172b4d; font-size: 15px; letter-spacing: -0.08px; line-height: 1.7; white-space: pre-wrap;&quot;&gt;API to a JSON file, you can use the tool, but the settings you need to provide are not obvious. Here are the settings which worked for me for its two main tabs: &lt;i&gt;Source Information&lt;/i&gt; and &lt;i&gt;Target Information &lt;/i&gt;(you would see them if you run the tool &lt;/span&gt;&lt;span style=&quot;background-color: white; color: #172b4d; font-size: 15px; letter-spacing: -0.08px; white-space: pre-wrap;&quot;&gt;&lt;span&gt;&lt;strong&gt;dtui.exe&lt;/strong&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Noto Sans, Ubuntu, Droid Sans, Helvetica Neue, sans-serif&quot;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;h2 data-renderer-start-pos=&quot;389&quot; id=&quot;Source-Information&quot; style=&quot;background-color: white; border-bottom-color: rgb(204, 204, 204); color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 1.42857em; font-weight: 500; letter-spacing: -0.008em; line-height: 1.2; margin: 1.8em 0px 0px; padding: 0px; white-space: pre-wrap;&quot;&gt;Source Information&lt;/h2&gt;&lt;ol class=&quot;ak-ol&quot; data-indent-level=&quot;1&quot; style=&quot;background-color: white; box-sizing: border-box; color: #172b4d; display: flow-root; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; margin: 12px 0px 0px; padding: 0px 0px 0px 24px; white-space: pre-wrap;&quot;&gt;&lt;li&gt;&lt;p data-renderer-start-pos=&quot;412&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Prepare data for assembling a connection string:&lt;/p&gt;&lt;ol class=&quot;ak-ol&quot; data-indent-level=&quot;2&quot; style=&quot;box-sizing: border-box; display: flow-root; list-style-type: lower-alpha; margin: 4px 0px 0px; padding: 0px 0px 0px 24px;&quot;&gt;&lt;li&gt;&lt;p data-renderer-start-pos=&quot;464&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Grab the value of &lt;em data-renderer-mark=&quot;true&quot;&gt;Azure Table Endpoint &lt;/em&gt;from &lt;em data-renderer-mark=&quot;true&quot;&gt;Overview &lt;/em&gt;page, for example: &lt;a href=&quot;#&quot;&gt;https://name-of-your-cosmos-db-account.table.cosmos.azure.com:443/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin-top: 4px;&quot;&gt;&lt;p data-renderer-start-pos=&quot;602&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Modify this URL, replacing &lt;em data-renderer-mark=&quot;true&quot;&gt;table.cosmos.azure.com &lt;/em&gt;with &lt;em data-renderer-mark=&quot;true&quot;&gt;documents.azure.com &lt;/em&gt;&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin-top: 4px;&quot;&gt;&lt;p data-renderer-start-pos=&quot;681&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Grab the value of PRIMARY KEY from &lt;em data-renderer-mark=&quot;true&quot;&gt;Connection String page&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin-top: 4px;&quot;&gt;&lt;p data-renderer-start-pos=&quot;742&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Grab the name of the root node on the &lt;em data-renderer-mark=&quot;true&quot;&gt;Data Explorer &lt;/em&gt;page, this will be your database name.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class=&quot;rich-media-item mediaSingleView-content-wrap image-center sc-caSCKo bEJxjw sc-fAjcbJ ihGUrv&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot; style=&quot;background-color: white; clear: both; color: #172b4d; float: none; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; margin: 24px auto; max-width: 100%; padding: 0px; transition: width 100ms ease-in 0s; white-space: pre-wrap; width: 458px;&quot; width=&quot;458&quot;&gt;&lt;div class=&quot;sc-eqIVtm kKrQEU&quot; style=&quot;margin: 0px; padding: 0px; position: relative;&quot;&gt;&lt;div class=&quot;sc-gRnDUn kiMzth&quot; data-collection=&quot;contentId-1983283219&quot; data-context-id=&quot;1983283219&quot; data-file-mime-type=&quot;image/png&quot; data-file-name=&quot;1.PNG&quot; data-file-size=&quot;46830&quot; data-height=&quot;316&quot; data-id=&quot;1c00bd28-2299-4b45-b744-d35d691d87a4&quot; data-node-type=&quot;media&quot; data-type=&quot;file&quot; data-width=&quot;458&quot; style=&quot;height: 0px; margin: 0px; padding: 0px; position: static; width: 458px;&quot;&gt;&lt;div class=&quot;sc-bZVNgQ LKshI&quot; data-testid=&quot;media-card-view&quot; style=&quot;border-radius: 3px; box-sizing: border-box; cursor: pointer; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Oxygen, Ubuntu, &amp;quot;Fira Sans&amp;quot;, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 14px; height: 316px; line-height: 22px; margin: 0px; max-height: 100%; max-width: 100%; padding: 0px; position: absolute; transition: all 0.3s ease 0s; width: 1320px;&quot;&gt;&lt;div role=&quot;presentation&quot; style=&quot;box-sizing: border-box; height: 910.742px; margin: 0px; max-height: 100%; max-width: 100%; padding: 0px; width: 1320px;&quot;&gt;&lt;div class=&quot;media-file-card-view sc-bOxvsH gKbysm&quot; data-test-media-name=&quot;1.PNG&quot; data-test-progress=&quot;1&quot; data-test-status=&quot;complete&quot; data-testid=&quot;media-file-card-view&quot; style=&quot;border-radius: 3px; box-sizing: border-box; display: flex; height: 316px; margin: 0px; max-height: 100%; max-width: 100%; overflow: hidden; padding: 0px; position: relative; width: 458px;&quot;&gt;&lt;img class=&quot;sc-kIPQKe cBrNsK&quot; data-testid=&quot;media-image&quot; draggable=&quot;false&quot; src=&quot;blob:https://tcmarin.atlassian.net/17197060-83df-4c0d-98d4-8805d3c573c3#media-blob-url=true&amp;amp;id=1c00bd28-2299-4b45-b744-d35d691d87a4&amp;amp;collection=contentId-1983283219&amp;amp;contextId=1983283219&amp;amp;mimeType=image%2Fpng&amp;amp;name=1.PNG&amp;amp;size=46830&amp;amp;width=458&amp;amp;height=316&quot; style=&quot;border: 0px; box-sizing: border-box; height: 316px; image-orientation: none; left: 229px; margin: 0px; object-fit: contain; padding: 0px; position: absolute; top: 158px; transform: translate(-50%, -50%);&quot; /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p data-renderer-start-pos=&quot;840&quot; style=&quot;background-color: white; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; letter-spacing: -0.005em; line-height: 1.714; margin: 0.75rem 0px 0px; padding: 0px; white-space: pre-wrap;&quot;&gt;2. Assemble the connection string as follows:&lt;/p&gt;&lt;p data-renderer-start-pos=&quot;887&quot; style=&quot;background-color: white; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; letter-spacing: -0.005em; line-height: 1.714; margin: 0.75rem 0px 0px; padding: 0px; white-space: pre-wrap;&quot;&gt;&lt;span class=&quot;code&quot; data-renderer-mark=&quot;true&quot; face=&quot;SFMono-Medium, &amp;quot;SF Mono&amp;quot;, &amp;quot;Segoe UI Mono&amp;quot;, &amp;quot;Roboto Mono&amp;quot;, &amp;quot;Ubuntu Mono&amp;quot;, Menlo, Consolas, Courier, monospace&quot; style=&quot;-webkit-box-decoration-break: clone; background-color: rgba(9, 30, 66, 0.08); border-radius: 3px; border-style: none; box-shadow: rgba(9, 30, 66, 0.08) -4px 0px 0px 0px, rgba(9, 30, 66, 0.08) 4px 0px 0px 0px; font-size: 13.712px; margin: 0px 4px; overflow: auto; padding: 2px 0px;&quot;&gt;AccountEndpoint=https://name-of-your-cosmos-db-account.documents.azure.com:443/;AccountKey=primary-key-goes-here;Database=Your-DB-Name&lt;/span&gt;&lt;/p&gt;&lt;p data-renderer-start-pos=&quot;1015&quot; style=&quot;background-color: white; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; letter-spacing: -0.005em; line-height: 1.714; margin: 0.75rem 0px 0px; padding: 0px; white-space: pre-wrap;&quot;&gt;3. Expand the root node (Your-DB-Name) and take a note of a table you want to export, for example &lt;em data-renderer-mark=&quot;true&quot;&gt;My-Table-Name&lt;/em&gt;&lt;/p&gt;&lt;p data-renderer-start-pos=&quot;1153&quot; style=&quot;background-color: white; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; letter-spacing: -0.005em; line-height: 1.714; margin: 0.75rem 0px 0px; padding: 0px; white-space: pre-wrap;&quot;&gt;4. Fill in the form on the &lt;em data-renderer-mark=&quot;true&quot;&gt;Source Information&lt;/em&gt; tab:&lt;/p&gt;&lt;div class=&quot;fabric-editor-block-mark fabric-editor-indentation-mark&quot; data-level=&quot;1&quot; style=&quot;background-color: white; clear: both; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; margin: 0px 0px 0px 30px; padding: 0px; white-space: pre-wrap;&quot;&gt;&lt;p data-renderer-start-pos=&quot;1205&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Import from: &lt;strong data-renderer-mark=&quot;true&quot;&gt;Azure Cosmos DB&lt;/strong&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;fabric-editor-block-mark fabric-editor-indentation-mark&quot; data-level=&quot;1&quot; style=&quot;background-color: white; clear: both; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; margin: 0px 0px 0px 30px; padding: 0px; white-space: pre-wrap;&quot;&gt;&lt;p data-renderer-start-pos=&quot;1235&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Connection String: use connection string created in step 2. Click &lt;strong data-renderer-mark=&quot;true&quot;&gt;Verify&lt;/strong&gt; button, it should work.&lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;fabric-editor-block-mark fabric-editor-indentation-mark&quot; data-level=&quot;1&quot; style=&quot;background-color: white; clear: both; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; margin: 0px 0px 0px 30px; padding: 0px; white-space: pre-wrap;&quot;&gt;&lt;p data-renderer-start-pos=&quot;1333&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Collection:  &lt;strong data-renderer-mark=&quot;true&quot;&gt;My-Table-Name&lt;/strong&gt; &lt;/p&gt;&lt;/div&gt;&lt;div class=&quot;fabric-editor-block-mark fabric-editor-indentation-mark&quot; data-level=&quot;1&quot; style=&quot;background-color: white; clear: both; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; margin: 0px 0px 0px 30px; padding: 0px; white-space: pre-wrap;&quot;&gt;&lt;p data-renderer-start-pos=&quot;1387&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Other fields: leave them to defaults, or you can optionally specify a query to limit the export&lt;/p&gt;&lt;/div&gt;&lt;p data-renderer-start-pos=&quot;1481&quot; style=&quot;background-color: white; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; letter-spacing: -0.005em; line-height: 1.714; margin: 0.75rem 0px 0px; padding: 0px; white-space: pre-wrap;&quot;&gt;5. Click &lt;strong data-renderer-mark=&quot;true&quot;&gt;Next&lt;/strong&gt; button to configure &lt;em data-renderer-mark=&quot;true&quot;&gt;Target Information&lt;/em&gt;&lt;/p&gt;&lt;h2 data-renderer-start-pos=&quot;1535&quot; id=&quot;Target-Information&quot; style=&quot;background-color: white; border-bottom-color: rgb(204, 204, 204); color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 1.42857em; font-weight: 500; letter-spacing: -0.008em; line-height: 1.2; margin: 1.8em 0px 0px; padding: 0px; white-space: pre-wrap;&quot;&gt;Target Information&lt;span class=&quot;heading-anchor-wrapper&quot; role=&quot;presentation&quot; style=&quot;height: 1.2em; margin-left: 6px; position: absolute;&quot;&gt;&lt;button class=&quot;sc-fBuWsC bDAhfN&quot; style=&quot;border-color: initial; border-style: none; border-width: initial; color: #42526e; cursor: pointer; display: inline; font-family: inherit; opacity: 0; outline: none; padding-left: 0px; padding-right: 0px; right: 0px; transform: translate(-8px, 0px); transition: opacity 0.2s ease 0s, transform 0.2s ease 0s;&quot;&gt;&lt;span aria-label=&quot;copy&quot; class=&quot;css-1i2mldy&quot; role=&quot;img&quot; style=&quot;display: inline-block; flex-shrink: 0; height: 24px; line-height: 1; width: 24px;&quot;&gt;&lt;svg height=&quot;24&quot; role=&quot;presentation&quot; viewbox=&quot;0 0 24 24&quot; width=&quot;24&quot;&gt;&lt;g fill-rule=&quot;evenodd&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M12.856 5.457l-.937.92a1.002 1.002 0 000 1.437 1.047 1.047 0 001.463 0l.984-.966c.967-.95 2.542-1.135 3.602-.288a2.54 2.54 0 01.203 3.81l-2.903 2.852a2.646 2.646 0 01-3.696 0l-1.11-1.09L9 13.57l1.108 1.089c1.822 1.788 4.802 1.788 6.622 0l2.905-2.852a4.558 4.558 0 00-.357-6.82c-1.893-1.517-4.695-1.226-6.422.47&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M11.144 19.543l.937-.92a1.002 1.002 0 000-1.437 1.047 1.047 0 00-1.462 0l-.985.966c-.967.95-2.542 1.135-3.602.288a2.54 2.54 0 01-.203-3.81l2.903-2.852a2.646 2.646 0 013.696 0l1.11 1.09L15 11.43l-1.108-1.089c-1.822-1.788-4.802-1.788-6.622 0l-2.905 2.852a4.558 4.558 0 00.357 6.82c1.893 1.517 4.695 1.226 6.422-.47&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/button&gt;&lt;/span&gt;&lt;/h2&gt;&lt;ol class=&quot;ak-ol&quot; data-indent-level=&quot;1&quot; style=&quot;background-color: white; box-sizing: border-box; color: #172b4d; display: flow-root; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; margin: 12px 0px 0px; padding: 0px 0px 0px 24px; white-space: pre-wrap;&quot;&gt;&lt;li&gt;&lt;p data-renderer-start-pos=&quot;1557&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Export To: &lt;b&gt;JSON file&lt;/b&gt;&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin-top: 4px;&quot;&gt;&lt;p data-renderer-start-pos=&quot;1581&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Choose &lt;em data-renderer-mark=&quot;true&quot;&gt;Local File&lt;/em&gt; radio button option, specify path, optionally select &lt;em data-renderer-mark=&quot;true&quot;&gt;Prettify JSON&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin-top: 4px;&quot;&gt;&lt;p data-renderer-start-pos=&quot;1670&quot; style=&quot;font-size: 1em; letter-spacing: -0.005em; line-height: 1.714; margin: 0px; padding: 0px;&quot;&gt;Click &lt;strong data-renderer-mark=&quot;true&quot;&gt;Next&lt;/strong&gt; to complete the wizard and run through the export. &lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p data-renderer-start-pos=&quot;1481&quot; style=&quot;background-color: white; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; letter-spacing: -0.005em; line-height: 1.714; margin: 0.75rem 0px 0px; padding: 0px; white-space: pre-wrap;&quot;&gt;&lt;em data-renderer-mark=&quot;true&quot;&gt;&lt;/em&gt;&lt;/p&gt;&lt;p data-renderer-start-pos=&quot;1736&quot; style=&quot;background-color: white; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; letter-spacing: -0.005em; line-height: 1.714; margin: 0.75rem 0px 0px; padding: 0px; white-space: pre-wrap;&quot;&gt;The JSON file should be saved in the directory you specified, or if you didn’t - in the folder you have started the data management tool from.&lt;/p&gt;&lt;div style=&quot;background-color: white; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Noto Sans&amp;quot;, Ubuntu, &amp;quot;Droid Sans&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; font-size: 16px; letter-spacing: -0.005em; line-height: 1.714; margin: 0.75rem 0px 0px; padding: 0px; text-align: left; white-space: pre-wrap;&quot;&gt;&lt;b&gt;UPDATE:&lt;/b&gt; importing from JSON into Azure Table storage in Cosmos DB also works. Same manipulations with connection string as described above for exporting scenario are needed. In addition, depending on your situation you may want to fill out extra parameters describing whether to regenerate Ids or not, etc.  &lt;a class=&quot;sc-iyvyFf kJXhAi&quot; data-renderer-mark=&quot;true&quot; href=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/import-data&quot; style=&quot;color: #0052cc; font-family: &amp;quot;Open Sans&amp;quot;; font-size: 15px; letter-spacing: -0.08px; line-height: 1.7; text-decoration-line: none;&quot; title=&quot;https://docs.microsoft.com/en-us/azure/cosmos-db/import-data&quot;&gt;The tutorial on using the data migration tool&lt;/a&gt;&lt;span style=&quot;color: #172b4d; font-family: &amp;quot;Open Sans&amp;quot;; font-size: 15px; letter-spacing: -0.08px; line-height: 1.7;&quot;&gt; covers these well.&lt;/span&gt;&lt;/div&gt;</description><link>http://neganov.blogspot.com/2021/05/migrate-data-from-cosmos-db-azure-table.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-8048211260290446459</guid><pubDate>Tue, 05 Jan 2021 02:04:00 +0000</pubDate><atom:updated>2021-01-04T18:31:00.919-08:00</atom:updated><title>Command-Line Utility to Validate LUDOWN Files </title><description>&lt;p&gt;Microsoft has released&lt;a href=&quot;https://docs.microsoft.com/en-us/composer/introduction&quot; target=&quot;_blank&quot;&gt; Bot Framework Composer&lt;/a&gt; in May 2020, and since then the tool was under active development. It allows to rapidly create rich conversational bots that leverage adaptive dialogs, language generation, skills and more.&lt;/p&gt;&lt;p&gt;In working with the Composer I have found that one of practical challenges was the &quot;teaching&quot; LUIS to recognize intents and entities: the labelling was quite verbose, the number of training examples was in dozens per intent (at least), and on top of that the documentation of the new&amp;nbsp;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/bot-service/file-format/bot-builder-lu-file-format?view=azure-bot-service-4.0&quot; target=&quot;_blank&quot;&gt;LUDOWN &lt;/a&gt;format could be improved, even though the format is by far more convenient than JSON.&lt;/p&gt;&lt;p&gt;I&#39;ve done some digging thanks to Composer being released as open source, and found a library that the Composer uses for parsing and validating the &lt;span style=&quot;font-family: courier;&quot;&gt;.lu&lt;/span&gt; files:&amp;nbsp;&lt;a href=&quot; https://github.com/microsoft/botframework-cli/tree/main/packages/lu   &quot; target=&quot;_blank&quot;&gt;@microsoft/bf-lu&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I thought it was easier to validate the&amp;nbsp;&lt;span style=&quot;font-family: courier;&quot;&gt;.lu&lt;/span&gt; files in CLI mode, so I ended up writing my own CLI to help with quick and verbose validation. As a &quot;bonus&quot; it can also create a temporary LUIS app from an &lt;span style=&quot;font-family: courier;&quot;&gt;.lu&lt;/span&gt; file since the&amp;nbsp;&lt;a href=&quot; https://github.com/microsoft/botframework-cli/tree/main/packages/lu   &quot; target=&quot;_blank&quot;&gt;@microsoft/bf-lu&lt;/a&gt;&amp;nbsp;validation may miss certain errors, which LUIS would complain about when attempting to create an app.&lt;/p&gt;&lt;p&gt;Here is the utility:&amp;nbsp;&lt;a href=&quot;https://www.npmjs.com/package/@softforte/lu&quot;&gt;https://www.npmjs.com/package/@softforte/lu&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;While the new &lt;a href=&quot;https://github.com/microsoft/botframework-cli&quot; target=&quot;_blank&quot;&gt;Bot Framework CLI&lt;/a&gt; offers similar and comprehensive features, I still find this utility handy for day-to-day LUIS development and hope that it will save you some troubleshooting time. Check it out!&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description><link>http://neganov.blogspot.com/2021/01/command-line-utility-to-validate-ludown.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-477342264573674629</guid><pubDate>Sun, 24 Nov 2019 23:36:00 +0000</pubDate><atom:updated>2019-11-24T16:33:30.973-08:00</atom:updated><title>Single Sign-On for Two Angular Apps with Local Accounts in Azure B2C Tenant</title><description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
In this day and age Single Sign-On (SSO) is thought of as a commodity, a &quot;flag&quot; an admin turns on somewhere, which makes logging into multiple related applications automatic to the end user. Indeed, mainstream identity providers support SSO for many protocols and across them for several years now.&lt;br /&gt;
&lt;br /&gt;
That&#39;s the mindset I had when I was approaching the SSO configuration in Azure B2C tenant. It ended up being a much more cumbersome task than I have expected, hence this post. While in a way it is a regurgitation of information already available on the subject on the Internet, I hope that the description of my &quot;SSO journey&quot; that follows will help reducing the research and experimentation time associated with SSO setup in Azure B2C that otherwise may be needed in order to get it working.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Applications and SSO objective&lt;/h3&gt;
&lt;div&gt;
I have two Angular 8 SPA applications hosted independently on two different domains &lt;i&gt;app1.mydomain.com&lt;/i&gt; and &lt;i&gt;app2.mydomain.com&lt;/i&gt;. I needed SSO between them, so that when a user signs into one, and then browses to another either in the same browser tab or in a new tab, the user should not be prompted for credentials.&lt;/div&gt;
&lt;div&gt;
Both applications are registered in the same Azure B2C tenant, and use the same policy. &lt;i&gt;Importantly&lt;/i&gt;, they only use local accounts for authentication, this was my constraint. I use &lt;a href=&quot;https://github.com/AzureAD/microsoft-authentication-library-for-js&quot; target=&quot;_blank&quot;&gt;MSAL&lt;/a&gt;&amp;nbsp;library for authentication/authorization. The application is redirecting users to the B2C policy&#39;s sign-in page.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
What I wish have worked but didn&#39;t...&lt;/h3&gt;
&lt;div&gt;
So I have started with using the built-in&amp;nbsp;&lt;b&gt;Sign up and Sign in&lt;/b&gt; user flow, also tried &lt;b&gt;Sign up and Sign in v2 &lt;/b&gt;flow with same results. If you go to properties of your flow in B2C web UI, there is a &lt;b&gt;Single sign-on configuration &lt;/b&gt;setting under &lt;b&gt;Session behavior&lt;/b&gt;. I&#39;ve set it to &lt;b&gt;Policy&lt;/b&gt;&amp;nbsp;as I had two applications sharing the same policy, then saved the user flow.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghIATMrNOs0p5I8TIwEv_XcyzYq1hDbRWhEPLQA0dHv0j5RojscnQWwHKp9vnGI_t9zYwp4zBukNFanyHJFaaQIiRwsbxLptC13QClU9XG4qv0fM9yUVlrWEw6mKsZLBg1EqtFVykCGYg/s1600/Blog_1.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;246&quot; data-original-width=&quot;694&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghIATMrNOs0p5I8TIwEv_XcyzYq1hDbRWhEPLQA0dHv0j5RojscnQWwHKp9vnGI_t9zYwp4zBukNFanyHJFaaQIiRwsbxLptC13QClU9XG4qv0fM9yUVlrWEw6mKsZLBg1EqtFVykCGYg/s1600/Blog_1.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It is when there was still no single sign-on I have realized that I was up for a longer ride here.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
What worked, but was the wrong path&lt;/h3&gt;
&lt;div&gt;
MSAL documentation describes the &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-js-sso&quot; target=&quot;_blank&quot;&gt;library&#39;s support for SSO&lt;/a&gt;. There are two ways to indicate SSO intention to MSAL library: by using login hint or session identifier (SID). Obviously the MSAL library supports this because the underlying identity provider (IdP) does, or it would be pointless.&lt;/div&gt;
&lt;div&gt;
So the idea here is to log in to the first application with user&#39;s credentials, then pass the SID or login hint to the second application, and B2C should authenticate the user to the second application without displaying prompts.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Cannot obtain SID from Azure B2C&lt;/h4&gt;
&lt;div&gt;
I tried hard, but could not find a way to get SID value from the Azure B2C IdP. I would think it is a claim emitted by the IdP in response to a successful sign on, which &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-claims-mapping&quot; target=&quot;_blank&quot;&gt;appears to be the case&lt;/a&gt; for Azure AD IdP, but I had not much luck with Azure B2C IdP.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Extra call to obtain login hint value&lt;/h4&gt;
&lt;div&gt;
The other option, the login hint I could work with. Just get the login claim from the identity or access JWT token returned by B2C and use it as a hint, right? Well, to my surprise the login claim was not present in JWT tokens returned by B2C IdP configured with a built-in Sign up or sign in policy.&lt;/div&gt;
&lt;div&gt;
That&#39;s OK, we can make an &lt;a href=&quot;https://docs.microsoft.com/en-us/graph/api/resources/profile-example?view=graph-rest-beta&quot; target=&quot;_blank&quot;&gt;MS Graph profile API&lt;/a&gt; call and get our login that way, paying with a few hundred milliseconds of page load time for this. Hmmm.....&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
MSAL Hurdles&lt;/h4&gt;
&lt;div&gt;
It is logical to start with &lt;a href=&quot;https://www.npmjs.com/package/@azure/msal-angular&quot; target=&quot;_blank&quot;&gt;MSAL-Angular&lt;/a&gt; if you are in an Angular application... Unfortunately the library is behind the MSAL core, and when it comes to SSO, and specifically passing on login hint, it just does not work.&lt;/div&gt;
&lt;div&gt;
While the MSAL Angular is appending the login hint as a &lt;i&gt;login_hint &lt;/i&gt;extra query parameter to the IdP call, the core Angular library expects the hint as a property of the &lt;a href=&quot;https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-core/src/AuthenticationParameters.ts&quot; target=&quot;_blank&quot;&gt;AuthenticationParameters&lt;/a&gt; object. This results in &lt;a href=&quot;https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-core/src/ServerRequestParameters.ts&quot; target=&quot;_blank&quot;&gt;ServerRequestParameters.isSSOParam()&lt;/a&gt; call returning false, resulting in the core MSAL library not understanding the login hints and not attempting to establish SSO.&lt;/div&gt;
&lt;div&gt;
I had to refuse from relying on MSAL-Angular and interact directly with MSAL core library. This got it to work, but as we will see later on, MSAL-Angular &quot;will be back&quot; on the scene.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Sharing the Login Hint between Apps&lt;/h4&gt;
&lt;div&gt;
OK, if I hardcode the login name as a login hint for the second application, then it works, I get the single sign-on as advertised, (or almost!) Now the challenge is to grab the username obtained upon successful logon to the first application through the Graph API call, and share it with the second application before the user authenticates to it.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
Since the apps are on separate domains they do not see each other&#39;s state, even if it is in&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;localStorage&lt;/span&gt;. Probably the simplest way around this is by using messaging API to communicate between the current window of the first app and a hidden iFrame pointing to the second app, making the latter set the username in its &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;localStorage &lt;/span&gt;in response to a received message to use later on as a login hint. Here is &lt;a href=&quot;https://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage&quot; target=&quot;_blank&quot;&gt;an example of this technique&lt;/a&gt;.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
At this point, the whole process was feeling too fragile and complex to me for what it does: too many obstacles, as if Microsoft was trying to implicitly warn me against this path &quot;hinting&quot; that there was a better way.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
PII and Sign Out Concerns&lt;/h4&gt;
&lt;div&gt;
And should I persevere and get over the MSAL-Angular incompatibility, the login hint sharing complexity, and accept the extra time that it takes to make a profile Graph call, I would still face the following issue: the login hint that I am sharing between the applications is what is classified as Personally Identifiable Information (PII). Immediately this becomes a concern from compliance perspective.&lt;/div&gt;
&lt;div&gt;
Last but not least there is a sign out complexity here: since in the above approach I store the login hint in &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;localStorage&lt;/span&gt;, I need to make sure to clear it when a user signs out, or closes her browser tabs.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
Under the pressure of the above considerations, which would have turned a seemingly simple identity solution to a needlessly complex subsystem with potential vulnerabilities, I had to look for an alternative.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Custom Identity Experience Framework Policies to the Rescue&lt;/h3&gt;
&lt;div&gt;
Once I&#39;ve understood that I&#39;ve exhausted the options available in the built-in policies (or user flows as they are also referred to), I had to turn to custom Identity Experience Framework (IEF) policies.&lt;/div&gt;
&lt;div&gt;
First things first, to take advantage of custom policies, one needs to follow this &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-get-started-custom?tabs=applications&quot; target=&quot;_blank&quot;&gt;Azure B2C preparation guidance&lt;/a&gt; word for word to get the environment ready for creation of custom policies.&lt;/div&gt;
&lt;div&gt;
Next, make sure to configure Azure Application Insights for monitoring B2C custom policies, as otherwise it will be quite hard to troubleshoot them.&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Get signInName Claim in Access Token&lt;/h4&gt;
&lt;div&gt;
I was looking for a way to avoid having to make the MS Graph call. I came across this great StackTrace thread, which &lt;a href=&quot;https://stackoverflow.com/questions/45699101/custom-b2c-policy-for-username-based-local-accounts/46282586#46282586&quot; target=&quot;_blank&quot;&gt;shows how to emit the signInName claim as a part of access and id tokens for the local Azure B2C accounts&lt;/a&gt;.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
The detailed instructions in the thread allow adding a &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;signInName &lt;/span&gt;claim to the tokens, which is quite helpful. And if you like me happen to hit the following error in process of getting it to work:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&amp;nbsp;&lt;span style=&quot;background-color: cornsilk; color: #242729; font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica neue&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif; font-size: 15px;&quot;&gt;Orchestration step &#39;1&#39; of in policy &#39;B2C_1A_signup_signin of tenant &#39;xxxxxxxxxx.onmicrosoft.com&#39; specifies more than one enabled validation claims exchange&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
Then the following thread contains &lt;a href=&quot;https://stackoverflow.com/questions/52726916/azure-ad-b2c-custom-policy-with-username-logon?noredirect=1&amp;amp;lq=1&quot; target=&quot;_blank&quot;&gt;the remedy&lt;/a&gt;.&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Single Sign-On &quot;Just Works&quot;&lt;/h4&gt;
&lt;div&gt;
Yes it just works as a much welcomed side effect. it was not obvious to me, as the thread was solving a different issue, namely the lack of username in the claims. I did have to modify one line in the &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;SelfAsserted-LocalAccountSignin-Username&lt;/span&gt;&amp;nbsp;Technical Profile in &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;TrustFrameworkExtensions.xml&lt;/span&gt;&amp;nbsp;(see the highlighted line below):&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtiwOIxt8u9fiEXsVrrmP52VikIl20d9EMCmWFRZ-Qhi04-8vjIsYDV0-okDaCWU_MaZvBnq-tXZ-xvcFDh6akrZ9pbjPhoKc9rkkZxukKzbVJCXi92p404MqU1tNdPWOp9tY0nkYBz1Y/s1600/Blog_2.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;168&quot; data-original-width=&quot;752&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtiwOIxt8u9fiEXsVrrmP52VikIl20d9EMCmWFRZ-Qhi04-8vjIsYDV0-okDaCWU_MaZvBnq-tXZ-xvcFDh6akrZ9pbjPhoKc9rkkZxukKzbVJCXi92p404MqU1tNdPWOp9tY0nkYBz1Y/s1600/Blog_2.PNG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This is all that I had to do. Now:&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;There is no need to share login hints and deal with associated compliance risks&lt;/li&gt;
&lt;li&gt;There is no need to make MS Graph API calls and deal with latency&lt;/li&gt;
&lt;li&gt;MSAL-Angular library &quot;is back in the picture&quot; and can be used again.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
Life is good!&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</description><link>http://neganov.blogspot.com/2019/11/single-sign-on-for-two-angular-apps.html</link><author>noreply@blogger.com (Ivan Neganov)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghIATMrNOs0p5I8TIwEv_XcyzYq1hDbRWhEPLQA0dHv0j5RojscnQWwHKp9vnGI_t9zYwp4zBukNFanyHJFaaQIiRwsbxLptC13QClU9XG4qv0fM9yUVlrWEw6mKsZLBg1EqtFVykCGYg/s72-c/Blog_1.PNG" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-1570093257655726921</guid><pubDate>Tue, 12 Nov 2019 18:38:00 +0000</pubDate><atom:updated>2019-11-12T10:45:08.968-08:00</atom:updated><title>MSAL acquireTokenSilent() and Azure B2C Permission Scopes</title><description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
One thing that was not obvious to me when securing an Angular app with Azure B2C tenant had to do with using permission scopes.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Let&#39;s say that you have authenticated through &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;loginRedirect()&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;, but need to make a call to &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;acquireTokenSilent()&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt; MSAL API from within your SPA app. Perhaps you are writing your own route guard or something... You need to pass an array of scopes to the method call. There are two ways to get this to work:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;1. When&amp;nbsp;&lt;/span&gt;you register your app in Azure B2C, it creates a scope for it named&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;user_impersonation&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;. You can take its value (&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;https://yourdomain.onmicrosoft.com/your-app-name/user_impersonation&lt;/span&gt;) and pass it to the&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;acquireTokenSilent()&lt;/span&gt;method as a single-item array. Or you can create your own scope instead...&lt;br /&gt;
&lt;br /&gt;
You may get an error back from the B2C when you call&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;acquireTokenSilent() &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;with this scope:&lt;/span&gt;&amp;nbsp;&lt;i&gt;AADB2C90205: This application does not have sufficient permissions against this web resource to perform the operation.&lt;/i&gt; To fix it you need to grant admin consent to the scope through the B2C tenant.&lt;br /&gt;
&lt;br /&gt;
2. There is another way. Check out how &lt;a href=&quot;https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/src/msal-guard.service.ts&quot; target=&quot;_blank&quot;&gt;MsalGuard&lt;/a&gt; class is implemented. It calls&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;acquireTokenSilent()&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;with a single-item array consisting of the app&#39;s &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;clientId&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;which we&#39;ve got through the app registration. That works without any additional consents.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
So both ways work, but there are important differences between them:&lt;br /&gt;
&lt;br /&gt;
In the former case, we are making a call to the&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;https://yourdomain.b2clogin.com/yourdomain.onmicrosoft.com/yourpolicy/oauth2/v2.0/authorize &lt;/span&gt;endpoint and pass 3 space-separated values in the &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;scope &lt;/span&gt;query string argument:&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;https://yourdomain.onmicrosoft.com/your-app-name/user_impersonation&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;your-policy-value&gt;openid profile&lt;/your-policy-value&gt;&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
In the latter case, the call to the endpoint is not made at all in my case. MSAL &quot;knows&quot; it is authorized as it has got the access token from preceding call to &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;loginRedirect()&lt;/span&gt;. Actually, let&#39;s take a look at what Fiddler shows when we call&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;loginRedirect()&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;, specifically I am interested in which scopes it passes on:&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;In the former case it is&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;your-policy-value&gt;https://yourdomain.onmicrosoft.com/your-app-name/user_impersonation openid profile&lt;/your-policy-value&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;In the latter case, it is only&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;openid profile&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Here is a good description of&amp;nbsp;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent&quot; target=&quot;_blank&quot;&gt;the meaning of these scopes&lt;/a&gt;.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;With that, here is my takeaway: MSAL converts the &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;clientId&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt; scope we pass in a call to its &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;loginRedirect()&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;acquireTokenSilent() &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;etc. calls to the&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;openid&amp;nbsp;&lt;/span&gt;and&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;profile&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;scopes known to Microsoft Identity Platform. It then also is smart enough to resolve calls for access token locally as long as it is valid.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;We can also present our SPA app as an API to the identity platform, create a permission for it, consent it, then acquire token for accessing it. But in a basic authentication scenario such as &quot;is user logged in or not?&quot;, there is no benefit in doing so.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;It may be useful if we have complex permissions in our application and want to be dynamically calling different permission scopes we define for various parts of our application.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
</description><link>http://neganov.blogspot.com/2019/11/msal-acquiretokensilent-and-azure-b2c.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-7971797660032490184</guid><pubDate>Wed, 26 Jun 2019 19:31:00 +0000</pubDate><atom:updated>2019-06-26T12:40:07.671-07:00</atom:updated><title>Extract and Inspect All SharePoint Solutions with PowerShell</title><description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Migration or upgrades of SharePoint content databases commonly involve provisioning of WSP solutions. At times you may find yourself in need to search for a particular feature GUID, which is burried somewhere inside of one of the dozens solution files that you have extracted from a farm in question.&lt;br /&gt;
&lt;br /&gt;
If you are on Windows Server 2012 or higher, you can leverage &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/expand&quot; target=&quot;_blank&quot;&gt;expand.exe&lt;/a&gt; &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;command to extract CAB files (WSP files are CAB files).&amp;nbsp; H&lt;/span&gt;ere is an one-liner PowerShell command to extract contents of your WSP solutions to respective folders:&lt;br /&gt;
&lt;!-- HTML generated using hilite.me --&gt;&lt;br /&gt;
&lt;div style=&quot;background: #111111; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;&quot;&gt;
&lt;pre style=&quot;line-height: 125%; margin: 0;&quot;&gt;&lt;span style=&quot;color: white;&quot;&gt;dir&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;*.wsp&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;|&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;%&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;{&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;New-Item&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;-Type&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;directory&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;-Path&lt;/span&gt; &lt;span style=&quot;color: #0086d2;&quot;&gt;&quot;.\$(&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #0086d2;&quot;&gt;_.Name.Remove(&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #0086d2;&quot;&gt;_.Name.Length - 4))&quot;&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;;&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;expand.exe&lt;/span&gt; &lt;span style=&quot;color: #fb660a;&quot;&gt;$_&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;.Name&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;-F:*&lt;/span&gt; &lt;span style=&quot;color: #fb660a;&quot;&gt;$_&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;.Name.Remove(&lt;/span&gt;&lt;span style=&quot;color: #fb660a;&quot;&gt;$_&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;.Name.Length&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;-&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;4)}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;b&gt;How to use:&lt;/b&gt; First place your solutions to a folder, CD to it, then run the above command, which will create a folder per solution extracted and dump its contents in there.&lt;br /&gt;
&lt;br /&gt;
Now you can quickly tell whether the feature Id you are after is among the ones extracted. For example, the following one-liner command will list all feature Ids, Titles as well as paths to &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Feature.xml&lt;/span&gt; files in a table format:&lt;br /&gt;
&lt;!-- HTML generated using hilite.me --&gt;&lt;br /&gt;
&lt;div style=&quot;background: #111111; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;&quot;&gt;
&lt;pre style=&quot;line-height: 125%; margin: 0;&quot;&gt;&lt;span style=&quot;color: white;&quot;&gt;dir&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;Feature.xml&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;-Recurse&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;|&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;%&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;{&lt;/span&gt; &lt;span style=&quot;color: #fb660a;&quot;&gt;$path&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #0086d2;&quot;&gt;[system.io.path]&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;::combine(&lt;/span&gt;&lt;span style=&quot;color: #fb660a;&quot;&gt;$_&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;.Directory,&lt;/span&gt; &lt;span style=&quot;color: #fb660a;&quot;&gt;$_&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;.Name);&lt;/span&gt; &lt;span style=&quot;color: #0086d2;&quot;&gt;[xml]&lt;/span&gt;&lt;span style=&quot;color: #fb660a;&quot;&gt;$doc&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;Get-Content&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;-Path&lt;/span&gt; &lt;span style=&quot;color: #fb660a;&quot;&gt;$path&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;;&lt;/span&gt; &lt;span style=&quot;color: #fb660a;&quot;&gt;$obj&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;New-Object&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;PSObject&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;-Property&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;@{Path=&lt;/span&gt;&lt;span style=&quot;color: #fb660a;&quot;&gt;$path&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;;&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;Id=&lt;/span&gt;&lt;span style=&quot;color: #fb660a;&quot;&gt;$doc&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;.Feature.Id;&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;Title=&lt;/span&gt;&lt;span style=&quot;color: #fb660a;&quot;&gt;$doc&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;.Feature.Title;};&lt;/span&gt; &lt;span style=&quot;color: #fb660a;&quot;&gt;$obj&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;}&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;|&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;select&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;Id,&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;Title,&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;Path&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Oh, and almost forgot that this may also be handy: you can use this line to dump all farm solution files to your current directory, once you make sure you are running it inside of elevated SP PowerShell session:&lt;br /&gt;
&lt;!-- HTML generated using hilite.me --&gt;&lt;br /&gt;
&lt;div style=&quot;background: #111111; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;&quot;&gt;
&lt;pre style=&quot;line-height: 125%; margin: 0;&quot;&gt;&lt;span style=&quot;color: white;&quot;&gt;(Get-SPFarm).Solutions&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;|&lt;/span&gt; &lt;span style=&quot;color: #fb660a; font-weight: bold;&quot;&gt;ForEach&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;-Object{&lt;/span&gt;&lt;span style=&quot;color: #fb660a;&quot;&gt;$var&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;(Get-Location).Path&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #0086d2;&quot;&gt;&quot;\&quot;&lt;/span&gt; &lt;span style=&quot;color: white;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #fb660a;&quot;&gt;$_&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;.Name;&lt;/span&gt; &lt;span style=&quot;color: #fb660a;&quot;&gt;$_&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;.SolutionFile.SaveAs(&lt;/span&gt;&lt;span style=&quot;color: #fb660a;&quot;&gt;$var&lt;/span&gt;&lt;span style=&quot;color: white;&quot;&gt;)}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Happy migrating!&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</description><link>http://neganov.blogspot.com/2019/06/extract-and-inspect-all-sharepoint.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-7352406374010494049</guid><pubDate>Mon, 17 Jun 2019 05:27:00 +0000</pubDate><atom:updated>2019-06-17T08:16:38.607-07:00</atom:updated><title>Azure AD Authentication and Graph API Access in Angular and ASP.NET Core</title><description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Wow, it&#39;s been quiet here... Enough with the intro ;) and onto the subject, which I find interesting and worthy of writing about...&lt;br /&gt;
&lt;br /&gt;
Consider this scenario, which I think makes a lot of practical sense: a web single-page application (SPA) authenticates users against Azure AD using&amp;nbsp;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-implicit-grant-flow&quot; target=&quot;_blank&quot;&gt;OpenID Connect implicit grant flow&lt;/a&gt;. Then some of the SPA&#39;s client-side components make queries to Graph API, while others hit its own server-side Web API.&lt;br /&gt;
&lt;br /&gt;
What follows is highlights from my experience implementing this scenario. These are the packages I was using:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;ASP.NET Core 3.0 preview 5&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Microsoft.IdentityModel.Tokens v5.3.0&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Angular v7.2.5&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-angular&quot; target=&quot;_blank&quot;&gt;MSAL for Angular&lt;/a&gt; v0.1.2&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/AzureAD/microsoft-authentication-library-for-js&quot; target=&quot;_blank&quot;&gt;MSAL for JS&lt;/a&gt; v0.2.1&lt;/li&gt;
&lt;/ul&gt;
Client-side components obtain access tokens from Azure AD and pass them along with calls to MS Graph API, or to the ASP.NET Web API. The former case is standard and well-explained, while the latter one is less so, and therefore more interesting. ASP.NET is configured to use bearer token authentication and creates user identity, which the rest of server-side logic can then use for its reasoning.&lt;br /&gt;
&lt;br /&gt;
When validating tokens coming down from client components of the application, I used code similar to the one shown below, inside of &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;ConfigureServices&lt;/span&gt;&amp;nbsp;method:&lt;br /&gt;
&lt;!-- HTML generated using hilite.me --&gt;&lt;br /&gt;
&lt;div style=&quot;background: #f8f8f8; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;&quot;&gt;
&lt;pre style=&quot;line-height: 125%; margin: 0;&quot;&gt;&lt;span style=&quot;color: #408080; font-style: italic;&quot;&gt;// Example of using Azure AD OpenID Connect bearer authentication.&lt;/span&gt;
services.AddAuthentication(sharedOptions =&amp;gt;
{
    sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =&amp;gt; 
{
    options.Authority = &lt;span style=&quot;color: #ba2121;&quot;&gt;&quot;https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111&quot;&lt;/span&gt;;
    options.TokenValidationParameters = &lt;span style=&quot;color: green; font-weight: bold;&quot;&gt;new&lt;/span&gt; TokenValidationParameters
    {
        ValidIssuer = &lt;span style=&quot;color: #ba2121;&quot;&gt;&quot;https://login.microsoftonline.com/11111111-1111-1111-1111-111111111111/v2.0&quot;&lt;/span&gt;,
        ValidAudiences = &lt;span style=&quot;color: green; font-weight: bold;&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #b00040;&quot;&gt;string&lt;/span&gt; [&lt;span style=&quot;color: #ba2121;&quot;&gt;&quot;22222222-2222-2222-2222-222222222222&quot;&lt;/span&gt;]
    };
});
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
where&amp;nbsp;&lt;span style=&quot;color: #ba2121;&quot;&gt;11111111-1111-1111-1111-111111111111&lt;/span&gt;&amp;nbsp;is the tenant Id, and&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #ba2121;&quot;&gt;22222222-2222-2222-2222-222222222222&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp;&lt;/span&gt;is the client Id of application registration.&lt;br /&gt;
&lt;br /&gt;
One of motivations for this post was the issue I kept getting with this authentication logic. I originally also had&amp;nbsp; an extra property setting on &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;TokenValidationParameters&lt;/span&gt; object:
&lt;!-- HTML generated using hilite.me --&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background: #f8f8f8; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;&quot;&gt;
&lt;pre style=&quot;line-height: 125%; margin: 0;&quot;&gt;IssuerSigningKey = &lt;span style=&quot;color: green; font-weight: bold;&quot;&gt;new&lt;/span&gt; X509SecurityKey(cert)
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The above line assigns&amp;nbsp;a public key encoded as X.509 certificate chain to be used later to decode a signature applied to the token by the Azure AD. Check out the &lt;a href=&quot;https://www.voitanos.io/blog/validating-azure-ad-generated-oauth-tokens&quot; target=&quot;_blank&quot;&gt;always-excellent insights from Andrew Connell&lt;/a&gt;, where he explains the need for the key-based signature checks when validating tokens and a mechanism to obtain the public key (the &quot;cert&quot; in the line of code above).&lt;br /&gt;
&lt;br /&gt;
My logic was however failing with the error &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;IDX10511&amp;nbsp;&lt;/span&gt;&quot;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Signature validation failed. Keys tried...&lt;/span&gt;&quot;, and my research into nuances of RSA algorithm implementation in ASP.NET and JSON Web Token encoding was fruitless until I have found &lt;a href=&quot;https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/1122&quot; target=&quot;_blank&quot;&gt;this thread&lt;/a&gt; on GitHub, and &lt;a href=&quot;https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/877#issuecomment-431113178&quot; target=&quot;_blank&quot;&gt;this related thread&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
It turned out that my signature validation was fine, although the line above was not needed, because the library I rely on for token validation, the &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Microsoft.IdentityModel.Tokens&lt;/span&gt;, takes care of it automatically by making a call to obtain the &lt;a href=&quot;https://login.microsoftonline.com/common/discovery/keys&quot; target=&quot;_blank&quot;&gt;Azure&amp;nbsp;&amp;nbsp;JSON Web Key Set&lt;/a&gt;, and deserializing response to .NET public keys used for signature checking.&lt;br /&gt;
&lt;br /&gt;
The actual wrong part had to do with my usage of access tokens: an access token obtained for a Microsoft Graph API resource happens to fail signature validation when used against a different resource (ASP.NET custom Web API in my case). This fact and that ASP.NET error message here&amp;nbsp; could be improved is covered in detail in the above GitHub threads.&lt;br /&gt;
&lt;br /&gt;
What I had originally, which I refer to as &quot;naive&quot; configuration, is shown on figure below.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNvB63873pgOiqZi6M-5jXPdgfGBxlFHDuMHzzk_YP5DSo9feKRhffqT_7PcRTOPFhq25SHUd2xpQjuUGroioVCG9LlwhhQneFJ4YOiy6pn7JvFHoBLp6em7mwvyEBTWyYBtf-3rRab-A/s1600/NaviveConfig.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;657&quot; data-original-width=&quot;917&quot; height=&quot;458&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNvB63873pgOiqZi6M-5jXPdgfGBxlFHDuMHzzk_YP5DSo9feKRhffqT_7PcRTOPFhq25SHUd2xpQjuUGroioVCG9LlwhhQneFJ4YOiy6pn7JvFHoBLp6em7mwvyEBTWyYBtf-3rRab-A/s640/NaviveConfig.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
On this image, I have an Azure app registration for my web application, requesting some graph permission scopes. Then during execution I acquire token on the client (1), use it when sending requests to Graph API (2), but fail to do the same against my ASP.NET Web API (3), which results in IDX10511 error.&lt;br /&gt;
&lt;br /&gt;
What is interesting here, is that:&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;This setup kind of makes sense: I have an app, it is registered, and it wants to use access token it gets from Azure to let its own API &quot;know&quot; that a user has logged in.&lt;/li&gt;
&lt;li&gt;The problem can be fixed by sending an ID token instead of access token in step (3). OpenID Connect protocol grants ID token upon login, which signifies authentication event, while access token signifies authorization event. ID token&#39;s signature is validated without errors, and ASP.NET creates a claims identity for the signed in user.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
What is not good about this design, is that the ID token is not meant to be used in this way. While one can choose to deviate from protocol&#39;s concept, it is not wise to do so without a compelling reason, since all tooling and third party libraries won&#39;t do the same.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Specifically, here are the problems I could identify with the above design:&lt;/div&gt;
&lt;div&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;OpenID Connect, and OAuth 2.0 by extension use different grant flows depending on types of clients used. For a web browser, it is &lt;a href=&quot;https://tools.ietf.org/html/rfc6749#section-4.2&quot; target=&quot;_blank&quot;&gt;Implicit Grant&lt;/a&gt;, then for a server-side client it is one of other flows, depending on a scenario. We are in essence trying to use a token issued to one audience, when calling another audience. In my example, the Angular SPA and Web API are on the same domain. If they were hosted on different domains, this issue would have been more obvious.&lt;/li&gt;
&lt;li&gt;Microsoft uses an OAuth 2.0 extension, and &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow&quot; target=&quot;_blank&quot;&gt;on-behalf-of flow&lt;/a&gt;&amp;nbsp;(aka OBO flow), which will be useful in scenarios when we decide to have our ASP.NET Web API enhanced by having it also access Graph API or another Microsoft cloud API. The current setup is not going to work with the OBO flow.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;br /&gt;
The figure below shows an improved design:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRX4nNhS6avAFF-XWX179gOdMkbe0s4f67LYiGxKtlWLxyqSKloolvNGSo4rUd9XNV6KA_jaFXsUzbytfSkoMWUKJGifth8YTW5yQftwOJ9_Ypdpuee5J5pGf__XxHSrYB8HLuOdAN-vc/s1600/CorrectedConfig.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;743&quot; data-original-width=&quot;917&quot; height=&quot;518&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRX4nNhS6avAFF-XWX179gOdMkbe0s4f67LYiGxKtlWLxyqSKloolvNGSo4rUd9XNV6KA_jaFXsUzbytfSkoMWUKJGifth8YTW5yQftwOJ9_Ypdpuee5J5pGf__XxHSrYB8HLuOdAN-vc/s640/CorrectedConfig.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
This time we treat server-side Web API as a separate application as far as Azure AD is concerned. We do have to make our SPA application acquire access token twice as shown in calls (1) and (3), doing it so for each audience: once for Graph, and second time - for our own API. Then both calls to Graph (2) and to our own API (4) succeed.&lt;br /&gt;
&lt;br /&gt;
Also, this design is fitting well with the OAuth paradigm. In fact, by the time we decide to augment our Web API and start making on-behalf-of calls from within it, we have already implemented its &quot;first leg&quot;.&lt;br /&gt;
&lt;br /&gt;
Lastly, a couple notes about the MSAL Angular configuration. Here is mine:&lt;br /&gt;
&lt;br /&gt;
&lt;!-- HTML generated using hilite.me --&gt;&lt;br /&gt;
&lt;div style=&quot;background: #f8f8f8; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;&quot;&gt;
&lt;pre style=&quot;line-height: 125%; margin: 0;&quot;&gt;    MsalModule.forRoot({
      clientID&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; environment.azureRegistration.clientId,
      authority&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; environment.azureRegistration.authority,
      validateAuthority&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: green; font-weight: bold;&quot;&gt;true&lt;/span&gt;,
      redirectUri&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; environment.azureRegistration.redirectUrl,
      cacheLocation&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ba2121;&quot;&gt;&#39;localStorage&#39;&lt;/span&gt;,
      postLogoutRedirectUri&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; environment.azureRegistration.postLogoutRedirectUrl,
      navigateToLoginRequestUrl&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: green; font-weight: bold;&quot;&gt;true&lt;/span&gt;,
      popUp&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: green; font-weight: bold;&quot;&gt;false&lt;/span&gt;,
&lt;span style=&quot;color: #408080; font-style: italic;&quot;&gt;//      consentScopes: GRAPH_SCOPES,&lt;/span&gt;
      unprotectedResources&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; [&lt;span style=&quot;color: #ba2121;&quot;&gt;&#39;https://www.microsoft.com/en-us/&#39;&lt;/span&gt;],
      protectedResourceMap&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; PROTECTED_RESOURCE_MAP,
      logger&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; loggerCallback,
      correlationId&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ba2121;&quot;&gt;&#39;1234&#39;&lt;/span&gt;,
      level&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; LogLevel.Verbose,
      piiLoggingEnabled&lt;span style=&quot;color: #666666;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: green; font-weight: bold;&quot;&gt;true&lt;/span&gt;
    }),
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
MSAL will automatically acquire access token right after an id token is acquired after calling &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;MsalService.loginPopup()&lt;/span&gt; with no scopes passed in as arguments. Commenting out or removing the &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;consentScopes&lt;/span&gt; config option results in MSAL defaulting to using apps&#39;s client Id as an audience and returning a somewhat useless access token with no scopes in it.&lt;br /&gt;
&lt;br /&gt;
I did this as I wanted to explicitly request separate access tokens for Graph and for my Web API. The way to do it is through passing scopes corresponding to an application to a call to&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;MsalService.acquireTokenSilent(scopes).&amp;nbsp;&lt;/span&gt;I am now thinking of changing it to pass the scopes of the Graph API&amp;nbsp; initially, so that my first access token is useful. For the second one I have no choice but to call the&amp;nbsp; &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;MsalService.acquireTokenSilent(myWebApi_AppScopes)&lt;/span&gt;again.&lt;/div&gt;
</description><link>http://neganov.blogspot.com/2019/06/azure-ad-authentication-and-graph-api.html</link><author>noreply@blogger.com (Ivan Neganov)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNvB63873pgOiqZi6M-5jXPdgfGBxlFHDuMHzzk_YP5DSo9feKRhffqT_7PcRTOPFhq25SHUd2xpQjuUGroioVCG9LlwhhQneFJ4YOiy6pn7JvFHoBLp6em7mwvyEBTWyYBtf-3rRab-A/s72-c/NaviveConfig.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-3924408979386408738</guid><pubDate>Wed, 26 Jun 2013 04:33:00 +0000</pubDate><atom:updated>2013-07-17T13:36:55.436-07:00</atom:updated><title>Thoughts about Building Multilingual Publishing Site on SharePoint 2013 - Part 3 of 3</title><description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
This is a third part of the series describing my experience in planning and building a multilingual WCM site on SharePoint 2013.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://neganov.blogspot.ca/2013/06/thoughts-about-building-multilingual.html&quot;&gt;Part 1&lt;/a&gt;&amp;nbsp;discusses basic requirements and architecture of the authoring site.&lt;br /&gt;
&lt;a href=&quot;http://neganov.blogspot.ca/2013/06/thoughts-about-building-multilingual_19.html&quot;&gt;Part 2&lt;/a&gt; &amp;nbsp;focuses on managed navigation for the authoring site.&lt;br /&gt;
This part discusses Cross-Site Publishing (XSP) and publishing sites.&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
A Quick Introduction to Cross-Site Publishing&lt;/h4&gt;
Microsoft has released a blog series describing in detail &lt;a href=&quot;http://blogs.office.com/b/sharepoint/archive/2013/04/12/use-cross-site-publishing-to-set-up-a-product-centric-website-in-sharepoint-server-2013.aspx&quot;&gt;how to set up a fictitious Contoso site leveraging XSP&lt;/a&gt;. Contoso is a product-centric web site using a concept of category pages and catalog item pages to illustrate the applicability of the XSP. A product sold at Contoso electronic store can be categorized by a hierarchy of categories. For example, a specific product, the &quot;Datum SLR Camera X142&quot;, is categorized as &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Cameras &amp;gt;&amp;gt; Digital Cameras&lt;/span&gt;. There are only &amp;nbsp;two kinds of pages that we need here: a product catalog item page showing product information, and a category page showing products matching the category. So, if you pick &quot;Cameras&quot; category from the navigation menu, you will see products qualifying as cameras; if you pick &quot;Digital Cameras&quot; - you will see a narrower set of products qualifying as digital cameras. Regardless of which category in the hierarchy you pick the principal is the same. So we need to figure the current category and render matching products for it. Category pages do exactly that. Next, you click on a specific product listed by the current view of the category page, and then the product details are rendered by the catalog item page, which accepts a unique product identifier. And so you can surface the entire product database on the SharePoint site by using just two pages - a category page and catalog item page.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
There are two &quot;magic ingredients&quot; here. Firstly, there is the ability to publish and consume lists as catalogs. What this does is it creates a search result source in the consuming site, and optionally pins the terms from the term set used to categorize the catalog as navigation terms to the navigation term set of the site consuming the catalog. Also behind the scenes, the&amp;nbsp;&lt;span style=&quot;font-family: &#39;Segoe UI&#39;, sans-serif; font-size: 9pt;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: small;&quot;&gt;Microsoft.SharePoint.Publishing.Navigation.TaxonomyNavigation&lt;/span&gt; &lt;span style=&quot;font-family: inherit; font-size: small;&quot;&gt;class callable&lt;/span&gt; &lt;span style=&quot;font-family: inherit; font-size: small;&quot;&gt;from&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;SharePoint.Publishing.HttpPublishingModule&lt;/span&gt;&amp;nbsp;class &quot;becomes aware&quot; of how to detect requested URLs&amp;nbsp;constructed of categories and unique identifiers aka &quot;Friendly URLs&quot; on this site, and route them to appropriate category or catalog item pages. Secondly, it is that the pages &quot;can be made aware&quot; of their current context and use this knowledge when issuing search queries for catalog items. This ability is there thanks to &lt;a href=&quot;http://technet.microsoft.com/en-us/library/jj683123.aspx&quot;&gt;a set of well-known search query variables&lt;/a&gt; available to developers or information workers placing search web parts on pages.&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Cross-Site Publishing as a Web Content Management Approach&lt;/h4&gt;
Things started to look a bit confusing when I tried to apply the XSP concept to the site publication scenario that I have described in Part 1. Here are the hurdles I faced:&lt;br /&gt;
&lt;br /&gt;
1. A web site page&amp;nbsp;is hard to fit in the product-centric model described above, because a page can often be both a category and a catalog item at the same time. Commonly sites use section landing pages, the ones the top navigation menus point at, which contain content and at the same time act as logical parents to child pages down the site map hierarchy. Let&#39;s say we make a landing page to be an XSP catalog category page. Then, according to the product-centric model we access its child pages as we would access catalog items &amp;nbsp;- by clicking on a list of these pages rendered by our landing page. Well, this is usually not how information architects expect users to navigate their web sites, unless they are online product stores. What we often need instead is navigation menus, the familiar top navigation and current navigation controls to let us access all pages on the site.&lt;br /&gt;
&lt;br /&gt;
2. Now think for a second about the managed navigation discussed in Part 2 and the requirement we had about maintaining the fidelity between authoring and publishing sites. Every page on the authoring site has a corresponding term used for navigation and forming a friendly URL. Because we use the managed navigation on the authoring site, we get our top and current navigation menus populated by these terms. We want the same behavior on the publishing site. This brings the question: &quot;Which pages should be the category pages, and which ones should be the catalog item pages?&quot; If we were to follow the classical product-centric approach, and designate pages corresponding to the top-level nodes as category pages, and leaf pages as item pages, we would lose the drop-down menus on the publishing site:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6znp7s8qFq7jwDWbfj4EwPQgnGgvhCpP3VB1wI8JI8obCxaQ08iLcjC3C2oo-CL-oMrbnfG5t5Ol5uSC2lf2qBhyphenhyphenfEiOYPEPoyXM2wplYFWm2sMJCNwiqiMgBdloLHosTBl0EjjJ9ec8/s1600/Authoring+and+Publishing+Term+Sets+-+Attempt+1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;465&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6znp7s8qFq7jwDWbfj4EwPQgnGgvhCpP3VB1wI8JI8obCxaQ08iLcjC3C2oo-CL-oMrbnfG5t5Ol5uSC2lf2qBhyphenhyphenfEiOYPEPoyXM2wplYFWm2sMJCNwiqiMgBdloLHosTBl0EjjJ9ec8/s640/Authoring+and+Publishing+Term+Sets+-+Attempt+1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
When I say &quot;designate&quot; I mean that we &quot;tag&quot; the pages with the terms or, in other words, assign term values to corresponding pages by setting managed metadata fields of these pages.&lt;br /&gt;
&lt;br /&gt;
3. On another extreme, if we tag each and every page on the authoring site with a term, then when we consume the pages library catalog, all our pages will logically become the category pages. How do we now render the catalog item information?&lt;br /&gt;
&lt;br /&gt;
We resolved the confusion by tagging all the pages on the authoring site, effectively making all of them to become the category pages on the publishing site, and modified their page layouts to make them simultaneously act as catalog item pages. This looked like a promising strategy, because by making all of our pages into the category pages, we would get exactly the same top and current navigation elements as on the authoring site, for free. The only thing left to do was to make the category pages render catalog item information - should be doable on a search-driven site.&lt;br /&gt;
&lt;br /&gt;
If you examine an automatically created content item page, you will see that it is based on a page layout, which in turn leverages &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.office.server.search.webcontrols.catalogitemreusewebpart.aspx&quot;&gt;Catalog Item Reuse (CIR) web parts&lt;/a&gt;. &lt;span lang=&quot;EN-CA&quot; style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;Each
CIR web part renders contents of a specific managed search property specified
in the &lt;/span&gt;&lt;span class=&quot;CodeChar&quot;&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-size: 10.0pt; line-height: 115%; mso-ansi-language: EN-CA; mso-bidi-font-size: 11.0pt; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin;&quot;&gt;SelectedPropertiesJSON&lt;/span&gt;&lt;/span&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt; property. Provided that the managed properties
correspond to the columns on the authoring site, this results in rendering the
same content on the publishing page as on the authoring page. Below is an
example of a CIR web part rendering a value of a managed property corresponding
to the Page Content column.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiglCY4jxLe6i9L_PGux8mKQdmhOYLbZqLjPivpl4CLfAyspM12VyPWvgOCoZhXC6MLyKZN8nb5hGLINcHouHTn78tmUkC2vbkpH_b2Y-v7OVoXnJuB4rgZr2U1-tQMCh-sxZo8EE6vClg/s1600/Snippet+1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiglCY4jxLe6i9L_PGux8mKQdmhOYLbZqLjPivpl4CLfAyspM12VyPWvgOCoZhXC6MLyKZN8nb5hGLINcHouHTn78tmUkC2vbkpH_b2Y-v7OVoXnJuB4rgZr2U1-tQMCh-sxZo8EE6vClg/s1600/Snippet+1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span lang=&quot;EN-CA&quot; style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;Note
that the value of &lt;/span&gt;&lt;span class=&quot;CodeChar&quot;&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-size: 10.0pt; line-height: 115%; mso-ansi-language: EN-CA; mso-bidi-font-size: 11.0pt; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;UseSharedDataProvider&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;property should be set to &lt;/span&gt;&lt;span class=&quot;CodeChar&quot;&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 10.0pt; line-height: 115%; mso-ansi-language: EN-CA; mso-bidi-font-size: 11.0pt; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin;&quot;&gt;True&lt;/span&gt;&lt;/span&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt; on
all CIR web parts on the page except for one, which serves as a data provider
for the rest of them. All CIR web parts on a page form what’s called a &lt;i&gt;query group&lt;/i&gt;, with one CIR web part
acting as a data provider, and the rest of them – as data consumers. The data
provider CIR web part in addition to &lt;/span&gt;&lt;span class=&quot;CodeChar&quot;&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-size: 10.0pt; line-height: 115%; mso-ansi-language: EN-CA; mso-bidi-font-size: 11.0pt; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin;&quot;&gt;S&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;electedPropertiesJSON&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt; property has &lt;/span&gt;&lt;span class=&quot;CodeChar&quot;&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: 10.0pt; line-height: 115%; mso-ansi-language: EN-CA; mso-bidi-font-size: 11.0pt; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin;&quot;&gt;DataProviderJSON&lt;/span&gt;&lt;/span&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt; property set as shown in the following example.&lt;/span&gt;&lt;br /&gt;
&lt;span lang=&quot;EN-CA&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpX_arok6du4QTkJvrjsmLfqdc1dcjt6Wf0XPxoIHjs4xVNSeTXjdxJBXdFysCtLaInPmbJnjJB-mMlQ1bXW2eCvU7W3pAFZ53uCJ-cw9tF_ADIaDwGj_tbYEi1EIFdqOpGevJBbawNm4/s1600/Snippet+2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpX_arok6du4QTkJvrjsmLfqdc1dcjt6Wf0XPxoIHjs4xVNSeTXjdxJBXdFysCtLaInPmbJnjJB-mMlQ1bXW2eCvU7W3pAFZ53uCJ-cw9tF_ADIaDwGj_tbYEi1EIFdqOpGevJBbawNm4/s1600/Snippet+2.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span lang=&quot;EN-CA&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span lang=&quot;EN-CA&quot;&gt;The value of &lt;/span&gt;&lt;span class=&quot;CodeChar&quot;&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-size: 10.0pt; line-height: 115%; mso-bidi-font-size: 11.0pt;&quot;&gt;DataProviderJSON&lt;/span&gt;&lt;/span&gt;&lt;span lang=&quot;EN-CA&quot;&gt; property sets properties on objects of &lt;/span&gt;&lt;span class=&quot;CodeChar&quot;&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-size: 10.0pt; line-height: 115%; mso-bidi-font-size: 11.0pt;&quot;&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/jj267485.aspx&quot;&gt;DataProviderScriptWebPart&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang=&quot;EN-CA&quot;&gt; type.
The key properties here are:&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;MsoListParagraphCxSpFirst&quot; style=&quot;mso-list: l0 level1 lfo1; text-indent: -.25in;&quot;&gt;
&lt;/div&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;span class=&quot;CodeChar&quot; style=&quot;text-indent: -0.25in;&quot;&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-size: 10.0pt; line-height: 115%; mso-bidi-font-size: 11.0pt;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;QueryTemplate&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;text-indent: -0.25in;&quot;&gt; – defines keyword search filtering criterion using a query variable
such as &lt;/span&gt;&lt;span class=&quot;CodeChar&quot; style=&quot;text-indent: -0.25in;&quot;&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-size: 10.0pt; line-height: 115%; mso-bidi-font-size: 11.0pt;&quot;&gt;{URLTOKEN.1}&lt;/span&gt;&lt;/span&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;text-indent: -0.25in;&quot;&gt; in the above example.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;CodeChar&quot; style=&quot;text-indent: -0.25in;&quot;&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-size: 10.0pt; line-height: 115%; mso-bidi-font-size: 11.0pt;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;SourceID&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;text-indent: -0.25in;&quot;&gt; – a unique ID of the search result source corresponding to the
catalog being consumed. The search result source is created automatically when
the catalog is connected to.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;CodeChar&quot; style=&quot;text-indent: -0.25in;&quot;&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;font-size: 10.0pt; line-height: 115%; mso-bidi-font-size: 11.0pt;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Scope&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span lang=&quot;EN-CA&quot; style=&quot;text-indent: -0.25in;&quot;&gt; – a URL of the catalog source list.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;An easy way to get started with the CIR web
parts is to let SharePoint auto-generate catalog Category and Item pages and
page layouts when connecting to a catalog, then harvest the web part markup
from the auto-generated page layouts.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;So conceptually the problem is solved now: we can create our own page layout and then a category page based on it, and configure CIR web parts to select the managed properties of interest from the catalog. &amp;nbsp;If the markup of the page layout and master page is the same as on the authoring site, then CIR web parts essentially replace the content fields, and the publishing page appears visually identical to its authoring counterpart, and the navigation is &amp;nbsp;working, except that only a single page exists on the publishing site. Pretty cool.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;Now let&#39;s consider some practical aspects of getting the XSP-based publishing site up and running.&lt;/span&gt;&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;XSP Navigation Term Set and Vanity Names&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;To properly publish pages library as a catalog we need to designate a field uniquely identifying each page, and a managed metadata field used for page categorization. We have come up with two fields for this purpose and defined them at the site collection level in order to make sure the required managed properties get created automatically when we do a full crawl:&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;Vanity Name - this is a text field where we enter a unique friendly name of each page.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;&quot;&gt;XSP Category &amp;nbsp;- is a managed metadata field using a new term set named XSP Navigation.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 15px; line-height: 17px;&quot;&gt;On the authoring site we are creating and managing a master term set, which is applied to the source variation, then its terms are getting re-used and translated on the target variations. We certainly want to avoid duplication of the effort required to manage the terms when we tag our pages, but we cannot reuse the existing master term set, because SharePoint complains about it being already used when we consume the catalog. We need a new term set, and so we just pin top-level terms with children from the master Site Navigation Term set. Another important thing we need to do is to create a Root term in the new XSP Navigation term set so that we could hook up to it when we consume the catalog. This is illustrated on the figure below:&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHOiumHRrBs4jvQNQWQo16Z4nPhBO8nOvIv4-odVI0hUGZl1AKTlqW8wkV0TTWA8caP-9iXUvMCoG5sGxBz0DYo9BhUprHRhwSpPbJVUZ58J1s8rnevmYTKyWreZt-gH3w3HjMUfQz1KA/s1600/XSP+and+Navigation+Term+Sets.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;425&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHOiumHRrBs4jvQNQWQo16Z4nPhBO8nOvIv4-odVI0hUGZl1AKTlqW8wkV0TTWA8caP-9iXUvMCoG5sGxBz0DYo9BhUprHRhwSpPbJVUZ58J1s8rnevmYTKyWreZt-gH3w3HjMUfQz1KA/s640/XSP+and+Navigation+Term+Sets.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 15px; line-height: 17px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;The convention we have used was that the &amp;nbsp;value of the Vanity Name field must match the value of the XSP Category Node for any given page on the site. This is important because it allows us to structure the query we issue from the data provider CIR web part as follows:&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;line-height: 16px;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;VanityNameOWSTEXT:{URLTOKEN.1}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
This query means &quot;select items where the value of the Vanity Name managed property contains the last segment of the current URL&quot;. So for the URL &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;http://www.softforte.com/softforte-corporate/about-us&lt;/span&gt; the &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;{URLTOKEN.1} == &quot;about-us&quot;&lt;/span&gt;, and due to the convention the &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;Vanity Name == &quot;about-us&quot;&lt;/span&gt; as well. The page is a category page in the XSP terms, and has a managed term created when we were consuming the catalog, which points at the URL &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;/softforte-corporate/about-us&lt;/span&gt;. This is exactly how we have hacked the category pages, giving them the ability to act as catalog item pages at the same time.&lt;br /&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;Navigation Translation on Publishing Sites&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;The terms used on the publishing sites are already translated by virtue of setting their labels for each culture, and customizing term-driven page settings down the re-use chain originating from the authoring source variation&#39;s navigation term set. The challenge however exists with regards to selecting the proper translation for the corresponding publishing site.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;In order to localize content and navigation of a variations-based site you do not need to install a language pack. The locale such as fr-CA is selected when a variation label is created. This is different for a publishing site, which does not rely on variations. The only way I found to get terms to translate to French was to install the French language pack, then create a site collection using the French target language template. &amp;nbsp;In order to still manage the site in English, the Alternate Language can be set under Site Settings &amp;gt;&amp;gt; Language Settings. This forces the SharePoint to read the language preferences the browser is sending to it. So if my preferred language is English, I will see the the managed navigation in English, if it is French then it will automatically use the French term translation if one is available. T&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 15px; line-height: 17px;&quot;&gt;he limitation here is the language packs - we can only publish in the languages supported by language packs, at least to the best of my knowledge.&lt;/span&gt;&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;Do I Really Need a Single Page on My Publishing Site?&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;Since most of the real-life sites use multiple page layouts, the same page layouts need to be mirrored &amp;nbsp;over to the publishing sites and CIR web parts configured there instead of content fields. Then, if all the content on the authoring site is static, i.e. there are no web parts, just the content fields, then we can simply create catalog category pages, one page per page layout, and that would be all we need to do.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;Real web sites use web parts to render dynamic content. Since web parts are not stored in index, cross-site publishing will not render them. This means that the web parts need to be re-created on the publishing site. Needless to say that since publishing and authoring sites have different security requirements, the web parts would need to be created differently on publishing and authoring sites.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;Where ever possible, we should therefore utilize Content Search (CS)web parts, which would get the content from the SharePoint index just as the CIR web parts do. We were able to meet 100% of requirements to the dynamic elements on the site using CS web parts, thanks to their great flexibility. When a CS web part is used on an authoring site page, it runs in a different context than when it is&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;used on a publishing site. Therefore &amp;nbsp;it needs to be adapted to the publishing site, and simply copying it over won&#39;t work. Most of the time the adaptation is quite simple however, as the same managed properties are available on both sites, and therefore the search queries are similar.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 15px; line-height: 17px;&quot;&gt;How big of an issue is the fact that the dynamic elements on content pages need to be recreated on a publishing site? We found it to be quite manageable in our case.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 15px; line-height: 17px;&quot;&gt;The level of work duplication was minor for us,&lt;/span&gt;&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 15px; line-height: 17px;&quot;&gt;&amp;nbsp;although it depends on how many dynamic web parts are you planning for. A general corollary here is you need to plan thoroughly your pages in advance, to get the most out of the XSP.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 15px; line-height: 17px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Calibri, sans-serif; font-size: 15px; line-height: 17px;&quot;&gt;So while you could only use a single category page to render all pages based on a specific page layout, once you add dynamic web parts to the mix you need to create a new page in the publishing site for each corresponding authoring page with the web part. If the same web part is used on multiple pages, then it makes sense to embed it into publishing page layout directly in order to reduce the number of publishing pages you need to create.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Here is an example of how an authoring page corresponds with a &amp;nbsp;publishing page layout and a publishing page:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEismoXt7mOO1pWMOwQBbfs4P6TPXIoS6QI82NMsHQ6HlcU6VYYbve7taYwMLx0wLyuOX7nJjid6d1lg8ahOwFvwoKPZQdiPa37fpSVNfLSneI-5Ot4U_uhYLhTofsadWbzn3oNEiz877mo/s1600/3+Pages.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEismoXt7mOO1pWMOwQBbfs4P6TPXIoS6QI82NMsHQ6HlcU6VYYbve7taYwMLx0wLyuOX7nJjid6d1lg8ahOwFvwoKPZQdiPa37fpSVNfLSneI-5Ot4U_uhYLhTofsadWbzn3oNEiz877mo/s1600/3+Pages.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
On the above illustration, the legend is as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Purple color - content fields;&lt;/li&gt;
&lt;li&gt;Gray color - items inherited from a master page or page layout;&lt;/li&gt;
&lt;li&gt;Green color - web parts;&lt;/li&gt;
&lt;li&gt;Blue color - navigation control.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
The Inconvenient Result Source ID Value&lt;/h4&gt;
In the code snippet above the&amp;nbsp;&lt;span style=&quot;line-height: 16px;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;DataProviderJSON&lt;/span&gt;&lt;/span&gt;&amp;nbsp;property included a &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;SourceID &lt;/span&gt;parameter, which is the ID of a Search Result Source that is automatically configured when a catalog is consumed on the site. This property controls the scope of search queries issued by the web parts participating in the query group by adding filtering to select items from the list &amp;nbsp;with a specific ID and source web site URL. If you let the SharePoint create catalog item and category pages automatically when connecting to a catalog, this Source ID would be embedded in the page layout. Pretty inconvenient, especially as each time you re-connect the Source ID changes, and you cannot control it by exporting and importing site search configuration.&lt;br /&gt;
&lt;br /&gt;
After researching alternatives, we ended up using a provisioning script, which would first provision the publishing page layouts, then determine the result source ID, then check out the layouts, replace the ID in them, and check them back in...&lt;a href=&quot;http://neganov.blogspot.ca/2007/12/master-page-deployment-through-features.html&quot;&gt; like I&#39;ve done in the old days&lt;/a&gt;...&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
The Big Picture&lt;/h4&gt;
Getting back to our business requirements described in &lt;a href=&quot;http://neganov.blogspot.ca/2013/06/thoughts-about-building-multilingual.html&quot;&gt;Part 1&lt;/a&gt;, by utilizing the XSP approach we have created 3 publishing sites, one for each variation. The publishing site corresponding to the source variation is not accessible to the Internet users, but the information workers can preview English-level content on it exactly how it would appear to anonymous visitors on the live site. This architecture required us to turn Pages libraries on each variation label into catalogs, and consume the catalogs from the corresponding publishing sites, meaning that we had to have 3 different setups of the publishing page layouts, pages and catalogs. This may seem like a lot, yet since the pages set up on the publishing sites are not created by information workers, but instead are viewed as a part of the application provisioning exercise, and since they are almost identical across the three publishing sites, it was a quite reasonable decision.&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Conclusion&lt;/h4&gt;
The XSP is new, and it can be difficult to depart from the product-centric model used in Microsoft demos. Practically it all gets down to retrieving content from a search index, something we&#39;ve been doing for a while with SharePoint. The XSP takes the concept to the next level of manageability and implementation convenience, and does not require us to write compiled code any more to take advantage of it. And of course SharePoint sticks to its traditions: planning is key to properly setting up the publishing sites and minimizing duplication of effort. As a result we get modern-looking dynamic publishing web sites and an enterprise-class content management process.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</description><link>http://neganov.blogspot.com/2013/06/thoughts-about-building-multilingual_25.html</link><author>noreply@blogger.com (Ivan Neganov)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6znp7s8qFq7jwDWbfj4EwPQgnGgvhCpP3VB1wI8JI8obCxaQ08iLcjC3C2oo-CL-oMrbnfG5t5Ol5uSC2lf2qBhyphenhyphenfEiOYPEPoyXM2wplYFWm2sMJCNwiqiMgBdloLHosTBl0EjjJ9ec8/s72-c/Authoring+and+Publishing+Term+Sets+-+Attempt+1.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-7752559781758175596</guid><pubDate>Wed, 19 Jun 2013 21:27:00 +0000</pubDate><atom:updated>2013-06-25T21:34:16.559-07:00</atom:updated><title>Thoughts about Building Multilingual Publishing Site on SharePoint 2013 - Part 2 of 3</title><description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
This is a second part of the series describing my experience in planning and building a multilingual WCM site on SharePoint 2013.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://neganov.blogspot.ca/2013/06/thoughts-about-building-multilingual.html&quot;&gt;Part 1&lt;/a&gt; discusses basic requirements and architecture of the authoring site.&lt;br /&gt;
This part focuses on managed navigation for the authoring site.&lt;br /&gt;
&lt;a href=&quot;http://neganov.blogspot.ca/2013/06/thoughts-about-building-multilingual_25.html&quot;&gt;Part 3&lt;/a&gt; discusses cross-site publishing and publishing sites.&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Term Set Organization&lt;/h4&gt;
SharePoint 2013 Managed Navigation is at the heart of our solution. We have defined a global term set containing the navigation hierarchy. The terms at the top level correspond to the items at the top navigation bar of the site:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHFyvRPIiU15Sa_HmfyZ1yJtK1TuH6T0RBJUjTPONXa0IqwPrMYNy_MEXFh1-pc2PKDjgLjd6DZnEBplAPPAl46dJhjnTI2qnpIpYBII5_QAzVo_acejMBZdzEqoPNVm7Sg-QJqILJdus/s1600/Relationship+between+terms+and+top+navigation.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;372&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHFyvRPIiU15Sa_HmfyZ1yJtK1TuH6T0RBJUjTPONXa0IqwPrMYNy_MEXFh1-pc2PKDjgLjd6DZnEBplAPPAl46dJhjnTI2qnpIpYBII5_QAzVo_acejMBZdzEqoPNVm7Sg-QJqILJdus/s640/Relationship+between+terms+and+top+navigation.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.blogger.com/&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; unselectable=&quot;on&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
So there is no single root or parent term for the global navigation term set, rather - there are several top-level terms. It is important to note that every single page needs to have a corresponding term in the term set pointing at it:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoHSWrQGlxQc2H8fWDLUqLESFX4KakWvht4N2UamR3rdXx9MvXYNh4eCLCT6d6H-HY4FveWMWnGy12cya9R26B7ncP8EEK0-nU8MQsVxvxmrJrQhrKKeVzJsglgjBIdUDkn4pn4nUmq5w/s1600/Term+to+URL+Mapping.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;297&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoHSWrQGlxQc2H8fWDLUqLESFX4KakWvht4N2UamR3rdXx9MvXYNh4eCLCT6d6H-HY4FveWMWnGy12cya9R26B7ncP8EEK0-nU8MQsVxvxmrJrQhrKKeVzJsglgjBIdUDkn4pn4nUmq5w/s640/Term+to+URL+Mapping.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, on the&amp;nbsp;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Site Settings &amp;gt;&amp;gt; Navigation&lt;/span&gt;&amp;nbsp;configuration page we set the managed navigation to point at the global navigation term set for the source variation label. The root site of the site collection is still using structured navigation. This site is not going to be exposed publicly and is logically above the top level the Internet users will see.&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Terms Sharing (Reuse)&lt;/h4&gt;
When variations are created by clicking on&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt; Site Settings &amp;gt;&amp;gt; Variation Labels &amp;gt;&amp;gt; Create Hierarchies&lt;/span&gt; &amp;nbsp;the background job will automatically create site collection-scoped term sets and re-use the terms from the source term set to the target term sets. Going forward, when an information worker publishes a new page to the source variation label, the&amp;nbsp;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Variations Propagate Page Job Definition&lt;/span&gt;&amp;nbsp;background job would propagate the page, and if the page is pointed at by a term, it will re-use this term from the target variations site (&lt;i&gt;Term reuse scenario A&lt;/i&gt;). If a page is published first and propagated to target variations, and a term pointing at it is created at a later time, then the term will not be reused on target variations and would need to be manually reused by selecting&amp;nbsp;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Reuse Terms&lt;/span&gt;&amp;nbsp;option on the parent term of the term to be reused.&lt;br /&gt;
&lt;br /&gt;
Terms can also be reused by manually pinning top-level terms instead of relying on the variations propagation job. In this case, the terms created automatically by variations can be removed. &amp;nbsp;Next, terms from the source term set can be pinned along with the children using the&amp;nbsp;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Pin Term With Children&lt;/span&gt;&amp;nbsp;menu option on the term set used for the target variation label&#39;s navigation top-level (&lt;i&gt;Term reuse scenario B&lt;/i&gt;). The advantage of scenario B over scenario A is that regardless of when a page is published and propagated, the term will always get reused. The advantage of scenario A is that only terms for published pages get reused, which may better align with a publishing business process. The good thing is that you can mix both scenarios in a single term set as they are term-specific.&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Terms Translation&lt;/h4&gt;
In order to translate a term you need to change a value of current language in the Language drop-down box on a &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;GENERAL&lt;/span&gt; tab, and enter a translated value for the&amp;nbsp;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Default Label&lt;/span&gt;. Regardless of which term set you do it on (global term set, the one for the&amp;nbsp;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;en-CA&lt;/span&gt;&amp;nbsp;label site or the one for the&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;fr-CA&lt;/span&gt;&amp;nbsp;label site), it updates the source term&#39;s value, i.e. the one belonging to the global term set. Below is an example of translating a term to Russian:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggr8bfVTIS01QGY5IjCZgaN72a1PpkQTsTj1BhG0utPQaZWGRWsPerE2dF13eu_7m4WqElZu6-9rnHGUlW3jYugy5SKnDbaQ6-W1-bVxAIIIl6p-dK6uQFh84ZRamQ0iCnBBZT9XxBKj4/s1600/Setting+Term+Language.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;174&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggr8bfVTIS01QGY5IjCZgaN72a1PpkQTsTj1BhG0utPQaZWGRWsPerE2dF13eu_7m4WqElZu6-9rnHGUlW3jYugy5SKnDbaQ6-W1-bVxAIIIl6p-dK6uQFh84ZRamQ0iCnBBZT9XxBKj4/s640/Setting+Term+Language.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
There is an interesting side effect of term translation. If a term is translated prior to being reused (scenario A) or pinned (scenario B) then the managed URL of the propagated page is created based on the translated label. Here is an example of how this looks for a Russian variation label:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirMReuTzkF9t_9C3wu9Mkte-MB7rdV_KMn4Uwy0Mo11j2EONIer0hsPVhS9TRCgzOw6E4nShhK2G1JvAU4-IEsg6opLzFsOws8HNa_CKqbkYGE8FOC4fzp74W273Eva-hFzs7s6QhVivM/s1600/Incorrect+URL.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;410&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirMReuTzkF9t_9C3wu9Mkte-MB7rdV_KMn4Uwy0Mo11j2EONIer0hsPVhS9TRCgzOw6E4nShhK2G1JvAU4-IEsg6opLzFsOws8HNa_CKqbkYGE8FOC4fzp74W273Eva-hFzs7s6QhVivM/s640/Incorrect+URL.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
The fix is easy: selecting the&amp;nbsp;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Customize&lt;/span&gt;&amp;nbsp;check box does it. In case of the scenario B, the friendly URL to a page in a target variation will return 404, since Target Page Settings on a TERM-DRIVEN PAGES tab for the target term are not defined. The URL of the target page needs to be entered manually.&lt;br /&gt;
&lt;br /&gt;
So as you might have noticed, terms connected via pinning or term reuse share certain properties, such as Default Label, which can only be changed in one place - on the source term, while you are allowed to independently customize term-driven pages settings. This opens up a possibility of having locale-specific URLs, especially in languages utilizing Latin alphabet: a page in source variation could have one term-driven URL, and a replica of the page in the target variation could have a completely different term-driven URL. This improves readability of the site and supports SEO.&lt;br /&gt;
&lt;br /&gt;
On our project we &amp;nbsp;went ahead with the Scenario A, assuming our information workers would get training to make the following logical workflow happen:&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;The user creates a page in source variation;&lt;/li&gt;
&lt;li&gt;The user creates a term in global term set;&lt;/li&gt;
&lt;li&gt;The user points a term at the new page;&lt;/li&gt;
&lt;li&gt;The page undergoes approval process and gets published.&lt;/li&gt;
&lt;li&gt;Variations Propagate Page Job Definition timer job picks up the page and creates a replica in target variations. It also reuses the term pointing at the page, and correctly points reused term(s) at the page&#39;s replica(s).&lt;/li&gt;
&lt;li&gt;The term can be translated now without a harm to the term-driven URLs.&lt;/li&gt;
&lt;li&gt;User can optionally change the term-driven page URLs for the target variations&#39; pages.&lt;/li&gt;
&lt;/ol&gt;
Should the workflow not be followed for whatever reason, the terms can always be manually reused, and incorrectly translated URLs fixed as shown above.&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Search Indexing and Managed Navigation&lt;/h4&gt;
I have noticed that a term needs to have either the &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;Show in Global Navigation Menu&lt;/span&gt;&amp;nbsp; or the &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;Show in Current Navigation Menu&lt;/span&gt; checkbox checked (or both of them) in order for the search to be able to index the page corresponding to the term. If the term is neither on global nor on current navigation, and &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;Hide physical URLs from search&lt;/span&gt; field is set to &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;True&lt;/span&gt; for the corresponding page, then the page will not get indexed. For the pages we did not want on the navigation, but still needed to be in the index we were able to workaround this behavior by selecting the &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;Show in Current Navigation Menu &lt;/span&gt;checkbox, but using a page layout that does not render a current navigation control.&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Global versus Local Term Sets&lt;/h4&gt;
One last note about using the global term set. We could have used a site collection-scoped term set (aka local term set) instead. The strategy was to keep all terms used for navigation in one place and then reuse them. Even for the purpose of cross-site publishing it is not necessary to have a global term set. Still we have chosen a global term set on the basis of a &quot;why not?&quot; approach. It gave us greater flexibility and eliminated potential issues having to do with local scope.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</description><link>http://neganov.blogspot.com/2013/06/thoughts-about-building-multilingual_19.html</link><author>noreply@blogger.com (Ivan Neganov)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHFyvRPIiU15Sa_HmfyZ1yJtK1TuH6T0RBJUjTPONXa0IqwPrMYNy_MEXFh1-pc2PKDjgLjd6DZnEBplAPPAl46dJhjnTI2qnpIpYBII5_QAzVo_acejMBZdzEqoPNVm7Sg-QJqILJdus/s72-c/Relationship+between+terms+and+top+navigation.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-8181664647747472234</guid><pubDate>Mon, 17 Jun 2013 12:18:00 +0000</pubDate><atom:updated>2013-06-25T21:34:41.673-07:00</atom:updated><title>Thoughts about Building Multilingual Publishing Site on SharePoint 2013 - Part 1 of 3</title><description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Publishing approach has drastically changed in SharePoint Server 2013, and the Web Content Management (WCM) solution and infrastructure architecture approaches&amp;nbsp;need to be revised from the ground up as a result. &lt;a href=&quot;http://technet.microsoft.com/en-us/library/jj635878.aspx&quot;&gt;The guidance&lt;/a&gt; suggests 2 methods of content publishing: &lt;em&gt;Author-in-place&lt;/em&gt; and &lt;em&gt;Cross-site publishing&lt;/em&gt;, and provides a decision flowchart for choosing one over the other. Although &lt;em&gt;&lt;a href=&quot;http://blogs.technet.com/b/stefan_gossner/archive/2009/10/30/content-deployment-the-complete-guide-part-1-the-basics.aspx&quot;&gt;content deployment&lt;/a&gt;&lt;/em&gt; publishing method is still supported, it is no longer in the list of recommendations. While&amp;nbsp;the reasons for this are unknown to me, at least I know that the content&amp;nbsp;deployment &lt;a href=&quot;http://qandasys.info/friendly-url-and-content-deployment/&quot;&gt;does not work&lt;/a&gt; with the new and sought-after&amp;nbsp;&lt;a href=&quot;http://technet.microsoft.com/en-us/library/dn194311.aspx&quot;&gt;&lt;em&gt;managed navigation&lt;/em&gt;&lt;/a&gt; feature. With the above in mind, how do you &lt;em&gt;practically &lt;/em&gt;approach construction of a multilingual&amp;nbsp;Internet-facing&amp;nbsp;SharePoint-based WCM site utilizing &lt;a href=&quot;http://en.wikipedia.org/wiki/Clean_URL&quot;&gt;clean URLs&lt;/a&gt; and a content&amp;nbsp;publishing process suitable for an enterprise?&lt;br /&gt;
&lt;br /&gt;
This blog post is the first one in a 3-part series dedicated to the aspects of a multilingual WCM site architecture. It sets the context and describes the architecture of the authoring site.&lt;br /&gt;
&lt;a href=&quot;http://neganov.blogspot.ca/2013/06/thoughts-about-building-multilingual_19.html&quot;&gt;Part 2&lt;/a&gt; describes managed metadata navigation on the authoring site;&lt;br /&gt;
&lt;a href=&quot;http://neganov.blogspot.ca/2013/06/thoughts-about-building-multilingual_25.html&quot;&gt;Part 3&lt;/a&gt; describes the architecture of publishing sites and utilizing the cross-site publishing.&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Setting the Context&lt;/h4&gt;
At &lt;a href=&quot;http://www.navantis.com/&quot;&gt;Navantis&lt;/a&gt;, we needed to build a bi-lingual Internet presence publishing site for our Canadian customer, based on an on-premises installation of SharePoint Server 2013. The&amp;nbsp;key&amp;nbsp;requirements at a high level were as follows:&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;div style=&quot;text-align: left;&quot;&gt;
The content of the site should be available in French and English;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div style=&quot;text-align: left;&quot;&gt;
Although the authors could publish French version of a piece of content independently of its English version, most of the time it was required for the two versions to go live simultaneously, such as in cases of company news announcements;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div style=&quot;text-align: left;&quot;&gt;
The site had two kinds of content - &quot;non-volatile&quot;, updated rarely, and &quot;volatile&quot; corporate blog content updated monthly when new postings were published;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div style=&quot;text-align: left;&quot;&gt;
Some pages in addition to containing content, such as text and images, needed to have dynamic elements pointing at other pages, for example products widget, blog postings widget, home page image slider widget, etc.;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div style=&quot;text-align: left;&quot;&gt;
English and French versions of the content would be hosted on two sites addressed by two different DNS host names;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div style=&quot;text-align: left;&quot;&gt;
Authors and approvers should be able to preview the content with high fidelity to its production appearance, and follow a translation and approval business process before exposing it to the anonymous Internet users.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
Pretty typical, I would think... &lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
General Architecture&lt;/h4&gt;
So, we have started with planning an application utilizing Cross-Site Publishing (XSP) method, and studying Microsoft guidance including the case study of &lt;a href=&quot;http://technet.microsoft.com/en-us/library/jj822912.aspx&quot;&gt;Mavention WCM site&lt;/a&gt;. I must point out that the case study and the excellent blog of Mavention&#39;s &lt;a href=&quot;http://blog.mastykarz.nl/&quot;&gt;Waldek Mastykarz &lt;/a&gt;were very much helpful to us. Yet our case was not identical to the Mavention&#39;s site. The key differences were as follows:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;We used managed navigation on the authoring site. This was done in order to provide the fidelity of the look and feel between the authoring and publishing sites to the authors and approvers. Here we have willingly deviated from the guidance &lt;a href=&quot;http://technet.microsoft.com/en-us/library/jj635877.aspx#BKMK_SiteStructure&quot;&gt;recommending structured navigation for authoring sites&amp;nbsp;that leverage XSP&lt;/a&gt;. Another reason for this choice was that&amp;nbsp;it provided for an easy fallback to the &lt;em&gt;author-in-place&lt;/em&gt; publishing method, should there be implementation issues with the XSP method.&lt;/li&gt;
&lt;li&gt;We were hosting authoring and publishing sites in two separate web applications in order to separate them physically. The customer &#39;s security policy allowed placing both authoring and publishing sites to the perimeter network, and&amp;nbsp;so we did.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Assets Site&lt;/h4&gt;
Some of the key architecture decisions to make have to do with where to store and how to publish&amp;nbsp;binary assets created by information workers, such as images and videos. Search index does not store binary content. This means that in an authoring-publishing setup the images need to be either shared or copied between authoring and publishing sites. While the images that are a part of the branding can be copied over during site provisioning, this cannot be done with the images used by&amp;nbsp;the information workers&amp;nbsp;when creating content pages. &lt;br /&gt;
&lt;br /&gt;
The two alternatives I see here are developing a solution for synchronizing the images between the authoring and publishing sides, and using a shared assets site. The synchronization solution could theoretically leverage content deployment between source and target site collections for the images, although the information workers would need to maintain &quot;dummy&quot; pages referencing all the used images so that they could be picked up and transferred over by content deployment. We have chosen the same approach as in the Mavention case study - a shared assets site. It is important to note some consequences of this decision:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Unless we keep authoring and publishing sites in the same web application and use path-based site collections, we have to use absolute URIs when referencing the assets (starting with protocol identifier, ex. &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;&quot;&gt;http://www.softforte.com/styles/softforte.jpg&lt;/span&gt;). This was our case based on requirement #5 above.&lt;/li&gt;
&lt;li&gt;Assets site would need to use &lt;em&gt;author-in-place&lt;/em&gt; publishing method and allow information workers to have authenticated access to the assets site, while also being available publically to anonymous users.&lt;/li&gt;
&lt;li&gt;If you use&amp;nbsp;&lt;a href=&quot;http://blogs.msdn.com/b/kaevans/archive/2012/03/27/what-every-sharepoint-admin-needs-to-know-about-host-named-site-collections.aspx&quot;&gt;host-named site collections&lt;/a&gt;&amp;nbsp;for your publishing sites, which are a general recommendation on the grounds of improved scalability, you further limit the available options: with host-named site collections there is only one security zone, and securing authenticated traffic with SSL becomes problematic. &lt;/li&gt;
&lt;/ul&gt;
So we have chosen to use the unsecured HTTP channel with NTLM authentication for the assets site.&lt;br /&gt;
&lt;br /&gt;
Blogs Site&lt;br /&gt;
We chose to keep blog postings in a sub-site of the main authoring site because only one &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;Pages&lt;/span&gt; library can be used per web site, and we wanted to have a separation between the two libraries in order to be able to manage publishing workflows for pages and blog posts independently of each other. Since we relied on search web parts to surface content from the blogs, it was not a problem to retrieve blogs content regardless of its location. The only thing to be aware of is configuration of navigation on the blogs site - it needed to be inherited from the parent site in order to maintain its navigation context.&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Variations and Publishing Process&lt;/h4&gt;
In order to meet the requirement #2 asking for pages in both languages to be published simultaneously we have taken a rather elegant approach: we have used 3 variations: &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;en-US&lt;/span&gt; (source English), &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;en-CA&lt;/span&gt; (target English),&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt; fr-CA&lt;/span&gt; (target French). The source variation is not visible to the Internet users, but still allows to approve and then publish content in English language, an action that triggers&amp;nbsp;propagation of published updates across the variations. Then in case of the &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;en-CA&lt;/span&gt; language variation label the content simply gets approved to become published, and in case of &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;fr-CA&lt;/span&gt; language&amp;nbsp;it undergoes a translation process then gets approved and published.&amp;nbsp;Such approach lets us publish French and English versions of a page quasi-simultaneously, leaving it up to the approver to determine the interval between approving French and English publications.&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Customizations and Search-Driven Content&lt;/h4&gt;
We have built the site 100% without having to write custom server-side components. All customizations were client-side only, 80% of them were the design templates for working with the Content Search web parts. The latter were used universally for almost each widget from a page with a dynamic list of blogs to a widget surfacing blog postings on select pages, to a content rotator with sliding images on the home page. After solving provisioning issues thanks to &lt;a href=&quot;http://www.sharepointnutsandbolts.com/2013/04/provisioning-content-search-web-part.html&quot;&gt;Chris O&#39;Brien&#39;s blog post&lt;/a&gt;, we were able to speed up deployment cycles and significantly improve the development process. After all, it wouldn&#39;t be an exaggeration to state that the site was 100% search-driven.&lt;br /&gt;
&lt;br /&gt;
We have also used traditional site search box and a search results page. For a relatively static web presence site we have opted to not use a search center, and instead use a custom search results page. We wanted to be able to search for blogs separately on the blogs listing page. There we have used content search web part, and a search box web part connected to it, and made the query to filter out anything but the blog postings. The global search results page would include a wider set of results, and allow user an option to switch to blog results only. I have earlier described &lt;a href=&quot;http://neganov.blogspot.ca/2013/05/customizing-search-navigation-on.html&quot;&gt;how to configure this functionality&lt;/a&gt;. Because of our use of variations, each variation label had its own search results page, with a query scoped to only content residing in that variation label site.&lt;br /&gt;
&lt;br /&gt;
With all the advantages of surfacing the content in content search web parts, I feel that the main drawback has to do with the obscurity of the content selection method, being the search query issued from a content search web part. This obscurity slows down development by making troubleshooting search queries or search results issues more difficult. The benefits clearly outweigh the complexities, and there are several &amp;nbsp;tools at our disposal: firstly the content search web parts themselves with the excellent ability to do query results previewing; secondly there is a &lt;a href=&quot;http://sp2013searchtool.codeplex.com/&quot;&gt;Search Query Tool&lt;/a&gt; released by Microsoft; lastly there is a &lt;a href=&quot;http://www.sharepointnutsandbolts.com/2013/01/calling-sharepoint-search-using-rest-eg.html&quot;&gt;REST web interface&lt;/a&gt;&amp;nbsp;which can be used also to troubleshoot the queries using a browser. Still we cannot fully get away from the &amp;nbsp;high complexity of the search sub-system, and from this point of view it is reminiscent to me of the past experience writing search-driven web parts in previous versions of SharePoint. If you compare complexity of troubleshooting your search queries with troubleshooting of equivalent SQL queries you will know what I mean, so just allow some extra time for getting it right before you start adding a lot of content and the time of full crawl would increase dramatically. The less time it takes to do a full crawl in your development environment the sooner you will get the search-driven functionality to a solid state.&lt;br /&gt;
&lt;br /&gt;
One search-related issue we have encountered is worth mentioning: the pages we were authoring had &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Hide physical URLs from search &lt;/span&gt;fields set to &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;False&lt;/span&gt; by default. Logically, we were getting duplicated sets of results in return to some of our search queries. Setting this field to True followed by re-indexing the content, only shows term-driven URLs in search results - duplication problem solved!&lt;br /&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Master Page, Page Layouts and Branding&lt;/h4&gt;
In general we have used a pretty standard approach that is in principal not much different from the one used in SharePoint 2010. The new Design Manager helps by letting us use HTML editor of choice, and not rely on the SharePoint Designer. The cost of this convenience was that we had to provision both *.html and *.aspx versions of our page layouts using features. When only the *.html versions are provisioned by a feature their conversion to *.aspx files isn&#39;t triggered automatically. Still we needed both of the kinds of files as during development it is important to have identically configured development environments that are ready for branding work. Exporting and re-importing a design package didn&#39;t quite work for us as we noticed this process changed columns on intrinsic content types we relied upon - a topic that deserves a blog post and a research on its own.&lt;br /&gt;
&lt;br /&gt;
The site had&lt;a href=&quot;http://mediaqueri.es/&quot;&gt; responsive web design&lt;/a&gt;, which we have selected over the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/jj862343.aspx&quot;&gt;device channels&lt;/a&gt; option since it allowed us to stay with the same set of master pages and page layouts, and change only the style sheets with some minimal JavaScript support for the changes in navigation at smaller view port sizes. This &quot;modern&quot; style not only impacts the design of the master page and page layouts, but also affects the design of the content, in general making it more complicated. In our case we have provided sample &quot;Lorem ipsum&quot; content for all of the default pages. The sample content was intended to demonstrate to the information workers&amp;nbsp;by a way of&amp;nbsp;example how to structure the real content, and which CSS classes to apply to it.&lt;br /&gt;
&lt;br /&gt;
The next topic, managed metadata navigation, is another key part of a WCM site architecture. It is described in the &lt;a href=&quot;http://neganov.blogspot.ca/2013/06/thoughts-about-building-multilingual_19.html&quot;&gt;Part 2&lt;/a&gt; of the series.&lt;/div&gt;
</description><link>http://neganov.blogspot.com/2013/06/thoughts-about-building-multilingual.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-3254595384547100087</guid><pubDate>Sun, 09 Jun 2013 14:11:00 +0000</pubDate><atom:updated>2013-06-09T09:03:01.129-07:00</atom:updated><title>Filtering Items by Date Range using SharePoint 2013 REST API</title><description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
For some reason I always had extra difficulty when filtering results by dates in SharePoint, especially when I needed a &quot;between&quot; filter. This time I needed to render a calendar on a page accessed anonymously. I used a &lt;a href=&quot;http://arshaw.com/fullcalendar/&quot;&gt;FullCalendar&lt;/a&gt; jQuery plugin for this, &amp;nbsp;and the SharePoint 2013 REST API. In my implementation when the end user changes a month in the calendar, it calls a function passing it start and end dates of a date range. The function then needs to retrieve JSON from SharePoint corresponding to the date range.&lt;br /&gt;
&lt;br /&gt;
I started with turning on Team Collaboration Lists feature on my publishing site and creating the Calendar list. Then I have got my REST endpoint, this time around&amp;nbsp;with a &quot;greater than or equal to&quot; filter:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;http://devserver2012/_api/web/lists/getbytitle(&#39;events&#39;)/items?$select=Id,Title,Description,EventDate,EndDate,fAllDayEvent&amp;amp;$filter=EventDate ge datetime&#39;2013-06-08T00:00:00&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
The reason for my blog post is that the above RESTful call doesn&#39;t work. Research has pointed out a few things: &lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;I am not the only one. &lt;a href=&quot;http://sharepoint.stackexchange.com/questions/59521/the-field-eventdate-of-type-datetime-cannot-be-used-in-the-query-filter-expr&quot;&gt;Other people have had the issue&lt;/a&gt;. &lt;a href=&quot;http://msmvps.com/blogs/windsor/&quot;&gt;Rob Windsor&#39;s&lt;/a&gt; comment was quite useful to me.&lt;/li&gt;
&lt;li&gt;The&amp;nbsp;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/fp142385&quot;&gt;MSDN&amp;nbsp;guidance&amp;nbsp;&lt;/a&gt;has a table of supported filtering operations. First of all, it incorrectly capitalizes the numeric comparison operations. For example, instead of &quot;Ge&quot; operator which does not work, I was using &quot;ge&quot; which does work. Second of all, the references pointing back at &lt;a href=&quot;http://www.odata.org/&quot;&gt;www.odata.org&lt;/a&gt; were unfortunately broken there, at the time of this writing at least.&lt;/li&gt;
&lt;li&gt;Later I&#39;ve learned that my filter actually works with a Boolean &quot;and&quot; operator as I will show below. Does this make it unsupported? It probably does, according to the mentioned MSDN article, although the article itself clearly needs a revision.&lt;/li&gt;
&lt;li&gt;OData documentation is your friend. I find it hard to read, yet it is ultimately helpful. You can see query options supported by OData in section 4.5 &lt;a href=&quot;http://www.odata.org/documentation/odata-v2-documentation/uri-conventions/&quot;&gt;on this page&lt;/a&gt;. Notice how the operators are all lowercase in the examples. &amp;nbsp;The formatting of dates in filter queries can be found &lt;a href=&quot;http://www.odata.org/documentation/overview#AbstractTypeSystem&quot;&gt;here&lt;/a&gt;. This is where the &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;datetime&#39;2013-06-08T00:00:00&#39;&lt;/span&gt; comes from. One interesting detail, although the format spec does not indicate this, the following works just as well: &lt;span style=&quot;font-family: Courier New;&quot;&gt;datetime&#39;2013-06-08T00:00:00Z&#39;.&lt;/span&gt; Apparently the &lt;a href=&quot;http://en.wikipedia.org/wiki/ISO-8601&quot;&gt;ISO-8601&lt;/a&gt; is still honored.&lt;/li&gt;
&lt;/ol&gt;
&lt;span style=&quot;font-family: Arial; font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: inherit; font-size: small;&quot;&gt;Getting back to my original REST&amp;nbsp;call - what &quot;fixes&quot; it? If I were to use&lt;/span&gt; &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: small;&quot;&gt;ListData.svc&lt;/span&gt; &lt;span style=&quot;font-family: inherit; font-size: small;&quot;&gt;instead then I&#39;d get the following:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace; font-size: x-small;&quot;&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;http://devserver2012/_vti_bin/ListData.svc/Events?$select=Id,Title,StartTime,EndTime,AllDayEvent&amp;amp;$filter=StartTime ge datetime&#39;2013-06-10&#39; and EndTime lt datetime&#39;2013-06-12&#39;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The above call actually works, although it ignores time portion when filtering. You can see that I get my &quot;between&quot; filter in there, also the column names are different - it uses display names of the columns with removed spaces. Also notice how the date values are formatted, actually conflicting with the OData format spec. In general, if you examine the Atom results returned, you will also find that date formatting is relaxed (no &quot;Z&quot; Zulu time indicator).&amp;nbsp;&amp;nbsp;So what! We can celebrate now... Well, almost - the call to &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;ListData.svc&lt;/span&gt; won&#39;t work&amp;nbsp;for anonymous users.&amp;nbsp;Since this was a deal breaker to me, I kept on looking.&amp;nbsp;Turning to the ULS log shows that the error message
&lt;span lang=&quot;EN&quot;&gt;&amp;nbsp;&lt;em&gt;&quot;The field &#39;EventDate&#39; of type &#39;DateTime&#39; cannot be used in the query filter expression.&quot;&lt;/em&gt;&lt;/span&gt; comes from here:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;Microsoft.SharePoint.SPListItemEntityCollectionCamlQueryBuilder.CheckFieldRefUsage(SPField field, FieldRefUsage fieldRefUsage)&lt;/span&gt;
&lt;br /&gt;
&lt;br /&gt;
With help of Reflector we see that the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spfield.filterable.aspx&quot;&gt;SPField.Filterable&lt;/a&gt; property is logically enough the driving force here. Then using &lt;a href=&quot;http://spm.codeplex.com/&quot;&gt;SharePoint Manager&lt;/a&gt; to examine the value of this property for the EventDate (&quot;Start Time&quot;) field of the Event content type we of course find that its Filterable property is set to &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;false&lt;/span&gt;, and this is what is causing the error message to be returned.&amp;nbsp;I should mention that there is little value in working around this behavior by using calculated fields - they are also rejected as filters by this method. To prove that it actually works in principle&amp;nbsp;I&#39;ve created a DateTime column from scratch and named it &quot;Date3&quot;. Here is how my REST call now looks like:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;http://devserver2012/_api/web/lists/getbytitle(&#39;events&#39;)/items?$select=Id,Title,Description,EventDate,EndDate,fAllDayEvent,Date3&amp;amp;$filter=Date3 ge datetime&#39;2013-06-13T00:00:00Z&#39; and Date3 le datetime&#39;2013-06-14T00:00:00Z&#39;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This works when accessing the list anonymously. Problem solved and lesson learned: do not rely on the OOB Calendar list for anonymously accessible events, or be prepared to add your own custom DateTime columns to that list.&lt;br /&gt;
&lt;br /&gt;
At the time of this writing I was running SharePoint Server 2013, Enterprise CAL, &lt;a href=&quot;http://support.microsoft.com/kb/2767999&quot;&gt;March 2013 update&lt;/a&gt;.&lt;br /&gt;
&lt;div&gt;
&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
</description><link>http://neganov.blogspot.com/2013/06/filtering-items-by-date-range-using.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-6634540439816317877</guid><pubDate>Thu, 30 May 2013 05:24:00 +0000</pubDate><atom:updated>2013-05-31T07:10:07.664-07:00</atom:updated><title>Customizing Search Navigation on a SharePoint 2013 Publishing Site</title><description>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Managed metadata-driven navigation in SharePoint 2013 lets us use &lt;a href=&quot;http://en.wikipedia.org/wiki/Clean_URL&quot;&gt;clean and implementation-independent&lt;/a&gt; URLs, which are often required&amp;nbsp;in WCM applications. I was working on a web presence site for my customer, which used clean URLs. A simple search interface was used on it: a search box on a master page, and a search results page containing search results web part, and a search box web part. I wanted that search box web part to have a drop-down list of options so the Internet users could choose whether to search the entire site, or just the blogs.&lt;br /&gt;
&lt;br /&gt;
First of all, in the past with SharePoint 2010 and 2007 we were using scopes to achieve this effect. It works differently in SharePoint 2013. Under Site Settings &amp;gt;&amp;gt; Search Settings you need to define the links to different destination pages:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyNW3jAqINR1y6__MaFkRe265xc1kdDBccEXNeROSUBv1zy2LUmIChI3-SasHCAAYCiECX91q9_IDgIp4ZPYoRjseutjKDH_T98xy3jIQ-cMswxc4zKYaUOJ2Ab1BQwVkRLFSaGCOXklw/s1600/Search+Settings.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;596&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyNW3jAqINR1y6__MaFkRe265xc1kdDBccEXNeROSUBv1zy2LUmIChI3-SasHCAAYCiECX91q9_IDgIp4ZPYoRjseutjKDH_T98xy3jIQ-cMswxc4zKYaUOJ2Ab1BQwVkRLFSaGCOXklw/s640/Search+Settings.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;strong&gt;Fig. 1 - Site Collection Search Settings&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
These links would point&amp;nbsp;at two different search results pages and pass user&#39;s search keywords as a query string to these pages.&amp;nbsp;In my case the first link &quot;All Results&quot; was pointing at a&amp;nbsp;site search results page, the second one &quot;Blog Results&quot; - at a blogs listing page.&lt;br /&gt;
&lt;br /&gt;
Second of all, we need to configure the search box web part. If you want to use the drop-down menu in the search box residing on the master page then you simply need to select the option titled &quot;Turn on the drop-down menu inside the search box, and use the first Search Navigation node as the destination results page.&quot; on the Fig. 1 above. In my case I wanted no drop-down menu there, but needed one on the search results page. This is done on the search box web part as shown on the Fig. 2.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoAPtQedjjrgCW9TwNhF5DVjenpHTmEB3dXh4BiU39UerjIml3IjTwmeDKdtDaO0MjcDUFs_xF93QayYIyY1hdpKByUBWWLx6Z2zlT38Fk_pI36Mt_888ApWZqy5Dq7dLsC0Fj9N18xpk/s1600/Search+Box+Toolpart.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoAPtQedjjrgCW9TwNhF5DVjenpHTmEB3dXh4BiU39UerjIml3IjTwmeDKdtDaO0MjcDUFs_xF93QayYIyY1hdpKByUBWWLx6Z2zlT38Fk_pI36Mt_888ApWZqy5Dq7dLsC0Fj9N18xpk/s400/Search+Box+Toolpart.png&quot; width=&quot;280&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;strong&gt;Fig. 2 - Search Box ToolPart showing how to configure the drop-down menu&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
That&#39;s pretty easy and gets you what you need. There is one problem however. Look at the Search Settings page illustrated on Fig.1 - the URL is pointing at an ASP page, which we certainly would like to change from &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;/auth/en-ca/Pages/Search-Results.aspx&lt;/span&gt; to something like&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt; /auth/en-ca/results&lt;/span&gt;. Should be simple, especially as exactly this is done under the &quot;Which search results page should queries be sent to?&quot; section on the same page. Well, turns out that it does not work if you attempt doing it through the UI -&amp;nbsp;it will complain about incorrect URL format unless you give it a page reference.&lt;br /&gt;
&lt;br /&gt;
These links are referred to as &quot;Search Navigation nodes&quot; for a reason. If you open PowerShell and check out the navigation of your current web, you will see the new property of &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;Microsoft.SharePoint.Navigation.SPNavigation &lt;/span&gt;type named SearchNav there:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBOE-VSRlqZYRbdDp7Xa3alDj81Hgg8oM3vZRFPxm8Y44eU7BAr6THDAu1cWM1CSVH9Ar8tHiloN942lKqcTKxhB-atQNK3DwP91NYI1RCOI9S_RoQkdfo0J_x0vJSvymyI1Y20laHCe4/s1600/Search+Navigation1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBOE-VSRlqZYRbdDp7Xa3alDj81Hgg8oM3vZRFPxm8Y44eU7BAr6THDAu1cWM1CSVH9Ar8tHiloN942lKqcTKxhB-atQNK3DwP91NYI1RCOI9S_RoQkdfo0J_x0vJSvymyI1Y20laHCe4/s1600/Search+Navigation1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;strong&gt;Fig. 3 - SearchNav is a new property of the &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;SPNavigation&lt;/span&gt; type in SharePoint 2013&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
OK great. The next obvious thing to do is change the URL of the &quot;All Results&quot; Search Navigation node from &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;/auth/en-ca/Pages/Search-Results.aspx&lt;/span&gt; to&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;/auth/en-ca/results &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;using the PowerShell. Guess what -&amp;nbsp; it would silently not update the URL property. &lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;The way I have got it to work was by creating the navigation&amp;nbsp;node entirely from PowerShell. I also had to use the &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;SPNavigationNode&lt;/span&gt; &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms415159.aspx&quot;&gt;constructor overload&lt;/a&gt; accepting a Boolean &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;isExternal&lt;/span&gt; flag and set it to &lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;$true&lt;/span&gt; in order to bypass the URL check, which SharePoint does and for some reason ignores the managed metadata-based navigation URLs.&amp;nbsp;So the PowerShell workaround in my case looks as follows:&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;$node1 = new-object `&lt;br /&gt;&amp;nbsp;-TypeName &quot;Microsoft.SharePoint.Navigation.SPNavigationNode&quot; `&lt;br /&gt;&amp;nbsp;-ArgumentList &quot;All Results&quot;, &quot;/auth/en-ca/results&quot;, $true&lt;br /&gt;$node2 = new-object `&lt;br /&gt;&amp;nbsp;-TypeName &quot;Microsoft.SharePoint.Navigation.SPNavigationNode&quot; `&lt;br /&gt;&amp;nbsp;-ArgumentList &quot;Blog Results&quot;, &quot;/auth/en-ca/blogs&quot;, $true&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;$web = Get-SPWeb &lt;/span&gt;&lt;a href=&quot;http://devserver2012/auth/en-ca&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;http://devserver2012/auth/en-ca&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;$web.Navigation.SearchNav.AddAsFirst($node1)&lt;br /&gt;$web.Navigation.SearchNav.AddAsLast($node2)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This gets all my URLs to be &quot;clean&quot;, including the ones pointed at from the Search Box drop-down menus. Interestingly, after creating the links through PowerShell you can modify their title, description, or even the URL&amp;nbsp;properties through the UI without issues.&lt;br /&gt;
&lt;br /&gt;
I was running SharePoint Server 2013 with &lt;a href=&quot;http://support.microsoft.com/kb/2767999&quot;&gt;March 2013 CU&lt;/a&gt;.&lt;/div&gt;
</description><link>http://neganov.blogspot.com/2013/05/customizing-search-navigation-on.html</link><author>noreply@blogger.com (Ivan Neganov)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyNW3jAqINR1y6__MaFkRe265xc1kdDBccEXNeROSUBv1zy2LUmIChI3-SasHCAAYCiECX91q9_IDgIp4ZPYoRjseutjKDH_T98xy3jIQ-cMswxc4zKYaUOJ2Ab1BQwVkRLFSaGCOXklw/s72-c/Search+Settings.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-173879727702930967</guid><pubDate>Sun, 28 Aug 2011 16:17:00 +0000</pubDate><atom:updated>2011-08-28T11:23:53.621-07:00</atom:updated><title>Custom Alerts in SharePoint - Templates or Code?</title><description>&lt;p&gt;My client needed a customized alert created each time a new issue was added to a standard Issues list. The only difference from out-of-the-box alert functionality was that customized alert Email message needed to have an Issue ID in its subject. I haven’t customized alerts before so I did some research, which showed that: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;you can customize HTML of an alert through alert templates and use placeholders to insert values in an Email message. &lt;/li&gt;    &lt;li&gt;there is an API letting you to tap into alert message processing pipeline and customize Email message before it is sent out. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;There is a lot of information online on the subject, yet I still had difficulties with this seemingly easy problem. The following resources were most useful to me: MSDN (&lt;a title=&quot;http://msdn.microsoft.com/en-us/library/bb802949.aspx&quot; href=&quot;http://msdn.microsoft.com/en-us/library/bb802949.aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/bb802949.aspx&lt;/a&gt;), &lt;a title=&quot;Customizing Alert Notifications and Alert Templates in Windows SharePoint Services 3.0&quot; href=&quot;http://blogs.msdn.com/b/sharepointdeveloperdocs/archive/2007/12/07/customizing-alert-notifications-and-alert-templates-in-windows-sharepoint-services-3-0.aspx&quot; target=&quot;_blank&quot;&gt;Albert Meerscheidt’s post about alerts in WSS 3.0&lt;/a&gt; and &lt;a title=&quot;Creating custom list alert templates in SharePoint 2010&quot; href=&quot;http://www.sharemuch.com/2010/08/15/creating-custom-list-alert-templates-in-sharepoint-2010/&quot; target=&quot;_blank&quot;&gt;Yaroslav Pentsarskyy’s post about customizing alerts in SharePoint 2010&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;For me empowered with this information the task came down to writing a correct alert template, or so I thought. Take a look at this fragment of an out-of-the-box immediate alert template defining Email message subject text (immediate alerts are sent right away while digest alerts are sent later as a summary):&lt;/p&gt;&lt;span class=&quot;Apple-style-span&quot;&gt;&amp;lt;Subject&amp;gt;&lt;br /&gt;  &amp;lt;GetVar Name=&quot;AlertTitle&quot; /&amp;gt;&lt;br /&gt;  &amp;lt;HTML&amp;gt;&amp;lt;![CDATA[ - ]]&amp;gt;&amp;lt;/HTML&amp;gt;&lt;br /&gt;  &amp;lt;GetVar Name=&quot;ItemName&quot; /&amp;gt;&lt;br /&gt;&amp;lt;/Subject&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The interesting part here is placeholders “AlertTitle” and “ItemName” and the way they are used. I have a field named “ID” (it is a part of a standard Issues list), and a naive approach of writing &lt;span&gt;&amp;lt;GetVar Name=”ID” /&amp;gt;&lt;/span&gt; didn’t get me anywhere. Same result with adding a custom text column named “ATextColumn” and then doing &lt;span&gt;&amp;lt;GetVar Name=”ATextColumn” /&amp;gt;&lt;/span&gt;. Well, the &lt;span&gt;&amp;lt;GetVar&amp;gt;&lt;/span&gt; element is a part of &lt;a title=&quot;GetVar Element (View)&quot; href=&quot;http://msdn.microsoft.com/en-us/library/ms429081.aspx&quot; target=&quot;_blank&quot;&gt;CAML Vew Schema&lt;/a&gt; and yields a value of a local or a global variable set in current page context, but what are these placeholders and how are they set? At this point I have realized that my effort estimates were a little too optimistic. Then I bumped into a &lt;a title=&quot;Managing Alerts&quot; href=&quot;http://isle.paisley.ac.uk/_vti_bin/HELP/1033/SPS/HTML/stsf13.htm&quot; target=&quot;_blank&quot;&gt;help article about alerts in WSS 2.0&lt;/a&gt;. Among other things it had a list of “tags” that could be included in alert templates. Here it is:&lt;br /&gt;&lt;br /&gt;&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;2&quot; width=&quot;750&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;205&quot;&gt;&lt;b&gt;Tag&lt;/b&gt;&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;727&quot;&gt;&lt;b&gt;Description&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;209&quot;&gt;SiteUrl&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;724&quot;&gt;The full URL to the site.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;212&quot;&gt;SiteName&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;721&quot;&gt;The name of the site.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;215&quot;&gt;SiteLanguage&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;719&quot;&gt;The &lt;a href=&quot;http://isle.paisley.ac.uk/spsglos.htm&quot;&gt;locale ID (LCID)&lt;/a&gt; for the language used in the site.&lt;br /&gt;For example, 1033 for U.S. English.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;217&quot;&gt;AlertFrequency&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;717&quot;&gt;Immediate (0), Daily (1), or Weekly (2).&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;219&quot;&gt;ListUrl&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;715&quot;&gt;The full URL to the list.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;221&quot;&gt;ListName&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;714&quot;&gt;The name of the list.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;222&quot;&gt;ItemUrl&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;713&quot;&gt;The full URL to the item.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;223&quot;&gt;ItemName&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;712&quot;&gt;The name of the item.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;224&quot;&gt;EventType&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;711&quot;&gt;ItemAdded (1), Item Modified (2), Item Deleted (4), DiscussionAdded (16),&lt;br /&gt;Discussion Modified (32), Discussion Deleted (64), Discussion Closed (128),&lt;br /&gt;Discussion Activated (256).&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;225&quot;&gt;ModifiedBy&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;711&quot;&gt;The name of the user who modified an item.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;225&quot;&gt;TimeLastModified&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;711&quot;&gt;The time the item was last modified.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign=&quot;top&quot; width=&quot;225&quot;&gt;MySubsUrl&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;711&quot;&gt;The full URL to the My Alerts on this Site page in &lt;b&gt;Site Settings&lt;/b&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Some of these tags are used in the out-of-the-box templates. I tried the rest of them and all have worked. So it appears as we are limited to using these 12 tags only, and that it is an old functionality which survived WSS 2.0, WSS 3.0 and SharePoint Foundation 2010 releases. If someone knows more about it please post a comment to validate, disprove or complete this statement.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Another thing that comes out of reflecting over template XML is usage of &lt;span&gt;&amp;lt;GetVar Name=”OldValue#{Field}” /&amp;gt;&lt;/span&gt; or &lt;span&gt;&amp;lt;GetVar Name=”NewValue#{Field}” /&amp;gt;&lt;/span&gt; or&lt;span&gt; &amp;lt;GetVar Name=”DisplayName#{Field}” /&amp;gt;&lt;/span&gt;. These elements are descendents of &lt;a title=&quot;Fields Element (Alert Templates)&quot; href=&quot;http://msdn.microsoft.com/en-us/library/ff407228.aspx&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&amp;lt;Fields&amp;gt;&lt;/span&gt;&lt;/a&gt; element for immediate alerts, and of &lt;a title=&quot;RowFields Element (Alert Templates)&quot; href=&quot;http://msdn.microsoft.com/en-us/library/ff408269.aspx&quot; target=&quot;_blank&quot;&gt;&amp;lt;RowFields&amp;gt;&lt;/a&gt; element for digest alerts. If you inspect generated alert body HTML then you would notice that fields (or columns) are iterated over and their values are inserted in the body except when a field is listed inside of&lt;span&gt; &lt;/span&gt;&lt;a title=&quot;ImmediateNotificationExcludedFields (Alert Templates)&quot; href=&quot;http://msdn.microsoft.com/en-us/library/ff408063.aspx&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&amp;lt;ImmediateNotificationExcludedFields&amp;gt;&lt;/span&gt;&lt;/a&gt; or &lt;a title=&quot;DigestNotificationExcludedFields Element (Alert Templates)&quot; href=&quot;http://msdn.microsoft.com/en-us/library/ff407637.aspx&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&amp;lt;DigestNotificationExcludedFields&amp;gt;&lt;/span&gt;&lt;/a&gt; elements. So then &lt;span&gt;&amp;lt;Fields&amp;gt;&lt;/span&gt; element establishes a loop, and the &lt;span&gt;{Field}&lt;/span&gt; must be a contextual variable inside this loop. With the above syntax you can get display name, old or new values for each field into the Email body and exclude fields you don’t want to be listed.&lt;br /&gt;&lt;br /&gt;Great, but how do I get the ID into my Email’s subject? I don’t want to list a bunch of fields in my subject, just the ID, so I don’t want to use &lt;span&gt;&amp;lt;Fields&amp;gt;&lt;/span&gt; element there. The API did the trick. I have created a class implementing &lt;a title=&quot;IAlertNotifyHandler Interface&quot; href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.ialertnotifyhandler.aspx&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;IAlertNotifyHandler&lt;/span&gt;&lt;/a&gt; interface and used regular expressions to replace a placeholder with a value:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre class=&quot;csharpcode&quot; style=&quot;line-height:70%&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MessageCustomizer : IAlertNotifyHandler&lt;br /&gt;{&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; OnNotification(SPAlertHandlerParams parameters)&lt;br /&gt;  {&lt;br /&gt;      &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; webUrl = parameters.siteUrl + parameters.webUrl;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (SPSite site = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; SPSite(webUrl))&lt;br /&gt;      &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt;(SPWeb web = site.OpenWeb())&lt;br /&gt;      {&lt;br /&gt;          &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; to = parameters.headers[&lt;span class=&quot;str&quot;&gt;&quot;To&quot;&lt;/span&gt;];&lt;br /&gt;          &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; subjectTemplate = parameters.headers[&lt;span class=&quot;str&quot;&gt;&quot;Subject&quot;&lt;/span&gt;];&lt;br /&gt;          &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; itemId = parameters.eventData[0].itemId.ToString();&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;rem&quot;&gt;//&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;rem&quot;&gt;// Below we are replacing a placeholder we have &lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;rem&quot;&gt;// created in our alert template with the actual value.&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;rem&quot;&gt;//&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; subject = Regex.Replace(&lt;br /&gt;              subjectTemplate,&lt;br /&gt;              &lt;span class=&quot;str&quot;&gt;&quot;#ID#&quot;&lt;/span&gt;,&lt;br /&gt;              itemId,&lt;br /&gt;              RegexOptions.IgnoreCase);&lt;br /&gt;          &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; result = SPUtility.SendEmail(&lt;br /&gt;              web,&lt;br /&gt;              &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;,&lt;br /&gt;              &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;,&lt;br /&gt;              to,&lt;br /&gt;              subject,&lt;br /&gt;              parameters.body);&lt;br /&gt;          &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; result;&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;style type=&quot;text/css&quot;&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, &quot;Courier New&quot;, courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;We still need a customized alert template – firstly to insert our own custom placeholder (in my example #ID#) and secondly to register the &lt;span&gt;MessageCustomizer&lt;/span&gt; class so its &lt;span&gt;OnNotification()&lt;/span&gt; method would get called. Here is updated fragment defining Email’s subject:&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Subject&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&amp;lt;!&lt;/span&gt;[CDATA[Issue ID #ID#: ]]&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;GetVar&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;AlertTitle&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&amp;lt;!&lt;/span&gt;[CDATA[ - ]]&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;HTML&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;GetVar&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;ItemName&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Subject&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Registration of &lt;span&gt;MessageCustomizer&lt;/span&gt; class and its assembly is done inside of &lt;a title=&quot;NotificationHandlerClassName Element&quot; href=&quot;http://msdn.microsoft.com/en-us/library/ff407449.aspx&quot; target=&quot;_blank&quot;&gt;&amp;lt;NotificationHandlerClassName&amp;gt;&lt;/a&gt; and &lt;a title=&quot;NotificationHandlerAssembly Element&quot; href=&quot;http://msdn.microsoft.com/en-us/library/ff407215.aspx&quot; target=&quot;_blank&quot;&gt;&amp;lt;NotificationHandlerAssembly&amp;gt;&lt;/a&gt; elements of the template:&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; font-size: 13px; white-space: pre; &quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;NotificationHandlerAssembly&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;AlertCustomization, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bda7bcef852778f0&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;NotificationHandlerAssembly&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;NotificationHandlerClassName&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;AlertCustomization.MessageCustomizer&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;NotificationHandlerClassName&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;style type=&quot;text/css&quot;&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, &quot;Courier New&quot;, courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;We can now wire up the templates and the handler. Handler’s assembly needs to go to the GAC, then you copy and rename &lt;span&gt;alerttemplates.xml&lt;/span&gt; file sitting in &lt;span&gt;14\TEMPLATE\XML&lt;/span&gt; folder, add your template (or again copy an existing one and change it), then you register this file with SharePoint running&lt;span class=&quot;Apple-style-span&quot;&gt; &lt;b&gt;stsadm –o updatealerttemplates&lt;/b&gt;&lt;/span&gt; command. I didn’t find PowerShell cmdlets equivalent to this command. Lastly you need to assign your template to a list using &lt;a title=&quot;SPList.AlertTemplate Property&quot; href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splist.alerttemplate.aspx&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;SPList.AlertTemplate&lt;/span&gt;&lt;/a&gt; property. You can write a PowerShell script or use a feature receiver. The latter approach is demonstrated in Yaroslav Pentsarskyy’s post mentioned earlier.&lt;br /&gt;&lt;br /&gt;So we are arriving at a standard “It depends…” answer to the question of whether to customize alerts via templates or via code. Regardless of which approach works for you for any such customization that is not an ad hoc fix or a proof of concept you are looking into creating a package including deployment script, a SharePoint solution and possibly a feature with feature receiver. The functionality is almost identical between WSS 3.0 and SharePoint Foundation 2010 with the latter adding SMS support. Also with Visual Studio 2010 it is much easier to package things, yet you are probably still looking into a few hours of work to get it done right.  &lt;/div&gt;</description><link>http://neganov.blogspot.com/2011/08/custom-alerts-in-sharepoint-templates.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-5820943211282341690</guid><pubDate>Wed, 13 Jul 2011 04:34:00 +0000</pubDate><atom:updated>2011-07-12T21:49:06.446-07:00</atom:updated><title>Calling WCF Web Services from a SharePoint Timer Job</title><description>&lt;p&gt;Imagine that you are building an enterprise application on top of SharePoint 2010, which is installed on a multi-server farm. The application consumes a WCF web service – custom libraries use generated proxy classes and endpoint configuration is stored inside of a web application’s web.config file. Configuration settings are applied to all servers in the farm by a script when application is provisioned. And your application needs to be deployed to development, testing and production farms, all of which have differences in how WCF endpoints and bindings are configured, including variance in WCF binding types.&lt;/p&gt;  &lt;p&gt;Now imagine that you need to call this web service from two places: from your custom web application code and from a timer job, perhaps because you need to cache results for better performance, but also be able to fall back to synchronous call when results get outdated. You will face a complication: how do you configure your WCF client when you invoke the service from a timer job? &lt;/p&gt;  &lt;p&gt;You have a few options:&lt;/p&gt;  &lt;p&gt;1. Implement a configuration file &lt;font face=&quot;Courier New&quot;&gt;OWSTIMER.exe.config&lt;/font&gt;;&lt;/p&gt;  &lt;p&gt;2. Construct binding and endpoint objects inside of a timer job, set their properties through code then create a channel or extended &lt;font face=&quot;Courier New&quot;&gt;ClientBase&amp;lt;T&amp;gt;&lt;/font&gt; object and execute a service method call on it.&lt;/p&gt;  &lt;p&gt;3. Load service model configuration from application’s &lt;font face=&quot;Courier New&quot;&gt;web.config&lt;/font&gt; file and create and populate appropriate binding and endpoint objects. Then create and use a channel or a &lt;font face=&quot;Courier New&quot;&gt;ClientBase&amp;lt;T&amp;gt;&lt;/font&gt; object to invoke the service method.&lt;/p&gt;  &lt;p&gt;Option 1 has issues with provisioning files to locations not intended for custom application files and keeping same configuration information in two locations on all farm servers.&lt;/p&gt;  &lt;p&gt;Option 2 hard-codes binding information, which makes it very difficult to maintain code and troubleshoot WCF issues in multiple environments.&lt;/p&gt;  &lt;p&gt;Option 3 is apparently the best choice since configuration is stored in one place, it can easily be changed in &lt;font face=&quot;Courier New&quot;&gt;web.config&lt;/font&gt;, and the changes will affect WCF service client objects in both locations. So let us look at what’s involved in implementing the option 3.&lt;/p&gt;  &lt;p&gt;Before you can load a configuration object from &lt;font face=&quot;Courier New&quot;&gt;web.config&lt;/font&gt; file you need to locate it. Here we can leverage &lt;font face=&quot;Courier New&quot;&gt;SPIisSettings&lt;/font&gt; object, which is available for each security zone. Next you load &lt;font face=&quot;courier ne&quot;&gt;web.config&lt;/font&gt; content by using &lt;font face=&quot;Courier New&quot;&gt;WebConfigurationManager.OpenMappedConfiguration()&lt;/font&gt; method: &lt;/p&gt;&lt;br /&gt;&lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;private&lt;/span&gt; System.Configuration.Configuration GetWebConfig(SPUrlZone zone)&lt;br /&gt;{&lt;br /&gt;    SPIisSettings iisSettings = &lt;span style=&quot;color: #0000ff&quot;&gt;this&lt;/span&gt;.WebApplication.IisSettings[zone];&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; rootPath = iisSettings.Path.ToString();&lt;br /&gt;    WebConfigurationFileMap map = &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; WebConfigurationFileMap();&lt;br /&gt;    map.VirtualDirectories.Add(&lt;br /&gt;        &lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;,&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; VirtualDirectoryMapping(rootPath, &lt;span style=&quot;color: #0000ff&quot;&gt;true&lt;/span&gt;));&lt;br /&gt;    System.Configuration.Configuration webConfig =&lt;br /&gt;        WebConfigurationManager.OpenMappedWebConfiguration(&lt;br /&gt;        map,&lt;br /&gt;        &lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;/web.config&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;return&lt;/span&gt; webConfig;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;Once you have obtained configuration object, you need to infer type of binding from service model configuration, and apply all attributes to it, as well as create an endpoint. Given names of a binding and an endpoint you find corresponding &lt;font face=&quot;Courier New&quot;&gt;BindingCollectionElement&lt;/font&gt; and &lt;font face=&quot;Courier New&quot;&gt;ChannelEndpointElement&lt;/font&gt;. The actual binding object is created using .NET Reflection and value of &lt;font face=&quot;Courier New&quot;&gt;BindingCollectionElement.BindingType&lt;/font&gt; property:&lt;/div&gt;&lt;div id=&quot;codeSnippetWrapper&quot;&gt;&lt;br /&gt;  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;private&lt;/span&gt; MyServiceClient MakeMyServiceClient(&lt;br /&gt;    System.Configuration.Configuration config)&lt;br /&gt;{&lt;br /&gt;    &lt;span style=&quot;color: #008000&quot;&gt;//&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #008000&quot;&gt;// Get endpoint and binding names from settings.&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #008000&quot;&gt;//&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; bindingName = GetValue(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Key_MyBindingName&amp;quot;&lt;/span&gt;);&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; endpointName = GetValue(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Key_MyEndpointName&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #008000&quot;&gt;//&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #008000&quot;&gt;// Determine endpoint and binding elements used.&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #008000&quot;&gt;//&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    var sectionGroup = ServiceModelSectionGroup.&lt;br /&gt;        GetSectionGroup(config);&lt;br /&gt;    ChannelEndpointElement endpointElement = &lt;span style=&quot;color: #0000ff&quot;&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;for&lt;/span&gt; (&lt;span style=&quot;color: #0000ff&quot;&gt;int&lt;/span&gt; i = 0; i &amp;lt; sectionGroup.Client.Endpoints.Count; ++i)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (sectionGroup.Client.Endpoints[i].Name == endpointName)&lt;br /&gt;        {&lt;br /&gt;            endpointElement = sectionGroup.Client.Endpoints[i];&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;break&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    BindingCollectionElement collectionElement = sectionGroup.&lt;br /&gt;        Bindings.BindingCollections.Find(&lt;br /&gt;            item =&amp;gt; item.BindingName == endpointElement.Binding);&lt;br /&gt;    IBindingConfigurationElement bindingConfig = &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt;&lt;br /&gt;        List&amp;lt;IBindingConfigurationElement&amp;gt;(&lt;br /&gt;            collectionElement.ConfiguredBindings).Find(item =&amp;gt;&lt;br /&gt;                item.Name == endpointElement.BindingConfiguration);&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #008000&quot;&gt;//&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #008000&quot;&gt;// Create address and binding of proper type and populate them.&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #008000&quot;&gt;//&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    Binding binding = (Binding)collectionElement.BindingType.&lt;br /&gt;        GetConstructor(&lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; Type[0]).Invoke(&lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;object&lt;/span&gt;[0]);&lt;br /&gt;    bindingConfig.ApplyConfiguration(binding);&lt;br /&gt;    EndpointAddress address = &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; EndpointAddress(&lt;br /&gt;        endpointElement.Address);&lt;br /&gt;&lt;br /&gt;    MyServiceClient client = &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; MyServiceClient(binding, address);&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;return&lt;/span&gt; client;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;That’s it. The credit for &lt;font face=&quot;Courier New&quot;&gt;MakeMyServiceClient()&lt;/font&gt; method goes to Microsoft. When I was searching for examples of inferring binding type and properties from configuration I bumped into implementation of a read-only property named &lt;font face=&quot;Courier New&quot;&gt;Binding&lt;/font&gt; on an internal type &lt;font face=&quot;Courier New&quot;&gt;Microsoft.SharePoint.Administration.Claims.SPSecurityTokenServiceApplication&lt;/font&gt; inside of &lt;font face=&quot;Courier New&quot;&gt;Microsoft.SharePoint&lt;/font&gt; assembly. I have reused that code with minor deviations in the example above. Open up Reflector and take a look at that property.&lt;br /&gt;&lt;/div&gt;</description><link>http://neganov.blogspot.com/2011/07/calling-wcf-web-services-from.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-7652772969021245369</guid><pubDate>Thu, 14 Apr 2011 03:47:00 +0000</pubDate><atom:updated>2011-04-14T06:02:04.131-07:00</atom:updated><title>Property Bag in Application Setting Manager Does Not Find a Key… Easily</title><description>&lt;p&gt;I am working on a custom SharePoint 2010 application now, which relies on &lt;a title=&quot;Developing Applications for SharePoint 2010&quot; href=&quot;http://207.46.16.248/en-us/library/ff770300.aspx&quot; target=&quot;_blank&quot;&gt;Microsoft SharePoint 2010 Guidance for developers&lt;/a&gt;. Today I came across an interesting issue while utilizing Application Setting Manager component of the guidance library. I thought I’ve set up my application according to &lt;a title=&quot;Using the Application Setting Manager Interfaces&quot; href=&quot;http://207.46.16.248/en-us/library/ff798443.aspx&quot; target=&quot;_blank&quot;&gt;the instructions&lt;/a&gt;, but I could not get settings retrieved. It turned out that there is a nuance that was not obvious from documentation, which I’d like to point out. &lt;/p&gt;  &lt;p&gt;So the setting manager stores configuration settings in a property bag of a web site, site collection, web application or a farm. It can be hierarchical, or you can specify level at which you want to store a setting. Quite powerful. In my case I used a site collection scoped feature to deploy my settings and store them in a site collection property bag. Here is a simplified fragment of my feature receiver class provisioning application settings:&lt;/p&gt;  &lt;div&gt;   &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; height: 184px; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;var site = properties.Feature.Parent &lt;span style=&quot;color: #0000ff&quot;&gt;as&lt;/span&gt; SPSite;&lt;br /&gt;var locator = SharePointServiceLocator.GetCurrent();&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #008000&quot;&gt;// Acquire instances of config manager and property bag&lt;/span&gt;&lt;br /&gt;var configManager = locator.GetInstance&amp;lt;IConfigManager&amp;gt;();&lt;br /&gt;configManager.SetWeb(site.RootWeb);&lt;br /&gt;var bag = configManager.GetPropertyBag(ConfigLevel.CurrentSPSite);&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #008000&quot;&gt;// Provision application settings&lt;/span&gt;&lt;br /&gt;configManager.SetInPropertyBag(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Key1&amp;quot;&lt;/span&gt;, &lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Value1&amp;quot;&lt;/span&gt;, bag);&lt;br /&gt;configManager.SetInPropertyBag(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Key2&amp;quot;&lt;/span&gt;, &lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Value2&amp;quot;&lt;/span&gt;, bag);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To retrieve the settings I used the following logic:&lt;/div&gt;&lt;div id=&quot;codeSnippetWrapper&quot;&gt;&lt;br /&gt;  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;var locator = SharePointServiceLocator.GetCurrent();&lt;br /&gt;var config = locator.GetInstance&amp;lt;IConfigManager&amp;gt;();&lt;br /&gt;var bag = config.GetPropertyBag(ConfigLevel.CurrentSPSite);&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (!bag.Contains(key))&lt;br /&gt;{&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;throw&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; MyKeyNotFoundException();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I would be not finding the key and getting an exception. My problem was in just relying on the intellisense – why not? Well, the Microsoft guidance had it right though: in the examples&amp;#160; the check is made as follows:&lt;/div&gt;&lt;div id=&quot;codeSnippetWrapper&quot;&gt;&lt;br /&gt;  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (!config.ContainsKeyInPropertyBag(key, bag))&lt;br /&gt;{&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;throw&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; MyKeyNotFoundException();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And this one works fine.&amp;#160; You can check quite easily what is in your site’s property bag; this and availability of the source code of Microsoft.Practices.SharePoint.Common library help to understand what is going on. Here is how you can see your site collection’s property bag contents using PowerShell (it is stored in the root web of the site collection):&lt;/div&gt;&lt;div id=&quot;codeSnippetWrapper&quot;&gt;&lt;br /&gt;  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;$web = Get-SPWeb http:&lt;span style=&quot;color: #008000&quot;&gt;//yoursitecollectionaddress/&lt;/span&gt;&lt;br /&gt;$web.AllProperties | fl&lt;/pre&gt;&lt;br /&gt;You will find that your keys are in the form &lt;strong&gt;PnP.Config.Key.&lt;/strong&gt;Key1&lt;strong&gt;._Site_ &lt;/strong&gt;where the highlighted parts are attached to your actual key. The prefix is a constant, the suffix depends on a property bag type you use. Now if you try calling original method &lt;font face=&quot;Courier New&quot;&gt;bag.Contains(key) &lt;/font&gt;passing it &lt;strong&gt;PnP.Config.Key.Key1&lt;/strong&gt; – then it will find the key!&lt;/div&gt;&lt;p&gt;One other observation, – you are probably using &lt;a title=&quot;SharePoint Service Locator&quot; href=&quot;http://207.46.16.248/en-us/library/ff798484.aspx&quot; target=&quot;_blank&quot;&gt;SharePoint Service Locator&lt;/a&gt; pattern with the setting manager, and like I do have unit tests. I needed to replace implementation of &lt;font face=&quot;Courier New&quot;&gt;IConfigManager&lt;/font&gt; and &lt;font face=&quot;Courier New&quot;&gt;IPropertyBag&lt;/font&gt; interfaces with mock classes. Without knowing about this “feature” my mock implementation would find a value for the key as follows: &lt;font face=&quot;Courier New&quot;&gt;bag.Contains(“Key1”) == true&lt;/font&gt;, which would add confusion when the same key would not work in a web site. So try to always use &lt;font face=&quot;Courier New&quot;&gt;config.ContainsInPropertyBag(key, bag) &lt;/font&gt;method instead.&lt;/p&gt;</description><link>http://neganov.blogspot.com/2011/04/property-bag-in-application-setting.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-5813168160561710535</guid><pubDate>Sat, 29 Jan 2011 19:46:00 +0000</pubDate><atom:updated>2011-01-29T11:54:26.476-08:00</atom:updated><title>Extending CoreResultsWebPart to Handle Search Queries Written in FAST Query Language</title><description>&lt;p&gt;This was one of &lt;a title=&quot;October 19 MSPUG meeting&quot; href=&quot;http://neganov.blogspot.com/2010/10/decks-source-code-and-resources-from.html&quot; target=&quot;_blank&quot;&gt;unanswered items&lt;/a&gt; in my recent two presentations on Search at &lt;a title=&quot;Toronto SharePoint Users Group&quot; href=&quot;http://www.meetup.com/TorontoSPUG/&quot; target=&quot;_blank&quot;&gt;TSPUG&lt;/a&gt; and &lt;a title=&quot;Mississauga SharePoint User Group&quot; href=&quot;http://www.mspug.ca/&quot; target=&quot;_blank&quot;&gt;MSPUG&lt;/a&gt;, so I was driven to figure it out and eventually did get it to work although not without some controversial steps. In this post I chose to also describe other approaches I tried and things I learned along the way, which didn’t necessarily get me to the end goal but may still be useful in your specific scenario. If you are looking for just extending &lt;font face=&quot;Courier New&quot;&gt;&lt;a title=&quot;Microsoft.Office.Server.Search.WebControls.CoreResultsWebPart&quot; href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.office.server.search.webcontrols.coreresultswebpart.aspx&quot; target=&quot;_blank&quot;&gt;CoreResultsWebPart&lt;/a&gt;&lt;/font&gt; so that it can “understand” FQL then you may want to scroll down a bit. You can download the complete source code &lt;a title=&quot;CoreResultsWebPartCustomization.zip&quot; href=&quot;http://www.softforte.com/resources/coreresultswebpartcustomization.zip&quot;&gt;here&lt;/a&gt;. I was testing my code on a SharePoint Server 2010 with December 2010 CU installed.&lt;/p&gt;  &lt;p&gt;As you may know search web parts in SharePoint 2010 are no longer sealed, which gives you lots of flexibility via extending them. &lt;font face=&quot;Courier New&quot;&gt;CoreResultsWebPart&lt;/font&gt; is probably the most important of all and therefore it is a great candidate for being extended. I wanted to take a search phrase passed as a query string argument to a search results page and write my own FQL query using this phrase as a parameter. My FQL query would do something interesting with it, for example use XRANK to boost documents created by a particular author. I certainly wanted to leverage all the goodness of &lt;font face=&quot;Courier New&quot;&gt;CoreResultsWebPart&lt;/font&gt;, just use my FQL query instead of a plain search phrase. Contrary to my expectations it turned out to be not trivial to accomplish. So let’s dive into the details.&lt;/p&gt;  &lt;p&gt;The story started with it completely not working, so I was forced to write a custom web part that used query object model and in particular the &lt;font face=&quot;Courier New&quot;&gt;&lt;a title=&quot;Microsoft.Office.Server.Search.Query.KeywordQuery&quot; href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.office.server.search.query.keywordquery.aspx&quot; target=&quot;_blank&quot;&gt;KeywordQuery&lt;/a&gt;&lt;/font&gt; class to deal with queries written in FAST Query Language (FQL). This is the one I have demonstrated at MSPUG and (with little success) at TSPUG.&amp;#160; Below is a fragment showing how the query is submitted and results are rendered (BTW here is &lt;a title=&quot;Walkthrough: Creating a Basic Search Web Part Using the Query Object Model&quot; href=&quot;http://msdn.microsoft.com/en-us/library/ms551453.aspx&quot; target=&quot;_blank&quot;&gt;related MSDN reference with example&lt;/a&gt;).&lt;/p&gt;  &lt;div&gt;   &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;using&lt;/span&gt; (KeywordQuery q = &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; KeywordQuery(ssaProxy))&lt;br /&gt; {&lt;br /&gt;     q.QueryText = fql;&lt;br /&gt;     q.EnableFQL = &lt;span style=&quot;color: #0000ff&quot;&gt;true&lt;/span&gt;;&lt;br /&gt;     q.ResultTypes = ResultType.RelevantResults;&lt;br /&gt;     ResultTableCollection tables = q.Execute();&lt;br /&gt;     &lt;br /&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (tables.Count == 0)&lt;br /&gt;     {&lt;br /&gt;         &lt;span style=&quot;color: #0000ff&quot;&gt;return&lt;/span&gt;;&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;using&lt;/span&gt; (ResultTable table = tables[ResultType.RelevantResults])&lt;br /&gt;     {&lt;br /&gt;         &lt;span style=&quot;color: #0000ff&quot;&gt;while&lt;/span&gt; (table.Read())&lt;br /&gt;         {&lt;br /&gt;             &lt;span style=&quot;color: #0000ff&quot;&gt;int&lt;/span&gt; ordinal = table.GetOrdinal(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;);&lt;br /&gt;             &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; title = table.GetString(ordinal);&lt;br /&gt;             TitleLabel.Controls.Add(&lt;br /&gt;                 &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; LiteralControl(&lt;br /&gt;                     String.Format(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;&amp;lt;br&amp;gt;{0}&amp;lt;/br&amp;gt;\r\n&amp;quot;&lt;/span&gt;, title)));&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         table.Close();&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As you can see, rendering of results is very basic. Of course it can be made whatever it needs to be but why bother if there is CoreResultsWebPart around, which does it great already and is also highly customizable? So at this point I rolled up my sleeves. I have a book titled “&lt;a title=&quot;Professional SharePoint 2010 Development&quot; href=&quot;http://www.wrox.com/WileyCDA/WroxTitle/Professional-SharePoint-2010-Development.productCd-0470529423.html&quot; target=&quot;_blank&quot;&gt;Professional SharePoint 2010 Development&lt;/a&gt;” with a red Boeing 767 on the cover, and in Chapter 6 there is a great discussion of how to extend &lt;font face=&quot;Courier New&quot;&gt;CoreResultsWebPart&lt;/font&gt;. Also &lt;a title=&quot;Todd Carter&quot; href=&quot;http://www.todd-carter.com/default.aspx&quot; target=&quot;_blank&quot;&gt;Todd Carter&lt;/a&gt; speaks about it and shows a demo &lt;a title=&quot;SharePoint 2010 Advanced Developer Training - Enterprise Search in SharePoint 2010&quot; href=&quot;http://msdn.microsoft.com/en-us/sharepoint/ff420377.aspx&quot; target=&quot;_blank&quot;&gt;in his excellent video on Search&lt;/a&gt;. If you haven’t seen it I highly recommend spending an hour and 16 minutes watching it (Module 7). &lt;/div&gt;&lt;div&gt;Empowered with all this I wrote a web part that extended the &lt;font face=&quot;Courier New&quot;&gt;CoreResultsWebPart&lt;/font&gt; and used a &lt;font face=&quot;Courier New&quot;&gt;FixedQuery&lt;/font&gt; property to set a custom query, being almost one-to-one copy of Todd’s demo example. Here is the listing of this web part class (note how ConfigureDataSourceProperties() method override is used to set the &lt;font face=&quot;Courier New&quot;&gt;FixedQuery&lt;/font&gt; property):&lt;/div&gt;&lt;div id=&quot;codeSnippetWrapper&quot;&gt;&lt;br /&gt;  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;class&lt;/span&gt; ExtendedCoreResultsWebPartWithKeywordSyntax : CoreResultsWebPart&lt;br /&gt;{&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;protected&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;override&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; ConfigureDataSourceProperties()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;const&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; LongQueryFormat = &lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;(FileExtension=\&amp;quot;doc\&amp;quot; OR FileExtension=\&amp;quot;docx\&amp;quot;) AND (Author:\&amp;quot;{0}\&amp;quot;)&amp;quot;&lt;/span&gt;;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;const&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; ShortQuery = &lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;(FileExtension=\&amp;quot;doc\&amp;quot; OR FileExtension=\&amp;quot;docx\&amp;quot;)&amp;quot;&lt;/span&gt;;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; query = &lt;span style=&quot;color: #0000ff&quot;&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (String.IsNullOrEmpty(AuthorToFilterBy))&lt;br /&gt;        {&lt;br /&gt;            query = ShortQuery;&lt;br /&gt;        }&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;else&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;            query = String.Format(LongQueryFormat, AuthorToFilterBy);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;this&lt;/span&gt;.FixedQuery = query;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;base&lt;/span&gt;.ConfigureDataSourceProperties();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [SPWebCategoryName(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Custom&amp;quot;&lt;/span&gt;),&lt;br /&gt;    Personalizable(PersonalizationScope.Shared),&lt;br /&gt;    WebPartStorage(Storage.Shared),&lt;br /&gt;    WebBrowsable(&lt;span style=&quot;color: #0000ff&quot;&gt;true&lt;/span&gt;),&lt;br /&gt;    WebDisplayName(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Author to filter by&amp;quot;&lt;/span&gt;),&lt;br /&gt;    Description(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;First and last name of the author to filter results by.&amp;quot;&lt;/span&gt;)]&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; AuthorToFilterBy { get; set; }&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The web part actually filters results by a given author. It uses &lt;em&gt;keyword query&lt;/em&gt; syntax and not the FQL so we are far from being done yet. Remember how in the previous code fragment there was a line &lt;font face=&quot;Courier New&quot;&gt;&lt;strong&gt;q.EnableFQL = true;&lt;/strong&gt;&lt;/font&gt;? If just we could set it somewhere we would be essentially done! Well right but the &lt;font face=&quot;Courier New&quot;&gt;KeywordQuery&lt;/font&gt; object is not directly accessible from the &lt;font face=&quot;Courier New&quot;&gt;CoreResultsWebPart&lt;/font&gt; because it uses federation object model on top of the query object model (as do other search web parts). Purpose of the federation object model is sending same query to multiple search results providers and aggregating results later either in different spots on results page or in the same list. This is done by abstracting each search results provider by means of a &lt;font color=&quot;#333333&quot; face=&quot;Courier New&quot;&gt;&lt;a title=&quot;Microosft.Office.Server.Search.Query.Location&quot; href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.office.server.search.query.location.aspx&quot; target=&quot;_blank&quot;&gt;Location&lt;/a&gt;&lt;/font&gt; class. Important classes in federation object model are shown on the diagram below.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&amp;#160;&lt;img style=&quot;border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto&quot; title=&quot;image&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;http://lh6.ggpht.com/_uLvQGkZ2Z10/TURujmuv3jI/AAAAAAAAADc/KgUZmz50fMs/image43.png?imgmax=800&quot; width=&quot;690&quot; height=&quot;687&quot; /&gt; &lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;As you can see, &lt;font face=&quot;Courier New&quot;&gt;CoreResultsWebPart&lt;/font&gt; is connected to the federation OM through &lt;font face=&quot;Courier New&quot;&gt;CoreResultsDatasource&lt;/font&gt; and &lt;font face=&quot;Courier New&quot;&gt;CoreResultsDatasourceView&lt;/font&gt; types with the latter actually doing all the hard work interacting with the model. And also our objective, the &lt;font face=&quot;Courier New&quot;&gt;EnableFQL&lt;/font&gt; property, exists in the &lt;font face=&quot;Courier New&quot;&gt;&lt;a title=&quot;Microsoft.Office.Server.Search.Query.FASTSearchRuntime&quot; href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.office.server.search.query.fastsearchruntime.aspx&quot; target=&quot;_blank&quot;&gt;FASTSearchRuntime&lt;/a&gt;&lt;/font&gt; class, which in turn sets this property on the &lt;font face=&quot;Courier New&quot;&gt;KeywordQuery&lt;/font&gt; class, and as I showed at the beginning, this is what’s required to get FQL query syntax accepted.&lt;/div&gt;&lt;div&gt;As Todd Carter and the authors of Professional SharePoint 2010 Development point out, we need to extend the &lt;font face=&quot;Courier New&quot;&gt;CoreResultsDatasourceView&lt;/font&gt; class in order to be able to control how our query is handled, and wire up our own class by also extending&lt;font face=&quot;Courier New&quot;&gt; CoreResultsDatasource&lt;/font&gt; class. &lt;font face=&quot;Courier New&quot;&gt;CoreResultsDatasourceView&lt;/font&gt; class creates a &lt;font color=&quot;#333333&quot; face=&quot;Courier New&quot;&gt;&lt;a title=&quot;Microsoft.Office.Server.Search.Query.LocationList&quot; href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.office.server.search.query.locationlist.aspx&quot; target=&quot;_blank&quot;&gt;LocationList&lt;/a&gt;&lt;/font&gt; with a single &lt;font face=&quot;Courier New&quot;&gt;Location&lt;/font&gt; object and correctly determines which concrete implementation type of &lt;font color=&quot;#333333&quot; face=&quot;Courier New&quot;&gt;&lt;a title=&quot;Microsoft.Office.Server.Search.Query.ILocationRuntime&quot; href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.office.server.search.query.ilocationruntime.aspx&quot; target=&quot;_blank&quot;&gt;ILocationRuntime&lt;/a&gt;&lt;/font&gt; to wire up based on search service application configuration. In other words, federation by default is not happening for the &lt;font face=&quot;Courier New&quot;&gt;CoreResultsWebPart&lt;/font&gt;. There is another web part, &lt;font color=&quot;#333333&quot; face=&quot;Courier New&quot;&gt;&lt;a title=&quot;How to: Enable HTML Rendering for the Federated Results Web Part&quot; href=&quot;http://msdn.microsoft.com/en-us/library/cc789859.aspx&quot; target=&quot;_blank&quot;&gt;FederatedResultsWebPart&lt;/a&gt;&lt;/font&gt;, and another view class, &lt;font face=&quot;Courier New&quot;&gt;FederatedResultsDatasourceView&lt;/font&gt;, whose purpose is to do exactly that. With that, let us get back to our objective.&lt;/div&gt;&lt;div&gt;If we were using SharePoint Enterprise Search then we would be almost done, because public virtual method &lt;font face=&quot;Courier New&quot;&gt;AddSortOrder(SharePointSearchRuntime runtime)&lt;/font&gt; defined in the &lt;font face=&quot;Courier New&quot;&gt;SearchResultsBaseDatasourceView&lt;/font&gt; class would let us get our hands on the instance of &lt;font face=&quot;Courier New&quot;&gt;ILocationRuntime&lt;/font&gt;. But since we deal with &lt;font face=&quot;Courier New&quot;&gt;FASTSearchRuntime&lt;/font&gt; we are sort of out of luck. Yes there exists a method overload &lt;font face=&quot;Courier New&quot;&gt;AddSortOrder(FASTSearchRuntime runtime)&lt;/font&gt; but it is internal! This is where the controversy that I have mentioned at the beginning comes to play: I was not able to find a better way than to invoke an internal member via Reflection. My way works for me, but keep in mind that usually methods are made private or internal for a reason. I used Reflection to access internal property &lt;font face=&quot;Courier New&quot;&gt;LocationRuntime&lt;/font&gt; of the &lt;font face=&quot;Courier New&quot;&gt;Location&lt;/font&gt; object. I don’t know why this property is internal. If someone knows or has a better way to get at the &lt;font face=&quot;Courier New&quot;&gt;FASTSearchRuntime&lt;/font&gt; instance or the &lt;font face=&quot;Courier New&quot;&gt;KeywordQuery&lt;/font&gt; instance – please leave a comment! Here is a code fragment showing extension of the &lt;font face=&quot;Courier New&quot;&gt;CoreResultsDatasourceView&lt;/font&gt; and getting an instance of &lt;font face=&quot;Courier New&quot;&gt;FASTSearchRuntime&lt;/font&gt; from there.&lt;/div&gt;&lt;div id=&quot;codeSnippetWrapper&quot;&gt;&lt;br /&gt;  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;class&lt;/span&gt; CoreFqlResultsDataSourceView : CoreResultsDatasourceView&lt;br /&gt;{&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; CoreFqlResultsDataSourceView(SearchResultsBaseDatasource dataSourceOwner, &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; viewName)&lt;br /&gt;        : &lt;span style=&quot;color: #0000ff&quot;&gt;base&lt;/span&gt;(dataSourceOwner, viewName)&lt;br /&gt;    {&lt;br /&gt;        CoreFqlResultsDataSource fqlDataSourceOwner = &lt;span style=&quot;color: #0000ff&quot;&gt;base&lt;/span&gt;.DataSourceOwner &lt;span style=&quot;color: #0000ff&quot;&gt;as&lt;/span&gt; CoreFqlResultsDataSource;&lt;br /&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (fqlDataSourceOwner == &lt;span style=&quot;color: #0000ff&quot;&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;throw&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; ArgumentOutOfRangeException();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;override&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; SetPropertiesOnQdra()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;base&lt;/span&gt;.SetPropertiesOnQdra();&lt;br /&gt;        &lt;span style=&quot;color: #008000&quot;&gt;// At this point the query has not yet been dispatched to a search &lt;/span&gt;&lt;br /&gt;        &lt;span style=&quot;color: #008000&quot;&gt;// location and we can set properties on that location, which will &lt;/span&gt;&lt;br /&gt;        &lt;span style=&quot;color: #008000&quot;&gt;// let it understand the FQL syntax.&lt;/span&gt;&lt;br /&gt;        UpdateFastSearchLocation();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;private&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; UpdateFastSearchLocation()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #0000ff&quot;&gt;base&lt;/span&gt;.LocationList == &lt;span style=&quot;color: #0000ff&quot;&gt;null&lt;/span&gt; || 0 == &lt;span style=&quot;color: #0000ff&quot;&gt;base&lt;/span&gt;.LocationList.Count)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;return&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;foreach&lt;/span&gt; (Location location &lt;span style=&quot;color: #0000ff&quot;&gt;in&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;base&lt;/span&gt;.LocationList)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style=&quot;color: #008000&quot;&gt;// We examine the contents of an internal &lt;/span&gt;&lt;br /&gt;            &lt;span style=&quot;color: #008000&quot;&gt;// location.LocationRuntime property using Reflection. This is &lt;/span&gt;&lt;br /&gt;            &lt;span style=&quot;color: #008000&quot;&gt;// the key step, which is also controversial since there is &lt;/span&gt;&lt;br /&gt;            &lt;span style=&quot;color: #008000&quot;&gt;// probably a reason for not exposing the runtime publically.&lt;/span&gt;&lt;br /&gt;            Type locationType = location.GetType();&lt;br /&gt;            PropertyInfo info = locationType.GetProperty(&lt;br /&gt;                &lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;LocationRuntime&amp;quot;&lt;/span&gt;,&lt;br /&gt;                BindingFlags.NonPublic | BindingFlags.Instance,&lt;br /&gt;                &lt;span style=&quot;color: #0000ff&quot;&gt;null&lt;/span&gt;,&lt;br /&gt;                &lt;span style=&quot;color: #0000ff&quot;&gt;typeof&lt;/span&gt;(ILocationRuntime),&lt;br /&gt;                &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; Type[0],&lt;br /&gt;                &lt;span style=&quot;color: #0000ff&quot;&gt;null&lt;/span&gt;);&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;object&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;value&lt;/span&gt; = info.GetValue(location, &lt;span style=&quot;color: #0000ff&quot;&gt;null&lt;/span&gt;);&lt;br /&gt;            FASTSearchRuntime runtime = &lt;span style=&quot;color: #0000ff&quot;&gt;value&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;as&lt;/span&gt; FASTSearchRuntime;&lt;br /&gt;&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #0000ff&quot;&gt;null&lt;/span&gt; != runtime)&lt;br /&gt;            {&lt;br /&gt;                &lt;span style=&quot;color: #008000&quot;&gt;// This is a FAST Search runtime. We can now enable FQL.&lt;/span&gt;&lt;br /&gt;                runtime.EnableFQL = &lt;span style=&quot;color: #0000ff&quot;&gt;true&lt;/span&gt;;&lt;br /&gt;                &lt;span style=&quot;color: #0000ff&quot;&gt;break&lt;/span&gt;;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;By the way, another limitation of my approach is that using Reflection requires full trust CAS policy level. That said, finally we have arrived at our objective – we can set the flag on the &lt;font face=&quot;Courier New&quot;&gt;FASTSearchRuntime&lt;/font&gt;, and it will understand our FQL queries. Our extended search results web part will show results as directed by the query (in the &lt;a title=&quot;CoreResultsWebPartCustomization.zip&quot; href=&quot;http://www.softforte.com/resources/coreresultswebpartcustomization.zip&quot;&gt;attached source code&lt;/a&gt; it uses XRANK) and leverage presentation richness of the &lt;font face=&quot;Courier New&quot;&gt;CoreResultsWebPart&lt;/font&gt;.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;</description><link>http://neganov.blogspot.com/2011/01/extending-coreresultswebpart-to-handle.html</link><author>noreply@blogger.com (Ivan Neganov)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_uLvQGkZ2Z10/TURujmuv3jI/AAAAAAAAADc/KgUZmz50fMs/s72-c/image43.png?imgmax=800" height="72" width="72"/><thr:total>8</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-8790783665674466882</guid><pubDate>Fri, 21 Jan 2011 13:03:00 +0000</pubDate><atom:updated>2011-01-22T10:39:56.700-08:00</atom:updated><title>Decks and Source Code from January 19th TSPUG  Meeting</title><description>&lt;p&gt;Thanks to all who came to Wednesday’s &lt;a href=&quot;http://www.tspug.com&quot;&gt;TSPUG&lt;/a&gt; meet up. I’ve uploaded a &lt;a title=&quot;Presentation Package TSPUG 2011-01-19&quot; href=&quot;http://www.softforte.com/resources/tspug-2011-01-19.zip&quot;&gt;package&lt;/a&gt; with presentation and source code files. I was able to resolve the first of the questions unanswered during &lt;a title=&quot;MSPUG presentation 2011-10-19&quot; href=&quot;http://neganov.blogspot.com/2010/10/decks-source-code-and-resources-from.html&quot;&gt;my previous talk about SharePoint search technologies&lt;/a&gt;. Although I meant to show it, I didn’t get to talk much about promoting user profile properties for selection in FAST user context for visual best bets. Basically as &lt;a title=&quot;Why do I get an access denied error when managing user contexts in SharePoint 2010&quot; href=&quot;http://blogs.technet.com/b/speschka/archive/2010/02/22/why-do-i-get-an-access-denied-error-when-managing-user-contexts-in-sharepoint-2010.aspx&quot; target=&quot;_blank&quot;&gt;Steve Peschka has pointed out&lt;/a&gt;,&amp;#160; the first thing that needs to be done is permissions granted to the profile store. This will let you see the list of properties in his Property Explorer tool. Secondly, to promote profile properties to be available for selection in &lt;font face=&quot;Courier New&quot;&gt;FAST Search user context &lt;/font&gt;administration section you need to edit value of &lt;font face=&quot;Courier New&quot;&gt;FASTSearchContextProperties&lt;/font&gt; property of FAST Query search service application (SSA). I wrote a command-line utility for this purpose, which can be invoked as follows:&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;FASTProfilePropertyUpdater.exe –ssaId &amp;lt;FAST query SSA Guid&amp;gt; -action Add|Remove -property &amp;lt;User Profile property name&amp;gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Code fragment below demonstrates how SSA reference is acquired and the “Add” operation is accomplished. Full source code is a part of the package. Ideally you want to use PowerShell script to manage this, I just wrote an executable as it was easier to get it working quickly for me. &lt;/p&gt;  &lt;div id=&quot;codeSnippetWrapper&quot;&gt;   &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;SPFarm farm = SPFarm.Local;&lt;br /&gt; var settingsService = SPFarm.Local.Services.GetValue&amp;lt;SearchQueryAndSiteSettingsService&amp;gt;();&lt;br /&gt; var serviceApp = settingsService.Applications[ssaId];&lt;br /&gt; var searchApp = serviceApp &lt;span style=&quot;color: #0000ff&quot;&gt;as&lt;/span&gt; SearchServiceApplication;&lt;br /&gt;&lt;br /&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #0000ff&quot;&gt;null&lt;/span&gt; == searchApp)&lt;br /&gt; {&lt;br /&gt;     Console.WriteLine(&lt;br /&gt;         &lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Cannot find search service application with the ID &#39;{0}&#39;.&amp;quot;&lt;/span&gt;, &lt;br /&gt;         ssaId);&lt;br /&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;return&lt;/span&gt; 2;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt; properties = (String)searchApp.Properties[FASTSearchContextProperties];&lt;br /&gt; Console.WriteLine(&lt;br /&gt;     &lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Updating service application properties for property key &#39;{0}&#39;... Value before update was: &#39;{1}&#39;&amp;quot;&lt;/span&gt;,&lt;br /&gt;     FASTSearchContextProperties,&lt;br /&gt;     properties);&lt;br /&gt; List&amp;lt;&lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt;&amp;gt; propertiesList = properties.Split(&lt;span style=&quot;color: #006080&quot;&gt;&#39;,&#39;&lt;/span&gt;).&lt;br /&gt;     Select(p =&amp;gt; p.Trim()).ToList();&lt;br /&gt; &lt;br /&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;if&lt;/span&gt; (ContextPropertyActions.Add == action &amp;amp;&amp;amp;&lt;br /&gt;     properties.IndexOf(propertyName, StringComparison.Ordinal) &amp;lt; 0)&lt;br /&gt; {&lt;br /&gt;     propertiesList.Add(propertyName);&lt;br /&gt;     properties = &lt;span style=&quot;color: #0000ff&quot;&gt;string&lt;/span&gt;.Join(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;,&amp;quot;&lt;/span&gt;, propertiesList.ToArray());&lt;br /&gt;     searchApp.Properties[FASTSearchContextProperties] = properties;&lt;br /&gt;     searchApp.Update(&lt;span style=&quot;color: #0000ff&quot;&gt;true&lt;/span&gt;);&lt;br /&gt;     Console.WriteLine(&lt;span style=&quot;color: #006080&quot;&gt;&amp;quot;Property added. Updated value is: &#39;{0}&#39;.&amp;quot;&lt;/span&gt;, properties);&lt;br /&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;return&lt;/span&gt; 0;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Also in the package is the source code for a web part demonstrating how to dynamically boost search relevance ranking from within an FQL query by using XRANK keyword.The demo of this web part didn’t go well, but the code is actually working (I dragged the wrong web part to the page during presentation!). Also someone has asked me about proximity-based filtering of results in FAST query language. Yes this is possible&amp;#160; - &lt;a title=&quot;FAST Query Language Operations&quot; href=&quot;http://msdn.microsoft.com/en-us/library/ff394462.aspx&quot; target=&quot;_blank&quot;&gt;there is a number of keywords that support this&lt;/a&gt;. &lt;/div&gt;</description><link>http://neganov.blogspot.com/2011/01/decks-from-january-19th-tspug-meeting.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-5830715909350352710</guid><pubDate>Sun, 09 Jan 2011 03:18:00 +0000</pubDate><atom:updated>2011-01-10T08:15:48.901-08:00</atom:updated><title>Automate Internet Proxy Management with PowerShell</title><description>&lt;p&gt;The solution is very simple, yet the issue was so annoying to me that I thought to share this. I have a laptop and do work on it on site at my client and when I am at home. When I am in the office connected to my client’s network I need to use a proxy to access the Internet, while usually I do not need a proxy when I am located elsewhere. You normally set up a proxy using browser settings. With Internet Explorer 8 you open a browser, then go to &lt;strong&gt;Tools &amp;gt;&amp;gt; Internet Options &amp;gt;&amp;gt; Connections &amp;gt;&amp;gt; LAN Settings&lt;/strong&gt;. There you configure the proxy parameters. As a part of configuration you can turn the proxy on or off by setting or clearing a &lt;strong&gt;Use a proxy server for your LAN &lt;/strong&gt;check box, and as you switch the proxy the rest of your proxy configuration settings such as exceptions is preserved for you. Great!&lt;/p&gt;  &lt;p&gt;My problem was that on almost daily basis I had to open the browser, navigate to settings then check or uncheck that box. I would come to work and forget to go through the steps so my browser would get stuck, and then I would go “oh yeah, I turned the proxy off last night”. Of course the reverse would happen at home… I tolerated this too long because I didn’t expect that a simple solution exists, but it does and here it is:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;font face=&quot;Courier New&quot;&gt;HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyEnable &lt;/font&gt;key stores a DWORD value, either 1 or 0 to indicate if the proxy is enabled. &lt;/p&gt;  &lt;p&gt;So I wrote two 1-line PowerShell scripts and added two shortcuts to them to my Windows taskbar: Enable Proxy, Disable Proxy! Here is how the script to enable proxy looks like:&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;Set-ItemProperty &amp;quot;HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings&amp;quot; -Name ProxyEnable -Value 1&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Then I’ve got excited, and wrote yet another rock star PowerShell script. Here it is:&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;$matches = @(ipconfig /all | findstr &amp;quot;myclientdomain&amp;quot;)     &lt;br /&gt;if($matches.Count -gt 0){      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ./EnableProxy.ps1      &lt;br /&gt;}else{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; ./DisableProxy.ps1      &lt;br /&gt;}&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;That’s right I am using output of the ipconfig command to determine if I am on the client’s network and if yes then I turn on my proxy. After I have added a scheduled task running at user logon to invoke this script, the quality of my professional life has improved.&lt;/p&gt;</description><link>http://neganov.blogspot.com/2011/01/automate-internet-proxy-management-with.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-7434132947817462162</guid><pubDate>Thu, 23 Dec 2010 22:45:00 +0000</pubDate><atom:updated>2011-02-24T13:35:42.855-08:00</atom:updated><title>Writing Trace Output to ULS Log in SharePoint 2010</title><description>&lt;p&gt;SharePoint 2010 supports writing custom messages to ULS log. A &lt;a title=&quot;Logging to ULS in SharePoint 2010&quot; href=&quot;http://blog.mastykarz.nl/logging-uls-sharepoint-2010/&quot; target=&quot;_blank&quot;&gt;blog post&lt;/a&gt; by Waldek Mastykarz of &lt;a title=&quot;Mavention&quot; href=&quot;http://www.mavention.nl/&quot; target=&quot;_blank&quot;&gt;Mavention&lt;/a&gt; provides a good example of how to do this. &lt;strong&gt;UPDATE 02/24/2011:&lt;/strong&gt; &lt;A href=&quot;http://msdn.microsoft.com/en-us/library/gg512103.aspx#bk_splog&quot; target=&quot;_blank&quot;&gt;Andrew Connell&#39;s article on MSDN from December 2010&lt;/a&gt; provides essential information on diagnostics logging.&lt;/p&gt;&lt;p&gt;Ability to send messages from &lt;a title=&quot;System.Diagnostics.Trace&quot; href=&quot;http://msdn.microsoft.com/en-us/library/system.diagnostics.trace.aspx&quot; target=&quot;_blank&quot;&gt;System.Diagnostics.Trace&lt;/a&gt;.Write() and Trace.Fail() method overloads to ULS is yet another “logging novelty” I will be focusing on in this post.&lt;/p&gt;  &lt;p&gt;There is a new type in Microsoft.SharePoint assembly, which was not there in version 12 – &lt;a title=&quot;Microsoft.SharePoint.SPULSTraceListener&quot; href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spulstracelistener.aspx&quot; target=&quot;_blank&quot;&gt;Microsoft.SharePoint.SPULSTraceListener&lt;/a&gt;. As its name suggests it allows sending trace messages to ULS. &lt;/p&gt;  &lt;p&gt;If you are instrumenting your custom SharePoint code and need to write diagnostic traces to ULS then you can wire up SPULSTraceListener type in your web.config and use tracing infrastructure available in &lt;font face=&quot;Courier New&quot;&gt;System.Diagnostics.Trace&lt;/font&gt;.&amp;#160; Here are the steps:&lt;/p&gt;  &lt;p&gt;1. Add a trace listener element to web.config. For more information see description of &lt;a title=&quot;system.diagnostics configuration element on MSDN&quot; href=&quot;http://msdn.microsoft.com/en-us/library/1txedc80.aspx&quot; target=&quot;_blank&quot;&gt;system.diagnostics&lt;/a&gt; element on MSDN.&lt;/p&gt;  &lt;div id=&quot;codeSnippetWrapper&quot;&gt;   &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;system.diagnostics&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;trace&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;listeners&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;remove&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;Default&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;add&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;ULSTraceListener&amp;quot;&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;Microsoft.SharePoint.SPULSTraceListener, Microsoft.SharePoint, version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;listeners&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;trace&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;system.diagnostics&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In this XML snippet note the &lt;strong&gt;&amp;lt;remove name=”Default”&amp;gt;&lt;/strong&gt;. This is done to remove &lt;a title=&quot;DefaultTraceListener&quot; href=&quot;http://msdn.microsoft.com/en-us/library/system.diagnostics.defaulttracelistener.aspx&quot; target=&quot;_blank&quot;&gt;default trace listener&lt;/a&gt;, which is wired up by default and displays a pop-up window with the message when &lt;font face=&quot;Courier New&quot;&gt;Trace.Fail()&lt;/font&gt; is called.&lt;/div&gt;&lt;p&gt;2. In central administration site configure diagnostic logging (Central Administration &amp;gt;&amp;gt; Diagnostic Logging). If you are using &lt;font face=&quot;Courier New&quot;&gt;Trace.Write()&lt;/font&gt; method calls then they are logged as &lt;strong&gt;Verbose &lt;/strong&gt;and so in order to actually see them in ULS logs you need to make sure that throttling level is set to &lt;strong&gt;Verbose&lt;/strong&gt; for &lt;strong&gt;SharePoint Foundation &amp;gt; Service Connections &lt;/strong&gt;category. If you use &lt;font face=&quot;Courier New&quot;&gt;Trace.Fail()&lt;/font&gt; overloaded methods then the message will be written as a &lt;strong&gt;High &lt;/strong&gt;level, which by default is on, so the message will normally end up being written to a log file. And yes, all messages will be written to the log under &lt;strong&gt;Service Connections&lt;/strong&gt; category.&lt;/p&gt;&lt;br /&gt;&lt;h5&gt;What About TraceContext.Write()?&lt;/h5&gt;&lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;UserControl&lt;/font&gt;, &lt;font face=&quot;Courier New&quot;&gt;Page&lt;/font&gt; and &lt;font face=&quot;Courier New&quot;&gt;HttpContext&lt;/font&gt; classes have a property named &lt;strong&gt;Trace&lt;/strong&gt; of type &lt;a title=&quot;System.Web.TraceContext&quot; href=&quot;http://msdn.microsoft.com/en-us/library/system.web.tracecontext.aspx&quot; target=&quot;_blank&quot;&gt;System.Web.TraceContext&lt;/a&gt;. It allows tracing messages using ASP.NET trace infrastructure, for example: &lt;font face=&quot;Courier New&quot;&gt;HttpContext.Current.Trace.Write(string message);.&lt;/font&gt; You can send ASP.NET trace messages to ULS using standard technique but with a caveat: &lt;/p&gt;&lt;p&gt;Add &lt;a title=&quot;trace Element&quot; href=&quot;http://msdn.microsoft.com/en-us/library/6915t83k.aspx&quot;&gt;trace&lt;/a&gt; configuration element under system.web element in your web.config as follows:&lt;/p&gt;&lt;div&gt;&lt;br /&gt;  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;system.web&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;trace&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;enabled&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;requestLimit&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;1000&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;mostRecent&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;writeToDiagnosticsTrace&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    ...&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here the key attribute is &lt;font face=&quot;Courier New&quot;&gt;writeToDiagnosticsTrace&lt;/font&gt; instructing ASP.NET trace to use tracing infrastructure from System.Diagnostics. Now trace messages written using &lt;font face=&quot;Courier New&quot;&gt;TraceContext.Write()&lt;/font&gt; will be sent to ULS.&lt;/div&gt;&lt;div&gt;Now the caveat: adding &lt;font face=&quot;Courier New&quot;&gt;system.web/trace&lt;/font&gt; element appears to destabilize SharePoint. I have tried this on SharePoint Foundation and SharePoint Server 2010 with October 2010 CU, and although tracing does work as expected I have got a consistent error when trying to create a new web part page:&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://lh4.ggpht.com/_uLvQGkZ2Z10/TRPRGBbwh4I/AAAAAAAAADU/OequMgi6-lA/s1600-h/UIErrorFromTracing%5B4%5D.jpg&quot;&gt;&lt;img style=&quot;border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px&quot; title=&quot;UIErrorFromTracing&quot; border=&quot;0&quot; alt=&quot;UIErrorFromTracing&quot; src=&quot;http://lh6.ggpht.com/_uLvQGkZ2Z10/TRPRGbBB54I/AAAAAAAAADY/7PwijdGvTrU/UIErrorFromTracing_thumb%5B2%5D.jpg?imgmax=800&quot; width=&quot;580&quot; height=&quot;258&quot; /&gt;&lt;/a&gt; &lt;/div&gt;&lt;div&gt;Looking at the ULS log, I found these messages logged under SharePoint Foundation category:&lt;/div&gt;&lt;p&gt;&lt;font size=&quot;1&quot; face=&quot;Courier New&quot;&gt;SharePoint Foundation&amp;#160;&amp;#160;&amp;#160; General&amp;#160;&amp;#160;&amp;#160; b9y3&amp;#160;&amp;#160;&amp;#160; High&amp;#160;&amp;#160;&amp;#160; Failed to open the file &#39;C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\Resources\wss.resx&#39;.&lt;br /&gt;    &lt;br /&gt;SharePoint Foundation&amp;#160;&amp;#160;&amp;#160; General&amp;#160;&amp;#160;&amp;#160; b9y4&amp;#160;&amp;#160;&amp;#160; High&amp;#160;&amp;#160;&amp;#160; #20015: Cannot open &amp;quot;&amp;quot;: no such file or folder.&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;SharePoint Foundation&amp;#160;&amp;#160;&amp;#160; General&amp;#160;&amp;#160;&amp;#160; b9y4&amp;#160;&amp;#160;&amp;#160; High&amp;#160;&amp;#160;&amp;#160; (#2: Cannot open &amp;quot;&amp;quot;: no such file or folder.)&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;SharePoint Foundation&amp;#160;&amp;#160;&amp;#160; General&amp;#160;&amp;#160;&amp;#160; b9y9&amp;#160;&amp;#160;&amp;#160; High&amp;#160;&amp;#160;&amp;#160; Failed to read resource file &amp;quot;C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\Resources\wss.resx&amp;quot; from feature id &amp;quot;(null)&amp;quot;.&lt;/font&gt;&lt;/p&gt;&lt;div&gt;&amp;#160;&lt;/div&gt;&lt;div&gt;As soon as I disable the &lt;font face=&quot;Courier New&quot;&gt;system.web/tracing&lt;/font&gt; the error disappears. I am not sure if this is a bug or adding &amp;lt;trace&amp;gt; element under &amp;lt;system.web&amp;gt; is not supported. In any case there is enough of rich diagnostic features available, and if you are using tracing in your application then just avoid &lt;font face=&quot;Courier New&quot;&gt;System.Web.TraceContext.Write()&lt;/font&gt; in favor of &lt;font face=&quot;Courier New&quot;&gt;System.Diagnostics.Trace.Write() &lt;/font&gt;or at least use it temporarily if you need to. By the way &lt;font face=&quot;Courier New&quot;&gt;System.Diagnostics.Debug.Write()&lt;/font&gt; also sends messages to trace log.&lt;/div&gt;&lt;p&gt;&lt;strong style=&quot;color:red&quot;&gt;UPDATE (01-16-2011):&lt;/strong&gt; There is yet another issue caused by turning on trace that I ran into today: SharePoint designer cannot open a site in a web application for which tracing is enabled, and keeps prompting for credentials. If you check out traffic with Fiddler, you will find that SPD makes requests to http://devserver2010/_vti_bin/shtml.dll/_vti_rpc, which return a 401 UNAUTHORIZED. Not even verbose logging reveals anything useful. Well, commenting out &amp;lt;trace&amp;gt; element in web.config restores normal functionality.&lt;/p&gt;</description><link>http://neganov.blogspot.com/2010/12/writing-trace-output-to-uls-log-in.html</link><author>noreply@blogger.com (Ivan Neganov)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_uLvQGkZ2Z10/TRPRGbBB54I/AAAAAAAAADY/7PwijdGvTrU/s72-c/UIErrorFromTracing_thumb%5B2%5D.jpg?imgmax=800" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-7015463810052257156</guid><pubDate>Mon, 13 Dec 2010 18:04:00 +0000</pubDate><atom:updated>2010-12-13T12:09:39.113-08:00</atom:updated><title>Configure Links Web Part to Open URLs In a New Window With SharePoint 2010</title><description>&lt;p&gt;With SharePoint 2010 (or SharePoint Foundation 2010) you can customize list views using XSLT, which is very powerful and for simple changes also quite simple. Here is an example of how to make URLs in Links list web part open up pages in a new browser window.&lt;/p&gt;  &lt;p&gt;Links web part as well as other list-based web parts uses a predefined list view to render its content. Since views are now defined using XSLT style sheets, all that is needed to control the HTML is to override appropriate XSLT template with a custom one that has HTML markup that we need, for example &amp;lt;a href=”….” &lt;strong&gt;target=”_blank”&lt;/strong&gt;&amp;gt;. List web part’s edit mode panel contains a text field titled &lt;strong&gt;XSL Link&lt;/strong&gt; under Miscellaneous category where you can provide a URL of an XSLT file, which will override default rendering behavior. &lt;/p&gt;  &lt;p&gt;Let’s say we have a Links list with a few URLs in it and we have added a Links web part to a page. We want to have all links shown by the web part open up in a new window. We need to find an XSLT template which describes rendering of the field with a link. One easy way to determine this is to sort by the URL field then take a note of the value of &lt;strong&gt;SortField&lt;/strong&gt; query string value, which tells us that the field name we need is &lt;strong&gt;URLNoMenu&lt;/strong&gt;. URL field is not a part of default view, default view has a &lt;b&gt;URL (URL with edit menu)&lt;/b&gt; column, so you would need to add a column titled &lt;b&gt;URL&lt;/b&gt;. As shown in the picture below, I’ve added my own view “Only Url” to Links list with this field only and set the web part to use this view.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;http://lh3.ggpht.com/_uLvQGkZ2Z10/TQZgLMJEdcI/AAAAAAAAADI/RkS_Lf_0P-4/s1600-h/LinksListExample%5B6%5D.jpg&quot;&gt;&lt;img style=&quot;border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px&quot; title=&quot;LinksListExample&quot; border=&quot;0&quot; alt=&quot;LinksListExample&quot; src=&quot;http://lh6.ggpht.com/_uLvQGkZ2Z10/TQZgLqjRhqI/AAAAAAAAADM/9iSlyqh3ywM/LinksListExample_thumb%5B4%5D.jpg?imgmax=800&quot; width=&quot;896&quot; height=&quot;683&quot; /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Now we need to find an XSLT template for the URLNoMenu field.&amp;#160; Out-Of-The-Box templates are stored under the &lt;strong&gt;14&lt;/strong&gt; hive in TEMPLATE\LAYOUTS\XSL on server file system. For what we need there are 2 important files there: &lt;strong&gt;main.xsl&lt;/strong&gt; and &lt;strong&gt;fldtypes.xsl&lt;/strong&gt;. The former file is a default file used for formatting, which imports other XSLT files including fldtypes.xsl. The latter file is the one which contains many templates for rendering different fields. Doing search inside this file for URLNoMenu yields: &lt;/p&gt;  &lt;pre style=&quot;background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #c71585&quot;&gt;xsl&lt;/span&gt;:&lt;span style=&quot;color: #800000&quot;&gt;template&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;name&lt;/span&gt;=&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;quot;FieldRef_URLNoMenu_body&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;ddwrt&lt;/span&gt;:&lt;span style=&quot;color: #ff0000&quot;&gt;dvt_mode&lt;/span&gt;=&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;quot;body&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;match&lt;/span&gt; =&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;quot;FieldRef[@Name=&#39;URLNoMenu&#39;]&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;mode&lt;/span&gt;=&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;quot;Computed_body&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Next we copy this template XML element and put it in a new XSLT file. I named mine &lt;strong&gt;TargetBlank.xsl. &lt;/strong&gt;Inside the new file we change HTML anchor tag to include target=”_blank” (or anything else we need) and save the file. Once we specify URL to this new file in the &lt;strong&gt;XSL Link&lt;/strong&gt; field of a web part being edited, it will override all default formatting, therefore we also need to make sure that other templates still apply. Thanks to XSL import and overriding mechanism this is easy to do, we just need to import &lt;strong&gt;main.xsl&lt;/strong&gt; file, and our version of the &lt;strong&gt;FieldRef_URLNoMenu_body&lt;/strong&gt; template will override the one located inside fldtypes.xsl. Here is the complete listing of the &lt;strong&gt;TargetBlank.xsl.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;  &lt;pre style=&quot;border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px&quot; id=&quot;codeSnippet&quot;&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:stylesheet&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;xmlns:x&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;xmlns:d&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://schemas.microsoft.com/sharepoint/dsp&amp;quot;&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;exclude-result-prefixes&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;xsl msxsl ddwrt&amp;quot;&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;xmlns:ddwrt&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://schemas.microsoft.com/WebParts/v2/DataView/runtime&amp;quot;&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;xmlns:asp&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://schemas.microsoft.com/ASPNET/20&amp;quot;&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;xmlns:__designer&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://schemas.microsoft.com/WebParts/v2/DataView/designer&amp;quot;&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;xmlns:xsl&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;http://www.w3.org/1999/XSL/Transform&amp;quot;&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;xmlns:msxsl&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;urn:schemas-microsoft-com:xslt&amp;quot;&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;xmlns:SharePoint&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;Microsoft.SharePoint.WebControls&amp;quot;&lt;/span&gt; &lt;br /&gt;                &lt;span style=&quot;color: #ff0000&quot;&gt;xmlns:ddwrt2&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;urn:frontpage:internal&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:import&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;/_layouts/xsl/main.xsl&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt; &lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:output&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;html&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;indent&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;no&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:template&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;FieldRef_URLNoMenu_body&amp;quot;&lt;/span&gt; &lt;br /&gt;                  &lt;span style=&quot;color: #ff0000&quot;&gt;ddwrt:dvt_mode&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;body&amp;quot;&lt;/span&gt; &lt;br /&gt;                  &lt;span style=&quot;color: #ff0000&quot;&gt;match&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;FieldRef[@Name=&#39;URLNoMenu&#39;]&amp;quot;&lt;/span&gt; &lt;br /&gt;                  &lt;span style=&quot;color: #ff0000&quot;&gt;mode&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;Computed_body&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:param&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;thisNode&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;select&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:variable&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;url&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;select&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;$thisNode/@URL&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:variable&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;desc&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;select&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;$thisNode/@URL.desc&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:choose&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:when&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;$url=&#39;&#39;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:value-of&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;select&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;$desc&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:when&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:otherwise&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:choose&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:when&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;@Format=&#39;Image&#39;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;img&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;onfocus&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;OnLink(this)&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;{$url}&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;alt&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;{$desc}&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:when&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:otherwise&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;a&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;onfocus&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;OnLink(this)&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;{$url}&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;_blank&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                            &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:choose&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                                &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:when&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;$desc=&#39;&#39;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                                    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:value-of&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;select&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;$url&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;                                &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:when&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                                &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:otherwise&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                                    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:value-of&lt;/span&gt; &lt;span style=&quot;color: #ff0000&quot;&gt;select&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;=&amp;quot;$desc&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;                                &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:otherwise&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                            &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:choose&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:otherwise&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:choose&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:otherwise&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:choose&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:template&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #800000&quot;&gt;xsl:stylesheet&lt;/span&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In this file the &lt;strong&gt;xsl:stylesheet &lt;/strong&gt;element is copied from the &lt;strong&gt;main.xsl&lt;/strong&gt; file. Also note the &lt;strong&gt;xsl:import &lt;/strong&gt;and the &lt;strong&gt;xsl:output &lt;/strong&gt;statements. Lastly we need to upload the XSLT file and reference its URL in the &lt;strong&gt;XSL Link&lt;/strong&gt; field of our web part. That’s all there is to it. Our links should now open in a new browser window.&lt;/p&gt;</description><link>http://neganov.blogspot.com/2010/12/open-links-in-new-window-and-more-with.html</link><author>noreply@blogger.com (Ivan Neganov)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_uLvQGkZ2Z10/TQZgLqjRhqI/AAAAAAAAADM/9iSlyqh3ywM/s72-c/LinksListExample_thumb%5B4%5D.jpg?imgmax=800" height="72" width="72"/><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-4959550088501888846</guid><pubDate>Wed, 20 Oct 2010 18:01:00 +0000</pubDate><atom:updated>2011-01-29T12:13:52.809-08:00</atom:updated><title>Decks, Source Code and Resources from October 19 MSPUG Meeting</title><description>&lt;p&gt;Thanks a lot to the folks who showed up yesterday at the Mississauga User Group meeting. Also I’d like to thank Ray Outair for his efforts in running the group in celebration of its first year anniversary. I have posted the deck for my presentation “Leveraging SharePoint 2010 Search Technologies” and the source code of the demo web part demonstrating FQL capabilities on &lt;a title=&quot;SoftForte Resources&quot; href=&quot;http://www.softforte.com/Resources.htm&quot; target=&quot;_blank&quot;&gt;SoftForte site here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;If you are planning search deployment I highly recommend checking out technical diagrams on TechNet: &lt;a title=&quot;http://technet.microsoft.com/en-ca/library/cc263199.aspx&quot; href=&quot;http://technet.microsoft.com/en-ca/library/cc263199.aspx&quot;&gt;http://technet.microsoft.com/en-ca/library/cc263199.aspx&lt;/a&gt;. There are 4 diagrams there dedicated specifically to Search. Also check out downloadable content here &lt;a title=&quot;http://technet.microsoft.com/en-ca/library/cc262788.aspx&quot; href=&quot;http://technet.microsoft.com/en-ca/library/cc262788.aspx&quot;&gt;http://technet.microsoft.com/en-ca/library/cc262788.aspx&lt;/a&gt; – it has been recently updated.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;img style=&quot;BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; MARGIN: 0px 30px 0px 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px&quot; title=&quot;Search&quot; border=&quot;0&quot; alt=&quot;Search&quot; align=&quot;left&quot; src=&quot;http://lh4.ggpht.com/_uLvQGkZ2Z10/TL8uX2KVhSI/AAAAAAAAADE/Tt17bhCA838/Search%5B10%5D.jpg?imgmax=800&quot; width=&quot;100&quot; height=&quot;125&quot; /&gt; &lt;/p&gt;&lt;p&gt;As I mentioned at the meeting, I also recommend a book titled &lt;a title=&quot;Professional Microsoft Search: FAST Search, SharePoint Search, and Search Server&quot; href=&quot;http://www.wrox.com/WileyCDA/WroxTitle/Professional-Microsoft-Search-FAST-Search-SharePoint-Search-and-Search-Server.productCd-0470584661.html&quot; target=&quot;_blank&quot;&gt;Professional Microsoft Search: FAST Search, SharePoint Search, and Search Server&lt;/a&gt; by Mark Bennett, Jeff Fried, Miles Kehoe and Natalya Voskresenskaya. It is a great resource on planning and architecture of SharePoint Enterprise Search, and specifically FAST Search products.&lt;/p&gt;&lt;p&gt;Last but not least is a reference to &lt;a title=&quot;Steve Peschka&#39;s Search Explorer&quot; href=&quot;http://blogs.technet.com/b/speschka/archive/2010/08/15/free-developer-search-tool-for-sharepoint-2010-search-and-fast-search-for-sharepoint.aspx&quot; target=&quot;_blank&quot;&gt;Steve Peschka’s blog post&lt;/a&gt; where Steve introduces a Search Explorer tool that he wrote. Steve’s blog is an essential resource on developing Search and other SharePoint development topics.&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;So I’d like to re-cap on a few questions we left unanswered yesterday:&lt;/p&gt;&lt;p&gt;1. FAST visual best bets were displayed, but did not get filtered based on User Context’s managed properties. The question is how to create/promote properties into user context for such filtering to happen correctly. &lt;strong&gt;UPDATE:&lt;/strong&gt; &lt;a href=&quot;http://neganov.blogspot.com/2011/01/decks-from-january-19th-tspug-meeting.html&quot;&gt;I figured this one out&lt;/a&gt;&lt;/p&gt;&lt;p&gt;2. I was not lucky extending &lt;a title=&quot;Microsoft.Office.Server.Search.WebControls.CoreResultsWebPart&quot; href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.office.server.search.webcontrols.coreresultswebpart.aspx&quot; target=&quot;_blank&quot;&gt;CoreResultsWebPart&lt;/a&gt; and make it process custom FQL queries, and was forced instead to write a web part from scratch. The question is whether there is a supported way to extend CoreResultsWebPart for FAST search queries.&lt;br&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; this one is now also addressed. Check it out &lt;a href=&quot;http://neganov.blogspot.com/2011/01/extending-coreresultswebpart-to-handle.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;3. Somebody has mentioned that they could not get PowerPoint visual preview to work with FAST search results, suspecting that SSL encryption between FAST Search Server and query SSA was to blame. Looks like some research is needed here.&lt;/p&gt;&lt;p&gt;I plan to look into these and post my findings. Please feel free to comment on if you get answers sooner.&lt;/p&gt;</description><link>http://neganov.blogspot.com/2010/10/decks-source-code-and-resources-from.html</link><author>noreply@blogger.com (Ivan Neganov)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_uLvQGkZ2Z10/TL8uX2KVhSI/AAAAAAAAADE/Tt17bhCA838/s72-c/Search%5B10%5D.jpg?imgmax=800" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-4254719022483682291</guid><pubDate>Sun, 19 Sep 2010 17:43:00 +0000</pubDate><atom:updated>2010-12-07T14:46:48.814-08:00</atom:updated><title>Enumerate SharePoint 2010 Databases</title><description>&lt;p&gt;If you are working with SharePoint in a lab environment and use one shared database server to store databases from multiple farms then with SharePoint 2010 you can quickly lose control of your databases since there are much more of them now. When you set up a lab farm you typically run Products Configuration Wizard which leaves you with several databases created whose names contain GUIDs, which makes it hard to distinguish between them and relate them to corresponding farms. &lt;/p&gt;&lt;p&gt;Let’s say you need to get rid of a farm and want to delete corresponding databases after. What do you do? If you haven’t yet disconnected from the farm and uninstalled SharePoint then PowerShell comes at help. Log in to one of the farm servers, start up SharePoint 2010 Management Shell and enter this command:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family:Courier New;&quot;&gt;&lt;strong&gt;Get-SPDatabase | % {$_.Name}&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;It will list names of all databases utilized in the current farm. You can now create a script to drop these databases or do whatever you needed to do with them. If however it is too late and you have uninstalled your servers, you can still get the list of database names using a SQL query:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family:Courier New;&quot;&gt;USE SharePoint_Config&lt;br /&gt;select distinct name from Objects WITH(NOLOCK) where Name in (&lt;br /&gt;select Name COLLATE Latin1_General_CI_AS_KS_WS from sys.databases WITH(NOLOCK))&lt;br /&gt;GO&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Replace &lt;strong&gt;SharePoint_Config &lt;/strong&gt;with the name of configuration database for your farm. SharePoint products use &lt;strong&gt;Latin1_General_CI_AS_KS_WS&lt;/strong&gt; collation so you need to do a cast. It is of course not supported to issue queries directly against SQL Server so I would use this approach for development environment only, and only when you are really cleaning it up and PowerShell isn’t an option.&lt;/p&gt;&lt;p&gt;Alternatively to avoid the mess in your database names from the start you can also pre-create them. &lt;a title=&quot;Deploy by using DBA-created databases (SharePoint Server 2010)&quot; href=&quot;http://technet.microsoft.com/en-us/library/cc262869.aspx&quot; target=&quot;_blank&quot;&gt;Here is the guidance&lt;/a&gt;. Lastly, although the guidance does not suggest sharing database role between farms in production environment, it is quite practical to share a SQL server in development environment if you are not using your farm for performance and capacity testing.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; on technet there is a list of databases used by SharePoint (a section in storage and SQL Server capacity planning article): &lt;a href=&quot;http://technet.microsoft.com/en-us/library/cc298801.aspx#section1a&quot;&gt;http://technet.microsoft.com/en-us/library/cc298801.aspx#section1a&lt;/a&gt;&lt;/p&gt;</description><link>http://neganov.blogspot.com/2010/09/enumerate-sharepoint-2010-databases.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-7534873084698528230</guid><pubDate>Mon, 30 Aug 2010 11:34:00 +0000</pubDate><atom:updated>2010-08-30T04:34:07.074-07:00</atom:updated><title>Slipstreamed Installation of SharePoint Server 2010 with June 2010 CU</title><description>&lt;p&gt;I wanted to create a slipstreamed installation point for SharePoint Server 2010, which would include &lt;a title=&quot;Stefan Goßner: The first cumulative update for SharePoint 2010 family has been released&quot; href=&quot;http://blogs.technet.com/b/stefan_gossner/archive/2010/07/22/the-first-cumulative-update-for-sharepoint-2010-family-has-been-released.aspx&quot; target=&quot;_blank&quot;&gt;June 2010 CU&lt;/a&gt;. I could not find guidance on how to do this for the current version. &lt;a title=&quot;Create an installation source that includes software updates (Office SharePoint Server 2007)&quot; href=&quot;http://technet.microsoft.com/en-us/library/cc261890(office.12).aspx&quot; target=&quot;_blank&quot;&gt;MOSS 2007 guidance&lt;/a&gt; recommends extracting patches into &lt;strong&gt;\Update&lt;/strong&gt; folder of the installation point. This works as well for the SharePoint 2010. Would the installer also pick up and apply executable packages, or&amp;#160; their extracts in subfolders under the &lt;strong&gt;\Update&lt;/strong&gt;? I tried both variants – it does not. &lt;/p&gt;  &lt;p&gt;The reason I went that path was because June 2010 CU consists of 6 packages, which is unusual given regular MOSS CUs single file format. Also when extracting each of the patches manually to a common folder the following two files are duplicated between &lt;a title=&quot;KB983319&quot; href=&quot;http://support.microsoft.com/default.aspx?scid=kb;EN-US;983319&quot; target=&quot;_blank&quot;&gt;KB983319&lt;/a&gt; and &lt;a title=&quot;KB983497&quot; href=&quot;http://support.microsoft.com/default.aspx?scid=kb;EN-US;983497&quot; target=&quot;_blank&quot;&gt;KB983497&lt;/a&gt; patches: &lt;strong&gt;osrchwfe-x-none.msp, osrchwfe-x-none.xml&lt;/strong&gt;; and the following two - between &lt;a title=&quot;KB2281364&quot; href=&quot;http://support.microsoft.com/default.aspx?scid=kb;EN-US;2281364&quot; target=&quot;_blank&quot;&gt;KB2281364&lt;/a&gt; and &lt;a title=&quot;KB983497&quot; href=&quot;http://support.microsoft.com/default.aspx?scid=kb;EN-US;983497&quot; target=&quot;_blank&quot;&gt;KB983497&lt;/a&gt;: &lt;strong&gt;pplwfe-x-none.msp, pplwfe-x-none.xml&lt;/strong&gt;. By reviewing KB articles it appears that the files are identical so it is ok to overwrite them, which is what I’ve done using a script:&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;office-kb2124512-fullfile-x86-glb.exe /extract:C:\temp\sharepoint\Updates     &lt;br /&gt;office-kb2204024-fullfile-x64-glb.exe /extract:C:\temp\sharepoint\Updates      &lt;br /&gt;office-kb2281364-fullfile-x64-glb.exe /extract:C:\temp\sharepoint\Updates      &lt;br /&gt;office-kb983319-fullfile-x64-glb.exe /extract:C:\temp\sharepoint\Updates      &lt;br /&gt;office-kb983497-fullfile-x64-glb.exe /extract:C:\temp\sharepoint\Updates      &lt;br /&gt;spf-kb2028568-fullfile-x64-glb.exe /extract:C:\temp\sharepoint\Updates&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Next I copied extracted files to the &lt;strong&gt;\Updates &lt;/strong&gt;folder in my installation point.&lt;/p&gt;  &lt;p&gt;After installing SharePoint and running configuration wizard most of the patches were applied, except for &lt;a title=&quot;KB2124512&quot; href=&quot;http://support.microsoft.com/default.aspx?scid=kb;EN-US;2124512&quot; target=&quot;_blank&quot;&gt;KB2124512&lt;/a&gt; and &lt;a title=&quot;KB2204024&quot; href=&quot;http://support.microsoft.com/default.aspx?scid=kb;EN-US;2204024&quot; target=&quot;_blank&quot;&gt;KB2204024&lt;/a&gt; according to DLL version check. I am running Windows 2008 R2, and SQL Server 2008 R2, and made a farm installation of SharePoint. It could be that either these patches do not apply in my environment, or something is not working in my installation. I will post an update if I find out more. For now I consider that the slipstream approach is generally the same as before even for multi-file CUs such as this one.&lt;/p&gt;  </description><link>http://neganov.blogspot.com/2010/08/slipstreamed-installation-of-sharepoint.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-7925214854131104247</guid><pubDate>Fri, 28 May 2010 05:19:00 +0000</pubDate><atom:updated>2010-07-20T08:43:02.984-07:00</atom:updated><title>Modified Date Field is not Visible after Content Deployment</title><description>&lt;p&gt;It is the simple things, or at least ones you assume must be simple that often create some extra anxiety with SharePoint – at least from what I’ve seen. Here is one I ran into a couple of days ago: my customer runs a SharePoint 2007 publishing portal with February 2010 CU, where content is created in authoring environment, then content deployment job transfers it to production farm located in perimeter zone and accessible to anonymous Internet users. The application is using a significant amount of custom code. In many cases SharePoint API is used as a data provider, and is accessed through an adapter layer, which helps decoupling custom code from the platform. Quite logical. &lt;/p&gt;&lt;p&gt;An example of how the adapter accesses SharePoint API is retrieving SharePoint document library information through &lt;strong&gt;SPList.GetItems(SPQuery).GetDataTable().&lt;/strong&gt; The &lt;strong&gt;DataTable&lt;/strong&gt; instance is then returned back to the consuming custom code. The problem is that Modified column is missing from the returned &lt;strong&gt;DataTable&lt;/strong&gt; in production farm, while it is there in authoring farm, which certainly breaks a lot of application logic.&lt;/p&gt;&lt;p&gt;It turns out that a Content Deployment Job Path setting (Central Administration &amp;gt; Operations &amp;gt; Manage Content Deployment Paths and Jobs &amp;gt; Content Deployment Path) is to blame: &lt;strong&gt;Security Information &lt;/strong&gt;must be set to &lt;strong&gt;All &lt;/strong&gt;in order for the issue to go away, and you would need to re-create the target site collection. Now this will not be a completely painless move – you will start getting a content deployment warning: &lt;strong&gt;User security information cannot be properly imported without setting UserInfoDateTime option to ImportAll.&lt;/strong&gt; This is because you have a &lt;strong&gt;Deploy User Names&lt;/strong&gt; checkbox cleared, which you should according to the &lt;a href=&quot;http://technet.microsoft.com/en-us/library/cc263468(office.12).aspx&quot; target=&quot;_blank&quot;&gt;guidance&lt;/a&gt;. Here is a related &lt;a href=&quot;http://murmurofawebmaster.blogspot.com/2008/07/user-security-information-cannot-be.html&quot; target=&quot;_blank&quot;&gt;post&lt;/a&gt; about this warning. &lt;/p&gt;&lt;p&gt;What actually happens is when &lt;strong&gt;Security Information &lt;/strong&gt;is not set to &lt;strong&gt;All&lt;/strong&gt;, this results in hiding certain fields, including &lt;strong&gt;Modified &lt;/strong&gt;date field. So the &lt;strong&gt;GetItems(SPQuery) &lt;/strong&gt;will still return correct items satisfying the &lt;strong&gt;SPQuery&lt;/strong&gt; parameter, but if you inspect properties of an &lt;strong&gt;SPField&lt;/strong&gt; for the returned items you will see that:&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt; item.Fields[&lt;span class=&quot;str&quot;&gt;&quot;Modified&quot;&lt;/span&gt;].CanToggleHidden == &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;&lt;br /&gt; item.Fields[&lt;span class=&quot;str&quot;&gt;&quot;Modified&quot;&lt;/span&gt;].Hidden == &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;style type=&quot;text/css&quot;&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, &quot;Courier New&quot;, courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt&lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;p&gt;and the &lt;strong&gt;SPListItemCollection.GetDataTable() &lt;/strong&gt;method omits hidden fields when it constructs the &lt;strong&gt;DataTable&lt;/strong&gt;. Knowing the above you can either edit content deployment path and do a clean content deployment, or if it is problematic for some reason, then you can change your custom code to manually construct a &lt;strong&gt;DataTable&lt;/strong&gt; rather than using &lt;strong&gt;SPListItemCollection.GetDataTable()&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color:#ff0000;&quot;&gt;UPDATE:&lt;/span&gt;&lt;/strong&gt; The issue was fixed in April Cumulative Update (see &lt;a href=&quot;http://support.microsoft.com/kb/981040/&quot;&gt;http://support.microsoft.com/kb/981040/&lt;/a&gt; for more details). Thanks to Bill Brockbank for noting this. A good moment to emphasize importance of running up-to-date software.&lt;/p&gt;</description><link>http://neganov.blogspot.com/2010/05/modified-field-is-not-visible-after.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-7384653670825187633.post-5020560805110589123</guid><pubDate>Thu, 29 Apr 2010 17:53:00 +0000</pubDate><atom:updated>2010-04-29T11:07:25.410-07:00</atom:updated><title>Records Management in SharePoint 2010</title><description>SharePoint 2010 has a lot more to offer in records management space than its predecessor. &lt;a href=&quot;http://www.khamis.net/&quot;&gt;Rez&lt;/a&gt; will be presenting at Mississauga SharePoint User Group on May 4th. The topic is &lt;a href=&quot;http://www.khamis.net/blog/Lists/Posts/Post.aspx?ID=26&quot;&gt;SharePoint 2010 Records Management Features&lt;/a&gt;. Rez has many years of experience with SharePoint and deep knowledge of the technology. I look forward to and highly recommend next week&#39;s session.</description><link>http://neganov.blogspot.com/2010/04/records-management-in-sharepoint-2010.html</link><author>noreply@blogger.com (Ivan Neganov)</author><thr:total>0</thr:total></item></channel></rss>