jueves, 17 de abril de 2014

Sharepoint event receivers Contribute access problem.

Hace poco me solicitaron desarrollar un event receiver, ya he desarrollado event receivers antes entonces todo parecía que venir sin ningún tipo de problema.

El cliente solicitó una eliminación en cascada, vamos a explicarlo, eran tres listas, "Project" , "Task" y "Project Documents",  primero se crea un proyecto, despúes crean  tareas en la lista "Task" para este proyecto, luego cabe la posibilidad de  subir documentos a la lista "Project Documents" y enlazarlos directamente al projecto o a una tarea específica, la idea del desarrollo era si se elimina un proyecto entonces que se eliminen las tareas relacionadas a este proyecto y tambien los documentos relacionados ya sea a  la tarea o al proyecto.

Nada fuera de lo común, escribí el código y todo bien, hasta que pasamos al "User acceptance test", todo va bien excepto que lo prueba alguien con acceso "Contribute" al sitio y se elimina el proyecto, las tares pero los documentos no se eliminan.

Ummm, que extraño si claramente estaba usando la "impersonation" de sharepoint para evitar este tipo de problemas. Despúes de realizar bastantes pruebas con diferentes usuarios sigue igual, lo curioso es que el acceso "Contribute" en sharepoint permite eliminar archivos, ¿ Qué podría estar pasando?.

El código estaba de esta manera.

private void processItemDeleting(SPItemEventProperties properties) {
 base.DisableEventFiring();
 SPSecurity.RunWithElevatedPrivileges(delegate(){
 using(SPWeb web = properties.OpenWeb()) {
 //aqui va toda la lógica que necesitamos hacer
     }
   }
 }

Como se puede apreciar estamos usando la función SP.Security.RunWithElevatedPriveleges, esto normalmente nos permite ejecutar código con el nivel más alto.
Despúes de investigar, leer acerca de permisos en sharepoint, de particularidades de event receiver, encontré un solo artículo que me ayudó.

Para solucionar el problema era necesario escribir el código de la siguiente manera.

private void processItemDeleting(SPItemEventProperties properties) {
 base.DisableEventFiring();
 SPSecurity.RunWithElevatedPrivileges(delegate(){
 using (SPSite site = new SPSite(properties.SiteId)) { 
 using (SPWeb web = site.OpenWeb("cla")) {
 using (SPWeb web2 = web.Webs["ProcessCon"]){
 var item = properties.ListItem;
 web.AllowUnsafeUpdates = true; 
       }
      }
     }
   }
}
La diferencia con el primer código que escribimos es que estamos abriendo de nuevo el sitio con el que queremos trabajar. Asi que para evitar el problema de "Acces denied" en un event receiver debemos de abrir de nuevo el sitio, si miramos el primer código de una vez accedemos al web donde estamos con el método de properties.OpenWeb(); pero en el segundo caso tomamos el SiteId que obtenemos en el objeto
SPItemEventProperties y abrimos un nuevo sitio.
La desventaja con esto es que tenemos que abrir la web donde vamos a trabar y si es como mi caso que el url era algo asi, http://server/sites/rootSite/subsite1/subsite2 se debe de hacer de la forma mostrada para acceder al subsite2 porque el método OpenWeb(); no tiene una sobrecarga que nos permita obtener el subsite2 de una forma directa.

Espero que esto les pueda ayudar si tiene un problema parecido o les ayude en su conocimiento del desarrollo en Sharepoint.

Muchas gracias.


domingo, 26 de enero de 2014

El poder de las interfaces Parte 1

Tengo un compañero que siempre dice que las interfaces no sirven para nada;  pero la realidad es de que despúes de investigar un poco sobre que opinan de este tema grandes programadores como Dan Wahlin ó Jeremy Clark, por mencionar algunos, veo que las interfaces son muy poderosas.

De esto se trata esta entrada.
Una de las razones por las que podemos utilizar interfaces además de su uso común es para hacer lo que llaman "Future proof" de nuestro código, podemos entender por "Future Proof" escribir código el cual resista a cambios sin tener que realizar demasiadas modificaciones al código existente, esto claro es más sencillo entenderlo con un ejemplo.
Para este ejemplo creé una solución usando Visual Studio 2012, y el primer proyecto es una aplicación tipo "Windows Forms", ustedes puede usar una aplicación  WPF si desean, la idea es tener un proyecto que solo se encargue de la interfaz de usuario. 
El proyecto es sencillo y solo cuenta con un boton y un ListBox.
A continuación una imagen de la interfaz de usuario.



El siguiente paso para nuestro ejemplo es crear un nuevo proyecto de tipo "Class Library" , despúes de añadirlo  vamos a crear dos Clases, una llamada RepositoryBook y la otra llamada Book.
Aqui lo que vamos a tener es lo siguiente:
RepositoryBook, va a ser nuestra base de datos, solo vamos a crear por el momento un método que devuelva una lista de libros, ya entendieron entonces para que nos va a servir la otra clase que  creamos llamada  Book, miremos el código en esta clase:
 public class Book
    {
        public string bookName { get; set; }
        public int totalPages { get; set; }
        public string publisher { get; set; }

    }// end of class book

Es una clase bastante sencilla, ahora veamos el código de la clase RepositoryBook.

public Book[] getBooks() { 
 return new Book[]
{ new Book{bookName="Amor en los tiempos del colera"},
 new Book{bookName="De que manera te olvido"},
 new Book{bookName="El país de las mujeres"},
 new Book{bookName="El amor es eterno mientras dura"}
 };
 }// end of getBooks

Podemos observar que esta clase tiene un método que devuelve un arreglo de objetos Book, y adentro de esto inicializamos los objetos y los devolvemos, con este método estamos simulando un Retrieve del conocido CRUD (Create,Retrieve,Update,Delete) que son operaciones básicas que se realizan a una base de datos, esto tambien es llamado mantenimientos.

Estas dos clases serían nuetra lógica de negocios, tratando de seguir un patron de separación de conceptos, en los cuales nuestra interfaz no tendría que saber cómo esta implementado todo esto. Ahora vamos a analizar el código en el boton de nuestra aplicación.
public partial class Form1 : Form {
 //instancia a nuestro hard coded repository 
 repositoryBook repository = new repositoryBook();
 public Form1() {
 InitializeComponent();
 }
 private void btnGetBooks_Click(object sender, EventArgs e) { 
 /***Ejemplo usando una clase concreta***/ 
Book[] books;
books = repository.getBooks();
foreach (Book book in books)
{
  lbData.Items.Add(book.bookName);
}
 }
 }
Aqui instanciamos una objeto de tipo repositoryBook en el cuerpo del Form, propiamente en el evento Click del botón creamos un arreglo de libro Book[] books  y le asignamos el valor que nos devuelve el método getBooks, despúes usando un foreach recorrermos el arreglo e imprimimos la propiedad bookName. 

Que quiero decir que las interfaces sirven para el concepto de "Future proof", en un ambiente laboral comúnmente nos asignan a trabajar en una parte específica de una aplicación, rara vez nos da una aplicación  para que nosotros la desarrollemos de principio a fin, esto solía darse mucho antes cuando el tipo de metodología de desarrollo era cascada pero ahora con la adopción de prácticas como XP (Extreme programming)  equipos se encargan de la intefaz de usuario, otro equipo de la lógica  de negocios y otros equipos de probar la aplicación.
Si analizamos nuestro método getBooks  solo nos devuelve un grupo de libros el cual se recorre y se imprime, que pasaría si el equipo que desarrolla la lógica de negocios decide que ya no se va a devolver más un arreglo de libros y cambian el código para que devuelve una lista de libros.
Ahora el método de nuestro repositoryBook sería el siguiente.
public List<Book> getBooks() {
 return new List{
 new Book{bookName="Amor en los tiempos del colera"},
 new Book{bookName="De que manera te olvido"},
 new Book{bookName="El país de las mujeres"}, 
 new Book{bookName="El amor es eterno mientras dura"}
 }; 
 }// end of getBooks

Simplemente cambiamos el tipo de retorno del método pero seguimos retornando objetos tipo Book.
Si miramos la interfaz de usuario despúes de este cambio vamos a notar que algo no anda bien.

Visual Studio nos indica que hay un error debido a que estamos asignando una lista de objetos tipo Book a un arreglo de objetos tipo Book y esto no es posible, Implicitamente no se puede dar esta conversión.
Ahora, donde entra aqui el "Future Proof", nosotros podríamos desarrollar código el cúal no le importe la implementación de este método siempre y cuando cumpla con algún  tipo de contrato, sí, contrato, lo que se supone que es una interfaz, un contrato.

En este caso específico no vamos a crear una interfaz, pero nos vamos a valer de las interfaces; al fin de cuentas para mostrar los resultados en nuestro control ListBox estamos recorriendo el arreglo de libros y agregando cada uno de los elementos a los items de la lista, aqui lo importante es entender que nuestra interfaz no le interesa saber como es la estructura de los datos que ocupa recorrer, solo que lo ocupa recorrer, no le interesa saber si es una lista genérica, si es un diccionario genérico si es una ArrayList solo le interesa recorrerlo.
Entonces  necesitamos algo que podamos recorrer con un foreach y que lo que sea que este ahi tiene una series de  objetos tipo Book los cuales se van a mostrar en la lista, para esto entonces vamos a decir lo siguiente.
IEnumerable books = repository.getBooks(); 
 foreach (Book item in books) 
 {
 lbData.Items.Add(item.bookName);
 }


Ahora el código compila y todo sirve como antes, volvamos a cambiar la actual lista de objetos tipo Book por el primer arreglo y veamos que pasa.
Nuestro programa no nos informa de ningún tipo de error, nuestra capa de interfaz no sabe la estructura que tiene nuestros datos, lo único que sabe es que puede recorrerla mediante un foreach y accesar a las propiedades del objeto tipo Book, asi sea un arreglo, una lista generica, un arrayList.
Podemos ver como fácilmente podemos cambiar la estructura de nuestros datos y la interfaz no sufre ningún problema, aqui estamos programando contra un tipo abstracto, IEnumerable, esto nos da la sensación de trabajar como un tipo de pluggins, podemos agregar otro método que nos devuelva datos y los procese como sea, solo se necesita que implemente la interfaz Ienumerable y podemos cambiar de un método a otro sin afectar nuestra interfaz.

Espero que les guste la entrada, este es un tema extenso y estaré escribiendo otra entrada sobre la idea
"Programar contra una abstracción y no un tipo concreto", "Program to an abstraction rather than a concrete type"




sábado, 14 de diciembre de 2013

Post- build events command line in Visual Studio 2012

Vengo con esta breve entrada y espero que les sea útil.

Si se elige las propiedades del projecto se puede ver las opciones de "Post-build events command line".
Propiedades de Projecto.

Se nos presentan dos opciones, "Pre-build events command line" y "Post-build events command line"
Para nuestro efecto vamos a utilizar la segunda opción,  es una de las primeras veces que investigo esta
opción entonces el ejemplo es bastante sencillo.
Podemos ver también que hay un drop down donde podemos escojer cuando queremos que estos 
eventos ocurran, las opciones que se nos proporcionan son:
  1. Always
  2. On successful build
  3. When the build updates the project output
He escojido "On successful build", en el  área en blanco he escrito lo siguiente.
"call C:\Users\Franklin\Desktop\TestBatch.bat", esto quiere decir que despúes de que exitosamente 
tengamos un build entonces se va a llamar a ese batch file. Lo que he escrito en el batch file es lo siguiente
"start iexplore www.google.com" que lo que va a hacer es abrir  el internet explorer y navegar hasta a la 
dirección que se ha específicado.
Esto nos abre una ventana de posibilidades como copiar .dll en un lugar específico o como cambiar algunas
propiedades.
Ahora no queda mas que dar click derecho sobre el project y oprimir RUN ó presionar F6.

Esto sería todo por el momento y tan pronto como sepa como manejar mejor esto estaré actualizando el post.
Muchas gracias.