Querying on Managed Metadata Field Values in SharePoint Server 2010‏

This two posts from Mario Cortes will give you a good understanding on how to use the Taxonomy in SharePoint 2010:

http://geeks.ms/blogs/mcortes/archive/2010/06/30/metadatos-administrados-modelo-de-objetos-y-controles-i.aspx

http://geeks.ms/blogs/mcortes/archive/2010/07/06/metadatos-administrados-modelo-de-objetos-y-controles-ii.aspx

Metadatos administrados: Modelo de objetos y controles (I)

Mediante el servicio de metadatos podremos asociar a nuestro contenido metadatos con una estructura con sentido para nuestra organización. Además de la poder manejarlos desde la interfaz gráfica, dispondremos de un modelo de objetos para realizar el mantenimiento, consultas y visualizarlo mediante controles.

Modelo de objetos

SharePoint nos proporciona una serie de clases para manejar y navegar por la estructura de metadatos. Para obtener una referencia al conjunto de almacenes de términos definidos para una Colección de Sitios utilizaremos la clase TaxonomySession. Mediante la propiedad TermStores podremos obtener los distintos almacenes de términos del tipo TermStore que representa un almacén de grupos de términos.

Para obtener los grupos de términos utilizaremos la propiedad Groups de la clase TermStore que nos devolverá una colección de elementos del tipo Group.

Para obtener los conjuntos de términos de un grupo utilizaremos la propiedad TermSets.

Para ilustrar un ejemplo:

SPSite site = SPContext.Current.Site; TaxonomySession session = new TaxonomySession(site); TermStore termStore = session.TermStores[“Servicio de metadatos administrados”]; // Almacén de términos Group group = termStore.Groups[“MiGrupo”]; // Grupo de términos TermSet productsTermSet = group.TermSets[“MiConjunto”]; // Conjunto de términos

Term termino = productsTermSet.Terms[“MiTérmino”]; // Término o palabra

Para manejar una columna de tipo “Metadatos administrados” disponemos de la clase TaxonomyField, con el método GetFieldValue() obtendremos una referencia del tipo TaxonomyFieldValue para manejar los valores almacenados en la columna.

De la clase TaxonomyFieldValue podemos obtener el identificador del término almacenado con la propiedad TermGuid y con la propiedad Label el texto del término.

SPList listaConMetadato = SPContext.Current.Site.RootWeb.Lists[“NombreLista”]; SPListItem itemConMetdato = listaConMetadato.Items[0]; TaxonomyFieldValue valordeMetadato = new TaxonomyFieldValue((string)itemConMetdato[“NombreColumna”]); string idTermino = valordeMetadato.TermGuid; string textoTermino = valordeMetadato.Label;

Controles

En la parte visual dispondremos de varios controles como:

  • TaxonomyFieldControl
  • TaxonomyWebTaggingControl

Ambos controles los encontraremos en la dll Microsoft.SharePoint.Taxonomy.dll en el namespace Microsoft.SharePoint.Taxonomy. Para registrar estos controles en una página o control utilizaremos:

<%@ Register Tagprefix=”Taxonomy” Namespace=”Microsoft.SharePoint.Taxonomy” Assembly=”Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c” %>

El control TaxonomyFieldControl lo utilizaremos para poder asociar un elemento de una lista o biblioteca a un metadato, es el control que utilizará SharePoint al visualizar una columna de tipo “Metadatos administrados”. Por ejemplo las páginas wiki disponen de la opción de catalogar las páginas mediante una columna de tipo “Metadatos administrados” y en el layouts:

<Taxonomy:TaxonomyFieldControl FieldName=”Wiki_x0020_Page_x0020_Categories” EmptyValueDescriptionForTargetTemplate=”<%$Resources:cms,enterwiki_nocategories_assigned%>” DisableInputFieldLabel=”true” runat=”server” />


El control TaxonomyWebTaggingControl lo utilizaremos para navegar por la estructura de metadatos. Para utilizarlo tendremos que indicarle que subconjunto del árbol de metadatos utilizará, por ejemplo:

taggingTaxonomy.SspId.Add(termStore.Id); taggingTaxonomy.TermSetId.Add(productsTermSet.Id); taggingTaxonomy.AllowFillIn = true; // Permite autocompletar taggingTaxonomy.IsMulti = false; // Indica si permite multiselección

Para leer el metadato seleccionado, disponemos de la propiedad “Text” que devuelve los términos seleccionados con el formato “Término|GUID”. En este caso no podremos utilizar una clase del tipo TaxonomyFieldValue para extraer los valores por separado ya que el formato que devuelve la propiedad TaxonomyWebTaggingControl.Text no es compatible.

Metadatos administrados: Modelo de objetos y controles (II)

Siguiendo con el post Metadatos administrados: Modelo de objetos y controles (I), veremos en esta ocasión cómo crear nuevas estructuras de metadatos y como consultar los elementos que estén asociadas a ellas mediante el modelo de objetos.

Creación de términos

Crearemos una estructura similar a la siguiente imagen:

Lo primero que haremos será hacer un “using Microsoft.SharePoint.Taxonomy;”, para conectar al servicio de metadatos obtendremos una referencia mediante “new TaxonomySession(site);”, a continuación agregaremos un código similar al siguiente:

public static void CrearTerminos() { using (SPSite site = new SPSite(“http://UrlColecciónDeSitios&#8221;)) { TaxonomySession session = new TaxonomySession(site); TermStore termStore = session.TermStores[“Servicio de metadatos administrados”]; // Almacén de términos Group NuevoGrupo = termStore.CreateGroup(“Grupo de Pruebas”); NuevoGrupo.AddContributor(“Dominio\\usuario”); TermSet conjuntoDeTerminos = NuevoGrupo.CreateTermSet(“Nuevo conjunto”); int lcidSpanish = System.Globalization.CultureInfo.GetCultureInfo(“es-ES”).LCID; Term termino1 = conjuntoDeTerminos.CreateTerm(“Término 1”, lcidSpanish); Term termino2 = conjuntoDeTerminos.CreateTerm(“Término 2”, lcidSpanish); termStore.CommitAll(); } }

Mediante la propiedad TermStores obtenemos una referencia al almacén de metadatos sobre el que crearemos nuestra estructura. Con el método CreateGroup() crearemos un nuevo grupo de términos. Con CreateTermSet crearemos un nuevo conjunto de términos, si no indicamos nada en el segundo parámetro se creará para el idioma por defecto. Con el método CreateTerm() crearemos términos por debajo del grupo de términos o debajo de otros términos, el segundo parámetro indica el código lcid del idioma del término.

Consulta de términos

Una vez hayamos asociado los metadatos a nuestros contenidos podremos realizar consultas sobre ellos con el modelo de objetos, CAML y el motor de búsqueda.

Para obtener un término a partir de su descripción utilizaremos el método GetTerms():

public static void ObtenerTerminos() { using (SPSite site = new SPSite(“http://UrlColecciónDeSitios&#8221;)) { TaxonomySession session = new TaxonomySession(site); int lcidSpanish = System.Globalization.CultureInfo.GetCultureInfo(“es-ES”).LCID; TermSetCollection termSetColl= session.GetTermSets(“Nuevo conjunto”, lcidSpanish); TermCollection termColl = session.GetTerms(“Término 1”, true); } }

Para realizar consultas con CAML nos encontraremos con que tendremos que realizar una serie de pasos adicionales ya que al agregar una columna de tipo “Metadatos administrados” SharePoint creará una columna oculta de tipo lookup para facilitar las búsquedas.

Tendremos que obtener entonces el identificador de la columna lookup para construir después la consulta CAML con una estructura similar a la siguiente:

<Query><Where><In><FieldRef LookupId=”TRUE” Name=”{Nombre interno de la columna a consultar}” /><Values><Value Type=”Integer”>{Id de la columna lookup de metadatos}</Value></Values></In></Where></Query>

El siguiente ejemplo muestra cómo obtener los elementos catalogados con el término “Automóvil” en una lista mediante CAML:

public static void ObtenerElementosConTermino() { using (SPSite site = new SPSite(“http://UrlColecciónDeSitios&#8221;)) { TaxonomySession session = new TaxonomySession(site); TermCollection termColl = session.GetTerms(“Automóvil”, true); foreach(Term term in termColl) { if (term.IsKeyword) { int[] arIdsDeElementos = TaxonomyField.GetWssIdsOfKeywordTerm(site, term.Id, 1000); }

int[] arIdsDeElementos2 = TaxonomyField.GetWssIdsOfTerm(site, term.TermStore.Id, term.TermSet.Id, term.Id, true, 1000); using (SPWeb web = site.OpenWeb()) { SPList listaDocumentos = web.Lists[“Documentos generales”]; SPQuery queryCAML = new SPQuery(); StringBuilder sb = new StringBuilder(); foreach(int idLookup in arIdsDeElementos2) { sb.Append(string.Format(“<Value Type=\”Integer\”>{0}</Value>”, idLookup)); } queryCAML.Query = string.Format(“<Query><Where><In><FieldRef LookupId=\”TRUE\” Name=\”{0}\” /><Values>{1}</Values></In></Where></Query>”, listaDocumentos.Fields[“Temática”].InternalName, sb.ToString()); SPListItemCollection items = listaDocumentos.GetItems(queryCAML); } } } }

Mediante el motor de búsqueda de SharePoint también podremos realizar filtros en base a términos. La propiedad de búsqueda “owstaxIdMetadataAllTagsInfo” nos permite filtrar por un identificador de un término. Además, cada vez que se agregue una nueva columna a una lista del tipo “Metadatos administrados” el motor de búsqueda crear una propiedad administrada para filtrar sobre esa columna, esta propiedad se creará con la estructura “owstax{NombreInternoDeColumna}”.

En el siguiente ejemplo se muestra cómo realizar una búsqueda con el motor de búsqueda de todos aquellos documentos catalogados con un término:

using Microsoft.Office.Server; using Microsoft.Office.Server.Search;

using Microsoft.Office.Server.Search.Query;

public static void ObtenerElementosConBuscador() { using (SPSite site = new SPSite(“http://UrlColecciónDeSitios&#8221;)) { TaxonomySession session = new TaxonomySession(site); TermCollection termColl = session.GetTerms(“Automóvil”, true);

FullTextSqlQuery myConsulta = new FullTextSqlQuery(site); myConsulta.RowLimit = 10; myConsulta.QueryText = string.Format(“SELECT Title, Author, URL FROM Scope() WHERE (\”SCOPE\” = ‘Todos los sitios’) AND (\”owstaxIdMetadataAllTagsInfo\”=’#0{0}’)”, termColl[0].Id); myConsulta.ResultTypes = ResultType.RelevantResults; ResultTableCollection misResultados = myConsulta.Execute(); ResultTable resultadosRelevantes = misResultados[ResultType.RelevantResults]; } }

En el filtro se ha utilizado la propiedad owstaxIdMetadataAllTagsInfo indicando un valor del tipo “#0{GUID del término}”. No se puede utilizar la propiedad owstaxIdMetadataAllTagsInfo en la parte de consulta Select, solo podremos utilizarla en la parte Where.

Podréis encontrar más información en:

http://msdn.microsoft.com/en-us/library/ff625182.aspx

Use Flash in SharePoint 2010

Post from Ryan McIntyre about how to use flash in SharePoint 2010:

http://blog.randomdust.com/index.php/2011/01/use-flash-in-sharepoint-2010/

The idea of using Flash inside SharePoint 2007 is well documented and I’ve even done it a few times myself. My preferred method (non-code) is to slap a Content Editor web part (CEWP) on the page, go into the HTML editor, and add my <object> code. Worked like a charm.

Not so much in 2010. You can add a CEWP to a 2010 page, you can go into the HTML editor and add your <object> code, but the page will never load the swf file. There are recommendations out there saying to change the Browser File Handling setting for the web application to Permissive from Strict, but this didn’t fix anything for me (tried in three separate environments.) What did work is the following method using a Page Viewer web part…

  1. Upload your swf file to a library in your site (I prefer Site Assets library if you’re not using publishing features)
  2. Create a HTML file locally with the content:
        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        <head>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
        <title>Flash Page</title>
        </head>
        <body>
        <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="300" height="300" id="&lt;your swf filename here>" align="middle">
        <param name="allowScriptAccess" value="sameDomain" />
        <param name="movie" value="&lt;your swf filename here>.swf" />
        <param name="quality" value="high" />
        <param name="bgcolor" value="#ffffff" />
        <embed src="http://site/SiteAssets/&amp;amp;lt;your swf filename here>.swf" quality="high" bgcolor="#ffffcc" width="300" height="300" name="<Flash File Name>" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
        </object>
        </body>
        </html>

    Replace the <your swf filename here> with your filename, and changing any other params you need.

  3. Upload the .html file to your Site Assets library (or wherever you put your .swf file)
  4. To test your progress, click on the .html file in the library. If you’ve done everything right so far, a page should open in your browser which loads the Flash file (it may prompt you to show the file depending on your browser settings)
  5. Copy the URL of the .html file in it’s new location
  6. Navigate to the page where you want the Flash file to appear and go into edit mode
  7. Add a Page Viewer web part
  8. Edit the Page Viewer web part and choose the Web Page option, entering the link to your .html file in the Link text box
  9. Click OK, and ta-da!
  10. You will want to edit the web part again to set height and width, and hide or change the title, etc. But that’s up to you.

That’s the only method that worked for me. I found that the Browser File Handling setting had no impact on whether this method worked or not, so don’t worry about messing with that.

Edit: Turns out the Browser File Handling does need to be set to Permissive. At least it needs to be Permissive when you upload your HTML file. You can change it back to Strict after that if you need to. It looks like SharePoint adds the headers during file upload, not run time. So if you upload the HTML file with Strict, headers get added that prompt the user to download the file instead of just view it in the browser.

Attach databases and upgrade to SharePoint Server 2010

Tehcnet article about how to upgrade to SharePoint 2010 attaching databases:

http://technet.microsoft.com/en-us/library/cc263299.aspx

Service Unavailable

http://blog.henryong.com/2010/04/24/sharepoint-2010-troubleshooting-503-service-unavailable-app-pool-shutdown

Resolutions:

Option 1 – Log on locally with the service account once to create a local profile for it.

Option 2 – Modify the application pool by going into IIS > Application Pools > Right-Click offending app pool > Advanced Settings > Set “Load User Profile” to False.

http://msdn.microsoft.com/en-us/library/aa952804(BTS.70).aspx

“Service Unavailable” error occurs when accessing the SharePoint Central Administration Web site

Problem

When you attempt to open the SharePoint Central Administration Web site, an error similar to the following is displayed:

Service Unavailable

Cause

The most common cause for this error is that the application pool (IIS 6.0 or IIS 7.0) or hosting COM+ application (IIS 5.x) for the SharePoint Central Administration Web site is stopped. This commonly occurs if the application pool or COM+ application is configured with an identity for which the specified user name and/or password is invalid.

Resolution

Follow the steps in the “Setting IIS Application Host Process Identity” section of the topic Guidelines for Resolving IIS Permissions Problems to set the appropriate host process identity.

http://sharepointapplied.com/2009/07/07/troubleshooting-sharepoint-service-unavailable-error

6) As I couldn’t find anything obvious in event logs or sharepoint logs navigated to C:\WINDOWS\system32\LogFiles\HTTPERR folder and looked through httperr.log files.

What is httperr file? I only learned about httperr logs recently when troubleshooting some pesky IIS issue.

Httperr.log is [pasted from MS site] “a new feature in IIS 6.0. If HTTP.sys is unable to write an error to a Web site log because the request did not reach user mode, the error will be entered in Httperr.log. Errors that are written to Httperr.log include the following:

•503 errors

•idle connection time-outs

•URL parsing errors

•the last 10 requests to a failed application pool.

If you need some help in decoding the errors logged in the flie you can refer to the following MS article: Error logging in HTTP API which includes a nice description of the different fields and the order of the fields in httperr log files.

Looking through the files I the following two errors getting logged repeatedly

HTTP/1.1 POST /_vti_bin/sitedata.asmx 503 1790625552 Disabled SharePoint+-+90

HTTP/1.1 POST /_vti_bin/sitedata.asmx 503 1370408763 Disabled SharePoint+-+90

So basically attempts to connect to the sitedata.asmx web service resulted in 503 errors (Service Unavailable). I googled IIS 1790625552 and IIS 1370408763 hoping to get some more info but couldn’t find any articles matching the codes.

A bit of searching led me to the following MS article:

503-Service Unavailable (IIS 6.0)

The article lists the different error codes and causes of 503-Service Unavailable IIS errors.

Looking through the error table I found that the “Disabled” word maps to the following cause “The administrator has stopped the application pool.”.

So the line in my httperr log:

HTTP/1.1 POST /_vti_bin/sitedata.asmx 503 1790625552 Disabled SharePoint+-+90

was basically telling me my application pool “Sharepoint – 90″ was stopped.

I opened IIS Manager, expanded the Application Pools node and noticed the application pool used for the problematic web application was indeed stopped.

Duplicate Web Parts appear when you activate and deactivate a feature

In this post Chris O’Brien explain in detail why sometimes duplicates web parts appear:

http://www.sharepointnutsandbolts.com/2009/02/extending-web-part-framework-part-2.html

Issues and resolutions

I think that many of the challenges we faced are worth sharing as they came about through general web part development, rather than anything specific to what we did. Before I detail the actual gotchas, take note of some key development characteristics of our project:

  • Solutions and features used to deploy artifacts such as page layouts, content types etc.
  • Kivati Studio used for some other deployment aspects
  • Main functionality implemented in user controls – web parts were effectively thin wrappers around the .ascx files using LoadControl()
  • Web parts which are ‘mandatory’ are added to pages using the AllUsersWebPart element in a feature (though as the points probably illustrate, we looked at numerous ways of dealing with this)

Finding #1 – web parts outside of web part zones cannot be edited

The reason we wanted to have web parts outside of zones (perfectly possible by dragging a web part directly into page layout markup in SharePoint Designer) is for ‘fixed’ page modules which could not be removed by the content author. When we placed web parts outside of web part zones, we found the web parts would run fine in presentation mode but unfortunately cannot be edited (e.g. to edit web part properties) – the edit menu for the web part simply does not appear. I speculate this is because it is web part zones which are linked to web part storage, and thus web part properties cannot be persisted without a zone (the values in the markup will always be used). Hence, if you want editable web parts, you need web part zones.

Resolution – ensure all web parts (even ones which cannot be removed) live in a web part zone.

Finding #2 – embedding web parts into user control markup appears to be problematic

We tested various permutations of using web parts in/out of web part zones, and also with the HTML markup directly in the page layout .aspx or in a child .ascx file. After establishing that web part zones were required, we also found that whether the markup was in the .aspx or .ascx appeared to make a difference. This was unexpected, but the net effect seems to be that if you insert the web part markup into a web part zone which is in a user control rather than directly in the page layout .aspx (i.e. by refactoring the HTML markup for the web part zone and it’s contents into a user control), again the edit menu will not display. I’m not sure why this is, but it could be related to the page execution lifecycle.

Resolution – accept that if web part zones will have web parts added to them at design-time by markup, the web part zone declaration cannot be in a user control.

Finding #3 – when using AllUsersWebPart element, duplicate web parts appear if the feature containing your page layouts is reactivated

Having decided our ‘fixed’ web parts would be added to pages using the AllUsersWebPart feature element (N.B. using this approach, ‘default’ web parts are associated with page layouts in the feature which deploys them. Web part zones are left empty on the page layout, and SharePoint provisions the web part into the zone at the time of creating a page from the layout). The issue we had with this is that all the web parts in all the zones in existing pages would be duplicated if the page layout feature was reactivated – this is because this XML is used both when the feature is activated (in the same way as say, provisioning for content types happens on activation) but also when new pages are created from a page layout.

Resolution – write a script (a Kivati task in our case) to remove duplicate web parts across all sites

[UPDATE – Waldek has an elegant solution to this problem in ‘Preventing provisioning duplicate Web Part instances on Feature reactivation’, as well as sample code similar to what we wrote for our script. DOH!]

Finding #4 – duplicate web parts can also appear when the page layout is customized (ghosted)

I’m not exactly clear on the reasons why customized files would ever cause duplicate web parts to appear, but that’s certainly what we seemed to find. What happened is that we would deploy our master pages/page layouts using a feature to our QA environment, but immediately these files would be provisioned in that site as customized (i.e. the content in the content database), instead of being uncustomized and referenced on the filesystem. After further investigation, we traced the cause of this unexpected behaviour to the use of these attributes SPD adds to page layouts:

meta:progid=”SharePoint.WebPartPage.Document” meta:webpartpageexpansion=”full”

Resolution – ensure the version of the file does not contain these attributes. We actually switched to running uncustomized master page/page layouts even in our development farm. This means that we deployed the files using a feature and thereafter never opened them in SPD (editing only the source-controlled feature file instead).

Finding #5 – avoid setting default properties in the web part definition file (.webpart)

A final lesson we learnt is that, when working with web parts it’s often better to avoid using the .webpart definition file extensively for setting default property values. There’s nothing wrong with the mechanism – effectively these values are read whenever the web part is provisioned on a page, and your instance will set it’s properties to these values. The problem, of course, is when you realize a property value you defined in the .webpart file needs to be updated because something changed. What happens to all the existing instances on pages around your site? As you might guess, the answer is nothing – unless you take steps to update those also, which generally means writing some kind of script to use SPLimitedWebPartManager. This can be pretty inconvenient when all you wanted to do was quickly change a default value.

Resolution – consider ensuring .webpart files are stripped to the bare minimum (assembly name etc.) and configuration comes from somewhere else. We typically rolled these config items into our use of the Config Store.

Summary

We ran into a few unexpected gotchas when building on the web part framework, but steps can be taken to minimise their impact. Hope you find these useful if you do web part development. Special thanks to Karoly Szalkary for helping to refresh my memory on some of these!

SharePoint and SSL – Configuring https for SharePoint on Windows Server 2008 IIS7

Post: http://www.sharepointassist.com/2009/02/01/sharepoint-and-ssl-configuring-https-for-sharepoint-on-windows-server-2008-iis7/

Problem

You would like your windows Server 2008 instance of SharePoint to respond to https.

Solution

Start computer management

Select the Internet Information Services role

Double click on Server Certificates

In the actions menu Create Self Signed Certificate (or if you are using these instructions for a production instance you can import your new certificate to IIS here as well.

Provide a friendly name for your cert

Right mouse key on your SharePoint web application and select Edit Bindings

In the bindings window add a new binding

Select SSL Settings for the SharePoint web application you’d like to communicate with via SSL / https.

Bind your certificate to “https” for the necessary IP addresses. Please note that port 443 is the default SSL port so don’t change that setting unless you are planning on providing the servername and port number to your end users (e.g. https://sharepoint:42843/)

Now launch your website with the https prefix in the url, if you followed these directions closely you will receive a certificate error since your self signed certificate was not provisioned by a valid certificate authority such as Verisign.

Success!!!

If you need to get a real SSL certificate instead of a self signed version you can browse the trusted certificate authorities in your browser

SharePoint Online for Office 365 Developer Guide

http://msdn.microsoft.com/en-us/library/hh147180.aspx