Administración de Implementaciones Sharepoint 2007 – Sharepoint Manager 2007

Quiero compartir con ustedes otra herramienta muy interesante que podemos usar para la administración de nuestras implementaciones Sharepoint. La misma fue creada por “Carsten Keutmann” y podrán acceder a la página para ver más sobre ella.
Con esta herramienta podemos navegar por toda la implementación de Sharepoint instalada, como pueden ver en la imagen 1, la herramienta nos brinda una vista completa de todos los servidores que están en la granja, los servicios que están corriendo, las sitio que tenemos creados y un montón de cosas adicionales.

[Imagen 1]
1_SpManager

En la siguiente imagen, imagen 2, vemos él árbol de propiedades y servicios expandidos donde vemos las distintas aplicaciones y propiedades que podes ver.

[Imagen 2]
2_SpManager

Vale la pena destacar que la aplicación está disponible en dos idiomas, español e ingles, lo que nos permite trabajar cómodamente con la aplicación, en la imagen 3 podemos ver como se puede cambiar el idioma en la aplicación.

[Imagen 3]
3_SpManager

También vale la pena destacar que muchas de las propiedades que podemos acceder utilizando esta herramienta, se pueden modificar, pero como dice “Carsten Keutmann” bajo su propia responsabilidad dado que podríamos estar modificando algunas propiedades que pueden afectar el correcto funcionamiento de nuestra implementación o sitio de Sharepoint.

Herramienta para planificar sitios Sharepoint 2007 y Wss 3.0

Haciendo investigación en internet en uno de esos tantos días que investigo la tecnología, me encontré con “System Center Capacity Planer 2007” la cual nos permite realizar una planificación para la implantación de nuestros sitios Microsoft Office Sharepoint Server 2007 y Windows Sharepoint Servicies 3.0. En el sitio de la herramienta vamos a encontrar el link para descargarla y además vamos a encontrar los complementos necesarios para realizar la planificación de nuestros portales.

Una vez instalada, accederemos a la pantalla de bienvenida de la misma, donde se nos preguntara que queremos hacer, si vamos a empezar a crear un plan para un sitio o vamos a modificar la lista de hardware que la herramienta trae por defecto. Como se puede apreciar en la imagen 1, la interfaz grafica es muy amigable y es 100% navegable a través de la barra de herramienta que poses. Los asistentes de configuración son muy intuitivos y fáciles de usar.

[Imagen 1]
1_Pantalla_Inicial

En la imagen 2 vemos como podemos configurar el hardware que queremos manejar, este hardware será utilizado para la panificación de los servidores que iremos colocando a lo largo de nuestra planificación.

[Imagen 2]
2_HardWare

Lo que deberíamos hacer ahora es iniciar un proyecto de planificación, en la página inicial de la herramienta seleccionamos del DropDownList que se encuentra bajo la sección “Capacity Models” Microsoft Office Sharepoint Server 2007 y presionamos sobre el link de crear nuevo modelo. En la imagen 3 vemos como iniciamos una nueva configuración y también tenemos la posibilidad de cargar una existente.

[Imagen 3]
3_Nueva_Planificacion

En la primera pantalla del proceso de creación del plan debemos establecer cómo se llamara la granja para MOSS y como estará compuesta la misma. Debemos indicar que tipos de usuarios estarán accediendo a la misma, la zona en la cual estará trabajando y algunos datos adicionales. Solo se nos permite ingresar una granja, a lo cual una vez que presionamos el botón “Add Sharepoint (MOSS) Farm” que se encuentra en la parte superior de la pantalla este se deshabilitara. En imagen 4 vemos como quedaría configurada la granja, una vez cargado todos los valores presionamos el botón “OK” para guarda la configuración y después el botón “Next” para pasar al próximo paso.

[Imagen 4]

4_Farm

En el paso siguiente deberíamos cargar las distintas oficinas (departamentos) que estarán accediendo a nuestra granja, pueden ser las oficinas centrales, que acceden a través de la LAN o oficinas distribuidas que acceden a través de la Wan (Internet) a nuestros servidor Sharepoint. Para agregar una nueva, presionamos “Add Branch Office Profile” que se encuentra en la parte superior de este paso y cargamos los parámetros necesarios para la misma. En la imagen 5 vemos como quedaría cargadas nuevas oficinas en nuestra configuración. Una vez cargadas todas las dependencias, presionamos el botón “Next” para pasar al siguiente paso.

[Imagen 5]
5_Office

En este paso debemos configurar como será la configuración de red entre nuestras oficinas anteriormente creadas y el servidor de Sharepoint. Nota: Vale la pena destacar que los valores y configuraciones de Hardware que se utilizaran en este artículo son a modo de ejemplo y se deberán utilizar los valores correspondientes para la implementación que tengamos que llevar a cabo. En la imagen 6 vemos como quedaría supuestamente configurada la conectividad y la red para nuestra configuración. Una vez cargadas la topología de la red, presionamos el botón “Next” para pasar al siguiente paso.

[Imagen 6]
6_Red

En el próximo paso vamos a establecer la configuración del hardware para nuestros servidores, en lo que respecta a procesadores y almacenamiento de discos duros. Una vez terminada la planificación muchos de estos valores se pueden cambiar, como así también la configuración de la memoria Ram. Los valores para los DropDownList que se muestran en esta pantalla son los cargados en la sección de “Hardware” que vimos en la pantalla inicial de la herramienta. En la imagen 7 vemos una posible configuración de las tantas que podemos realizar. Una vez cargada la configuración del hardware que estaríamos usando, presionamos el botón “Next” para pasar al siguiente paso.

[Imagen 7]
7_Hardware_Server

El próximo paso debemos contestar dos preguntas que se nos hacen con respecto a la disponibilidad y el espacio en disco que se debe utilizar para las bases de contenido. Esto dependerá del tipo de sitio que tengamos que construir y de la cantidad de usuarios que tenemos relevado que estarán accediendo a Sharepoint, en mi caso para este ejemplo deje los valores por defecto. En la imagen 8 podemos ver los valores cargados. Una vez contestadas las preguntas, presionamos el botón “Next” para pasar al siguiente paso.

[Imagen 8]
8_Performance_Applicacion

El próximo paso se nos presentará un informe del modelo que acabamos de crear, con todos los detalles cargados y los distintos servidores que componen nuestra granja. En la imagen 9 podemos ver el informe creado y si necesitamos cambiar alguna configuración simplemente retrocedemos hasta el paso correspondiente.

[Imagen 9]
9_Informe

Una vez que verificamos el los datos cargados, presionamos el botón “Finish” para que se nos presente un dibujo del modelo que acabamos de configurar. En la imagen 10 vemos el modelo creado por la herramienta para este ejemplo.

[Imagen 10]
10_Modelo

Podemos editar cualquiera de los elementos del dibujo o podemos acceder al detalle de cada uno para ver como se compone el mismo. En la imagen 11 vemos el detalle completo de “Moss Siderys” y como se componen la arquitectura del mismo. Simplemente debemos marcar el objeto que deseamos, presionamos botón derecho para que se nos muestre el menú contextual y seleccionamos la opción. También podemos acceder al detalle de cada uno usando el menú lateral izquierdo y con el menú lateral derecho podemos agregar nuevos objetos y componentes a este modelo para ir ajustándolo más a la realidad que estamos armando si bien la misma cambia.

[Imagen 11]
11_Modelo_Moss

Una vez que tenemos todos configurado, podemos correr una simulación de la planificación que acabamos de hacer, la misma nos arrojara informes sobre utilización de CPU de los distintos servidores, conectividad, almacenamiento, etc. En la imagen 12 vemos el resultado obtenido para la simulación realizada para este ejemplo.

[Imagen 12]
12_Informe_Simulacion

Existen muchas otras opciones de configuración que nos permiten alterar la planificación que estamos haciendo para instalar nuestra aplicación MOSS o Wss. Incluso una vez que tenemos el modelo creado, podemos seguir extendiéndolo y agregando distintos objetos o cambiando los existentes y corriendo la simulación hasta lograr la implantación que mejor se asemeja a la realidad que estamos modelando.

En próximos artículos les estaré mostrando otras herramientas que hemos estado utilizando para llevar a cabo distintas tareas en los proyectos que hemos estado involucrados.

Small Bdc for Wss – Campos de Lista desde Base Datos

Hace tiempo que me estaba dando vuelta esta idea en la cabeza, la había empezado a codificar, pero por razones de tiempo la tuve que abandonar. En el día de ayer la retome y termine de implementar. La idea había surgido para un proyecto, que después no se llevo a cabo por diferentes motivos y a mí la idea me había gustado, dado que tener la posibilidad de cargar una columna de una lista con datos de una base de datos en Windows Sharepoint Services 3.0 me seducía mucho ya que esta funcionalidad (mucho más robusta y escalable) viene con la versión de MOSS 2007.

La vez pasada habíamos publicado un artículo sobre tener Campos Únicos en una lista de Sharepoint, nos permitía controlar que los datos que cargaba el usuario fueran diferentes entre sí. Basándonos en ese mismo artículo “Valores únicos en una lista” lo que hicimos acá fue llenar campos de una lista desde una base de datos. Para darle un poco más de aplicabilidad, no nos concentramos en solo un motor de Base de Datos, como podría haber sido SQL Server, si no que usamos OLEDB para realizar la conexión con la base y ejecución de la consulta. Como se trata de un campo de una lista, y lo que se busca es cargar el valor de la lista con registros almacenados en una base de datos, lo que hicimos fue simplemente contemplar la primera columna que se devuelve en el origen de datos, es decir que si se carga una consulta compleja como ser “Select * from tabla o Select Campo1, Campo2 from tabla” solo se tendrá en cuenta la primera columna del schema que devuelva la ejecución de la consulta.

Vale la pena realizar una aclaración antes de meternos de lleno al código, cuando estaba realizando la codificación del tipo de campo, me tope con un problema en la secuencia de cómo WSS y Sharepoint manejan el guardado de los valores del campo, la primera vez (cuando e crea) y cuando se modifica el mismo. Por eso, realizando un searching en google me tope con este artículo “Custom Field Type Properties” que explica que es lo que sucede y nos da una solución alternativa para salir del paso, la cual aplique con éxito. Cuando se dispara el método OnAdded del campo que estamos creando la instancia del campo que se nos pasa es diferente a la que teníamos en determinado momento (cuando lo estábamos configurando) y los valores de las custom properties utilizadas para almacenar la cadena de conexión y consulta select se pierden, es por ello que tuvimos que utilizar un Diccionario (Dictionary) estático y almacenar los valores de forma provisoría, para que cuando se dispara el método OnAdded tuviéramos los valores para guardarlos en nuestras custom properties correspondientes.

Hecha esta aclaración, lo que vamos hacer en primer lugar es crearnos un proyecto de Sharepoint vacio, podríamos utilizar un proyecto de biblioteca de clases, de no tener instalado la extensiones de WSS para visual studio 2005, sigo trabajando con visual studio 2005, pero próximamente me estaré migrando a visual studio 2008 dado que me estoy armando una maquina virtual con todo el ambiente, Windows 2008, Sql Server, Sharepoint con SP1 y visual studio 2008.

Una vez tenemos el proyecto creado vamos a configurar el mismo, lo que vamos hacer es editar las propiedades y colar un nombre para el Assembly que se va a generar, un espacio de nombre por defecto para todas las clases que se creen y vamos a firmar el mismo utilizando un arhivo .snk, en mi caso este archivo se llama “Siderys.snk”

Una vez configurado el proyecto, lo primero que vamos agregar al mismo es el archivo Xml que define a nuestro tipo de campo. En este archivo que lo llamaremos “fldtypes_BdcWss.xml” indicaremos cual es el nombre, descripción, la clase que lo implemente, el Assembly que contiene esa clase, el tipo de campo base que vamos a estar utilizando y algunas propiedades más que se pueden ver en la sección 1. También crearemos dos propiedades personalizadas, ocultas, que serán las que van almacenar la cadena de conexión con la base de datos y la consulta que vamos a estar ejecutando.

[Sección 1]

<FieldTypes>
    <FieldType>
        <Field Name="TypeName">BdcWss</Field>
        <Field Name="TypeDisplayName">Bdc Wss</Field>
        <Field Name="TypeShortDescription">Bdc Wss</Field>
        <Field Name="ParentType">Choice</Field>
        <Field Name="FieldTypeClass">Siderys.Blog.CustomField.BdcWss, Siderys.Blog.CustomField.BdcWss, 
Version=1.0.0.0, Culture=neutral, PublicKeyToken=711eed342842acee</Field> <field name="UserCreatable">TRUE</field> <Field Name="Sortable">TRUE</Field> <Field Name="Filterable">TRUE</Field> <Field Name="FieldEditorUserControl">/_controltemplates/BdcWssEditFieldType.ascx</Field> <PropertySchema> <Fields> <Field ID="StringConnection" Hidden="TRUE" Name="StringConnection"
DisplayName="StringConnection" Type="Text" ></Field> <Field ID="StringSelect" Hidden="TRUE" Name="StringSelect"
DisplayName="StringSelect" Type="Text" ></Field> </Fields> </PropertySchema> </FieldType> </FieldTypes>

Una vez el archivo Xml está creado, lo próximo que vamos hacer es crear el primer control de usuario. Este control de usuario es el que se utilizara cuando estemos creando un nuevo elemento en la lista y nos desplegara un DrodDownList con los datos cargados para que el usuario seleccione uno de los valores recogidos de la base de datos. En la sección 2 vemos el código de nuestro ASCX llamado “BdcWssFieldType.ascx” y en la sección 3 vemos el código fuente de la clase que implementa la lógica del control.

[Sección 2]

<%@ Control Language="C#"%>
<%@Assembly Name="Siderys.Blog.CustomField.BdcWss, Version=1.0.0.0, Culture=neutral, 
PublicKeyToken=711eed342842acee" %>
<%@Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=12.0.0.0,
Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.WebControls"%>
<SharePoint:RenderingTemplate ID="BdcWss" runat="server"> <Template> <asp:DropDownList ID="ddlResultSelect" runat="server"> </asp:DropDownList> </Template> </SharePoint:RenderingTemplate>

[Sección 3]

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Data.OleDb;

/// <summary>
/// Summary description for BdcWssFieldType
/// </summary>
namespace Siderys.Blog.CustomField
{
    public class BdcWssFieldType : BaseFieldControl
    {
        protected DropDownList ddlResultSelect;
        private OleDbConnection mConnection = null;
        private OleDbCommand mCommand = null;
        private OleDbDataReader mReader = null;

        public BdcWssFieldType()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        protected override string DefaultTemplateName
        {
            get
            {
                return "BdcWss";
            }
        }

        public override object Value
        {
            get
            {
                return ddlResultSelect.SelectedItem.Text;
            }

            set
            {
                EnsureChildControls();
                ddlResultSelect.Items.FindByText(value.ToString()).Selected = true;
            }
        }

        public override void Focus()
        {
            EnsureChildControls();
            ddlResultSelect.Focus();
        }

        private void FillDropDownListFromDataBase()
        {
            try
            {
                //obtengo los valores para la conexion y la consulta almacenados en las propiedades del campo.
                string lConnectionString = this.Field.GetCustomProperty("StringConnection").ToString();
                string lSelectString = this.Field.GetCustomProperty("StringSelect").ToString();

                mConnection = new OleDbConnection(lConnectionString);
                mConnection.Open();
                mCommand = new OleDbCommand(lSelectString, mConnection);
                mReader = mCommand.ExecuteReader();
                ddlResultSelect.Items.Clear();
                while (mReader.Read())
                {
                    ddlResultSelect.Items.Add(new ListItem(mReader.GetString(0)));
                }               
            }
            catch (OleDbException ex)
            {
                throw ex;
            }
            finally
            {
                mReader.Close();
                mConnection.Close();
            }
        }

        protected override void CreateChildControls()
        {
            if (this.Field == null) return;
            base.CreateChildControls();
            if (this.ControlMode == Microsoft.SharePoint.WebControls.SPControlMode.Display)
                return;
            ddlResultSelect = (DropDownList)(TemplateContainer.FindControl("ddlResultSelect"));
            if (ddlResultSelect == null)
            {
                throw new ArgumentException("DropDowList es nulo.......");
            }

            if (!Page.IsPostBack)
            {
                try
                {
                    FillDropDownListFromDataBase();
                }
                catch (Exception ex)
                {
                    ddlResultSelect.Items.Add(ex.Message);
                }
            }
        }
    }
}

Lo próximo que vamos a realizar es un control de usuario que será utilizado cuando estemos creando el campo en la lista y nos permitirá ingresar la cadena de conexión a la base de datos y probar la misma. También nos permitirá ingresar la consulta que queremos ejecutar y probarla, donde se cargara un DropDownList de ejemplo con los datos sacados de la base de datos. En la sección 4 vemos el código del control ASCX llamado “BdcWssEditFieldType.ascx” y en la sección 5 vemos el código fuente de la clase que implementa la lógica del control de usuario.

[Sección 4]

<%@ Control Language="C#" AutoEventWireup="false" Inherits="Siderys.Blog.CustomField.BdcWssEditFieldType, 
Siderys.Blog.CustomField.BdcWss, Version=1.0.0.0, Culture=neutral, PublicKeyToken=711eed342842acee" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormControl" Src="~/_controltemplates/InputFormControl.ascx" %> <%@ Register TagPrefix="wssuc" TagName="InputFormSection" Src="~/_controltemplates/InputFormSection.ascx" %> <%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint,
Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Import Namespace="Microsoft.SharePoint" %> <wssuc:InputFormSection runat="server" id="BdcSection" Title="Bdc - Configuracion Base de Datos"> <template_inputformcontrols> <wssuc:InputFormControl runat="server" LabelText="Ingrese una cadena de conexion y una consulta select."> <Template_Control> <table> <tr class="ms-authoringcontrols"> <td> <asp:Label ID="lblConnectionString" runat="server" Text="Connection String">
</
asp:Label> </td> </tr> <tr> <td> <asp:TextBox ID="txtConnectionString" runat="server" TextMode="MultiLine"
Rows="5" Columns="40"></asp:TextBox> </td> </tr> <tr> <td> <asp:Button ID="cmdTestConnection" runat="Server" Text="Test Connection" /> </td> </tr> <tr> <td> <asp:Label ID="lblTestConnection" runat="server" ForeColor="Red"></asp:Label> </td> </tr> <tr class="ms-authoringcontrols"> <td> <asp:Label ID="lblSelect" runat="server" Text="Select Command"></asp:Label> </td> </tr> <tr> <td> <asp:TextBox ID="txtSelect" runat="server" TextMode="MultiLine" Rows="5"
Columns="40"></asp:TextBox> </td> </tr> <tr> <td> <asp:Button ID="cmdTestSelect" runat="Server" Text="Test Select" /> </td> </tr> <tr> <td> <asp:Label ID="lblTestSelect" runat="server" ForeColor="Red"></asp:Label> </td> </tr> <tr> <td> <asp:DropDownList ID="ddlSelectResult" runat="server" Visible=false> </asp:DropDownList> </td> </tr> </table> </Template_Control> </wssuc:InputFormControl> </template_inputformcontrols> </wssuc:InputFormSection>

[Sección 5]

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Data.OleDb;

/// <summary>
/// Summary description for BdcWssEditFieldType
/// </summary>
namespace Siderys.Blog.CustomField
{
    public class BdcWssEditFieldType : UserControl, IFieldEditor
    {
        protected TextBox txtConnectionString = null;
        protected Button cmdTestConnection = null;
        protected Label lblTestConnection = null;
        protected TextBox txtSelect = null;
        protected Button cmdTestSelect = null;
        protected Label lblTestSelect = null;
        protected DropDownList ddlSelectResult = null;
        private OleDbConnection mConnection = null;
        private OleDbCommand mCommand = null;
        private OleDbDataReader mReader = null;

        public BdcWssEditFieldType()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            //agrego el metodo para manejar el evento click
            this.cmdTestConnection.Click += new EventHandler(cmdTestConnection_Click);
            //agrego el metodo para manejar el evento click
            this.cmdTestSelect.Click += new EventHandler(cmdTestSelect_Click);
        }

        #region IFieldEditor Members

        public bool DisplayAsNewSection
        {
            get
            {
                return true;
            }
        }

        public void InitializeWithField(SPField field)
        {
            BdcWss lBdc = (BdcWss)field;
            if (lBdc != null)
            {
                EnsureChildControls();
                string lStringConnection = lBdc.GetCustomProperty("StringConnection").ToString();
                string lStringSelect = lBdc.GetCustomProperty("StringSelect").ToString();

                txtConnectionString.Text = lStringConnection;
                txtSelect.Text = lStringSelect;
            }
        }

        public void OnSaveChange(SPField field, bool isNewField)
        {
            BdcWss lBdcWss = (BdcWss)field;
            if (isNewField)
            {
                lBdcWss.UpdateConnectionStringProperty(this.txtConnectionString.Text);
                lBdcWss.UpdateSelectStringProperty(this.txtSelect.Text);
            }
            else
            {
                //Almaceno la cadena de conexion.
                lBdcWss.ConeectionString = this.txtConnectionString.Text;
                //Almaceno la consulta Select.
                lBdcWss.SelectString = this.txtSelect.Text;
            }
        }

        #endregion

        protected void cmdTestConnection_Click(object sender, EventArgs e)
        {
            try
            {
                mConnection = new OleDbConnection(this.txtConnectionString.Text);
                mConnection.Open();
                lblTestConnection.Text = "Se conecto correctamente";
            }
            catch (OleDbException ex)
            {
                lblTestConnection.Text = ex.Message;
            }
            finally
            {
                mConnection.Close();
            }
        }

        protected void cmdTestSelect_Click(object sender, EventArgs e)
        {
            try
            {
                mConnection = new OleDbConnection(this.txtConnectionString.Text);
                mConnection.Open();
                mCommand = new OleDbCommand(this.txtSelect.Text, mConnection);
                mReader = mCommand.ExecuteReader();
                ddlSelectResult.Visible = true;
                ddlSelectResult.Items.Clear();
                while (mReader.Read())
                {
                    ddlSelectResult.Items.Add(new ListItem(mReader.GetString(0)));
                }
                lblTestSelect.Text = "Se ejecuto correctamente";
            }
            catch (OleDbException ex)
            {
                lblTestSelect.Text = ex.Message;
            }
            finally
            {
                mReader.Close();
                mConnection.Close();
            }
        }
    }
}

Por último nos queda implementar la clase que representara a nuestro tipo de campo, esta clase extiende de “SPFieldText” como ya comentamos en el artículo anterior y dado que lo que vamos a guardar es un dato simple, seleccionado por el usuario no necesitamos implementar ningún otro tipo de campo más complejo. En la sección 6 vemos el código de la clase llamada “BdcWss”.

[Sección 6]

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;

namespace Siderys.Blog.CustomField
{
    public class BdcWss : SPFieldText
    {
        private string mConnectonString = string.Empty;
        private string mSelectString = string.Empty;

        private static Dictionary<int, string> mDicConnectionStriong = new Dictionary<int, string>();
        private static Dictionary<int, string> mDicSelectString = new Dictionary<int, string>();

        public BdcWss(SPFieldCollection pFields, string pFieldName)
            : base(pFields, pFieldName)
        {
            
        }

        public BdcWss(SPFieldCollection pFields, string pTypeName, string pDisplayName)
            : base(pFields, pTypeName, pDisplayName)
        {
            
        }

        public void Init()
        {
            mConnectonString = this.GetCustomProperty("StringConnection").ToString();
            mSelectString = this.GetCustomProperty("StringSelect").ToString();
        }

        private int GetContextId
        {
            get
            {
                return SPContext.Current.GetHashCode();
            }
        }
        public string ConeectionString
        {
            get
            {
                return mDicConnectionStriong.ContainsKey(GetContextId) ? mDicConnectionStriong[GetContextId] : mConnectonString;
            }
            set
            {
                mConnectonString = value;
            }
        }

        public string SelectString
        {
            get
            {
                return mDicSelectString.ContainsKey(GetContextId) ? mDicSelectString[GetContextId] : mSelectString;
            }
            set
            {
                mSelectString = value;
            }
        }

        public void UpdateConnectionStringProperty(string pValue)
        {
            mDicConnectionStriong[GetContextId] = pValue;
        }

        public void UpdateSelectStringProperty(string pValue)
        {
            mDicSelectString[GetContextId] = pValue;
        }

        public override void OnAdded(SPAddFieldOptions op)
        {
            base.OnAdded(op);
            Update();
        }

        public override void Update()
        {
            this.SetCustomProperty("StringConnection", ConeectionString);
            this.SetCustomProperty("StringSelect", SelectString);
            base.Update();
            if (mDicConnectionStriong.ContainsKey(GetContextId))
            {
                mDicConnectionStriong.Remove(GetContextId);
            }
            if (mDicSelectString.ContainsKey(GetContextId))
            {
                mDicSelectString.Remove(GetContextId);
            }
        }

        public override Microsoft.SharePoint.WebControls.BaseFieldControl FieldRenderingControl
        {
            get
            {
                Microsoft.SharePoint.WebControls.BaseFieldControl BdcWssControl = new BdcWssFieldType();
                BdcWssControl.FieldName = InternalName;
                return BdcWssControl;
            }
        }
    
    }
}

Una vez implementado, lo que nos resta es compilarlo e instalar todo en nuestro servidor de Sharepoint 2007, para lo cual en mi caso me cree un archivo .Bat para instalar todo. El Assembly lo debemos colocar en la GAC y los demás archivos debemos colocarlo en la carpeta “CONTROLTEMPLATES” donde está instalado Sharepoint. En la sección 7 podemos ver el código del archivo .bat creado para ejecutar la instalación.

[Sección 7]

iisreset /stop
"%programfiles%Microsoft Visual Studio 8SDKv2.0Bingacutil.exe" -uf Siderys.Blog.CustomField.BdcWss
"%programfiles%Microsoft Visual Studio 8SDKv2.0Bingacutil.exe" 
-if binDebugSiderys.Blog.CustomField.BdcWss.dll copy /y fldtypes_BdcWss.xml "%CommonProgramFiles%Microsoft Sharedweb server extensions12TEMPLATEXML" xcopy /s /Y BdcWssFieldType.ascx "%CommonProgramFiles%Microsoft Sharedweb server
extensions12TEMPLATECONTROLTEMPLATES" xcopy /s /Y BdcWssEditFieldType.ascx "%CommonProgramFiles%Microsoft Sharedweb server
extensions12TEMPLATECONTROLTEMPLATES" iisreset /start pause

Bien una vez instalado todo, lo que nos resta es probar nuestro nuevo tipo de columna. Para testearla me voy a conectar a una base de datos creada en SQL Server 2005, con una tabla llamada productos, en la imagen 1 podemos ver dicha tabla cargada con datos de pruebas.

[Imagen 1]

1_TablaProductos

Lo que debemos hacer ahora es ir a una lista de Sharepoint y acceder a la configuración de la misma. Una vez en la sección de configuración lo que vamos hacer es crear una nueva columna en la misma, para ello seleccionamos el link “Crear Columna” . Una vez en dicha página lo que vamos hacer es colocar un nombre a esta nueva columna, en mi caso la llame “Productos”, en la imagen 2 vemos la pantalla para crear una nueva columna en la lista y en la lista de campos disponibles vemos nuestra nueva columna, cargamos el nombre y seleccionamos dicho tipo de campo.

[Imagen 2]

2_Configuracion_Columna_1

Una vez que seleccionamos el tipo de campo que queremos, la página se vuelve a cargar y nos muestra la sección codificada por nosotros en el control de usuario “BdcWssEditFieldType.ascx” donde vamos a carga la cadena de conexión y la consulta que queremos ejecutar. La imagen 3 nos muestra estos campos cargados y probados y lo próximo que debemos realizar es guardar nuestra nueva columna, para lo cual vamos a presionar el botón “Aceptar” de la página.

[Imagen 3]

3_Configuracion_Columna_2

Una vez guarda la nueva columna en la lista, lo próximo que debemos de realizar es crear un nuevo elemento en la misma y seleccionar un valor del DropDownList correspondiente. En la imagen 4 vemos el formulario para dar de altas nuevos elementos en la lista, con la nueva columna cargada.

[Imagen 4]

4_Nuevo_Elemnto_Lista

Una vez cargados los valores del nuevo elemento, presionamos el botón “Aceptar” para guardar los mismos en la lista. En la imagen 5 vemos la página de todos los elementos de la lista y en nuevo valor ingresado en la misma.

[Imagen 5]

5_Elemento_Vista_All

También quiero destacar que el comportamiento del nuevo campo es similar a todos los campos en una lista de Sharepoint, es decir que podemos editar la configuración y modificar en cualquier momento los valores de conexión y la consulta que estamos ejecutando. Como también podemos editar cualquier elemento creado y cambiar el valor almacenado en la lista por cualquier otro valor de la base de datos. En la imagen 6 vemos la edición del elemento recientemente creado y el nuevo valor seleccionado.

[Imagen 6]

6_Valor_Modificado

Espero que este artículo les sea de utilidad, en lo que respecta al uso que le podemos dar, creo que podemos tener valores en nuestras listas desde un origen de datos y sobre WSS 3.0 principalmente y también lo podemos utilizar en Sharepoint 2007 si no queremos configurar la característica BDC que este nos brinda. De todas formas vale la pena aclarar nuevamente que esto no intenta ser un sustituto de esa gran característica que nos provee MOSS, si no una versión de un tipo de campo que nos permite mostrar datos desde una base de datos.

Les pido disculpas por lo extenso de este artículo, pero hacerlo de una forma más corta hubiera implicado tener que dejar cosas afuera.

Aquí puede descargar el código fuente de este articulo.

Controles de Usuario (ASCX) en Sharepoint 2007 – SmartPart

Se que hace muy difícil a veces el desarrollo de formularios o WebParts para representar lo que tenemos que hacer. Por eso, en nuestros desarrollos usamos muchas veces controles de usuario en Sharepoint y los cargamos con una WebPart hecha por nosotros. Pero hace tiempo que venimos usando SmartPart para Sharepoint, que nos permite cargar cualquier control de usuario realizado en Sharepoint, sin tener la necesidad de tener que crear una WebPart, simplemente instalamos esta característica y desarrollamos los controles de usuarios y los instalamos en el servidor. La instalación se puede llevar a cabo con código fuente, colocando la clase en la misma carpeta o mediante un Assembly que puede estar en el directorio de ejecución o en la GAC.

Es un proyecto de CodePlex que me pareció muy bueno y simplifica mucho el desarrollo sobre Sharepoint. Los aliento a utilizarlo y verán como es de mucha utilidad.

Muchas gracias a todos los que participan en el desarrollo de este tipo de herramientas ya que su colaboración es enorme.