•  
    September 1st, 2009stuartwhitefordSharePoint

    In an attempt to solve the issue of the never-ending workflow I kicked off the installation of Service Pack 2 for WSS and MOSS this morning. Both updates installed successfully but both failed during the Products and Technologies Configuration Wizard.

    Investigating the PSCDiagnostics log I found the following line: -

    09/01/2009 08:32:26  8  ERR            The B2B upgrader timer job failed.

    and in the Upgrade log: -

    [SPIisWebSiteWssSequence] [ERROR] [9/1/2009 7:57:04 AM]: Access to the path 'C:\Inetpub\wwwroot\wss\VirtualDirectories\portal.stuartwhiteford.org80\App_GlobalResources\cms.en-us.resx' is denied.

    Q. Why would access be denied?

    A. Because the root web directory is a web project in Visual Studio, is under source control and is checked in.

    So, the resolution is either to check the project out from Visual Studio or change the attributes using Windows Explorer.

    Tags:
  •  
    June 29th, 2009stuartwhitefordJavaScript, SharePoint

    I’ve been working with a serial device that captures a signature recently and one of the methods of its associated ActiveX control lets me have a VBScript array of bytes that represents the captured image. It’s a reasonably simple method to convert this into a JavaScript array of bytes and I thought that once I had this it would be easy enough to call the SharePoint web services using jQuery’s built-in AJAX methods. Calling the web service is a piece of cake but it won’t just accept an array of byes, it needs to be a Base64 encoded string, so what follows is how to get yourself one of those from the aforementioned array of bytes and pass it to the Copy web service.

    For a good description on how to achieve Base64 encoding have a look at the example on this Wikipedia page.

    Firstly, the table variable contains the allowable character in a Base64 encoded string. The OctetPad() function pads a given string parameter to 8 characters in length with zeroes. The Decimal() function accepts a string parameter in binary format and converts it to its decimal equivalent.

    The Base64String() method accepts an array of bytes and deals with them in chunks of 3 at a time. It converts each byte to a bit pattern and then concatenates them into a single bit pattern having a length of 24. This bit pattern is split into 4 chunks of 6, converted to a decimal number and the character from the table variable at the index equal to the decimal number is appended to the encoded string.

    If the length of the array is not a multiple of 3 then we deal with the remaining 1 or 2 bytes in a slightly different manner. If there are 2 bytes remaining construct the bit pattern with these 2 bytes (giving us 16 bits) and add 2 zeroes to the end to give us 18 bits (divisible by 6). In this case we manually set the fourth Base64 encoded chracter to “=”. If there is 1 byte remaining construct the bit pattern with this single byte (giving us 8 bits) and add 4 zeroes to the end to give us 12 bits (again, divisible by 6). In this case we manually set the third and fourth Base64 encoded chracters to “=”.

    var table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     
    function OctetPad(str) {
        return Array(8 + 1 - str.length).join("0") + str;
    }
     
    function Decimal(bin) {
        var len = bin.length;
        var ans = 0;
        var plc = len - 1;
        for (i = 0; i < len; i++) {
            if (bin.substr(i, 1) == 1) {
                ans = ans + Math.pow(2, plc);
            }
            else if (bin.substr(i, 1) != 0) {
                return;
            }
            plc--;
        }
        return ans;
    }
     
    function Base64String(bytes) {
        var base64 = "";
        while (bytes.length > 0) {
            var byte1 = null;
            var byte2 = null;
            var byte3 = null;
            var enc1 = null;
            var enc2 = null;
            var enc3 = null;
            var enc4 = null;
            byte1 = bytes.shift().toString(2);
            if (bytes.length > 0) {
                byte2 = bytes.shift().toString(2);
                if (bytes.length > 0) {
                    byte3 = bytes.shift().toString(2);
                }
                else {
                    enc4 = "=";
                }
            }
            else {
                enc3 = "=";
                enc4 = "=";
            }
            var bitPattern = OctetPad(byte1) + (byte2 != null ? OctetPad(byte2) : "00") + (byte3 != null ? OctetPad(byte3) : "00");
            enc1 = table.charAt(Decimal(bitPattern.substr(0, 6)));
            enc2 = table.charAt(Decimal(bitPattern.substr(6, 6)));
            if (enc3 == null) { enc3 = table.charAt(Decimal(bitPattern.substr(12, 6))); }
            if (enc4 == null) { enc4 = table.charAt(Decimal(bitPattern.substr(18, 6))); }
            base64 = base64 + enc1 + enc2 + enc3 + enc4;
        }
        return base64;
    }

    Our Upload() function makes use of the jQuery ajax method and looks like the following: -

    function Upload(jsArray, sourceUrl, destinationUrl) {
        var jsStream = Base64String(jsArray);
        var soap12Env =
            "<soap12:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap12='http://www.w3.org/2003/05/soap-envelope'> 
                <soap12:Body> 
                    <CopyIntoItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'> 
                        <SourceUrl>" + sourceUrl + "</SourceUrl> 
                        <DestinationUrls> 
                            <string>" + destinationUrl + "</string> 
                        </DestinationUrls> 
                        <Fields> 
                            <FieldInformation Type='File' /> 
                        </Fields> 
                        <Stream>" + jsStream + "</Stream> 
                    </CopyIntoItems> 
                </soap12:Body> 
            </soap12:Envelope>";
        $.ajax({
            url: "http://sharepoint/_vti_bin/copy.asmx",
            type: "POST",
            dataType: "xml",
            data: soap12Env,
            contentType: "text/xml; charset="utf-8""
        });
    }

    I’ve fixed the value of the SharePoint web service URL in this function but it’s probably a better idea to have it passed in as a parameter to the function. All we’re doing here is creating a SOAP envelope for the Base64 stream of characters and the method would be called as follows: -

    var jsArray = new Array(71,73,70,56,57,97,2,0,2,0,241,0,0,255,255,0,255,0,0,51,204,0,0,0,255,44,0,0,0,0,2,0,2,0,0,2,3,12,52,5,0,59);
    var sourceUrl = "test.gif";
    var destinationUrl = "http://sharepoint/ImageLibrary/test.gif";
    Upload(jsArray, sourceUrl, destinationUrl);

    In this example I’ve set the sourceUrl parameter to the file name we want to give the image when uploaded, this works around the “This item is a copy of…” issue when using the Copy web service.

    Tags: , ,
  •  
    June 29th, 2009stuartwhitefordHardware

    Recently, my Lacie Big Disk (500GB) died on me. It just stopped appearing as a drive on my PC and I tried it on other machines without success. Looking at some of the forum posts it appeared as if it was going to be one of two problems. Either one (or both) of the drives had failed or the internal controller had failed.

    Hoping that it was the controller I decided to get myself another one (eBay to the rescue). Taking both of them apart I swapped the drives from the bust one into the bought one, plugged it in and voila, it worked! So, I copied off all the stuff I wanted to keep then took it apart again.

    Now I had four 250GB drives sitting and I can only put two back into the Lacie enclosure. That wouldn’t do at all. I acquired myself a 3Ware RAID card (eBay again), albeit an older model as it had to support IDE drives not SATA. On arrival, off came the PC cover and in went the card and the four drives. I fired up the machine and opted for a RAID5 configuration giving me 750GB-ish, left it to format the drives and build the array for a few hours.

    Once in Windows I installed the drivers downloaded from the 3Ware support site. I had to force Vista to allow the unsigned drivers but other than that all went smoothly, and now I have 700GB+ fault tolerant drive in my PC. So if you’ve got an external hard drive, Lacie or otherwise, that’s broke and there’s a chance it’s not the disk itself then there just might be some of getting your data back and re-using the disk.

    Tags: , ,
  •  
    March 16th, 2009stuartwhiteford.NET, C#

    This is the code I used in response to an answer to a question I posted on stackoverflow.

    Briefly, I was wondering how to hold a reference to the parent object in one of it’s children when deserializing the following hierarchical XML: -

    <report xmlns="http://schemas.stuartwhiteford.com/">
        <id>1</id>
        <dateCreated>2009-03-16</dateCreated>
        <title>Report Title</title>
        <subTitle>Report SubTitle</subTitle>
        <sections>
            <section>
                <id>2</id>
                <title>Section</title>
            </section>
        </sections>
    </report>

    The answer was to use the DataContractSerializer, which is used to serialize and deserialize data sent in Windows Communication Foundation (WCF) messages. For this to work though, we need to modify our XML slightly to include references between the parent and child elements: -

    <report z:Id="1" xmlns="http://schemas.stuartwhiteford.com/" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
        <id>1</id>
        <dateCreated>2009-03-16</dateCreated>
        <title>Report Title</title>
        <subTitle>Report SubTitle</subTitle>
        <sections>
            <section z:Id="2">
                <report z:Ref="1" xsi:nil="true"/>
                <id>4</id>
                <title>Section</title>
            </section>
        </sections>
    </report>

    Here’s the code required to deserialize: -

    using System;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Xml;
     
    namespace ReportSample
    {
     
        [DataContract(Name = "report", Namespace = "http://schemas.stuartwhiteford.com/")]
        public class Report
        {
     
            private int _id;
            private DateTime _dateCreated;
            private string _title;
            private string _subTitle;
            private Sections _sections;
     
            [DataMember(Name = "id", Order = 1)]
            public int ID
            {
                get
                {
                    return _id;
                }
                set
                {
                    _id = value;
                }
            }
     
            [DataMember(Name = "dateCreated", Order = 2)]
            public DateTime DateCreated
            {
                get
                {
                    return _dateCreated;
                }
                set
                {
                    _dateCreated = value;
                }
            }
     
            [DataMember(Name = "title", Order = 3)]
            public string Title
            {
                get
                {
                    return _title;
                }
                set
                {
                    _title = value;
                }
            }
     
            [DataMember(Name = "subTitle", Order = 4)]
            public string SubTitle
            {
                get
                {
                    return _subTitle;
                }
                set
                {
                    _subTitle = value;
                }
            }
     
            [DataMember(Name = "sections", Order = 5)]
            public Sections Sections
            {
                get
                {
                    return _sections;
                }
                set
                {
                    _sections = value;
                }
            }
     
        }
     
        [DataContract(Name = "section", Namespace = "http://schemas.stuartwhiteford.com/")]
        public class Section
        {
     
            private Report _report;
            private int _id;
            private string _title;
     
            [DataMember(Name = "report", Order = 1)]
            public Report Report
            {
                get
                {
                    return _report;
                }
                set
                {
                    _report = value;
                }
            }
     
            [DataMember(Name = "id", Order = 2)]
            public int ID
            {
                get
                {
                    return _id;
                }
                set
                {
                    _id = value;
                }
            }
     
            [DataMember(Name = "title", Order = 3)]
            public string Title
            {
                get
                {
                    return _title;
                }
                set
                {
                    _title = value;
                }
            }
     
            public string Key
            {
                get
                {
                    return _id.ToString();
                }
            }
     
        }
     
        public class Sections : KeyedCollection<string, Section>
        {
     
            protected override string GetKeyForItem(Section item)
            {
                return item.Key;
            }
     
        }
     
        class Program
        {
     
            static void Main(string[] args)
            {
                try
                {
                    DataContractSerializer dcs = new DataContractSerializer(typeof(Report), null, int.MaxValue, false, true, null);
                    FileStream fs = new FileStream(@"C:\OfficeReportsReportSample.xml", FileMode.Open);
                    XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
                    Report r = (Report)dcs.ReadObject(reader, true);
                    reader.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                    Console.ReadLine();
                }
            }
     
        }
     
    }

    References

    Tags: , , ,
  •  
    March 15th, 2009stuartwhiteford.NET, C#

    Let’s finish this trilogy off Revenge Of The Sith style (going through the motions, nobody really cares anymore, etc.). I have to admit to cheating a bit with this one. I used the DocumentReflector tool that comes with the SDK, mainly because my attempts to create a presentation from scratch were proving fruitless and it seems you need a fair amount of code just to create the most basic of presentations.

    Given the increased amount of code I’ve decided to provide it as a download rather that display it in the page. You can get it from here.

    That’s enough Open XML for now. Something different next time I think.

    Tags: , , ,
  • « Older Entries

    Newer Entries »