Mostrando entradas con la etiqueta Sharepoint. Mostrar todas las entradas
Mostrando entradas con la etiqueta Sharepoint. Mostrar todas las entradas

miércoles, 15 de febrero de 2012

Error occurred in deployment step 'Recycle IIS Application Pool': The local SharePoint server is not available

Estos días he tenido que pelearme un poco con un servidor MSS2010 de desarrollo debido al error que da el título a este artículo, os pongo en antecedentes:

Situación inicial

Estamos desarrollando una WebPart para MSS 2010, nada fuera de lo común, una WebPart sencillita, cuyos detalles además no vienen al caso.

Por motivos que tampoco vienen al caso, el desarrollo se estaba realizando con un usuario ‘genérico’ mediante escritorio remoto. Todo funcionando de lujo hasta que otro compañero necesita conectar en remoto también con ese usuario, como ya sabréis no puede haber (creo) dos conexiones remotas distintas con el mismo usuario (si se puede ya me avisaréis).

El caso es que ya no se puede desarrollar con el dichoso usuario ‘genérico’… Ningún problema, inicio el escritorio con mi usuario, mapeo el código de TFS y a funcionar…

El problema

El proyecto se abre sin problema, compila de lujo (como era esperado) pero (siempre hay un pero) al ir a realizar el despliegue de la Web Part, de repente mensaje de error:

image

y en los detalles del error en la ventana de “Error List”:

image

Ay ay ay, uy uy uy…

Menos mal que nos queda Google… Revisando por ahí posibles soluciones al problema, resulta que el error viene (lógico por otra parte) por un problema de permisos de mi usuario en la infraestructura Sharepoint del servidor de desarrollo.

La solución

Gracias al siguiente artículo, el problema se soluciona utilizando el comando Add-SPShellAdmin.

¿Cómo lo utilizamos para solucionar el problema?

Iniciamos una consola de administración de Sharepoint y ejecutamos el comando:

Add-SPShellAdmin dominio\usuario

Puede producirse un error de conexión con el servidor local (el mismo que nos da desde Visual Studio) si se produce no nos queda otra que pedir que nos ejecuten el comando con el usuario ‘genérico’

Una vez ejecutado el comando, al intentar realizar el despliegue, puede producirse el siguiente error:

image

Si revisamos el visor de sucesos del servidor, podemos ver que se trata de un acceso denegado con la Base de Datos de contenido del servidor Sharepoint. Para solucionar este problema, tenemos que utilizar el mismo comando anterior, especificando el id de la Base de Datos de Contenido que nos indica en el visor de sucesos.

Averiguar el ID de la Base de Datos de contenido

Ejecutamos el siguiente comando PowerShell:

Get-SPDatabase | Select Name, Id

Localizamos el nombre que hemos obtenido en el Visor de Sucesos, y apuntamos el Id, que utilizaremos en la siguiente instrucción:

Add-SPShellAdmin dominio\usuario –database Id

 

y con esto, a funcionar!!!

jueves, 9 de febrero de 2012

Instalar una aplicación web ASP.NET en un sitio de Sharepoint 2010

Una de las preguntas que vuelve de tiempo en tiempo es ¿Cómo ponemos una aplicación ASP.NET en un sitio web que esté ocupado por Sharepoint?
La respuesta en principio es sencilla, basta con generar un directorio virtual en el sitio web de Sharepoint en el que alojar la aplicación.
Peeeero, es muy probable que nos aparezcan errores relacionados con el archivo web.config de la aplicación, ya que como ya sabemos los archivos web.config se van heredando en la estructura IIS, y el primer web.config que aparece en la estructura es el de Sharepoint, que añade sus entradas (y que normalmente interfieren con nuestra aplicación)
A continuación vamos a ver una serie de posibles problemas que podemos encontrar y una solución ‘sencilla’ para los mismos.
NOTA: Los errores que vamos a ver a continuación, ni son todos los que están, ni están todos los que son. Conforme vayamos encontrando más problemas, los iremos añadiendo a la lista.

Security Exception

Uno de los primeros errores que podemos encontrarnos es este, provocado por la configuración de seguridad del sitio web.
image

Solución

Cuidadito, porque igual esto no podemos / debemos hacerlo a la ligera.
En el web.config de la aplicación indicamos explícitamente el nivel de confianza de la aplicación, como por ejemplo:
<system.web>
….
    <trust level="Full" originUrl="" />
</system.web>

Problemas con la sesión

Otro problema que podemos encontrarnos tiene que ver con las variables de sesión, ya que Sharepoint gestiona las sesiones de una manera específica.

Solución

En el web.config de la aplicación añadimos el módulo ‘estándar’ de gestión de la sesión de .net:
<system.webServer>

    <modules>
    …
        <add name="Session" type="System.Web.SessionState.SessionStateModule" />
    </modules>
</system.webServer>

A continuación configuramos las páginas de la aplicación para habilitar la gestión de la sesión:
<system.web>

    <pages enableSessionState="true">

    </pages>

</system.web>

A funcionar (por el momento)

Cómo acceder a una aplicación ASP.NET externa desde Sharepoint

Situación inicial

No preguntéis por qué, pero surgió la necesidad de acceder desde un servidor Sharepoint 2010 a una aplicación ASP.NET alojada en otro servidor, ambos accesibles desde internet y en distintos dominios.
Pongamos que la ruta de acceso al servidor Sharepoint 2010 era “www.mss2010.es” y la ruta de acceso a la aplicación era “aplicacion.aplicaciones.es”

Solución sencilla

Nada complicado, vamos al servidor Sharepoint, añadimos una Web Part “Visor de Páginas” y configuramos la URL de acceso para que muestre la página de inicio de la aplicación. ¡Listo!

Problema

¿Listo? Noooo. Una vez realizada la operación, podemos observar que la aplicación externa hace (perdón por la expresión) ‘cosas raras’. Por ejemplo:
Al acceder a la aplicación, almacenamos una serie de información en variables de sesión (de nuevo, no preguntéis por qué) que luego se utilizan en distintas páginas de la aplicación. Cuando accedemos a la aplicación directamente desde el navegador web, todo funciona sin problemas, pero al acceder a la aplicación desde el Visor de Páginas de Sharepoint 2010, esas variables de sesión NO se mantenían al navegar por la aplicación; es más, cada página a la que accedemos dentro de ese visor reiniciaba la sesión en la aplicación externa
Después de mirar y remirar por ahí, llegamos a la conclusión de que este funcionamiento es correcto. ¿Por qué? el navegador de internet (en este caso Internet Explorer, y no, por favor no preguntéis por qué) detecta que estamos incluyendo en una página de un dominio (www.mss2010.es) un marco (el visor de páginas) cuya información proviene de otro dominio (aplicacion.aplicaciones.es) esta operación por defecto es considerada como ‘insegura’ en las zonas de sitios de confianza e Internet.

¿Cómo lo solucionamos?

La opción “sencilla” pasaría por configurar los clientes para que tanto el sitio web de Sharepoint como el de la aplicación estuvieran en la zona de Intranet Local…
¿Perdón?¿Hola? estamos en Internet, NO podemos hacer eso!
La segunda posibilidad pasa por poner las dos aplicaciones en el mismo dominio de Internet (reconozco que no lo he probado, porque en este caso no era una posibilidad)
La tercera opción es modificar la aplicación web para que se identifique como ‘segura’ ante el navegador de internet, pero claro, cuidado porque para hacer esto tenemos que poder modificar la aplicación externa. En este caso podíamos hacerlo, así que lo hicimos.

Al turrón

Entiendo que habrá múltiples maneras de hacerlo, pero resultó muy sencillo modificar el archivo global.asax de la aplicación externa para que cuando se inicia la petición a la aplicación, ésta añada un encabezado concreto a la petición HTTP que marque la aplicación como segura. Por ser más ‘puristas’ este es un extracto en inglés explicando un poco más el tema:
Starting in Internet Explorer 6 support for the Platform for Privacy Preferences (P3P) Project was introduced. The P3P standard notes that if a FRAMESET or a parent window references another site inside a FRAME or inside a child window, the child site is considered third party content. Internet Explorer, which uses the default privacy setting of Medium, silently rejects cookies sent from third party sites. So consequently a large percentage of your visitors may end up having an unhappy experience on your site.
You can add a P3P compact policy header to your child content, and you can declare that no malicious actions are performed with the data of the user. If Internet Explorer detects a satisfactory policy, then Internet Explorer permits the cookie to be set.
Al final, el método en el evento “Application_BeginRequest” queda como se ve a continuación (ojo, que está en VB.NET)
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
    HttpContext.Current.Response.AddHeader("p3p", "CP=""CAO PSA OUR""")
End Sub


Una vez añadido el evento y compilada y publicada la aplicación externa, el sistema comienza a funcionar de nuevo…

jueves, 12 de enero de 2012

Generar builds en TFS para proyectos de Sharepoint

O cómo compilarlos automáticamente sin morir en el intento.

Los últimos días he retomado el desarrollo de componentes para Sharepoint, que tenía bastante “oxidado” y como no podía ser de otra manera, he integrado el proceso de desarrollo dentro del TFS 2010. La situación que tenía (para tener claro de qué estoy hablando) era la siguiente:

  • Equipo de desarrollo: Windows 2008 R2 de 64 Bits.
  • Sharepoint Server 2010 instalado en el equipo de desarrollo.
  • Visual Studio 2010.
  • Servidor de fuentes: Team Foundation Server 2010.

 

Pasos Previos

Lógicamente antes de nada, hay que realizar las operaciones clásicas cuando utilizamos TFS (creación del Team Project, rama Main, etc.)

Hasta aquí nada nuevo bajo el sol, estuve realizando el componente (en este caso una WebPart) y llegó la hora de probarlo en el entorno de Preproducción.

Para la instalación en ese entorno, únicamente utilicé el WSP que genera Visual Studio al ‘empaquetar’ el proyecto de Sharepoint, pero se me ocurrió que tenía que ser posible utilizar las Builds de TFS para que ese paquete WSP se genere automáticamente, como el resto de productos alojados en TFS.

La verdad es que no resultó tan sencillo como yo esperaba, aunque los problemas y pasos para solucionarlos tienen mucho sentido.

Primer intento

Lo primero que intenté fue lo típico, generé una nueva Build Definition, y la ejecuté… Resultado:

image

Como vemos, al realizar la compilación el agente detecta que en el proyecto hay referencias que no le gustan, o que no conoce, vamos, que no existen en el servidor…

Esto es normal, ya que ni Visual Studio ni, por supuesto, Sharepoint están instalados en el servidor de compilación.

Segundo intento

Como no funcionó, tocó “googlear” un rato, y lo primero que encontré fue un “apunte” en el que indicaba que con una Build Definition ”normal” no se conseguía generar el WSP para el componente. Para solucionar ese problema, es suficiente con añadir el parámetro “/p:IsPackaging=True” en la sección de “MSBuild Arguments” de la Build Definition:

image

Pero aún hay más, encontré una pequeña ‘maravilla’ que en principio simplifica el proceso. Dicha maravilla es un script de Powershell que en un primer paso permite coger los ensamblados de Sharepoint de la máquina de desarrollo, y en una segunda pasada los copia y registra en el servidor de compilación. No voy aquí a repetir los pasos de ejecución de dicho script, ya que está suficientemente explicado aquí, pero baste una captura para ver el resultado de la compilación una vez ejecutado el script tanto en la máquina de desarrollo como en el servidor de compilación:

image

Bueno, tampoco íbamos a esperar que funcionase a la primera no?

Lo que ha pasado es que el script que hemos ejecutado sólo coge los ensamblados básicos de Sharepoint:

"Microsoft.SharePoint.dll"
"Microsoft.SharePoint.Security.dll"
"Microsoft.SharePoint.WorkflowActions.dll"

Como nuestro proyecto es una Web Part que hereda de un tipo de "Microsoft.Office.Server.Search.dll", tendremos que añadir dicho ensamblado en la sección “$Script:SharePoint14ReferenceAssemblies” del script que hemos ejecutado.

NOTA: Al ejecutar el nuevo script en la máquina de desarrollo es posible que nos dé un error de que ese ensamblado no se puede localizar, si es el caso, basta con copiarlo desde la carpeta ISAPI de Sharepoint a la carpeta “Files” que se genera al ejecutar el script (si no sabes dónde está la carpeta ISAPI, creo que te has equivocado de post)

Al final, después de pruebas y error, llegamos al…

Tercer intento

En el script mágico tuve que añadir los siguientes ensamblados en la sección que indicaba antes:

"Microsoft.Office.Server.dll"
"Microsoft.Office.Server.Search.dll"
"System.Web.DataVisualization.dll"

Tras ejecutarlo en el servidor de compilación, lanzamos la Build y:

image

¡Por fin! ya tenemos compilaciones automáticas desde TFS 2010 de proyectos para Sharepoint; además, podemos observar en la carpeta de los Drops que la compilación ha generado el paquete WSP:

image

Nota final

Como podemos ver en la última captura, la Build no sólo genera el paquete WSP, sino que también está llevando a la carpeta de Drops los ensamblados que hemos añadido durante el proceso. He investigado un poquillo y parece ser que se podrían eliminar de dicha carpeta en uno de los pasos del Workflow de la Build Definition, pero reconozco que no he ahondado más en el tema. Si por lo que sea llegamos a tener problemas de espacio, podemos borrar todos esos ensamblados de las distintas compilaciones. Oye, aunque tengamos que borrarlos a mano, sigue siendo mejor que lo que teníamos antes no?

viernes, 28 de octubre de 2011

Cómo descargar documentos de Sharepoint rápidamente

Así como vimos una manera sencilla de publicar documentos en un servidor de Sharepoint (acceso), en esta ocasión vamos a proceder a la descarga de esos documentos.
En este proceso vamos a utilizar la clase “System.Net.WebClient” lo que implica que estas operaciones no son exclusivas de Sharepoint, sino que servirían ‘virtualmente’ para cualquier tipo de servidor web.

Al turrón

  1. Instanciamos y configuramos el objeto “WebClient”:
    WebClient objWebClient = new WebClient();    
    objWebClient.Credentials = CredentialCache.DefaultCredentials;
  2. Descargamos el documento:
    objWebClient.DownloadFile(txtSource.Text, rutaDes + "\\" + nombreArchivo);

Descargar sin permisos en la biblioteca de origen

En muchas ocasiones, las bibliotecas de Sharepoint que se utilizan como repositorio de aplicaciones tienen especificada una seguridad específica para evitar que el acceso a esa documentación se realice desde ‘fuera’ de las aplicaciones concretas. Para poder realizar el download en estos casos, tendremos que disponer de una cuenta de acceso ‘genérica’ a la biblioteca con los permisos mínimos para poder descargar documentación, y utilizar esa cuenta en la configuración de las credenciales del objeto “WebClient”:
objWebClient.Credentials = new System.Net.NetworkCredential("user","pwd","domain"); 

¿Fácil no?

Adjuntos

Descargar

jueves, 27 de octubre de 2011

Cómo subir un documento a Sharepoint rápidamente con Servicios Web

Cuando queremos utilizar Sharepoint como repositorio de documentos de nuestras aplicaciones, lo primero que tenemos que decidir es cómo queremos conectar con el servidor para almacenar dichos documentos. La decisión en sí no es muy complicada, aunque sí es cierto que dependerá de factores como arquitectura, formas de conexión, seguridad, etc…
En este artículo vamos a desarrollar paso a paso una función de ‘Upload’ utilizando los servicios web nativos de Sharepoint, en su versión 2010. Esta aproximación es la más sencilla de implementar y a continuación veremos cómo

Añadir la referencia web

Como comentaba más arriba, vamos a subir documentación a un servidor de Sharepoint mediante los Servicios Web nativos; en consecuencia, lo primero que tenemos que hacer es añadir la referencia web correspondiente en nuestro proyecto. En el ejemplo realizado se ha utilizado Visual Studio 2010, pero es perfectamente válido también para versiones anteriores.
  1. Sobre el proyecto, clic con el botón derecho del ratón, “Add Service Reference”

    image
  2. Para añadir la referencia web, hacemos clic en el botón “Advanced” y a continuación en el botón “Add Web Reference”

    image

    image
  3. En la caja de texto “URL:” introducimos la url de acceso al servicio web de Sharepoint que nos permitirá subir documentos. Dentro de todos los servicios web que proporciona Sharepoint, el que nos interesa en esta ocasión es “Copy.asmx” y como el resto de los servicios web está alojado en la carpeta “_vti_bin” en este ejemplo vamos a utilizar como ruta para la referencia “http://srvmv07/_vti_bin/copy.asmx
  4. Una vez que la ventana anterior nos ha comprobado la referencia, le damos un nombre (en el ejemplo “WSCopy”) y hacemos clic en “Add Reference” para incluir la referencia en el proyecto.

    image
En este ejemplo, vamos a trabajar con dos parámetros en el archivo de configuración. Uno indicará el sitio de Sharepoint donde queremos subir el documento (“WebUrl”) en formato http://servidor/sitio y el otro indicará la biblioteca de destino (“DocumentLibraryDestination”)

Al turrón

  1. Instanciamos el servicio web:
    //Configuración del Servicio Web         
    WSCopy.Copy copyService = new WSCopy.Copy();         
    copyService.Url = Properties.Settings.Default.WebUrl + "/_vti_bin/copy.asmx";         
    copyService.Credentials = System.Net.CredentialCache.DefaultCredentials;      
    Como podemos ver en el fragmento de código, en este ejemplo estamos utilizando las credenciales por defecto del usuario que está ejecutando el programa. Más adelante veremos cómo actuar si dicho usuario no tendrá permisos sobre la carpeta de destino.
  2. Preparamos los objetos necesarios para realizar el Upload:
    //Declare and initiates the Copy WebService members for uploading       
    string sourcePath = “Ruta completa al archivo a publicar”;       
    string[] destinationUrl = {       
                               Properties.Settings.Default.WebUrl + "/" +       
                               Properties.Settings.Default.DocumentLibraryDestination + "/" +       
                               “Nombre del archivo”       
                               };       
    WSCopy.CopyResult cResult1 = new WSCopy.CopyResult();       
    WSCopy.CopyResult cResult2 = new WSCopy.CopyResult();       
    WSCopy.CopyResult[] cResultArray = { cResult1, cResult2 };       
    WSCopy.FieldInformation fFiledInfo = new WSCopy.FieldInformation();       
    WSCopy.FieldInformation[] fFiledInfoArray = { fFiledInfo };     
    En este fragmento, la parte más relevante está en las últimas dos instrucciones, ya que nos permitirán, completando el código, establecer los valores de metadatos del documento en Sharepoint. De momento no vamos a publicar ningún atributo, así que lo dejamos como está.
  3. Abrimos el archivo que vamos a ‘subir’ y lo convertimos en un array de Bytes, que será lo que tendremos que enviar al servicio web como parámetro:
    //Reading the document contents in to stream       
    FileStream strm = new FileStream(sourcePath, FileMode.Open, FileAccess.Read);       
    byte[] fileContents = new Byte[strm.Length];       
    byte[] r = new Byte[strm.Length];       
    int ia = strm.Read(fileContents, 0, Convert.ToInt32(strm.Length));       
    strm.Close();
  4. Invocamos a la función “CopyIntoItems” del Servicio Web para realizar el upload y… listo!

    uint copyresult = copyService.CopyIntoItems(sourcePath, destinationUrl, fFiledInfoArray, fileContents, out cResultArray);

    Ojo con esta última parte, ay que según la documentación, la función devolverá “0” si todo a ido bien, y otro valor si ha habido algún problema; sin embargo, la manera de comprobar si todo ha ido bien es mediante el parámetro de vuelta “cResultArray”

Realizar el Upload sin permisos en la biblioteca de destino


En muchas ocasiones, las bibliotecas de Sharepoint que se utilizan como repositorio de aplicaciones tienen especificada una seguridad específica para evitar que el acceso a esa documentación se realice desde ‘fuera’ de las aplicaciones concretas. Para poder realizar el upload en estos casos, tendremos que disponer de una cuenta de acceso ‘genérica’ a la biblioteca con los permisos mínimos para poder subir documentación, y utilizar esa cuenta en la configuración de las credenciales del servicio web:
copyService.Credentials = new System.Net.NetworkCredential("user","pwd","domain");
 
Cuidado porque esta práctica provoca que en la biblioteca de documentos el usuario que aparece como última modificación será ese usuario genérico.

Modificar propiedades del documento


Las bibliotecas de Sharepoint pueden contener propiedades o atributos que etiquetan al contenido de las mismas. Para poder aplicar valor a esas propiedades al reaalizar el upload de un documento, tendremso que ‘jugar’ con la clase “FieldInformation” que comentaba más arriba:
fFiledInfo.DisplayName = "Nombre del atributo";
fFiledInfo.Type = WSCopy.FieldType.Text;//Tipo
fFiledInfo.Value = "valor";
 

Adjuntos

Descargar

miércoles, 12 de mayo de 2010

Tipos de contenido multi-idioma en Sharepoint


Objetivo

El objetivo de este documento es explicar el procedimiento a seguir para generar tipos de contenido con soporte para varios idioma.
Al final del documento conseguiremos un Tipo de contenido cuyas columnas se mostrarán en el idioma del sitio en el que estemos.
Captura del resultado en un sitio en inglés:


Captura del resultado en un sitio en español:


Consideraciones previas

Entorno:
Visual Studio 2008
Visual Studio 2008 extensions for Windows SharePoint Services 3.0 (version 1.3) Sharepoint Server 2007
Procedimiento
Creación del proyecto
En Visual Studio 2008, creamos un Nuevo proyecto vacío, de tipo Sharepoint:


Y elegimos el nivel máximo de seguridad (Full Trust)


Creación del tipo de contenido

Hacemos clic con el botón derecho del ratón sobre el nombre del proyecto que hemos creado, y elegimos “Add / New Item…”
Seleccionamos la plantilla de “Content Type” y hacemos clic en “Add”


Seleccionamos el tipo de contenido ‘Base’ del que deseamos partir y hacemos clic en “OK”.


En este documento trabajaremos
con un tipo de contenido básico al que no se le añadirá ningún manejador de
eventos, ya que el procedimiento elegido funcionará de la misma manera si
añadimos los manejadores de eventos. Se ha querido mantener el documento lo más
liviano posible.

Como observamos en la siguiente captura, en la ventana del visor de WSP (WSP View) ha aparecido la entrada correspondiente a la característica que acabamos de añadir:


Haciendo doble clic en el archivo “feature.xml” accedemos a la definición de la característica, que indica cómo se muestra la misma en la pantalla “Características de la colección de sitios”. En este archivo realizaremos los primeros cambios para disponer de nuestro tipo de contenido
multi-idioma.
Definición de la característica por defecto:


Definición de la característica modificada:


Como podemos observar en el código definitivo, hemos modificado la siguiente información:
* Title à Utilizamos el ‘token’ $Resources: para indicar que el valor lo obtendremos de un archivo de recursos.
* Description à Idéntico al anterior.
* DefaultResourceFile à Sustituimos el valor original “core” por el personalizado “_Res”. Al establecer este valor, el sistema buscará los recursos necesarios en una carpeta dentro de
la estructura física de carpetas en la que se instala la característica.

Creación de las columnas del tipo de contenido

En la ventana de “WSP View” hacemos doble clic sobre el archivo “Multi1.xml” para acceder a la definición del tipo de contenido.
Definición del tipo de contenido por defecto:


Definición del tipo de contenido modificada:


Las modificaciones realizadas son:
* ContentType.Name à añadimos el ‘token’ para el archivo de recursos.
* ContentType.Description à añadimos el ‘token’
* Field.DisplayName à añadimos el ‘token’
* Field.DisplaceOnUpgrade à añadiendo este atributo indicamos al sistema que si ya existe una definición para el campo, fuerce actualizaciones de propiedades del campo con los valores que se especifican en esta definición de campos. Con este atributo conseguimos que el tipo de contenido ‘raíz’ que estamos creando pueda actualizar los valores de sus columnas en posteriores instalaciones.
Esta actualización ‘forzada’ sólo se realiza en el tipo de contenido ‘raíz’, todos los tipos de contenido que hereden del raíz (al haberse incluido en una biblioteca, por ejemplo) NO se actualizan.

Añadir un archivo de recursos

Hasta el momento hemos utilizado el ‘token’ “$Resources:” para indicar al sistema que el valor del atributo reside en un archivo de recursos; pero, ¿cómo incluimos estos archivos al sistema?
El objetivo de esta parte del documento es conseguir la siguiente estructura en la carpeta de instalación de la característica:


Cada vez que el sistema encuentre el ‘token’ “$Resources:” en los archivos de definición de la característica y/o del tipo de contenido, irá a buscar los recursos a la carpeta “Resources” que aparece en la captura anterior.
Accedemos en Visual Studio al explorador de soluciones, y generamos la siguiente estructura de carpetas en el proyecto:


Como vemos en la captura anterior, tenemos que ‘recrear’ la estructura física que tendrá la característica una vez instalada en el servidor Sharepoint.
En la carpeta “Resources” hacemos clic con el botón derecho del ratón y elegimos Add, New Item… y elegimos la plantilla de archivo de recursos:


Haciendo doble clic en el archivo “Resources.resx” accedemos al archivo de recursos y generamos tantas entradas como ‘tokens’ hayamos utilizado:


Este primer archivo de recursos será el utilizado cuando el idioma del sitio no tenga ningún archivo de recursos asociado. Dicho de otra forma, determina los literales por defecto del tipo de contenido y su característica asociada.

Generar el paquete de la solución

En el explorador de soluciones, hacemos clic con el botón derecho del ratón sobre el proyecto y elegimos ‘Package’
Esta operación nos genera el archivo WSP que instalaremos en el servidor Sharepoint.
La instalación o despliegue de soluciones WSP se escapa al alcance de este documento, por lo que se asume que el procedimiento de instalación es conocido por todos.

Resultado

Una vez instalada la característica y desplegada en los portales necesarios, aparecerá en la página de “Características de la colección de sitios”


Antes de activar la característica, vamos a fijarnos en los literales que aparecen en la captura… son los literales definidos en el archivo de recursos, sí; pero, un momento, ¡según el botón “Activar”, el sitio de Sharepoint está en castellano! ¿Qué ha pasado aquí?
Como hemos comentado antes, el sistema intenta localizar un archivo de recursos que se ajuste al idioma del sitio en el que estamos. Si no lo encuentra utiliza el archivo por defecto (en este caso el único que hemos añadido)

Añadiendo más archivos de recursos

Para añadir más archivos de recursos (teóricamente uno para cada idioma que tengamos disponible) vamos en el proyecto a la carpeta Resources y añadimos un nuevo archivo de recursos, que se llamará exactamente igual que el primero que hemos añadido, pero con el sufijo id-ID que indicará el idioma y la localización de los recursos. La estructura de esta carpeta Resources quedará:


El contenido del archivo tiene que ser exactamente igual que el archivo de recursos por defecto, obviamente traducido al idioma del archivo (en este caso es-ES, español de España)


Volvemos a generar el paquete WSP, lo reinstalamos en el servidor Sharepoint, y observamos el resultado:


¡¡¡Ya tenemos la característica traducida!!!
Ahora sólo hace falta activar la característica y ya tenemos el tipo de contenido generado tal y como se veía al principio, con distintos literales para cada idioma.
Detalle del tipo de contenido:


Añadir este tipo de soporte multi-idioma es relativamente sencillo, pero hay que tener en cuenta las limitaciones especificadas anteriormente. Una vez que un tipo de contenido se utiliza en una lista de Sharepoint, las modificaciones realizadas al tipo de contenido raíz mediante este procedimiento NO se trasladan a dichos tipos de contenido ‘hijos’.