May 2004 - Posts

Bryant Likes has published his solution to show SQL Server Reporting Services stuff in SharePoint. For the latest releases, you can visist the GotDotNet Workspace. Nice work Bryant!

Steve Hebert has started an interesting GotDotNet Workspace: .Math.

The dotMath library is a two-pass expression compiler written entirely in C# for the Microsoft .NET platform. The library requires only the core .NET library (supporting all shipping versions 1.0 and 1.1). The library is capable of running on any system.

By using the .Math library you can evaluate functions that are entered as plain strings (for example “(a + b)/c”) without having to fall back on Reflection. Test-drive it here. Great!

A lot of bloggers have mentioned it today, so I'm going to say only one word about it: finally.

Some resources:

Serge van den Oever posted some interesting questions regarding my SharePoint Workflow project:

  • Why do you use the parameter1, parameter2, ... construct, why not have the amount of parameters as needed or is this to have a simple schema? Wouldn't it be better to have separate tags for the different actions?
    I want to have a simple schema that doesn’t break when I add a new action. A specific node for each different action would result in a more complex and less maintainable schema.
  • Is it possible to extend the functionality to add an entry to any list in any site, and to any listing in any portal area? Would be great to set any property in those lists/listings to any area.
    In this version of SharePoint you can only attach event handlers to document libraries. That’s really a pity, but I’ve read somewhere (I think on Patrick’s blog) that the reason was limited time. So let’s hope in a next version, or a Service Pack event handlers can be attached to lists as well. This would create some opportunities to add audit trails to list items as well.
  • Is it possible to make an action that calls a function in an assembly? Would be great if you could specify for example the assembly, the class implementing a defined interface, and in this class a standard function to be called, and finally two parameters: the url of the source document and a string constructed with the field replacements you already defined. This would give infinite possibilities!
    This is a great idea! I won’t make a commitment for the first version, but I definitely will implement it in a next version (if it doesn’t make into V1). I see this as a new action, so besides the default defined actions, you can create your own custom implemented actions. Thus this would be the best of both worlds: simplicity and ease of use for the default actions and extensibility with custom actions as well.
  • Could you make the sourcecode available? We could help you in implementing additional features!
    I’ve started a GotDotNet Workspace, but at this point I’m the only member. :-) Once I’ve got a quite stable code base (probably around V1), I’ll admit members so everyone can come and contribute.

I always tell everyone that SharePoint is very extensible and customizable, and this is really true. For example, let's take a look at the search functionality in SharePoint. By default only Office documents (which are in a document library for example) are indexed by the Indexing Service so they can be found by using the search functionality of SharePoint. Of course in the real world there are a lot more document types that are used, for example a lot of companies have PDF documents. So I get quite a lot questions of people asking if PDF documents can be indexed too. The good news is that the Indexing Service can be extended by using the IFilter interface:

The IFilter interface scans documents for text and properties (also called attributes). It extracts chunks of text from these documents, filtering out embedded formatting and retaining information about the position of the text. It also extracts chunks of values, which are properties of an entire document or of well-defined parts of a document. IFilter provides the foundation for building higher-level applications such as document indexers and application-independent viewers.

Even better news is that Adobe has a free IFilter DLL for PDF documents!

Adobe PDF IFilter is a free, downloadable Dynamic Link Library (DLL) file that provides a bridge between a Microsoft indexing client and a library of Adobe PDF files. It consists of code that understands the Adobe PDF file format as well as code that can interface with the indexing client. When an indexing client needs to index content from PDF documents, it will look in its registry for an appropriate DLL and it will find the Adobe PDF IFilter. Adobe PDF IFilter will return text to the indexing client. The indexing client will then index the results and return the appropriate results to the user.

For more info on how to install it, take a look at Eric Legault's post. If you look in the internet you'll find plenty of other IFilter implementations, for example this one for JPEG files. There's even an IFilter Shop! Some other cool IFilter implementations: Visio 2003, XML, MP3.

Yesterday Kaneboy created a GotDotNet Workspace for his SharePoint Workflow Engine. It's a pitty that all his documentation and installation guidelines are in Chinese. Although I do not speak Chinese, I've checked out this project and it resembles my Workflow Lite For SharePoint project a lot (bases on the screen shots). The only difference is that Kaneboy's approach is to create actions in code (C#) rather than having a set of predefined actions. Anyway I have to practise my Chinese a little bit more to keep an eye on this project! :-)

Now that we're talking workflow, a small update on my Workflow Lite For SharePoint: I've put quite some work in it the past days and I'm feeling comfortable to release a V1 in the next few days, so stay tuned. There are some changes compared to the first version, the most cool one is (in my opinion) the Send Email action. So you can have the workflow process sending emails either to a specific person, or to a group of SharePoint users (defined on the SharePoint site). I'm really happy with that solution because it integrates well with permission settings, which in many scenarios is also based on groups. Ofcourse the content of the emails is fully customizable, it even can contain values of specific fields of the SharePoint document library item! More on this, really soon...

It must be around 16 or 17 years ago that I got my first computer on which I actually wrote some code on: a Commodore 64 (previously I had a Sinclair ZX81, but I’ve never programmed on that little black box). I vividly remember the first computer code I ever saw, it was a demo program written in Basic that was shown in a welcome demo:
10 INPUT “Number”, number
20 FOR i = 1 TO number
30 PRINT i * number
40 NEXT i

I guess these few lines are my programming roots, thanks to the incredible support I got from my father I managed to write all sorts of programs and games on this hideous brown box. Times have changed: now I have a Commodore 64 emulator running on my Pocket PC (which has around 5000 times more memory!). But of course nothing beats playing games in front of a television, so I was very delighted when I read following press announcement:

Tulip Computers N.V. (Tulip Computers) today announced that the company, together with Ironstone Partners Ltd (Ironstone), has developed a Commodore 64 (C64) mini game console with the powerful name C64 Direct-to-TV. This entertainment system for videogames is based upon the world famous Commodore 64 home PC, the most famous and well known home computer for videogames and will be brought to the market by Tulip Computers. With a simple and straightfoward to use connection to the TV, users of the C64 Direct-to-TV can play 30 popular C64 games. This will be the first of a whole series of entertainment products of which Tulip Computers will launch on the market using the Commodore name and label. (read more)

Nothing special you think? Wait, and take a look at the “case”:

Yep, it’s INSIDE a joystick! It comes with 30 games (including the legendary California Games) and it will only cost around 30 Euros. I really want to have one… :-) So what are your programming roots?

Some time ago I've posted a code snippet to solve following exception which in some cases can happen when you're calling a web service:

System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send.
at System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(WebRequest request)
at System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(WebRequest request)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at ...

It seems that this exception also pops up when using Web Services Enhancements (WSE), but the solution I provided doesn't work in that case. You can't get directly to the underlying HttpWebRequest to set the KeepAlive property to false. But recently some people posted two solutions in the comments, so all kudos goes to these people, this time I'm just the messenger! Both solutions use Reflection to get a hold of the HttpWebRequest, nice work!

Solution by Skeup&Zeb
using System;
using System.Net;
using System.Reflection;

// Web service reference entered in wizard was "MyWebService.MyWebServiceWse"
using MyProject.MyWebService;

namespace MyProject
{
    public class MySubClassedWebService : MyWebServiceWse { 
        private static PropertyInfo requestPropertyInfo = null;

        public MySubClassedWebService(){}

        protected override System.Net.WebRequest GetWebRequest(Uri uri) { 
            WebRequest request = base.GetWebRequest(uri);

            if (requestPropertyInfo==null) 
            // Retrieve property info and store it in a static member for optimizing future use 
            requestPropertyInfo = request.GetType().GetProperty("Request");

            // Retrieve underlying web request 
            HttpWebRequest webRequest = 
            (HttpWebRequest)requestPropertyInfo.GetValue(request,null);

            // Setting KeepAlive 
            webRequest.KeepAlive = false; 
            return request; 
        } 
    }
}

Solution by Schwank:
protected override System.Net.WebRequest GetWebRequest(Uri uri)

    PropertyInfo requestPropertyInfo = null;

    WebRequest request = base.GetWebRequest(uri);

    if (requestPropertyInfo==null)

    requestPropertyInfo = request.GetType().GetProperty("Request");

    // Retrieve underlying web request 
    HttpWebRequest webRequest = (HttpWebRequest)requestPropertyInfo.GetValue(request, null);

    // Setting KeepAlive 
    webRequest.KeepAlive = false;

    return request;
}

To install the Workflow Lite For SharePoint event handler, you need to complete following steps, which are described in more detail in the ReadMe.txt file that’s included in the beta release:

  • Enable SharePoint Event Handlers
  • Deploy the workflow assembly to the GAC
  • Extract and modify the config file
  • Configure settings
  • Enable the Event Handler for a Document Library

I’ve also created a video that shows each installation step and creates a simple example. Probably the most tricky part is modifying the configuration XML file. A very basic example of such a configuration file could contain following XML:

<ns0:WorkflowConfiguration xmlns:ns0="http://Leadit.SharePoint.Workflow/WorkflowConfiguration">
  <ns0:WorkflowStage DocumentLibraryURL="
http://localhost:8000/workflowinstall/Drop">
    <ns0:Description>Drop</ns0:Description>
    <ns0:Properties>
      <ns0:Property Name="Status">
        <ns0:Triggers>
          <ns0:Trigger PropertyValue="Ready">
            <ns0:Actions>
              <ns0:Action Type="COPY" Parameter1="Destination"
                  
Parameter2="" Parameter3="" />
              <ns0:Action Type="DELETESOURCE" Parameter1="" 
                   Parameter2="" Parameter3="" />
            </ns0:Actions>
          </ns0:Trigger>
        </ns0:Triggers>
      </ns0:Property>
    </ns0:Properties>
  </ns0:WorkflowStage>
</ns0:WorkflowConfiguration>

Schematic:

A configuration file contains one or more WorkflowStage nodes, each node corresponds to a stage in the workflow process, so a SharePoint document library corresponds to a WorkflowStage. The DocumentLibraryURL tag sets the location of the document library for which it should work, the Description tag is descriptive only. A WorkflowStage node can contain one or more Property nodes, contained in the Properties tag. A Property node corresponds with a field of the document library which will be used by the workflow process. The Name attribute of the Property tag should contain the name of that document library field. Each Property node can contain one or more Trigger nodes, contained in the Triggers tag. A Trigger node corresponds with a specific value of the document library field, which should be specified in the PropertyValue attribute. Finally a Trigger node can contain one or more Action nodes, contained in the Actions tag. An Action node corresponds with an action that the workflow process should execute. Each Action node has a specific type, and three optional parameter values. Here’s a list of the Action types that are currently implemented:

  • <ns0:Action Type="COPY" Parameter1="Destination" Parameter2="" Parameter3="" />
    Copies the document library item to another document library
    Parameter1: name of the destination document library
    Parameter 2 and 3: not used
  • <ns0:Action Type="SETFIELDVALUE" Parameter1="Field" Parameter2="Value" Parameter3="" />
    Sets the value of a specific field of the document library item to the specified value. The value can be any string which can contain references to other fields:
    {FIELD:field} the value of field from the originating document library item
    {NEWLINE} a new line
    {NOW} current timestamp
    Example: “Comments of reviewer: {FIELD:Comments}
  • <ns0:Action Type="DELETESOURCE" Parameter1="" Parameter2="" Parameter3="" />
    Deletes the originating document library item.
    No parameters used
  • <ns0:Action Type="CREATEEVENTITEM" Parameter1="Eventlog" Parameter2="type" Parameter3="comments" />
    Creates an eventlog item in the specified SharePoint list.
    Parameter 1: name of the SharePoint list
    Parameter 2: type of the event
    Parameter 3: comments, can contain references (see SETFIELDVALUE)
    The event list should contain following fields: Title (text), Event (text), Initiator (lookup, user information), Comments (multiple lines of text)

Generic configurable document library event handler that can be used to create simple workflow and approval scenarios in Windows SharePoint Services or SharePoint Portal Server 2003.

Finally I've completed a version that is stable enough to be released. Be aware it's still a beta version! :-) To download it, visit the GotDotNet Workspace. Also check out the demo video that shows what you accomplish with it. To install the Event Handler take following steps:

Enable SharePoint Event Handlers:
- Open "SharePoint Central Administration" from the Administrative Tools
- Click "Configure virtual server settings"
- Select a Virtual Server from the list
- Choose "Virtual server general settings"
- Select "Event handlers are: On" (bottom of the page)

Deploy the Leadit.SharePoint.Workflow assembly to the GAC:
- Extract Leadit.SharePoint.Workflow.dll to a temporary location
- Browse to X:\Windows\Assembly (or X:\WINNT\Assembly)
- Drag and drop Leadit.SharePoint.Workflow.dll into this folder
- The assembly should now be in the list

Extract the config file
- Extract Sample.xml to a folder
- Make sure the account you'll configure below has access to this folder
- Create your own config file based on the sample

Configure settings
- Make a backup of the machine.config file
  C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\CONFIG\machine.config
  or C:\WINNT\Microsoft.NET\Framework\v1.1.4322\CONFIG\machine.config
- Edit the machine.config file with NotePad
- Find the <appSettings> tag (by default it's commented out)
- Add following text between </configSections> and <system.diagnostics>
    <appSettings>
        <add key="Leadit.SharePoint.Workflow.Username" value="xxx"/>
        <add key="Leadit.SharePoint.Workflow.Password" value="yyy"/>
        <add key="Leadit.SharePoint.Workflow.Domain" value="zzz"/>
        <add key="Leadit.SharePoint.Workflow.Configfile" value="c:\folder\config.xml"/>
    </appSettings>
- xxx, yyy and zzz should be the credentials of a SharePoint account that has enough rights on your SharePoint site (for example administrator account)
- The ConfigFile tag should point the config file from the previous step
- Use the IISRESET command to force a refresh of the config settings

Enable the Event Handler for a Document Library
- Open a document library in SharePoint
- Click "Modify settings and columns"
- Choose "Change advanced settings"
- In the Event Handler section fill out following values:
  Assembly Name:
  Leadit.SharePoint.Workflow, Version=0.1.0.0, Culture=neutral, PublicKeyToken=dd064a5b12b5277a
  Class Name:
  Leadit.SharePoint.Workflow.EventHandler

I'll post more detailed installation and configuration instructions as soon as I'll find some more time. Until then I recommend to check the event log to find out what could be going wrong.

More Posts Next page »