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…

2 comentarios sobre “SharePoint 2010. Job de importación de perfiles de usuario”

  1. 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.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *