Miguel Isidoro

Blog sobre .NET, Sharepoint e tecnologia em geral.

My Links

Archives

Post Categories

Login

Blog Stats

Blogs Portugueses

Blogs Sharepoint

Saturday, July 12, 2008 #

SharePoint 2007 - New instances of this workflow template are currently disallowed

When creating a new custom workflow project using Visual Studio 2008, a strong key file (.snk) file is automatically included in the project to sign the workflow assembly. A few days ago, I started developing a SharePoint 2007 Sequential Workflow project. After finishing developing the workflow, I deployed it and started testing it by associating the workflow to a content type (Site Settings > Site Content Type Gallery > Site Content Type > Workflow settings). I then noticed that the strong key file that was being used to sign the workflow assembly wasn't the one I usually use and modified the project settings so that it started using it. After recompiling the project and redeploying the workflow, I started to get an error message: "New instances of this workflow template are currently disallowed". The reason for this message to appear is that a new version version of the workflow had been deployed (same assembly with a different public key token due to the change in the strong key file used to sign the assembly). In these situations, the existing workflow associations made from older versions of the workflow are automatically set to "No New Instances", meaning that new instances of the workflow for those workflow associations are not allowed. The image below shows the Remove Workflow page with my custom workflow association set to "No New Instances". To access this page, go to Site Settings > Site Content Type Gallery > Site Content Type > Workflow settings > Remove Workflows if the workflow is associated with a content type.

To solve the problem, all you have to do is to set the workflow association to "Allow" and new instances of the workflow can again be created.

posted @ 11:29 AM | Feedback (0)

Saturday, July 05, 2008 #

SharePoint 2007 - Start a Workflow Programmatically

Introduction

This blog post will show you how to start a workflow programmatically every time an item is updated in a SharePoint list. For those who don’t know, Windows Workflow Foundation (WF) is the new engine for building custom workflows (you can find more information about WF on the official web site). It was released as part of the .NET Framework 3.0 along with Windows Presentation Foundation (WPF) and Windows Communication Foundation (WCF). In the SharePoint world, workflows can be associated both to a list and to a content type. Both options are valid and the choice for one or the other option depends on your needs:

  • If you want to run a workflow in a list, independently of the content type of each list item, you should associate the workflow to a list. If you have more than one content type associated to the list, care should be taken in the workflow implementation since each content type can have different columns that may not be present in the other content types;
  • If you want to run the workflow on all items of a specific content type, you should associate the workflow to a content type. The workflow will be associated to all list items from that content type in all lists across a site or the whole site collection (depending on the scope of the workflow, typically defined in its deployment feature) that are associated with the content type.
Example

The following example shows how both options can be addressed. This example uses an event handler and starts a workflow every time an item is updated in a SharePoint list.

public class ProgrammaticWorkflowInitiationEventReceiver : SPItemEventReceiver
{
    /// <summary>
    /// Event handler for item updated event.
    /// </summary>
    /// <param name="properties"></param>
    public override void ItemUpdated(SPItemEventProperties properties)
    {
        //use this method if the workflow is associated to a list
        StartListWorkflow(properties);

        //use this method if the workflow is associated to a content type
        StartContentTypeWorkflow(properties);
    }

    /// <summary>
    /// Starts a workflow associated to a list programmatically.
    /// </summary>
    /// <param name="properties"></param>
    private void StartListWorkflow(SPItemEventProperties properties)
    {
        //get list item from event handler properties
        SPListItem listItem = properties.ListItem;

        using (SPWeb web = listItem.Web)
        {
            using (SPSite site = web.Site)
            {
                //obtain an instance of SPWorkflowManager 
                //which will be later used to start the workflow
                SPWorkflowManager manager = site.WorkflowManager;
                //get item's parent list
                SPList parentList = listItem.ParentList;
                //get all workflows that are associated with the list
                SPWorkflowAssociationCollection associationCollection = 
                    parentList.WorkflowAssociations;
                //lookup and start the worflow
                LookupAndStartWorkflow(listItem, manager, 
                    associationCollection, "MyListWorkflow");
            }
        }
    }

    /// <summary>
    /// Starts a workflow associated to a content type programmatically.
    /// </summary>
    /// <param name="properties"></param>
    private void StartContentTypeWorkflow(SPItemEventProperties properties)
    {
        //get list item from event handler properties
        SPListItem listItem = properties.ListItem;

        using (SPWeb web = listItem.Web)
        {
            using (SPSite site = web.Site)
            {
                //obtain an instance of SPWorkflowManager 
                //which will be later used to start the workflow
                SPWorkflowManager manager = site.WorkflowManager;
                //get item's content type
                SPContentType contentType = listItem.ContentType;
                //get all workflows that are associated with the content type
                SPWorkflowAssociationCollection associationCollection = 
                    contentType.WorkflowAssociations;
                //lookup and start the worflow
                LookupAndStartWorkflow(listItem, manager, 
                    associationCollection, "MyContentTypeWorkflow");
            }
        }
    }

    /// <summary>
    /// Lookup and start the workflow.
    /// </summary>
    /// <param name="manager"></param>
    /// <param name="associationCollection"></param>
    /// <param name="workflowInstanceName"></param>
    private static void LookupAndStartWorkflow(SPListItem listItem, 
        SPWorkflowManager manager, 
        SPWorkflowAssociationCollection associationCollection, 
        string workflowInstanceName)
    {
        //iterate workflow associations and lookup the workflow to be started
        foreach (SPWorkflowAssociation association in associationCollection)
        {
            //if the workflow association matches the workflow we are looking for,
            //get its association data and start the workflow
            if (association.Name.ToLower().Equals(workflowInstanceName))
            {
                //get workflow association data
                string data = association.AssociationData;

                //start workflow
                SPWorkflow wf = manager.StartWorkflow(listItem, association, data);
            }
        }
    }
}

In the previous example, the following actions are being performed:

  • The ItemUpdated event in the event handler is being handled. For demonstration purposes, I am assuming that two workflow associations were created, one to the list (named "MyListWorkflow") and another to a content type (named "MyContentTypeWorkflow");
  • A call is made to the StartListWorkflow method, which starts the workflow associated with a list;
  • A call is made to the StartContentTypeWorkflow method, which starts the workflow associated with a content type.

posted @ 9:27 AM | Feedback (0)

Monday, June 23, 2008 #

SharePoint 2007 - Getting an SPListItem by ID after a Search

After making a search to a SharePoint site, it isn't always easy to get a reference to each item returned in the search. This is because we don't know the Web and List where each item is located. The following example shows how this can be achieved:

class SiteCollectionSearch
{
    /// <summary>
    /// Search items by title
    /// </summary>
    /// <param name="web"></param>
    /// <returns></returns>
    private static DataTable Search(SPWeb web)
    {
        //search items by title
        StringBuilder query = new StringBuilder();
        query.Append("<Where>");
        query.Append("<Contains>");
        query.Append("<FieldRef Name='Title' />");
        query.Append("<Value Type='Text'>SharePoint</Value>");
        query.Append("</Contains>");
        query.Append("</Where>");
        query.RowLimit = 100;

        SPSiteDataQuery query = new SPSiteDataQuery();
        query.Webs = "<Webs Scope='SiteCollection' />";
        spQuery.Query = query.ToString();

        //perform the search
        DataTable searchResults = web.GetSiteData(query);

        //return results - since ViewFields property is not specified in
        //the query, WebId, ListId and Item Id are automatically returned
        return searchResults;
    }

    /// <summary>
    /// After a search, obtains each item by its Id.
    /// </summary>
    /// <param name="list"></param>
    private static void GetItemsByID()
    {
        SPSite site = new SPSite("http://portal");
        using (SPWeb web = site.OpenWeb())
        {
            //search documents by title
            using (DataTable docs = Search(web))
            {
                //iterate results
                foreach (DataRow row in docs.Rows)
                {
                    //get webId of the current item
                    Guid webId = new Guid(Convert.ToString(row["WebID"]));
                    //get listId of the current item
                    Guid listId = new Guid(Convert.ToString(row["ListID"]));
                    //get id of the current item
                    int itemId = Convert.ToString(row["ID"]);

                    //get the web where the item is located
                    using (SPWeb itemWeb = site.AllWebs[webId])
                    {
                        //get list using the list id
                        SPList list = itemWeb.Lists[listId];

                        SPListItem listItem = null;
                        try
                        {
                            //get item using its id
                            listItem = list.Items[itemId];
                        }
                        catch { }
                        if (listItem != null)
                        {
                            //do something with the item. Example: 
                            //update the title
                            listItem["Title"] = listItem["Title"] 
                                + " Updated";
                            listItem.Update();
                        }
                    }
                }
            }
        }
    }
}

In the previous example, the following actions are being performed:

  • A search is performed to entire site collection for documents containing the word "SharePoint". As a result of that search, a DataTable instance is returned containing the search results;
  • Each row of the search results is iterated. For each row, three important values are obtained: the item's ID, ListId and WebId. These are obtained automatically in the result of a SPSiteDataQuery when the ViewFields property is not set;
  • The SPWeb instance where the item is located is obtained using the previously obtained WebId;
  • The SPList instance where the item is located is obtained using the previously obtained ListId;
  • The SPListItem is obtained from the list using the item's ID;
  • Finally, something is done with the item. For example, updating its title.

posted @ 6:09 PM | Feedback (2)

Saturday, June 07, 2008 #

SharePoint 2007 - "Value does not fall within the expected range" when updating an SPListItem in a Search

A very common error message that appears when developing in the SharePoint platform is "Value does not all within the expected range" when trying to update an SPListItem that is the result of a query to a SharePoint list. Let's look at the following example:

class SearchListItem
{
    /// <summary>
    /// Search document by title
    /// </summary>
    /// <param name="list"></param>
    /// <returns></returns>
    private static SPListItem SearchDocument(SPList list)
    {
        //get receipt by using a query
        StringBuilder query = new StringBuilder();
        query.Append("<Where>");
        query.Append("<Eq>");
        query.Append("<FieldRef Name='Title' />");
        query.Append("<Value Type='Text'>My document</Value>");
        query.Append("</Eq>");
        query.Append("</Where>");

        SPView queryView = list.Views["All Documents"];
        SPQuery spQuery = new SPQuery(queryView);
        spQuery.Query = query.ToString();
        spQuery.ViewAttributes = "Scope=\"RecursiveAll\"";

        SPListItemCollection items = list.GetItems(spQuery);
        if (items != null && items.Count > 0)
            return items[0];

        return null;
    }

    /// <summary>
    /// Update document.
    /// </summary>
    /// <param name="list"></param>
    private static void UpdateDocumentError(SPList list)
    {
        //search document by title
        SPListItem doc = SearchDocument(list);
        //update item in list
        doc["Title"] = "My document modified";
        doc.Update(); //error "Value does not fall 
        //within the expected range" is thrown
    }

    /// <summary>
    /// Update document.
    /// </summary>
    /// <param name="list"></param>
    private static void UpdateDocumentSucess(SPList list)
    {
        //search document by title
        SPListItem doc = SearchDocument(list);
        //get SPListItem directly from list
        SPListItem item = doc.ParentList.GetItemById(doc.ID);
        //update item in list
        item["Title"] = "My document modified";
        item.Update(); //item updated sucessfully
    }
}

In the previous example, the following actions are being performed:

  • A search is performed within a list for a document named "My Document". As a result of that search, a SPListItem instance is returned containing the document information;
  • In the "UpdateDocumentError" method, after the search is performed, the returned item is modified and the list is updated. This action will cause the exception "Value does not fall within the expected range" to be raised;
  • In the "UpdateDocumentSucess" method, after the search is performed, we obtain the item directly from the list using the ID of the SPListItem returned from the search (the line "SPListItem item = doc.ParentList.GetItemById(doc.ID);" was added, returning a new SPListItem instance). The new instance is then modified and used to update the item in the list. This way, the item is sucessfully updated.

posted @ 11:33 AM | Feedback (0)

Friday, May 16, 2008 #

SharePoint 2007 - Save Site As Template in Publishing Sites

One situation that you may have experienced is the lack of the "Save site as template" link in the Site Settings page of a MOSS 2007 site even if you have administrative privileges on the site or site collection. This will happen if your site is a Publishing site (either a Publishing site, used primarily for public faced Internet web sites or a Collaboration Portal, used primarily for Intranet Portals). You can check if your site is a Publishing site by checking if you have the Office SharePoint Server Publishing Infrastructure feature activated if you are at the top level of your site collection or if Office SharePoint Server Publishing feature is activated if you are in a sub site. Microsoft has disabled the "Save site as template" for Publishing sites and it is not supported. If you still want to save your publishing site as a template, you can do it by appending  "/_layouts/savetmpl.aspx" to the URL of your site. If the URL of your site is

http://intranetportal/site

you just have to go to

http://intranetportal/site/_layouts/savetmpl.aspx

in order for you to save your site as a template. I have already successfully managed to save collaboration portal sites as templates but it might happen that you encounter some problems if you try to save a publishing site as template since this is not a supported procedure. For more information on this, please check this Microsoft Support article.

posted @ 6:10 AM | Feedback (0)

Wednesday, April 16, 2008 #

Windows Workflow - Using the HandleExternalEventActivity

Introduction

This is the first in a series of blog posts dedicated to Windows Workflow. For those who don’t know, Windows Workflow Foundation (WF) is the new engine for building custom workflows (you can find more information about WF on the official web site). It was released as part of the .NET Framework 3.0 along with Windows Presentation Foundation (WPF) and Windows Communication Foundation (WCF).

Local Service Communication

Workflows are not isolated entities and most of the times need to communicate with the outside world in order to perform some task. There are several ways of communicating with external entities/services, being one of them External Data Exchange and Local Service Communication. Local Service Communication basically allows workflows to communicate with an external service that resides within the workflow host. There are two main activities inside WF that allow communication between a workflow and an external service using Local Service Communication:

  • CallExternalMethodActivity – Allows a workflow to call a method from an external service. The workflow and the host establish a contract (using an interface) that defines the way they communicate with each other. Basically the workflow calls a method of a service residing within the host that implements the contract interface. For more details about this activity, click here.
  • HandleExternalEventActivity – Besides allowing the workflow to call an external method, it is also possible for the host to send an event to the workflow in order for it to perform some task. This is achieved using the HandleExternalEventActivity that will put the workflow on an idle state until an external event is raised. Just as in CallExternalMethodActivity, the communication between the workflow and the external is based on a contract.
Summary

To build a workflow that uses HandleExternalEventActivity to communicate with a service using Local Service Communication, you’ll need to:

  • Define a contract (interface);
  • Implement a service based on the defined contract;
  • Develop a workflow that uses HandleExternalEventActivity;
  • Develop a host for the workflow;
  • Add the service to the workflow runtime in the host;
  • Start the workflow and handle the workflow WorkflowIdled event in the host;
  • Raise the event.
Example

As already explained, the HandleExternalEventActivity allows communication between a workflow and an external service using Local Service Communication based on event notifications. Next, I will present a simple demo that will show a very basic usage of this activity. The demo is based on a simple Approval State Machine Workflow Console Application. The console application will ask the user if he/she wants to approve and based on the answer it will pass the corresponding answer to the workflow through the raise of an event. This is how the workflow looks like:

 

This workflow will basically handle the external event inside the StartState activity and set the approved or rejected state according to the information supplied by the host in the event. The interface of the service is defined like this:

[ExternalDataExchange]
public interface IApprovalEventService
{
    void RaiseSetStateEvent(Guid instanceId, bool approve);

    event EventHandler<ApprovalExternalDataEventArgs> ExternalDataEvent;
    
}

The interface uses the ExternalDataExchange attribute which allows the workflow to use it to communicate with the host using Local Service Communication. The interface defines the event, whose arguments are of type ApprovalExternalDataEventArgs, a type derived from ExternalEventArgs. It also defines a RaiseSetStateEvent method that will be used by the host to raise the event. This method defines an additional Boolean parameter named approve in order to pass the approval information to the workflow. This is how the ApprovalExternalDataEventArgs class looks like:

[Serializable]
public class ApprovalExternalDataEventArgs : ExternalDataEventArgs
{
    private bool _result;

    public bool Result {
        set {
            _result = value; 
        }
        get {
            return _result;
        }
    }

    public ApprovalExternalDataEventArgs(Guid instanceId, bool approve)
        : base(instanceId) {
        Result = approve;
    }
}

In the constructor, a Boolean approve parameter is used. This parameter is populated by the host when raising the event and is used to set the Result property that will be used later by the workflow. The other parameter used in the constructor is instanceId, which is used to correlate the event with the right workflow instance.

The HandleExternalEventActivity is defined inside the StartState activity and is named handleSetState. Here are the details of the StartState activity:

As shown in the image above, the external event is handled by the HandleExternalEventActivity handleSetState. Then, based on the value that was supplied by the host, approval or rejected activities will be executed (in this case a simple message will be written to the application console). The properties for the HandleExternalEventActivity handleSetState look like this:

There are three properties worth mentioning here:

  • e – It will hold the event arguments for the workflow instance. In this case it is set to ExternalDataEvent, a public property in the workflow of type ApprovalExternalDataEventArgs.
  • EventName – name of the event that will be handled. Also set to ExternalDataEvent.
  • InterfaceType – name of the interface. Set to IApprovalEventService.

The IfElseActivity defined after the HandleExternalEventActivity will evaluate a code condition to determine whether to execute the Approve or Reject activities.

The code condition is based on a CheckState method that will verify the Result property of the workflow ExternalDataEvent property.

// Code condition to evaluate whether to take the 1st branch, YesIfElseBranch
// Since it always returns true, the 1st branch is always taken.
private void CheckState(object sender, ConditionalEventArgs e) {
    e.Result = ExternalDataEvent.Result;
}

The two remaining pieces of this demo are the service and the host console application. Here is the definition of the service:

class ApprovalEventService : IApprovalEventService
{
    #region IApprovalEventService Members

    public void RaiseSetStateEvent(Guid instanceId, bool approve)
    {
        // create event
        EventHandler<ApprovalExternalDataEventArgs> setStateEvent 
        = this.ExternalDataEvent;

        // launch event
        if (setStateEvent != null)
            setStateEvent(null, new ApprovalExternalDataEventArgs
                (instanceId, approve));
    }

    public event EventHandler<ApprovalExternalDataEventArgs> 
        ExternalDataEvent;
   

    #endregion
}

The console application code looks like this:

private static ApprovalEventService service;
private static Guid instanceId; 

/// <summary>
/// We've decorated the IEventService interface with the 
/// ExternalDataExchangeAttribute.
/// The event args class (ApprovalExternalDataEventArgs) 
/// derives from ExternalDataEventArgs.
/// The event args class (ApprovalExternalDataEventArgs) is serializable.
/// ApprovalEventService implements IEventService.
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
    using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
    {
        //add ApprovalEventService service to the workflow runtime
        AutoResetEvent waitHandle = new AutoResetEvent(false);
        ExternalDataExchangeService dataExchange = 
        new ExternalDataExchangeService();
        workflowRuntime.AddService(dataExchange);
        service = new ApprovalEventService();
        dataExchange.AddService(service);
        
        workflowRuntime.WorkflowCompleted += 
        delegate(object sender, WorkflowCompletedEventArgs e) 
        {
            //display workflow completion message
            Console.WriteLine("Workflow completed.");
            waitHandle.Set();
        };
        workflowRuntime.WorkflowTerminated += 
        delegate(object sender, WorkflowTerminatedEventArgs e)
        {
            //display error message if an exception is raised
            Console.WriteLine(e.Exception.Message);
            waitHandle.Set();
        };
        workflowRuntime.WorkflowIdled += 
        delegate(object sender, WorkflowEventArgs e)
        {
            //read the input from keyboard (yes/no) and raise 
            //the event passing the answer as a boolean parameter
            Console.WriteLine("Workflow idled.");
            Console.Write("Do you want to approve? (Y/N) ");
            string key = Console.ReadLine();
            bool approved = key.ToLower() == "y" ? true : false;
            Console.WriteLine("Sending event to workflow.");
            service.RaiseSetStateEvent(instanceId, approved);
        };

        //start workflow
        WorkflowInstance instance = 
        workflowRuntime.CreateWorkflow(
        typeof(StateMachineCommunicationDemo.SimpleStateMachine));
        instanceId = instance.InstanceId;
        Console.WriteLine("Starting workflow.");
        instance.Start();

        //put workflow in an idle state
        waitHandle.WaitOne();

        //stop runtime
        workflowRuntime.StopRuntime();

        Console.WriteLine("Press any key.");
        Console.Read();
    }
}

In the code above, the following actions are performed:

  • The service is added to the workflow runtime. In order for the service to be correctly added to runtime, two AddService methods must be executed and in the right order. First, an instance of ExternalDataExchangeService is added to the workflow runtime. Then, an instance of our service (ApprovalEventService) is added to the ExternalDataExchangeService instance.
  • The workflow is started
  • The workflow is placed in an idle state
  • Several delegate functions are defined to handle workflow events. The most important one is the event handler for the WorkflowIdled event. The event handler will be trigger once the workflow is placed in an idle state. Then, the user will be asked the approval question and the event is raised which will cause the HandleExternalEventActivity in the workflow to be executed.

Here is the application’s output in case of approval:

And in case of rejection:

posted @ 11:10 AM | Feedback (0)

Monday, March 17, 2008 #

TechDays 2008 – 3º Dia

Decorreu na passada semana entre os dias 12 e 14 de Março a edição deste ano do TechDays, o maior evento de tecnologia do país. Este evento juntou mais de 2000 profissionais na área das TI, tendo sido dadas mais de 150 sessões técnicas por 120 oradores, tendo sido claramente a maior edição deste evento. De seguida, deixo o meu testemunho relativamente às sessões a que tive oportunidade de assistir no 3º dia.

COL10 - Como Criar Soluções/Aplicações Utilizando o Open XML

Oradores: Marcos Santos (Microsoft), Susana Guedes (Microsoft) e Bernardo Antunes (Devscope)

Esta sessão abordou o tema do Open XML e de como este pode ser usado no desenvolvimento de aplicações. O Open XML pretende endereçar os seguintes problemas:

  • A informação é guardada em muitos formatos diferentes
  • Difícil trocar e guardar a informação
  • Diferentes aplicações usam formatos de documento de forma diferente

O objectivo passa por uniformizar o formato de documentos usado pelas aplicações de forma a facilitar a interoperabilidade na troca de documentos entre organizações. O Open XML é já o formato usado pelo Office 2007. Para quem não sabe, se renomear um ficheiro .docx como exemplo para .zip pode ver a estrutura interna do ficheiro, basicamente um conjunto de ficheiros xml.

Mais informações e demos de utilização do OpenXML em: http://openxmldeveloper.org e http://www.openxmlcommunity.org/.

ARC05 - Construção de Software+Services com a Plataforma Volta

Oradores: Daniel Fisher e Michael Willers, DevCoach

O tema desta sessão foi muito interessante. "Volta" é o nome de código de um projecto ainda em desenvolvimento por parte da Microsoft cujo objectivo é o de uma forma transparente e sem qualquer esforço de desenvolvimento compilar código de assemblies .NET (em qualquer linguagem .NET compliant) em código Javascript compatível "cross-browser". Detalhando um pouco mais o conceito, a ideia é desenvolver uma aplicação (cliente, serviços) em .NET e por meio de atributos definir se o código corre no cliente ou no servidor (basta incluir o atributo ["RunAtOrigin"]). O "Volta" vai gerar código javascript para a camada de cliente, web services para a camada de servidor e todo o código de "plumbing" (comunicação, serialização, segurança, etc) entre as duas camadas.

Basicamente, a ideia é desenvolver as aplicações em .NET do lado do servidor na nossa linguagem preferida e como output obter uma aplicação AJAX distribuída.

Mais informação pode ser obtida em http://labs.live.com/volta/.

WEB05 - ASP.NET Futures - Dynamic Data Controls and Astoria Services

Orador: Matt Gibbs, Microsoft (Blog: http://blogs.msdn.com/mattgi)

Esta sessão foi apresentada pelo Matt Gibbs que é Development Manager da equipa de ASP.NET da Microsoft e abordou algumas das novidades que irão estar presentes na próxima versão do ASP.NET. A sessão foi dividida em duas partes distintas:

  • Dynamic Data Controls
  • Astoria Web Data Services
Dynamic Data Controls

Os Dynamic Data Controls permitem a obtenção de forma dinâmica da estrutura da base de dados em tempo real e adaptar a sua apresentação automaticamente de acordo com a mesma. Estes controlos irão estar integrados como extensões na próxima versão do ASP.NET e vêm alterar o ciclo de desenvolvimento de uma aplicação ASP.NET "data-bounded". Antes tínhamos:

  • Criação do modelo de BD
  • Criação das páginas
  • Adição dos controlos às páginas
  • Adição lógica de validação

Com estes novos controlos e a com as novas templates de projectos existentes no Visual Studio 2008, teremos:

  • Criação do modelo de dados
  • Criação automática de um aplicação com base no modelo de dados
  • Customização da aplicação (alteração páginas .aspx e controlos .ascx base)

Mais informação sobre Dynamic Data Controls: http://quickstarts.asp.net/Futures/dynamicdatacontrols/default.aspx.

Astoria Web Data Services

Ainda em fase de protótipo (será designado por "ADO.NET Data Services"), a principal ideia é simplificar o acesso a dados através do consumo de serviços com base em URIs (http://quickstarts.asp.net/3-5-extensions/adonetdataservice/ConsumingDataService.aspx) e retornar os dados em formatos JSON (método de serialização mais simples para evitar o "overhead" do XML na troca de informação em web services - http://www.json.org/ muito ligado ao Javascript e AJAX) ou XML. Os serviços poderão ser consumidos tanto por AJAX ou por qualquer outro cliente non-AJAX (serviço WCF, aplicação web, aplicação Windows-Forms, etc).

Mais informação sobre Astoria Web Data Services em http://astoria.mslivelabs.com/ e http://quickstarts.asp.net/3-5-extensions/adonetdataservice/ADONETDataServicesFramework.aspx.

 

VST03 - Hardcore Debuging e Profiling de Aplicações .NET

Oradores: Filipe Prezado e João Loureiro, Microsoft

Foi mais a curiosidade que me levou a assistir a esta sessão, tendo-se revelado uma sessão bastante interessante, embora com um certo nível de complexidade. Basicamente, foram apresentadas as técnicas usadas pela equipa de suporte técnico da Microsoft para resolução de problemas aplicacionais em produção, tanto em cenários em que detêm o acesso remoto ao servidor como em casos em que tal não sucede. Algumas das ferramentas apresentadas foram: Mdbg, WinDbg (a mais conhecida), SOSAssistant, Hawkeye. Com base nestas ferramentas, foram apresentadas técnicas que permitiram a identificação de "memory leaks", efectuar o memory dump para ficheiro (útil em cenários em que não existe acesso remoto ao servidor) para posterior análise, entre outras. Uma sessão diferente mas interessante.

WEB04: MVC Framework on Future ASP.NET

Orador: Matt Gibbs, Microsoft (Blog: http://blogs.msdn.com/mattgi)

Esta foi a segunda sessão apresentada pelo Matt Gibbs sobre a futura versão do ASP.NET. Desta vez, foi apresentada a framework MVC para ASP.NET que é a implementação da Microsoft desta "pattern". Esta framework basicamente divide uma aplicação em 3 "roles":

  • Model (Modelo) – representa os componentes da aplicação que são responsáveis pela manutenção do estado da aplicação (os dados). O caso mais típico é a persistência do estado numa base de dados (ex: uma classe Client que representa os dados de uma tabela Client numa base de dados SQL Server)
  • View (Vista) – representa os componentes responsáveis pela camada de apresentação da aplicação
  • Controller (Controlador) – representa os componentes responsáveis pela interacção com o utilizador, manipulação do modelo e selecção da vista a utilizar. É o controlador que fica encarregue pela interacção com o utilizador e não a vista, sendo esta apenas usada para apresentação da informação

Um ponto importante a referir é que o MVC não vem substituir o modelo de desenvolvimento ASP.NET tradicional, apresentando-se antes como uma alternativa onde a ideia é haver uma maior separação de responsabilidades entre os componentes da aplicação.

As demos apresentadas não foram tão bem conseguidas quanto estava à espera, tendo ficado por explicar como exemplo a forma como são obtidos ou como são editados/inseridos dados numa base de dados (tipicamente a lógica será colocada no componente "Model").

Mais informação sobre o MVC em http://weblogs.asp.net/scottgu/archive/2007/10/14/asp-net-mvc-framework.aspx e http://weblogs.asp.net/scottgu/archive/2007/11/13/asp-net-mvc-framework-part-1.aspx.

 

Podem consultar as sessões do dia 1 aqui e do dia 2 aqui.

posted @ 5:52 PM | Feedback (0)

TechDays 2008 – 2º Dia

Decorreu na passada semana entre os dias 12 e 14 de Março a edição deste ano do TechDays, o maior evento de tecnologia do país. Este evento juntou mais de 2000 profissionais na área das TI, tendo sido dadas mais de 150 sessões técnicas por 120 oradores, tendo sido claramente a maior edição deste evento. De seguida, deixo o meu testemunho relativamente às sessões a que tive oportunidade de assistir no 2º dia.

INT04 - Qual é o Contexto desta Conversação? Activando Conversações Longas em Serviços de Workflow. Serviços "Duráveis"

Orador: José António Silva, Microsoft

Tendo em consideração a natureza dos workflows onde uma instância de workflow pode estar activa durante um período de tempo longo ("long running instance"), é necessário desenvolver os serviços WCF de forma a suportar este tipo de cliente. Esta sessão abordou o tema de serviços "duráveis". Estes são um novo tipo de serviço da .NET Framework 3.5 que permite simplificar a persistência de estado numa "conversação" entre um serviço WCF e um cliente (ex: um workflow). O modelo de persistência do estado de um serviço WCF é em tudo idêntico ao de WF, sendo possível guardar o estado em BD, files system, etc . De forma a tornar um serviço WCF "durável" basta usar o prefixo "Durable" nos atributos da classe do serviço. Exemplo:

[Serializable]

[DurableService]

public class TextComposer : ITextComposer

{

    private string CurrentText ;

[DurableOperation]

    public string PowerOn(string text)

    {

        CurrentText = text;

        return CurrentText;

    }

}


Mais informação sobre "Durable Services" em http://weblogs.asp.net/gsusx/archive/2007/06/14/orcas-durable-services.aspx (post antigo mas com uma boa explicação) e em http://www.microsoft.com/uk/msdn/nuggets/nugget/270/Durable-Services-with-WCF-V35.aspx (screencast).

Algumas tools interessantes para WCF referidas durante a sessão:

Configuration Editor Tool – aplicação que permite que permite a edição das configurações de serviços WCF com uma interface gráfica (StartàRunà SvcConfigEditor). Mais informação em http://msdn2.microsoft.com/en-us/library/ms732009.aspx.

WCF Test Client – aplicação que permite efectuar testes "offline" sobre serviços WCF (StartàRunà WcfTestClient). Mais informação em http://msdn2.microsoft.com/en-us/library/bb552364.aspx.

Service Trace Viewer Tool – aplicação que permite a análise dos logs de mensagens geradas pelo WCF (StartàRunà SvcTraceViewer). Mais informação em http://msdn2.microsoft.com/en-us/library/ms732023.aspx.

 

ARC01 - Software + Services: The Convergence of SaaS, SOA and Web 2.0

Orador: Beat Schwegler, Microsoft

Esta sessão retratou um tema muito em voga: o Software + Services. A sessão não teve qualquer demo, tendo tido uma componente bastante teórica, tendo sido iniciada com a referência a três conceitos importantes: SaaS (http://msdn2.microsoft.com/en-us/architecture/aa699384.aspx), SOA (http://msdn2.microsoft.com/en-us/architecture/aa948857.aspx) e Web 2.0 (http://twopointouch.com/2006/08/17/10-definitions-of-web-20-and-their-shortcomings/). Foram referidos alguns exemplos de modelos de negócio usados com S+S: Subscription/License Model, Advertisement Base Model (ex: Google). Foram dados ainda alguns exemplos de aplicações S+S: Eve Online (http://www.eve-online.com/), o Amazon S3 (http://www.amazon.com/gp/browse.html?node=16427261) e a British Library. Por fim, foram ainda referidos alguns exemplos concretos de implementação do S+S pela Microsoft:

  • Finished Services – Windows Live, Office Online
  • Attached Services – XBOX Live
  • Building Blocks – BizTalk Services

 

INT06: Viagem ao Centro da Núvem – O Internet Service Bus (ISB) e os BizTalk Services

Orador: João Pedro Martins a.k.a "Jota", Create IT

A sessão começou de uma forma muito interessante com o Jota a "provocar" a audiência com algumas ideias sobre a forma como será o mundo das aplicações no futuro como a transição de um mundo com "data centers" nas próprias empresas para um em que o "hosting" é feito por grandes empresas com super "data centers" dedicados a fazer o "hosting" de milhares de aplicações. Foi uma forma interessante de cativar desde início a audiência. Neste sentido, foram dadas algumas estatísticas interessantes como a previsão do aumento de número de servidores de hosting da Microsoft de 200000 actuais para 800000 em 2011, indo de encontro à adopção do conceito de Software como um serviço (S+S) com as aplicações a ser alojadas em "hosting" externo e serem expostas como serviços. Os BizTalk Services, são basicamente a visão da Microsoft da forma como as aplicações irão comunicação entre si no futuro, facilitando o desenvolvimento de aplicações orientadas a serviços (SOA). A ideia fundamental dos BizTalk Services é a de permitir a comunicação segura entre as aplicações das organizações através de firewalls.

COL07 - Microsoft Search Server 2008 - Introdução e Apresentação de Novas Funcionalidades

Oradores: Bruno Valente e Luís Calado, Microsoft

O Microsoft Search Server 2008 (MSS 2008) é a versão 2 do já existente "SharePoint Server for Search". As principais diferenças de para a versão anterior são:

  • Melhorias significativas na interface de administração
  • Pesquisa federada (a maior novidade)
  • Melhorias de performance e estabilidade
  • Pesquisa "cross-site" mesmo na versão Express (ao contrário do que acontecia antes)
  • Melhorias nos relatórios
    • Duração última indexação e da actual
    • Última indexação completa, etc

Vão existir duas versões do produto:

  • Search Server 2008 – versão paga que pode ser instalada num cenário de farm. Os clientes MOSS não terão custos adicionais para fazer o upgrade para MSS 2008.
  • Search Server 2008 Express – versão gratuita que apenas pode ser instalada num único servidor.

A principal novidade do produto é a pesquisa federada. A ideia passa por permitir a pesquisa sobre outros motores de pesquisa ou aplicações, integrada no SharePoint, sem ter que ter os conteúdos indexados no índice de SharePoint. Alguns dados sobre a pesquisa federada:

  • A única desvantagem é a inexistência de "ranking" dos resultados de pesquisa pelo facto de não estarem indexados.
  • Cada motor de pesquisa tem que ser configurado no SharePoint como uma localização federada.
  • A pesquisa é efectuada com base no standard OpenSearch (http://www.opensearch.org/Home) onde a query de pesquisa é enviada por URL. Ex: http://search.live.com/result.aspx?q={searchTerms}
  • Resultados de pesquisa devolvidos em XML

Existem duas web parts "out-of-the-box" para pesquisa federada:

  • Federated Results Web Part: mostra todos os resultados de uma localização federada
  • Top Federated Results Web Part: mostra os "top x" resultados de uma ou mais localizações federadas

 

Podem consultar as sessões do dia 1 aqui.

posted @ 5:49 PM | Feedback (0)

TechDays 2008 – 1º Dia

Decorreu na passada semana entre os dias 12 e 14 de Março a edição deste ano do TechDays, o maior evento de tecnologia do país. Este evento juntou mais de 2000 profissionais na área das TI, tendo sido dadas mais de 150 sessões técnicas por 120 oradores, tendo sido claramente a maior edição deste evento. De seguida, deixo o meu testemunho relativamente às sessões a que tive oportunidade de assistir no 1º dia.

COL03 – Arquitectura e Desenvolvimento de Aplicações que Permitem Pesquisa com MOSS

Orador: Beat Schwegler, Microsoft (Blog: http://blogs.msdn.com/beatsch/)

Esta sessão foi dividida em duas partes:

  • Como tornar informação das aplicações pesquisável no MOSS
  • Como efectuar pesquisas no MOSS a partir de aplicações e apresentar os resultados
Como tornar informação das aplicações pesquisável no MOSS

Foi dada uma introdução sobre a arquitectura de pesquisa do MOSS e os seus componentes (Content Sources [File, BDs, Exchange,etc], Protocol Handlers [http, ftp, file, BDC, etc], IFilters, Metadata e permissões).

De seguida, foram referidos os requisitos para tornar formatos de ficheiro proprietários pesquisáveis no MOSS, tendo que para tal ser instalado um iFilter de forma a que o motor de indexação do MOSS possa ler o conteúdo dos ficheiros e indexá-los.

Para tornar conteúdos de aplicações LOB pesquisáveis, deve ser usado o BDC. Deve ser criado o ficheiro xml de meta dados (metadata.xml). No ficheiro de meta dados devem ser especificados:

  • Entidades
  • Métodos - devem ser especificados métodos Finder e SpecificFinder de forma a que os dados possam ser pesquisados.
Como efectuar pesquisas no MOSS a partir de aplicações e apresentar os resultados

Podem ser usados 3 métodos:

Informação adicional: http://msdn2.microsoft.com/en-us/library/bb887531.aspx

ARC04 – Database Design Patterns: Boas Práticas para os Modelos de Dados

Orador: Stephen Forte, Corzen, Inc. (Blog: http://www.stephenforte.net/)

Esta sessão foi muito interessante, das mais interessantes a que assisti. O orador (americano) é um comunicador nato, cativando desde o início a audiência. Durante a sessão foram abordados dois tópicos essenciais:

  • Data Model Patterns
  • Infrastructure Patterns – Data Partitioning
Data Model Patterns

Existem 3 patterns:

  • Transactional Design Pattern – este modelo deve ser usado para as bases de dados operacionais, com elevado nível de transacções (OLTP), tipicamente bases de dados de suporte ao negócio. O modelo de dados deve ser definido para que a base de dados se encontre normalizada. Não devem ser usados índices de forma a evitar perdas de performance nas operações de insert, delete e update.
  • Slowly Changing Dimensions Design Pattern (SCD)– esta pattern deve ser usada para bases de dados de reporting e consulta de informação. O seu preenchimento é feito a partir da BD OLTP, devendo a a estrutura da BD ser desnormalizada e as tabelas desenhadas de forma a agregar toda a informação que se pretenda consultar na mesma tabela de forma a simplificar as querys (evitando joins com outras tabelas) e desta forma conseguir-se querys mais rápidas. Com este modelo evita-se que as querys de report sejam efectuadas sobre a BD OLTP. Neste tipo de BDs, podem e devem ser usados índices para acelerar as querys.
  • Data Warehouse Design Pattern – este modelo é uma extensão do anterior, tendo um pouco mais de estrutura (existem N tabelas de dimensão [Tempo, Produto, Sexo, etc] e uma tabela de Factos [com uma chave estrangeira para cada tabela de dimensões] onde são guardados os dados a partir da BD OLTP). Este modelo deve ser usado em detrimento do SCD em BDs com volumes massivos de dados.

Existem várias formas para popular as BDs SCD ou DW: por T-SQL, DTS, SSIS, etc.

Foi dado um exemplo concreto da utilização destes modelos: a Amazon.com usa uma BD OLTP para todas as ordens de compra e uma BD SCD para os catálogos de produtos.

Infrastructure Patterns – Data Partitioning

Os patterns seguintes devem ser usados quando se tiver um volume muito grande de informação e as querys à BD começarem a ficar lentas.

Existem 2 patterns:

  • Horizontal Partitioning – consiste em dividir os dados em várias tabelas com a mesma estrutura. Exemplos: dados anuais, dados semestrais, etc conforme o volume de dados.
  • Vertical Align – consiste em dividir os dados em duas ou mais tabelas, mantendo o número de registos intacto. Numa tabela, são guardados as colunas mais acedidas (ex: nome, email, etc), colocando-se na(s) restante(s) as colunas menos acedidas.

Estas duas patterns podem ser usadas em conjunto.

O particionamento de dados pode também ser feito, separando os dados em vários discos, de forma a que se um disco ficar inoperacional, os outros continuam a funcionar.

COL01 - Gestão de Conteúdos e Usabilidade com Sharepoint (MOSS)

Oradores: Carla Faria e Luís Calado, Microsoft

Esta sessão foi composta por duas partes distintas, apresentadas por cada um dos oradores:

  • Acessibilidade na Web em geral - Carla Faria
  • Acessibilidade com SharePoint (MOSS) – Luís Calado
Acessibilidade na Web em geral

A Carla Faria é uma especialista em acessibilidade na Web. De seguida, fica um resumo das "guidelines" de acessibilidade apresentadas na sessão:

Acessibilidade com SharePoint (MOSS)

O Luís deixou alguns conselhos práticos para melhorar a acessibilidade dos sites em MOSS:

  • Incluir textos alternativos para todos os elementos textuais
  • Utilizar tamanhos de letra relativos (usar font-size na unidade ".em") em detrimento de tamanhos fixos (http://www.bigbaer.com/css_tutorials/css_font_size.htm e http://clagnut.com/blog/348/)
  • Em WCM, evitar usar Web parts J ou alterar forma de renderização das Web part zones
  • Utilizar sempre que possível controlos de publicação MOSS ou web controls ASP.NET sempre que possível em deterimento de web parts
  • Incorporação de solução de terceiros para edição de conteúdos (Telerik RAD Editor – W3C WAG level A)
  • Começar sempre por desenhar master page mínima
  • Validar página para acessibilidade = validar master page + validar page layouts + validar conteúdos
  • Nos menus SharePoint, não usar a classe Menu do ASP.NET mas antes renderizar
    • .

    Encontra-se em http://www.codeplex.com/aks o Accessibility Toolkit for SharePoint (AKS), um conjunto de templates, master pages, controlos e web parts acessíveis. Este toolkit é instalado através de um solution package (.wsp) e contém alterações à implementação das web part zones. Na próxima versão do AKS vai ser lançado um gestor de conteúdos acessível (Accessible Rich Text Editor [aRTE]). O roadmap do AKS encontra-se disponível em http://blogs.msdn.com/sharepoint/archive/2008/03/12/announcing-accessibility-kit-for-sharepoint-1-1-and-future-roadmap.aspx.

    DEV06 - ADO.NET Entity Framework e LINQ To Entities

    Orador: Luís Falcão (ISEL)

    Nesta sessão foi abordada a ADO.NET Entity Framework (http://msdn2.microsoft.com/en-us/library/aa697427(VS.80).aspx), uma nova framework cujo objectivo é o de aumentar o nível de abstracção no que diz respeito à programação da camada de acesso a dados. Um dos problemas mais comuns no desenho das classes DAL é o esforço associado ao mapeamento entre as classes DAL e a BD. A Entity Framework permite facilitar esta tarefa ao disponibilizar um diagrama integrado no Visual Studio 2008. Usando o Solution Explorer é possível importar todo a estrutura de uma base de dados para um diagrama de classes que é a transformação do modelo de dados num modelo de classes mapeado directamente com a estrutura da BD. Depois é possível definir novas relações entre as classes, definir heranças entre classes (não é possível definir herança ao nível da BD), mapear os dados de uma classe para que estes sejam divididos entre duas ou mais tabelas entre outras funcionalidades.

    Na nova API vem incluído um novo .NET provider para Entity Framework (Entity Client) que é o correspondente ao SqlClient (para SQL Server) para actuar sobre as entidades criadas com a Entity Framework.

    Ainda se encontra em versão beta e nesta fase só permite gerar o Entity Model a partir da BD, não permitindo ainda criar primeiro o modelo antes e gerar a BD a partir deste.

posted @ 5:46 PM | Feedback (2)

Wednesday, February 20, 2008 #

SharePoint 2007 and WSS 3.0 Dispose Patterns by Example

When developing for the SharePoint platform, developers should be very careful in using the SharePoint API in order to avoid memory leaks in a production SharePoint farm. Roger Lamb has written a great post that shows a series of examples where code can lead to memory leaks and best practices on how to avoid them. Definitely, a must read for all SharePoint developers.

Another suggestion I leave before deploying any custom development into a SharePoint farm, is to use a stress tool on your SharePoint web site. I recommend using Microsoft Web Application Stress Tool and take a good look into the IIS Application Pool Processes (w3wp.exe) memory consumption in order to ensure they remain stable (you should have one w3wp.exe process for each application pool).

posted @ 3:35 PM | Feedback (1)

Sunday, December 09, 2007 #

SharePoint 2007 - Getting URL from Image Field in WCM Web Sites

It is a common scenario in WCM web sites, to have content page images stored in a column of type Image. SharePoint stores this kind of fields in the content database by storing the image HTML markup, storing an <IMG> tag like in the following example:

<IMG src="/PublishingImages/picture.GIF" />

When working in context of a page layout, we can easily include image fields by inserting an Image Field control using SharePoint Designer. However, there are situations where we must use the SharePoint Publishing API and there's where the ImageFieldValue class comes in hand. This class represents an <IMG> tag and its properties. A common situation is when you want to get the Image URL from its HTML markup. This example shows how it can easily be achieved by using the ImageFieldValue class:

public static string getImageUrl(string imageFieldHTMLMarkup)

{

Microsoft.SharePoint.Publishing.Fields.ImageFieldValue image =

new Microsoft.SharePoint.Publishing.Fields.ImageFieldValue(imageFieldHTMLMarkup);

 

return image.ImageUrl;

}

More information about the ImageFieldValue class can be found in the MSDN web site.

posted @ 9:41 AM | Feedback (1)

Saturday, December 08, 2007 #

Using Windows Explorer to Get GAC Files

The .NET Framework installs an Explorer extension that basically allows you to view the installed assembly list, view its properties and uninstall them. The purpose of this extension is to hide the internal structure of the GAC so that users cannot delete or move files from there using the default Windows Explorer and corrupt any of the installed assemblies. However, there are situations where you need to have access to the physical files installed in the GAC folder. This can easily be achieved by assigning a drive letter to the GAC folder. For example if you want to assign drive G, just type the following command in a DOS command line:

subst g: %windir%\assembly\gac

Now, you will be able to access the physical files in the GAC using the default Windows Explorer view. Use it with care.

posted @ 9:02 AM | Feedback (0)

Monday, November 26, 2007 #

Dealing with Memory Pressure problems in MOSS and WSS

I just a found another great post about memory management and performance issues on the SharePoint platform. This article defines the concept of "Memory Pressure" and discusses in great detail the most common reasons for memory pressure situations and best practices on how to avoid them. For more details, click here.

posted @ 5:30 PM | Feedback (0)

Sunday, November 25, 2007 #

Development Tools and Techniques for Working with Code in Windows SharePoint Services 3.0

I just found two great articles posted in the MSDN web site by Patrick Tisseghem of U2U that covers a series of aspects on development with the SharePoint platform, including explanation of the differences between ASP.NET and SharePoint development, several code samples and deployment techniques for solution deployment, maintenance and upgrading:

posted @ 1:25 PM | Feedback (0)

How to Create a SharePoint Server 2007 Custom Master Page and Page Layouts for a Web Content Management Site

I found another very useful article in the MSDN web site for SharePoint developers that are working on WCM. This article provides a step-by-step guide on how to build and deploy a custom master page and associated page layouts with a very complete set of examples. You can read it here.

posted @ 10:35 AM | Feedback (0)

Saturday, November 24, 2007 #

How to Optimize a SharePoint Server 2007 Web Content Management Site for Performance

In any web site, performance should be among the main concerns (especially if a large amount of users is expected) and SharePoint web sites are no exception. This MSDN article provides a series of guidelines to optimize the performance of a SharePoint, Internet-facing WCM web site.

posted @ 1:26 PM | Feedback (0)

Monday, November 19, 2007 #

Page.EnableEventValidation and “Invalid postback or callback argument” error

In a project I am currently working on, I developed a custom web part that basically renders a form and submits the entered data into a SharePoint list. The problem I was having is that when the form button was clicked, I got the following error:

"Invalid postback or callback argument. Event validation is enabled
using <pages enableEventValidation="true"/> in configuration or <%@ Page
EnableEventValidation="true" %> in a page. For security purposes, this
feature verifies that arguments to postback or callback events originate
from the server control that originally rendered them. If the data is
valid and expected, use the
ClientScriptManager.RegisterForEventValidation method in order to
register the postback or callback data for validation."

This error message is related to a new security enhancement brought by ASP.NET 2.0 called EventValidation. If enabled (default value), this new feature ensures that ASP.NET will only allow the specific events that are raised on a given control during a postback or callback. The main purpose of this security validation is to reduce the risk of unauthorized postback requests and callbacks (more information on this here).

After some research on the Internet, two main approaches were given:

  • Set the <pages EnableEventValidation="false" …/> in the web.config or at the page level – This is not a recommended approach due to the associated security risks, since event validation will not be performed and the risk of unauthorized postback requests and callbacks will increase.
  • Use the Page.ClientScript.RegisterForEventValidation(ctrl. UniqueID) in the control – this approach will register the given control and its events for event validation. This seemed like a good approach since it would allow maintaining the event validation but it didn't solve the problem. Apparently, the internal variable _requestValueCollection of the Page class, is never initialized, so method EnsureEventValidationFieldLoaded will never load the dictionary with UniqueIDs and therefore cannot find the control which is authorized to make postback via RegisterForEventValidation.

After this, I tried a different approach, more successfully. The web part is included in the context of a SharePoint page layout. After analyzing this web page, I found out that it included two nested <form></form> elements. After removing these elements, the form submission started working properly.

posted @ 7:39 AM | Feedback (0)

Sunday, November 18, 2007 #

SharePoint 2007 - Exporting Web Parts

When web parts are deployed in a SharePoint Site Collection, they become available in the Web Part Gallery, so that they can be added to web part pages. The Web Part Gallery page shows the list of web parts installed in a Site Collection and each of the web part listed is represented by an xml file of .webpart extension that contains its definition. An example of a .webpart file is the following:

<?xml version="1.0" encoding="utf-8"?>
<webParts>
<webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
<metaData>
<type name="MyNamespace.SharePoint.WebParts.MyCustomWebPart, MyNamespace.SharePoint.WebParts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5874548632a535ab" />
<importErrorMessage>Cannot import this Web Part.</importErrorMessage>
</metaData>
<data>
<properties>
<property name="Title" type="string"> MyCustomWebPart </property>
</properties>
</data>
</webPart>
</webParts>

From the Web Part Gallery page, you can export (download) the web part definition into a file for later import or inclusion in a deployment package.

You can also enable the Export option from web part itself when included in a web part page (this option is disabled by default). To do that, you must include the following lines of codes into the OnLoad event of your web part:

protected override void OnLoad(EventArgs e)

{

base.OnLoad(e);

 

if (this.WebPartManager.DisplayMode != WebPartManager.BrowseDisplayMode)

this.ExportMode = WebPartExportMode.All;

}

By adding this code, you will enable the web part to be exported when the page is being edited. An "Export…" option will be added to the web part edit context menu.

posted @ 11:17 AM | Feedback (0)

SharePoint 2007 - No parameterless constructor defined for this object

In a project I am currently working on, I needed to edit a page layout in a Publishing Site and I was adding a custom web part using SharePoint Designer. Everything seemed to be working fine (the web part was successfully added to the page) but when I browsed to the page, I got a "No parameterless constructor defined for this object". I checked the SharePoint trace logs (check my previous post on Diagnostic Logging for more information on this) and the following error message was written:

An unexpected error has been encountered in this Web Part.  Error: Cannot create an object of type 'Microsoft.SharePoint.SPListItem' from its string representation ' Microsoft.SharePoint.SPListItem' for the 'CurrentItem' property.

The reason for this error to be shown was that SharePoint Designer was adding a CurrentItem property (a public property of the custom web part of type Microsoft.SharePoint.SPListItem) to the web part declaration:

<WebParts:MyCustomWebPart CurrentItem=" Microsoft.SharePoint.SPListItem" …/>

When the web part tried to access this property, the above error was thrown, because an instance of an object of type Microsoft.SharePoint.SPListItem was trying to be created from its string representation. Once I removed this property from the web part declaration, it started to work fine.

posted @ 10:42 AM | Feedback (0)

SharePoint 2007 Debugging – Show Error Messages

Sometimes debugging SharePoint errors is not the easiest of tasks. The most common and annoying situation is when the "An unexpected error has occurred" error message is shown and nothing is written to both the trace log files (check my previous post on Diagnostic Logging for more information on this) and Event Viewer. In order for the real error message to be shown, two settings must be changed in the web.config file:

  • <SafeMode MaxControls="200" CallStack="false"… /> must be changed to <SafeMode MaxControls="200" CallStack="true" … />
  • The customError setting must be changed to "Off":    

<customErrors mode="Off"/>

After these changes, the "An unexpected error has occurred" will no longer be shown and you will see the real error message in a standard ASP.NET error page, including all the debugging information you need.

posted @ 10:14 AM | Feedback (11)