jueves, 9 de octubre de 2008

Acceso a datos de lista e item de lista desde una tarea de un workflow

El día de hoy me encontré con el problema de intentar acceder a la información de una lista o al item de una lista desde una tarea de un workflow.

La razón para querer hacer esto, es que desde las tareas de un workflow, se puede mostrar información relevante al usuario para contextualizarlo (entregarle información del item para que recuerde porque tiene esa tarea), o bien recoger información desde la tarea para modificar directamente el item de la lista a la que pertenece el workflow.

Con esto, el usuario no tendrá que revisar la tarea, recordar lo que tenía que completar, ir al elemento de la lista, modificarlo, volver a la tarea y completarla. En lugar de eso, podemos recoger la información que le correspondía completar, modificar nosotros el item internamente, y simplemente completar la tarea.

Recordar que la idea básica de como construir el workflow de estados lo saqué del cuarto capítulo de la excelente serie de Robert Shelton (http://rshelton.com/archive/2007/10/05/free-sharepoint-document-workflow-workshop---part-4-on-workflow.aspx).

private SPWeb _myTeamSite; // Represents my SubSite or Teamsite in my case (e.g., http://localhost/demosite1)
protected SPList _TaskListAttachedTo; // Represents the Task List associated with the workflow
protected SPListItem _TaskListItem; // Represents the item or data point within the task list that we are working
protected SPListItem _ListItem;
protected string _myTaskData; // Represents the data from the user that will be sent to the workflow
string _paramTaskListItemID; // Represents the ID Task List Item being worked on
string _paramSPListGuid = string.Empty; // The GUID of the Task List being attached to
public SPWorkflow _activeWorkflow; // Represents the current workflow
Guid _workflowInstanceGuid; // Represents the ID of the running workflow
protected SPList itemList; // Lista en la que se inició el workflow
protected SPListItem item; // Item de la lista en la que se inició el workflow

this._myTeamSite = SPControl.GetContextWeb(Context);
this._paramSPListGuid = Request.Params["List"]; // The SharePoint Document Libary ID

this._paramTaskListItemID = Request.Params["ID"]; // The associated Task Lists ID

// Get the Task List that we are attached to, by converting the Guid Parameter into a Guid
this._TaskListAttachedTo = this._myTeamSite.Lists[new Guid(this._paramSPListGuid)];
// Get the Task Item Object that the workflow has created

this._TaskListItem = this._TaskListAttachedTo.GetItemById(System.Convert.ToInt16(this._paramTaskListItemID));
// Get the ID of the Workflow Instance that we are running with in

this._workflowInstanceGuid = new Guid(Convert.ToString(this._TaskListItem["WorkflowInstanceID"]));
// Instantiate the workflow

this._activeWorkflow = new SPWorkflow(this._TaskListItem, this._workflowInstanceGuid);

// Las siguientes líneas hacen la magia
itemList = this._myTeamSite.Lists[new Guid(_TaskListItem["WorkflowListId"].ToString())];

item = this.itemList.GetItemById(System.Convert.ToInt16(_TaskListItem["WorkflowItemId"]));



Con lo anterior, tendremos disponibles los objetos itemList e item, para consultar o modificar cualquier valor en ellos. Así por ejemplo, podríamos recoger observaciones del usuario, que luego irían a parar directamente a un campo "Observaciones" en el item de la ficha:

item["Observaciones"] = txtObservaciones.ToString(); // Se modifica el valor
item.Update(); // Se actualiza el elemento para aplicar los cambios

Es importante señalar que lo anterior fue posible debido a que instanciamos la lista y el item de la lista. Esto a su vez fue posible porque contábamos con los parámetros WorkflowListId y WorkflowItemId del objeto _TaskListItem, que es del tipo SPListItem.

Como dato interesante, al recorrer todos sus campos utilizando un foreach sobre _TaskListItem.Fields (de donde pude sacar los 2 anteriores), obtuve varios campos que podrían resultar útiles para otras tareas:

ContentTypeId
Title
_ModerationComments
File_x0020_Type
SRLook
Priority
Status
PercentComplete
AssignedTo
TaskGroup
Body
StartDate
DueDate
WorkflowLink
OffsiteParticipant
OffsiteParticipantReason
WorkflowOutcome
WorkflowName
TaskType
FormURN
FormData
EmailBody
HasCustomEmailBody
SendEmailNotification
PendingModTime
Completed
WorkflowListId
WorkflowItemId
ExtendedProperties
ContentType
ID
Modified
Created
Author
Editor
_HasCopyDestinations
_CopySource
owshiddenversion
WorkflowVersion
_UIVersion
_UIVersionString
Attachments
_ModerationStatus
Edit
LinkTitleNoMenu
LinkTitle
SelectTitle
InstanceID
Order
GUID
WorkflowInstanceID
FileRef
FileDirRef
Last_x0020_Modified
Created_x0020_Date
FSObjType
PermMask
FileLeafRef
UniqueId
ProgId
ScopeId
HTML_x0020_File_x0020_Type
_EditMenuTableStart
_EditMenuTableEnd
LinkFilenameNoMenu
LinkFilename
DocIcon
ServerUrl
EncodedAbsUrl
BaseName
MetaInfo
_Level
_IsCurrentVersion

jueves, 2 de octubre de 2008

HRESULT: 0x80040E14

Luego de agregar un tipo de contenido personalizado (Custom Content Type) para poder utilizar formularios personalizados de tareas en un workflow de estados, pasé mucho tiempo a prueba y error hasta hacerlo funcionar (más adelante subiré todas esas experiencias en español, para que ojalá alguien más pueda aprovecharlo).

Cuando intenté modificar un item de la lista a la que había agregado el workflow, apareció un error:

Exception from HRESULT: 0x80040E14

Luego de MUCHO buscar, el problema es genérico, y quiere decir que ha ocurrido algún problema con SQL Server. Los típicos problemas por los que se produce, pueden encontrarlos acá:

http://www.michaelmarkel.com/labels/List%20Versioning%20Error.html

Pero que en resumen son:
  1. Se instaló Service Pack 1 recientemente
  2. El disco en donde se escriben los datos de SQL Server se llenó
  3. Luego de agregar tipos de contenido personalizados a una lista, aparece el error al intentar modificar un item de la lista
El problema es el caso 3 (mi caso), ya que lo único que encontré en internet como "solución" es desactivar el control de versiones. Efectivamente funciona, pero al volver a agregar el control de versiones, el problema regresa, por lo tanto o tenía control de versiones, o tenía tipos de contenido personalizados.

Como yo necesitaba las 2 cosas, investigando encontré que es un error conocido por microsoft, que se reparó en un hotfix de febrero:

http://support.microsoft.com/kb/948945/en-us

Deben inscribirse en un link que aparece en la parte superior (Ver y solicitar la descarga de la revisión). Una vez hecho esto, les llegará un correo con el link de descarga y la contraseña para descomprimirlo.

Mis problemas sin embargo no terminaron ahí. Una vez instalado, al intentar ingresar al portal, apareció el siguiente mensaje:

Error de servidor: http://go.microsoft.com/fwlink?LinkID=96177

Continuando con la búsqueda, al parecer ocurre cuando la instalación ha tenido problemas. Afortunadamente encontré este blog:

http://fnoja.blogspot.com/2008/01/sharepoint-service-pack-1-crash.html

En donde Fadi dio con la solución: ejecutar "stsadm -o upgrade -inplace -forceupgrade" en una consola. Después de unos minutos, el proceso terminó y al intentar ingresar nuevamente al portal, pude entrar sin problemas.