September, 2006

  • Notes from the Field

    Flickr and .NET

    • 2 Comments

    I recently came across this article: Flickr-ing about with .NET. Anyone who has uploaded photos to Flickr or has an interest in the site can programmatically walk the site with this API. It's rather straight forward. The difficulty lies in coming up with a need for an application. I don't have all of my photos on one computer and walking. My Flickr site has shots taken over two years ago that currently reside on PCs that have gone into a closet and are collecting dust. It would be easier to pull photos from my flickr site rather than going back to those PCs. Perhaps a backup routine could store a local copy of the photos on a personal Flickr site. It could also be used to search for odd criteria. JPG Magazine accepts photo submissions for publication with the stipulation that they must be over 2200 pixel along its longest dimension. It's currently not possible to look for photos matching this criteria in Flickr's default interface. With that, we have two needs:

    • Back Up existing photos to local storage
    • Search for photos by obscure criteria
  • Notes from the Field

    Inferring SharePoint 2007 Web Service Parameters

    • 1 Comments

    The SharePoint 2007 SDK documentation for the Beta2TR is currently lacking in details around invoking the web services. One approach you can use is to use the .NET Reflector to crack open the assembly and see what the service in question does with the parameters once recieved. In this example, let's take a look at the StartWorkflow method of the Workflow web service. The web services deployed with SharePoint are in the C:\Program Files\common files\microsoft shared\web server extensions\12\ISAPI directory, including the Workflow web service, and accessible through the _vti_bin virtual director of your SharePoint site (e.g. http:\\servername\_vti_bin\webservice.asmx). Opening the workflow.asmx file in notepad.exe reveals that the work is done in the Microsoft.Office.WorkflowSoap assembly. Two locations I've searched for SharePoint assemblies are either across all  subdirectories of C:\Program Files\common files\microsoft shared\web server extensions\12 and the GAC. In this case, the Microsoft.Office.WorkflowSoap.dll, is located in the ...\12\Config\bin so once we load it into Reflector, we can see what the StartWorkflow method really does. The current Beta2TR SDK shows the following:

    public XmlNode StartWorkflow ( string item, Guid templateId, XmlNode workflowParameters )

    Walking through the dissassembled code in Reflector shows that it uses the internal WorkflowImpl class to then invoke the StartWorkflow method on the SPWorkflowManager class and that the first parameter is the URL to the file on which the workflow will perform, the second is the GUID of the SPWorkflowAssociation object defining the association between the hosting document library and a workflow and, finally, the third parameter is the data that's passing into the workflow upon initialization.

    While we might have been able to infer these parameters from reading the StartWorkflow methods defined in the SDK on the Workflow web service and on the SPWorkflowManager and taking an educated guess as to how they're invoked, walking through the disassembled code removes all doubt. Clearly, the same technique can be applied to any of the other web services.

  • Notes from the Field

    Infopath Form Serialization and Schema Names

    • 1 Comments

    If you are working with SharePoint 2007 workflows, then you've probably had a need to serialize and deserialize InfoPath forms xml data based on the instructions here: How to: Access Association and Initiation Form Data in a Workflow. I've found that running the xsd.exe on the myschema.xsd exported in the source files of an Infopath form results in a root class defined as follows:

    ...
    [System.Xml.Serialization.XmlRootAttribute(Namespace="http://schemas.microsoft.com/office/infopath/2003/myXSD", IsNullable=false)]
    public partial class myFields {
    ...

    That myFields class name irks me a bit. The instructions referenced in the HowTo article above includes the following text to address this:

    Specifying a unique name for the form fields collection, rather than using the default name of myfields, helps ensure the class that is generated from the form schema file also has a unique name. This is especially important when you are programming a workflow that uses multiple forms.

    However, you might not have control over the form design if you are not creating the forms yourself. Rather than editing the code in the generated scheme, you can alter the name of the myFields class inside the InfoPath form before generating your concrete class with xsd.exe.

    ...
    [System.Xml.Serialization.XmlRootAttribute(Namespace="http://schemas.microsoft.com/office/infopath/2003/myXSD", IsNullable=false,ElementName="myFields")]
        public partial class InitWorkflow {
    ...

    Specifying the ElementName in the XmlRootAttribute maintains compatibility with the xml document while allowing for a more logical class name. The price paid lies in the alteration of a tool-generated class. If xsd.exe is run against the myschema.xsd source file, then this manual change will need to be re-applied.

  • Notes from the Field

    Recover Documents from SharePoint 2003 Database

    • 7 Comments

    This will not work with MOSS 2007. If you are looking for a MOSS 2007 solution for recovering document go here: 

    Recover Documents from MOSS 2007 Database

    At some point a file will be accidentally deleted from a SharePoint library. There are tools to guard against unintentionally file deletions such as the Recycle Bin for SharePoint 2003, but it's not installed with the product out of the box. Incidentally, MOSS '07 comes with a recycle bin. However, with SPS 2003/WSS 2.0 if a user deletes a file most often the recovery path is to restore a backup copy of the appropriate content database and extract the file. Building the backup environment can be time consuming. Instead, the file can be extracted by going directly against a restored copy of the content database with a simple VB Script. This approach is rather old school. It could have been done with a .NET exe to do the job, but it takes so little code that it didn't seem worthwhile to put together a compiled assembly and include parameter handling logic.

    A few disclaimers are necessary. This script goes directly against a SharePoint 2003/WSS 2.0 content database which is generally discouraged. Any code using the database directly will not be supported by MS Product Support Services. Instead, the SharePoint and WSS APIs are the way to go. If the database is modified directly rather than through the published SharePoint and WSS APIs Product Support Services cannot properly troubleshoot any unexpected issues. This script reads from the database so we're safe from errant modifications. However, the data structure the script queries could change in a future service pack. This will not work with MOSS 2007. The need for this kind of approach should be reduced with the introduction of the MOSS 2007 Recycling Bin.

    With that out of the way, let's proceed. The script queries the Docs table which contains the application documents and retrieves the most current version based on the document name which is then streamed out as binary data to a file:

    Set cn = CreateObject("ADODB.Connection")
    Set rs = CreateObject("ADODB.Recordset")
    cn.Open "Provider=SQLOLEDB;data Source=[SERVERNAME];Initial Catalog=[DATABASE_NAME];Trusted_Connection=yes"
    Set rs = cn.Execute("SELECT Content FROM Docs WHERE LeafName = 'FILENAME.EXT'")
    Set mstream = CreateObject("ADODB.Stream")
    mstream.Type = 1
    mstream.Open
    mstream.Write rs.Fields("Content").Value
    mstream.SaveToFile "C:\FILENAME.EXT", 2
    rs.Close
    cn.Close

    Copy this code into Notepad and ,naturally , replace your [SERVERNAME], [DATABASE_NAME], and FILENAME.EXT with appropriate values. Save this file as a VBS script and execute from the command line as:

    C:\>CSCRIPT ExtractDoc.vbs

    Note that the SQL Query is rather straight-forward. It simply looks for a file according to the LeafName which corresponds to the document name. The code assumes that there will be at least one row returned. It doesn't do any check should the query return zero rows. It's recommended that the query executed in the script is first tested in SQL Query Analyzer to ensure that you retrieve the expected single result. The same file name found in more than one document library or folder you'll have multiple results. There's no guarantee that the first file returned will be the file you want. Use other values in the Docs table to narrow the file down to one, then paste the desired query into the script.

    This is certainly not something to use in a production environment where automated document retrieval must be a repeatable and reliable process. But it is a quick and dirty means of extracting a document from a restored database that spares you from the overhead of restoring a SharePoint/WSS environment.

    Update: I recently came across a post for SPExplorer. It's a tool for walking a SharePoint 2003 database directly rather than through an API and related blog that mentions SP Explorer mentions that it has the ability to extract documents.

Page 1 of 1 (4 items)