Wednesday, June 6, 2012

Debugging Custom SharePoint 2010 Timer Jobs

For those of you who have seen posts on how to debug custom timer jobs, you have probably noticed that many of the solutions do not work, or only work part of the time. The foolproof, 100% method for getting an instance of the debugger running on your timer job is to add this line of code at the top of your Execute method:

System.Diagnostics.Debugger.Launch();

This will immediately pause the job and prompt you to launch a debug instance, which can be done in your open VS project. Once the debug instance is running, you can resume running the job.

Tuesday, August 16, 2011

Cross-Site (Web) XsltListViewWebPart

It's been awhile since I've updated the blog, but just stumbled on something that may help anyone looking to display list information across multiple sites within a single site collection. Previously we handled this through jQuery, but I've found a much better way to display this information without the use of a CQWP, and the solution was lying directly under my nose the whole time.

I was looking at creating a list view web part that would allow us to present data from one Web on another Web while maintaining the same look and functionality of the ListViewWebPart. I created a web part project in Visual Studio, and began hacking apart the XsltListViewWebPart class in Reflector (shh... don't tell), when I noticed a property in the XsltListViewToolPart class called "WebId". Why would WebId be a property in the XsltListViewWebPart you might ask? Very curious I thought...

To begin, I created a new view on the list that I wanted to share, and exported the .webpart file from the XsltListView. To export the .webpart file, you simple click on Site Actions > Edit Page, and on the List View Web Part context menu click "Export" to save the file to your local machine. Web Part files are simply an XML representation of the properties of the web part, and can be imported back into the Web Parts library at the parent site for reuse throughout your Site Collection.

<webParts>
  <webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
    <metaData>
      <type name="Microsoft.SharePoint.WebPartPages.XsltListViewWebPart, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
      <importErrorMessage>Cannot import this Web Part.</importErrorMessage>
    </metaData>
    <data>
      <properties>
        <property name="InitialAsyncDataFetch" type="bool">False</property>
        <property name="ChromeType" type="chrometype">Default</property>
        <property name="Title" type="string" />
        <property name="Height" type="string" />
        <property name="CacheXslStorage" type="bool">True</property>
        <property name="ListDisplayName" type="string" null="true" />
        <property name="AllowZoneChange" type="bool">True</property>
        <property name="AllowEdit" type="bool">True</property>
        <property name="XmlDefinitionLink" type="string" />
        <property name="DataFields" type="string" />
        <property name="Hidden" type="bool">False</property>
        <property name="ListName" type="string">{B7B83EDB-714E-47A8-AF42-92A194B09169}</property>
        <property name="NoDefaultStyle" type="string" />
        <property name="AutoRefresh" type="bool">False</property>
        <property name="ViewFlag" type="string">8388613</property>
        <property name="Direction" type="direction">NotSet</property>
        <property name="AutoRefreshInterval" type="int">60</property>
        <property name="AllowConnect" type="bool">True</property>
        <property name="Description" type="string" />
        <property name="AllowClose" type="bool">True</property>
        <property name="ShowWithSampleData" type="bool">False</property>
        <property name="ParameterBindings" type="string">
			&lt;ParameterBinding Name="dvt_sortdir" Location="Postback;Connection"/&gt;
			&lt;ParameterBinding Name="dvt_sortfield" Location="Postback;Connection"/&gt;
			&lt;ParameterBinding Name="dvt_startposition" Location="Postback" DefaultValue=""/&gt;
			&lt;ParameterBinding Name="dvt_firstrow" Location="Postback;Connection"/&gt;
			&lt;ParameterBinding Name="OpenMenuKeyAccessible" Location="Resource(wss,OpenMenuKeyAccessible)" /&gt;
			&lt;ParameterBinding Name="open_menu" Location="Resource(wss,open_menu)" /&gt;
			&lt;ParameterBinding Name="select_deselect_all" Location="Resource(wss,select_deselect_all)" /&gt;
			&lt;ParameterBinding Name="idPresEnabled" Location="Resource(wss,idPresEnabled)" /&gt;
			&lt;ParameterBinding Name="NoAnnouncements" Location="Resource(wss,noXinviewofY_LIST)" /&gt;
			&lt;ParameterBinding Name="NoAnnouncementsHowTo" Location="Resource(wss,noXinviewofY_DEFAULT)" /&gt;
		</property>
        <property name="Xsl" type="string" null="true" />
        <property name="CacheXslTimeOut" type="int">86400</property>
        <property name="WebId" type="System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">820a89d6-8509-4bc4-9d39-4fd91e420f7a</property>
        <property name="ListUrl" type="string" null="true" />
        <property name="DataSourceID" type="string" />
        <property name="FireInitialRow" type="bool">True</property>
        <property name="ManualRefresh" type="bool">False</property>
        <property name="ViewFlags" type="Microsoft.SharePoint.SPViewFlags, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">Html, TabularView, Mobile</property>
        <property name="ChromeState" type="chromestate">Normal</property>
        <property name="AllowHide" type="bool">True</property>
        <property name="PageSize" type="int">-1</property>
        <property name="SampleData" type="string" null="true" />
        <property name="BaseXsltHashKey" type="string" null="true" />
        <property name="AsyncRefresh" type="bool">False</property>
        <property name="HelpMode" type="helpmode">Modeless</property>
        <property name="ListId" type="System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">b7b83edb-714e-47a8-af42-92a194b09169</property>
        <property name="DataSourceMode" type="Microsoft.SharePoint.WebControls.SPDataSourceMode, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">List</property>
        <property name="AllowMinimize" type="bool">True</property>
        <property name="TitleUrl" type="string">/kb/Lists/Emerging Issues</property>
        <property name="CatalogIconImageUrl" type="string" />
        <property name="DataSourcesString" type="string" />
        <property name="GhostedXslLink" type="string">main.xsl</property>
        <property name="PageType" type="Microsoft.SharePoint.PAGETYPE, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">PAGE_NORMALVIEW</property>
        <property name="DisplayName" type="string">OnlineWPItems</property>
        <property name="UseSQLDataSourcePaging" type="bool">True</property>
        <property name="Width" type="string" />
        <property name="ExportMode" type="exportmode">All</property>
        <property name="XslLink" type="string" null="true" />
        <property name="ViewContentTypeId" type="string">0x</property>
        <property name="HelpUrl" type="string" />
        <property name="XmlDefinition" type="string">&lt;View Name="{863AE444-CE71-4B03-A037-976A884DFA9B}" MobileView="TRUE" Type="HTML" DisplayName="OnlineWPItems" Url="/kb/Lists/Emerging Issues/OnlineWPItems.aspx" Level="1" BaseViewID="1" ContentTypeID="0x" ImageUrl="/_layouts/images/generic.png"&gt;&lt;Query&gt;&lt;OrderBy&gt;&lt;FieldRef Name="Modified" Ascending="FALSE"/&gt;&lt;/OrderBy&gt;&lt;Where&gt;&lt;And&gt;&lt;And&gt;&lt;Contains&gt;&lt;FieldRef Name="Intuit_x0020_Services"/&gt;&lt;Value Type="Text"&gt;Software (SaaS):Online Payroll&lt;/Value&gt;&lt;/Contains&gt;&lt;IsNotNull&gt;&lt;FieldRef Name="Issue_x0020_Status"/&gt;&lt;/IsNotNull&gt;&lt;/And&gt;&lt;Neq&gt;&lt;FieldRef Name="Issue_x0020_Status"/&gt;&lt;Value Type="Text"&gt;Updated&lt;/Value&gt;&lt;/Neq&gt;&lt;/And&gt;&lt;/Where&gt;&lt;GroupBy/&gt;&lt;/Query&gt;&lt;ViewFields&gt;&lt;FieldRef Name="Issue_x0020_Status"/&gt;&lt;FieldRef Name="LinkTitle"/&gt;&lt;/ViewFields&gt;&lt;RowLimit Paged="TRUE"&gt;5&lt;/RowLimit&gt;&lt;Aggregations Value="Off"/&gt;&lt;Toolbar Type="Standard"/&gt;&lt;/View&gt;</property>
        <property name="Default" type="string" />
        <property name="TitleIconImageUrl" type="string" />
        <property name="MissingAssembly" type="string">Cannot import this Web Part.</property>
        <property name="SelectParameters" type="string" />
      </properties>
    </data>
  </webPart>
</webParts>

The highlighted line shows the WebId property in the exported web part file. If you open the file in a text editor or Visual Studio, you can modify the WebId before uploading the new file to your Web Parts Gallery. By default, the WebId is Guid.Empty() or 00000000-0000-0000-0000-000000000000.

To get the WebId, fire up powershell on one of your sharepoint servers and use this snippet:

$web = Get-SPWeb http://[url]
$web.Id

Be sure to include the full path of the web, e.g. if the list is hosted under a subsite it would be http://sharepoint/listlocation.

Now that you have your WebId, copy it from the powershell window and paste it into the WebPart file property "WebId" overwriting the default value. Save the file.

Uploading the Web Part File
  1. Navigate to the top-level site in your site collection
  2. Click on Site Actions > Site Settings
  3. Click on "Web Parts" under the "Galleries" section
  4. Upload your .webpart file to the Web Part Gallery (Name the file something that will easily be recognizable when adding the web part to your pages. I also tend to organize my web parts into groups, and in this case I've created a new Group called "Cross-site List View Web Parts")
  5. Save your file properties.

At this point you should be at the "Web Part Gallery" items view. From here you can click on the title of your newly added web part to see how it will render on your pages.

To add the web part to a page in SharePoint, simply edit your page and click the "Add Web Part" option, find the group you created in the "Add Web Part" menu, and click on you web part to add it to the page. Don't forget to save or Checkin your page. If you have publishing enabled, be sure to publish the page so that the changes are available to all users.

Tuesday, April 12, 2011

Group Calendar - Default Display

So... as it always seems in my world, I get a lot of "That's great, but what about this?" questions. Getting the Group Calendar to display default resources was fine, but a new requirement to set the default display to month view popped up. Here's how you do it.

Within the code I provided in my previous post, if you kept the code line-for-line and included the jQuery reference, insert this line at the bottom:

MoveView('month', $(el).attr('ctxid'));

If you chose a less sophisticated approach, you could use:

MoveView('month', '[Context ID]');

This will automagically shift your Calendar view to the month view, still displaying your default resources.

Here is the complete code reference:

<script type="text/javascript" src="/Style Library/lib/jQuery.min.js"></script>

<script type="text/javascript">

var el = $(".ms-acal-rootdiv");

var xml = "\u003cEntities Append=\u0022True\u0022 Error=\u0022\u0022 DoEncodeErrorMessage=\u0022True\u0022 Separator=\u0022;\u0022 MaxHeight=\u00223\u0022\u003e\u003cEntity Key=\u0022All Computers\u0022 DisplayText=\u0022All Computers\u0022 IsResolved=\u0022True\u0022 Description=\u0022\u0022\u003e\u003cExtraData\u003e\u003cArrayOfDictionaryEntry xmlns:xsi=\u0022http:\u002f\u002fwww.w3.org\u002f2001\u002fXMLSchema-instance\u0022 xmlns:xsd=\u0022http:\u002f\u002fwww.w3.org\u002f2001\u002fXMLSchema\u0022\u003e\u003cDictionaryEntry\u003e\u003cKey xsi:type=\u0022xsd:string\u0022\u003eResourceMembers\u003c\u002fKey\u003e\u003cValue xsi:type=\u0022xsd:string\u0022\u003e1;#Computer 01;#2;#Computer 02;#3;#Computer 03;#4;#Computer 04;#5;#Computer 05;#6;#Computer 06;#7;#Computer 07;#8;#Computer 08;#9;#Computer 09;#10;#Computer 10;#11;#Computer 11;#12;#Computer 12;#13;#Computer 13;#14;#Computer 14;#15;#Computer 15\u003c\u002fValue\u003e\u003c\u002fDictionaryEntry\u003e\u003cDictionaryEntry\u003e\u003cKey xsi:type=\u0022xsd:string\u0022\u003eSPResourceId\u003c\u002fKey\u003e\u003cValue xsi:type=\u0022xsd:string\u0022\u003e30\u003c\u002fValue\u003e\u003c\u002fDictionaryEntry\u003e\u003cDictionaryEntry\u003e\u003cKey xsi:type=\u0022xsd:string\u0022\u003ePrincipalType\u003c\u002fKey\u003e\u003cValue xsi:type=\u0022xsd:string\u0022\u003eResourceGroup\u003c\u002fValue\u003e\u003c\u002fDictionaryEntry\u003e\u003c\u002fArrayOfDictionaryEntry\u003e\u003c\u002fExtraData\u003e\u003cMultipleMatches \u002f\u003e\u003c\u002fEntity\u003e\u003c\u002fEntities\u003e";



var sel = SP.UI.ApplicationPages.CalendarSelector.instance().getSelector(1, $(el).attr('ctxid'));

sel.selectEntities(xml, true);


MoveView('month', $(el).attr('ctxid'));

}

ExecuteOrDelayUntilScriptLoaded(_setDefaultResources, "sp.ribbon.js");
</script>

Tuesday, March 29, 2011

Displaying Default Resources on the Group Calendar

[IMPORTANT NOTE]  It has been pointed out that some of the forum users who have tried this solution cannot get it to work. I forgot to mention that I'm using JQuery-1.5.1.min.js, which is why you see $() references in the solution. You could use substitute the JQuery variable "ID" for the actual ID of the Web Part Zone, e.g. "WPQ1", but I would suggest uploading the JQuery min file to your Style Library and using the following reference:

<script src="/Style%20Library/JQuery-1.5.1.min.js" type="text/javascript">
</script>

Sorry for the miscommunication.

It's been awhile since I've posted any ground-breaking new discoveries, so I thought I would pass on a bit of info about the Group Calendar and displaying default groups. Disclaimer: this is still in beta, and not running on a production site yet.

I've stumbled across a few blog posts about the group calendar, and the need to display a default set of resources on the calendar. The OOB functionality requires the user to select a resource/resource group before items show up on the calendar. Being the stubborn developer that I am, I decided that I would come up with a fix for this based on a specific requirement from one of our Business Units. This solution works for Resource Groups, but I'm sure it can be modified to easily display resources or people, depending on your requirements.

Looking at the calendar in action, you will quickly realize that the calendar uses the picker dialog for selecting resources, and AJAX to render selected items on the calendar. So, how does one go about calling the necessary functions to populate the calendar? Magic! ;-)

I started by viewing the source of the parent page to get an idea of what was actually taking place when the picker dialog closes. Here is the event you are looking for:


Great! But how does this help you? You may notice that the dialog result is xml, and that setting the result requires a call to SP.UI.ApplicationPages.CalendarSelector.instance().getSelector(type, id). After a bit of searching in the SP.UI.Calendar.debug.js file, I found some information around the ResourceSelector and retrieving the selector type. If you do a search of the source code in your view source window for "add_resource", you'll see that the "Add Resources" link attribute "evtid" is "add_resource". Searching through the SP.UI.Calendar.debug.js on "add_resource" yielded this handy bit of information:

$p0.$z('add_resource', Function.createDelegate(this, function ($p1_0) {
            __spPickerDialogFunc(1, this.$w_1, true);
}));

This shows that the type is 1, and add = true. Once I had that information, I just needed to track down the XML data being passed from the picker dialog. That's where Fiddler comes in. If you aren't familiar with Fiddler, you should be. I won't go into too much detail, but will give you the gist below.

First, I opened an instance of fiddler and launched IE, browsing to my home page (which contains my group calendar). I then clicked the "Add Resources" link, and added a Resource Group called "All Computers" and clicked "OK".

You'll see below that the events now display for each resource in the calendar.


I then went into fiddler, and took a look at the final request from Picker.aspx, and began scanning the TextView for any information that might be helpful.




And there it is, in an ecma encoded string. The full XML return value from the dialog window. I copied the ret variable and began scripting a new function for the home page.

NOTE:  If you don't already know this, you can build your javascript into an html or txt file and upload it to a document library for reference in a Content Editor Web Part. I've found that if you just paste the javascript directly into the Content Editor, SharePoint has a nasty habit of correcting it for you, which can really break your code. I typically put my text/html files into a folder called "ctrl" in the Style Library. That way, if I reuse the code on multiple pages, I can update one single file and call it a day.

Here is my final script to populate the calendar:

<script type="text/javascript" src="/Style Library/Jquery.min.js"></script>
<script type="text/javascript">

function _setDefaultResources() {
        var el = $(".ms-acal-rootdiv");
        var xml = "\u003cEntities Append=\u0022True\u0022 Error=\u0022\u0022 DoEncodeErrorMessage=\u0022True\u0022 Separator=\u0022;\u0022 MaxHeight=\u00223\u0022\u003e\u003cEntity Key=\u0022All Computers\u0022 DisplayText=\u0022All Computers\u0022 IsResolved=\u0022True\u0022 Description=\u0022\u0022\u003e\u003cExtraData\u003e\u003cArrayOfDictionaryEntry xmlns:xsi=\u0022http:\u002f\u002fwww.w3.org\u002f2001\u002fXMLSchema-instance\u0022 xmlns:xsd=\u0022http:\u002f\u002fwww.w3.org\u002f2001\u002fXMLSchema\u0022\u003e\u003cDictionaryEntry\u003e\u003cKey xsi:type=\u0022xsd:string\u0022\u003eResourceMembers\u003c\u002fKey\u003e\u003cValue xsi:type=\u0022xsd:string\u0022\u003e1;#Computer 01;#2;#Computer 02;#3;#Computer 03;#4;#Computer 04;#5;#Computer 05;#6;#Computer 06;#7;#Computer 07;#8;#Computer 08;#9;#Computer 09;#10;#Computer 10;#11;#Computer 11;#12;#Computer 12;#13;#Computer 13;#14;#Computer 14;#15;#Computer 15\u003c\u002fValue\u003e\u003c\u002fDictionaryEntry\u003e\u003cDictionaryEntry\u003e\u003cKey xsi:type=\u0022xsd:string\u0022\u003eSPResourceId\u003c\u002fKey\u003e\u003cValue xsi:type=\u0022xsd:string\u0022\u003e30\u003c\u002fValue\u003e\u003c\u002fDictionaryEntry\u003e\u003cDictionaryEntry\u003e\u003cKey xsi:type=\u0022xsd:string\u0022\u003ePrincipalType\u003c\u002fKey\u003e\u003cValue xsi:type=\u0022xsd:string\u0022\u003eResourceGroup\u003c\u002fValue\u003e\u003c\u002fDictionaryEntry\u003e\u003c\u002fArrayOfDictionaryEntry\u003e\u003c\u002fExtraData\u003e\u003cMultipleMatches \u002f\u003e\u003c\u002fEntity\u003e\u003c\u002fEntities\u003e";


        var sel = SP.UI.ApplicationPages.CalendarSelector.instance().getSelector(1, $(el).attr('ctxid'));
        sel.selectEntities(xml, true);
}
 
ExecuteOrDelayUntilScriptLoaded(_setDefaultResources, "sp.ribbon.js");
</script>

A few important items to note... if you have multiple calendars on a single page, you will need to find the id of the calendar you are populating. The ctxid is actually a dynamically populated id (via javascript) of the web part context, which in this case is WPQ2. Make sure that you are using the ExecuteOrDelayUntilScriptLoaded( function, "sp.ribbon.js") call. The context id of the web part is not assigned until sp.ribbon.js is fully loaded. Once you have all that, it will work like a charm.

As always, if you have any questions, feel free to ping me. Hopefully, this will save you some time and make you look like a rockstar!

Thursday, February 10, 2011

SharePoint 2010 Search - Thesaurus Files

This year is the year of search for us. We're looking at implementing fast, focusing on metadata and better tagging in our content, and improving the overall search experience for our users. With that in mind, I just wanted to touch on creating Thesaurus files in SharePoint 2010 Search, as I've found the content on Technet and MSDN to be a bit cryptic.

Modifying Thesaurus Files
If you've been referencing Technet (http://technet.microsoft.com/en-us/library/dd361734.aspx), there is some pretty good information on how to create thesaurus files to improve your search. There are two main priniples in a thesaurus file: expansion sets and replacement sets.

To create an expansion set, which essentially maps synonyms to a specific keyword, you simply need to add the following code to your thesasurus file:

<expansion>
    <sub>401k</sub>
    <sub>401 k</sub>
    <sub>401-k</sub>
</expansion>

An important item to note, parentheses are not acceptable in a thesaurus file. I found this out the hard way when attempting to add <sub>401(k)</sub>, which is the approved standard for 401(k). Luckily for us, the parentheses are ignored in the keyword, so 401(k) will still appear in the search results, even when the user keys in 401-k.

To create a replacement set, the schema is similar:

<expansion>
    <pat>IE8</pat>
    <pat>IE7</pat>
    <sub>Internet Explorer</sub>
</expansion>


In this case, IE8 or IE7 would be replaced by Internet Explorer.

While we don't have much use for replacement sets, expansion sets have proven extremely valuable. Instead of providing Best Bets links via the Search Keywords administration tool, we can populate our search results with all synonyms immediately, which reduces the need for multiple clicks to get a specific result.

Updating Thesaurus Files


The update process is where I have found the least amount of information. Thesaurus files are stored in multiple locations on a SharePoint Server, and determining the correct location can be a real pain in the butt. We update our Thesaurus files in 2 locations in the /Program Files/Microsoft Office Servers/14.0/ folder.

First, we update the thesaurus files here: \Program Files\Microsoft Office Servers\14.0\Data\Config. Updates to the thesaurus files here will ensure that any new Search Service Applications that you create will have the updated thesaurus definitions when they spin up.

Second, we copy the thesaurus files to the: \Program Files\Microsoft Office Servers\14.0\Data\Applications\[GUID]\Config folder. The GUID will be the guid of your Search Service Application, which can be found using this bit of Powershell goodness: Get-SPServiceApplication. This powershell command will list all of your service applications and their corresponding IDs.

Once the files are copied to this location, you'll need to restart the search service for the changes to take affect. You can do this from Administrative Tools > Services > SharePoint Server Search 14, or by running these commands:

net stop osearch
net start osearch

Once the service is resarted, go to your search center and plug in one of the newly added expansion/replacement terms to see your results.

It is important to note that if you're running search on multiple servers, you will need to perform these steps on each server running search. If you already have multiple search applications running, you will also need to copy your thesaurus files to each config directory under the GUID folder for each search service application.

For safety sake, we also updated the tsneu.xml along with tsenu.xml. NEU is the language neutral thesaurus file, and ENU is the US English thesaurus file. Definitions for each language prefix can be found on technet.

Tuesday, February 8, 2011

Setting Managed Metadata Fields via Javascript - UPDATE

As I mentioned in a previous post, Managed Metadata fields can be set using Javascript. I've actually found an easier method to retrieve and update the values via javascript that I wish to share quickly.

Previously, I was retrieving the Managed Metadata Field Value in display format. I encountered an issue when attempting to use this value to update a form field on a modal popup however, due to multiple results in the Term Store being found for a single string. To remedy this, I found the hidden value for the Metadata Field including the GUID of the term. To do this, I used my handy Powershell script from my previous post, and located the field name for the Metadata Field. I then located the following XML for my field:


<Field Type="Note" DisplayName="Role_1" StaticName="RoleTaxHTField" Name="RoleTaxHTField" ID="{bbaf434e-cc7e-40b5-b43e-5605ee3c3543}" ShowInViewForms="FALSE" Required="FALSE" Hidden="TRUE" CanToggleHidden="TRUE" SourceID="{d96d858a-03f7-4b0f-a73f-fc0ee68996cd}" Customization="" ColName="ntext9" RowOrdinal="0"/>
    <Field Type="TaxonomyFieldTypeMulti" DisplayName="Role" List="{aff9fc9f-40b8-4a89-aaa3-f5f566117446}" WebId="d96d858a-03f7-4b0f-a73f-fc0ee68996cd" ShowField="Term1033" Mult="TRUE" Sortable="FALSE" Required="FALSE" Group="Knowledge Base Columns" ID="{5050205f-5771-40e1-b356-ec6c989147f1}" SourceID="{d96d858a-03f7-4b0f-a73f-fc0ee68996cd}" StaticName="Role" Name="Role" Version="4" EnforceUniqueValues="FALSE" Customization="" ColName="int8" RowOrdinal="0">
      <Default/>
      <Customization>
        <ArrayOfProperty>
          <Property>
            <Name>SspIdName>
            <Value xmlns:q1="http://www.w3.org/2001/XMLSchema" p4:type="q1:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">d6d8e56a-06c9-4c99-a5b0-1ea8b6eb747fValue>
          Property>
          <Property>
            <Name>GroupIdName>
          Property>
          <Property>
            <Name>TermSetIdName>
            <Value xmlns:q2="http://www.w3.org/2001/XMLSchema" p4:type="q2:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">50857e97-8bdf-4000-bf13-5b1ba34d745aValue>
          Property>
          <Property>
            <Name>AnchorIdName>
            <Value xmlns:q3="http://www.w3.org/2001/XMLSchema" p4:type="q3:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">00000000-0000-0000-0000-000000000000Value>
          Property>
          <Property>
            <Name>UserCreatedName>
            <Value xmlns:q4="http://www.w3.org/2001/XMLSchema" p4:type="q4:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">falseValue>
          Property>
          <Property>
            <Name>OpenName>
            <Value xmlns:q5="http://www.w3.org/2001/XMLSchema" p4:type="q5:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">falseValue>
          Property>
          <Property>
            <Name>TextFieldName>
            <Value xmlns:q6="http://www.w3.org/2001/XMLSchema" p4:type="q6:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{bbaf434e-cc7e-40b5-b43e-5605ee3c3543}Value>
          Property>
          <Property>
            <Name>IsPathRenderedName>
            <Value xmlns:q7="http://www.w3.org/2001/XMLSchema" p4:type="q7:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">falseValue>
          Property>
          <Property>
            <Name>IsKeywordName>
            <Value xmlns:q8="http://www.w3.org/2001/XMLSchema" p4:type="q8:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">falseValue>
          Property>
          <Property>
            <Name>TargetTemplateName>
          Property>
          <Property>
            <Name>CreateValuesInEditFormName>
            <Value xmlns:q9="http://www.w3.org/2001/XMLSchema" p4:type="q9:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">falseValue>
          Property>
          <Property>
            <Name>FilterAssemblyStrongNameName>
            <Value xmlns:q10="http://www.w3.org/2001/XMLSchema" p4:type="q10:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429cValue>
          Property>
          <Property>
            <Name>FilterClassNameName>
            <Value xmlns:q11="http://www.w3.org/2001/XMLSchema" p4:type="q11:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">Microsoft.SharePoint.Taxonomy.TaxonomyFieldValue>
          Property>
          <Property>
            <Name>FilterMethodNameName>
            <Value xmlns:q12="http://www.w3.org/2001/XMLSchema" p4:type="q12:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">GetFilteringHtmlValue>
          Property>
          <Property>
            <Name>FilterJavascriptPropertyName>
            <Value xmlns:q13="http://www.w3.org/2001/XMLSchema" p4:type="q13:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">FilteringJavascriptValue>
          Property>
        ArrayOfProperty>
      Customization>
    Field>

As you can see, there are 2 fields listed in the XML. The first field is the hidden value including the GUID of the term or terms, and the second field is the container/display field that is rendered as a string in Display Mode.

On my display form for the items that will be receiving feedback, I added a hidden field in the XSLT, and set the value to 

<xsl-value-of select="@RoleTaxHTField" />

When opening the dialog, the arguments passed include the value of this field.  On my dialog I now set the following the hidden storage field of the Metadata Field to the value passed. Now when the user submits the feedback, the value is mapped to the correct term without any errors, and there is no need to run the javascript that forces the metadata field to update.




Monday, February 7, 2011

Working with Lists and Schemas

I thought I would put up a quick post about retrieving list schema definitions via powershell while at the SPTechCon 2011 in SF this week. I've been working on some new Metadata functionality with JQuery and the SPServices Library (http://spservices.codeplex.com/ courtesy of Marc D Anderson), and realized that it's a real pain in the a** working with Managed Metadata Columns in SharePoint.

Here's a quick reference for grabbing the XML Schema of a list definition so you can get to internal field names, column definitions, and the Taxomony Ids required for interacting with the TaxonomyClientService.

$site = Get-SPSite http://[Site Url]
$web = $site.OpenWeb() - note: leave the value blank for the top-level web, or specify "/web url" between the parentheses to retrieve a specific web
$list = $web.Lists["List Name"]
$list.SchemaXML | Out-File C:\Temp\schema.xml


Now you should have an xml file containing the schema of your list. Open the file in your XML editor of choice, and have a blast locating the attributes you need.