SharePoint 2010. Job de importación de perfiles de usuario

[ACTUALIZADO] He subido el código del artículo.

En el artículo anterior nos encontramos con un problema en la sincronización de perfiles. No podemos sincronizar el campo Administrador de un perfil utilizando un origen externos (BCS) como lo hacíamos en SharePoint 2007. Para saltarnos este problema, en lo que el equipo de producto de SharePoint saca un Hotfix, vamos a ver como desarrollar un Timer Job que sea el encargado de obtener los datos a importar, utilizando la entidad del BCS, y guarde la información en el perfile correspondiente.

Un Timer Job en SharePoint es una programación de una tarea que se encarga de ejecutar un cierto código con la frecuencia programada. En nuestro servidor, debemos de tener un gran número de Jobs programados que son los encargados de analizar y mantener la plataforma, por ejemplo, hay un job que se encarga de enviar las alertas de los usuarios. En la sección de Supervisión, tenemos una opción que nos permite visualizar la definiciones de estos jobs.

sharepoint2010_timerjobs_1

Para crear un Job sólo necesitamos una clase que herede de la clase del sistema Microsoft.SharePoint.Administration.SPJobDefinition y una característica que lo registre en la definición de trabajos en nuestro servidor.

Nuestra clase debe de sobrescribir el método Execute(), que es el método que se ejecuta cuando se activa la tarea, y crearnos unos constructores de clases que se encargan de inicializar el job. Para esto nos vamos a crear un proyecto vacío de SharePoint 2010 y añadimos la siguiente clase:

class SyncJob : SPJobDefinition
{
    string linkField = "UserID";
 
    public SyncJob()
        : base()
    {
    }
 
    public SyncJob(string jobName, SPService service, SPServer server, SPJobLockType targetType)
        : base(jobName, service, server, targetType)
    {
    }
 
    public SyncJob(string jobName, SPWebApplication webApplication)
        : base(jobName, webApplication, null, SPJobLockType.Job)
    {
        this.Title = "Anada Sync Job";
    }
 
    public override void Execute(Guid targetInstanceId)
    {
        //Obtenemos la aplicación web en la que se está ejecutando el job
        SPWebApplication webApplication = this.Parent as SPWebApplication;
        SPContentDatabase contentDb = webApplication.ContentDatabases[targetInstanceId];
 
        ImportPeople(webApplication.Sites[0]);
    }
}

Una vez que tenemos nuestra estructura de Job, nos creamos una nueva característica a nivel de Site y añadimos un Event Receiver que se encargará de registrar nuestro Job en el servidor, cuando esta sea activada.

sharepoint2010_timerjobs_2

public class FeatureAnadaSyncJobEventReceiver : SPFeatureReceiver
{
    const string List_JOB_NAME = "AnadaSyncJob";
 
    public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        SPSite site = properties.Feature.Parent as SPSite;
        
        //Eliminamos el Job si ya existe
        foreach (var job in site.WebApplication.JobDefinitions)
        {
            if (job.Name == List_JOB_NAME)
                job.Delete();
        }
 
        //Registramos el job con una programación por defecto.
        Job.SyncJob syncJob = new Job.SyncJob(List_JOB_NAME, site.WebApplication);
        SPDailySchedule schedule = new SPDailySchedule();
        schedule.BeginHour = 0;
        schedule.EndHour = 1;
        syncJob.Schedule = schedule;
        syncJob.Update();
    }
 
    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
    {
        //Cuando se desactiva la característica, eliminamos el Job del sistema
        SPSite site = properties.Feature.Parent as SPSite;
 
        foreach (var job in site.WebApplication.JobDefinitions)
        {
            if (job.Name == List_JOB_NAME)
                job.Delete();
        }
    }
}

Sincronización de los perfiles

En el método Execute del Job, vamos a añadir la llamada al método ImportPeople, que es el encargado de instanciar todas las entidades del BCS y actualizar los perfiles de los usuarios con esos datos.

Lo primero es ejecutar el método del BCS ReadList que es el que obtiene todas las entidades People del origen externo.

//Instanciamos el servicio de BDC
BdcService service = SPFarm.Local.Services.GetValue<BdcService>();
IMetadataCatalog catalog = service.GetDatabaseBackedMetadataCatalog(context);
 
//Obtenemos la definición de la entidad y del sistema externo
IEntity entity = catalog.GetEntity("GSC.Anada.SharePoint.PeopleModel", "Person");
ILobSystemInstance lobSystemInstance = entity.GetLobSystem().GetLobSystemInstances()[0].Value;
 
//Realizamos la consulta con el método ReadList
IMethodInstance methodInstance = entity.GetMethodInstance("ReadList", MethodInstanceType.Finder);
IEntityInstanceEnumerator ientityInstanceEnumerator = entity.FindFiltered(methodInstance.GetFilters(), lobSystemInstance);
 
while (ientityInstanceEnumerator.MoveNext())
{
    //Actualizamos los datos del perfile correspondiente
}

Ahora recorremos cada una de las entidades externas y actualizamos el perfil correspondiente en el manager de los perfiles de SharePoint, incluyendo la foto que subimos al sitio de los perfiles para que esté accesible para todos los usuarios del servidor.

//Obtenemos el id del usuarios de la entidad externa actual
string userId = ientityInstanceEnumerator.Current["UserID"].ToString();
 
//Obtenemos el perfile del usuario, buscando con el id del usuario externo
UserProfile user = upm.GetUserProfile(userId);
if (user != null)
{
    //Actualizamos los valores del perfile con los de la entidad externa
    user["WorkPhone"].Value = GetNullValue(ientityInstanceEnumerator.Current["Phone"]);
    user["CellPhone"].Value = GetNullValue(ientityInstanceEnumerator.Current["Mobile"]);
    user["Title"].Value = GetNullValue(ientityInstanceEnumerator.Current["JobTitle"]);
    user["Office"].Value = GetNullValue(ientityInstanceEnumerator.Current["WorkName"]);
    user["SPS-Location"].Value = GetNullValue(ientityInstanceEnumerator.Current["WorkAddress"]);
    user["Department"].Value = GetNullValue(ientityInstanceEnumerator.Current["Department"]);
    user["SPS-HireDate"].Value = ientityInstanceEnumerator.Current["HireDate"];
    user["Manager"].Value = GetNullValue(ientityInstanceEnumerator.Current["Manager"]);
    user["PhoneShort"].Value = GetNullValue(ientityInstanceEnumerator.Current["PhoneShort"]);
    user["MobileShort"].Value = GetNullValue(ientityInstanceEnumerator.Current["MobileShort"]);
    user["CustomerPhone"].Value = GetNullValue(ientityInstanceEnumerator.Current["CustomerPhone"]);
    user["NIF"].Value = GetNullValue(ientityInstanceEnumerator.Current["NIF"]);
    user["WorkPhoneCentro"].Value = GetNullValue(ientityInstanceEnumerator.Current["WorkPhone"]);
    user["WebSite"].Value = GetNullValue(ientityInstanceEnumerator.Current["WebUrl"]);
 
    //Actualizamos la foto utilizando el binario de la foto de la entidad externa
    if (ientityInstanceEnumerator.Current["Photo"] != null)
    {
        byte[] photo = ientityInstanceEnumerator.Current["Photo"] as byte[];
 
        SPFolder folder = UploadUserPhoto(userId, photo, site);
        if (folder != null)
        {
            SPSite userSite = folder.ParentWeb.Site;
 
            string fileNameWithoutExtension = GetFileNameFromAccountName(userId);
 
            string pictureUrl = String.Format("{0}/{1}/{2}_MThumb.jpg", userSite.Url, folder.Url, fileNameWithoutExtension);
 
            user["PictureUrl"].Value = pictureUrl;
        }
    }
 
    //Guardamos los cambios del perfile actual
    user.Commit();
}

Y con esto conseguimos actualizar los perfiles de nuestros usuarios desde una entidad externa, salvando el problema de la actualización del Administrador (manager) que no funciona en SharePoint 2010. Ya avisaré cuando me llegue el Hotfix y lo pruebe, para que quitemos este Job y utilicemos el servicio de sincronización de SharePoint.

No he puesto todo el código auxiliar, si alguien lo necesita que me lo pida que lo publico para que pueda utilizarlo.

Os dejo el código del job y del BCS, se puede descargar desde mi skydrive

 

Saludos a todos…

Published 17/10/2010 19:26 por Alberto Diaz Martin
Comparte este post:

Comentarios

# re: SharePoint 2010. Job de importación de perfiles de usuario

Friday, October 15, 2010 12:30 AM por Viviana Franco

Hola Alberto,

Esta muy bueno tu post, yo soy nueva en el tema y me interesa mucho que publicaras tu código para entender mejor el tema.

Gracias.

# SharePoint 2010. Bug en la importación del Responsable en los perfiles de usuarios

Monday, November 22, 2010 11:50 AM por Alberto Diaz

Hace algunos artículos en mi blog, hablaba de la sincronización de los datos de los perfiles de usuarios