Next generation's garbage RSS 2.0
# Monday, June 01, 2009
I'm kinda surprised I haven't run into this situation before. I need to execute two web requests in series (because the second call depended on information from the first) against an array of values. Naturally, I wanted the array to perform in parallel, but how to get the second call to either execute automatically after the first call is done or force execution if requested before the second call is made.

Here's the pattern I came up with:
    Public Class TwoPartRequest
        Private req1, req2 As HttpWebRequest
        Private res1, res2 As IAsyncResult
        Private run1, run2 As Integer
        Private coolResult As CoolObject

        Public Sub New(ByVal url As String)
            req1 = WebRequest.Create(url)
            req1 = req1.BeginGetResponse(AddressOf Part1Complete, Nothing)
        End Sub

        Private Sub Part1Complete(ByVal ar As IAsyncResult)
            If System.Threading.Interlocked.Increment(run1) = 1 Then
                Using resp As HttpWebResponse = req1.EndGetResponse(ar)
                    Dim url As String = FigureOutNextUrlUsingResponse(resp)
                    req2 = WebRequest.Create(url)
                    res1 = req2.BeginGetResponse(AddressOf Part2Complete, Nothing)
                End Using
            End If
        End Sub

        Private Sub Part2Complete(ByVal ar As IAsyncResult)
            If System.Threading.Interlocked.Increment(run2) = 1 Then
                Using resp As HttpWebResponse = req2.EndGetResponse(ar)
                    coolResult = BuildResultUsingResponse(resp)
                End Using
            End If
        End Sub

        Public Function Result() As CoolObject
            Part1Complete(res1)
            Part2Complete(res2)
            Return coolResult
        End Function
    End Class
To use this, I have a list of these objects that I new up in a loop. In a second loop, I get all the results. If the target server can process requests in parallel well the number of iterations on the loop shouldn't matter.

Clearly, one could generalize the heck out of this, but I happy with it working.

Monday, June 01, 2009 5:10:03 PM (US Mountain Standard Time, UTC-07:00)  #    Comments [0] -

# Thursday, June 19, 2008
SharePoint has a great API for most things, but some of things seem a bit lacking.

I recently had a need to auto-create folders inside a document library. Basically, like mkdir with command extensions does on the command line. If directory x exists, but x\y doesn't, mkdir x\y\z will mkdir x\y and mkdir x\y\z.

After some struggling, here's what I ended up with:

    Public Shared Sub CreateDocLibFolders(ByVal url As String)
        Using site As New SPSite(url)
            Using web As SPWeb = site.OpenWeb()
                If url.StartsWith(web.Url) Then
                    Dim folder As SPFolder = web.RootFolder
                    For Each segment As String In url.Substring(web.Url.Length + 1).Split("/")
                        Dim nextfolder As SPFolder = web.GetFolder(folder.Url & IIf(folder.Url.Length > 0, "/", "") & segment)
                        If Not nextfolder.Exists Then
                            folder = folder.SubFolders.Add(nextfolder.Name)
                        Else
                            folder = nextfolder
                        End If
                    Next
                End If
            End Using
        End Using
    End Sub


Okay, I know it doesn't look like much, but that code represents some hard won knowledge. The main thing was dealing with folders that had spaces in them. Before, I was System.Web.HttpUtility.UrlDecode()ing them, but my use of .Name on a .Exists=false proved to be much more elegant. Even though I'm doing a GetFolder on a escaped url, the .Name property returns a nice, suitable for passing into SubFolders.Add(), de%20ed name. But why use this ugly indirect path string building technique? Well, I could not find an exception-free way of doing existence testing of a folder other than web.GetFolder() which, of course, needs a web relative url -- this lead to the more clunky looking GetFolder expression.
RaiseEvent OnReligiousArgument
For the two people that read this blog (me and uh, that might be an exagerated figure) the reason my snippets have been in VB.NET lately is because I think VB.NET is underloved in the SharePoint community. VSEWSS, for example, is a C# only club. Heck with that. It doesn't provide enough juice to justify the opaqueness of its wsp builder. VB.NET has some nice features and I like taking advantage of them -- I know both cold and I make no apologies for choosing VB.NET. If you are one of those C# 1337ists... run the benchmarks and tell me its so much better. Tell me what it does so much better that it makes up for the utter lack of exception filters, XML literals (VB9), pleasant event raising, beyond 1980s-era switch/select case, optional parameters, automatic by-reference parameters for callers, array resizing, and procedure scoped static vars. I'm not saying C# is worse -- it's like the difference between ibuprofen and acetaminophen. Minor advantages in some edge cases both ways but they all fix most headaches.

I've seen some comparisons between the two languages before on the net, but none seemed entirely complete. If I ever am put in jail with nothing but a toilet and a laptop for a few years, perhaps I'd blog /the/ definitive list.

For those of you thinking of writing in your reasons why C# is soooo superior to VB.NET, please refer to the Logical Fallacy article on Wikipedia before embarrassing yourself. Reasons like "real programmers use semicolons" or "only a moron would use a language with the word 'basic' in the name" will be ridiculed mercilessly. There are some valid arguments for C# and one could make an equally compelling valid case for it over VB.NET.

Thursday, June 19, 2008 2:20:09 AM (US Mountain Standard Time, UTC-07:00)  #    Comments [1] -
.NET Internals | SharePoint
# Thursday, June 12, 2008

SharePoint advertises the fact that you can access files on a document library via WebDAV. This is done via \\{server}\{site}\{doclibname}\ and you can easily get to it with the list menu under "Actions", "Open with Windows Explorer". A lesser known fact is that you can also use WebDAV to access the attachments collection of a list with attachments enabled. This is done via \\{server}\{site}\Lists\{listname}\Attachments\{listitemid}\

You should be aware that the WebDAV folder for the list item will not exist until a file has been added to the attachment collection. If you need it to always exist, you can make an ItemAdded event handler that simply adds a file and deletes it, like this:

Public Overrides Sub ItemAdded(ByVal properties As Microsoft.SharePoint.SPItemEventProperties)
   Const tempFileName As String = "deleteme.txt"
   If item.Attachments.Count = 0 Then
      Try
         Me
.DisableEventFiring()
         item.Attachments.AddNow(tempFileName, System.Text.Encoding.ASCII.GetBytes("This is a temporary file. If you find it, please delete it."))
         item.Attachments.DeleteNow(tempFileName)
         ' Here we also save a WebDAV hyperlink
         Dim u As New Uri(item.Attachments.UrlPrefix)
         item("AttachmentsLink") = String.Format("file://{0}{1}, Attachments", u.Host, u.AbsolutePath))
         item.Update()
      Finally
         Me.EnableEventFiring()
      End Try
   End If
End Sub

In the code above, I also set a hyperlink field so the user has easy access to the WebDAV view of the list item. I simply added a hyperlink column called "AttachmentsLink" to the list.

If you are having trouble using the WebDAV access, be sure that your WebClient service is enabled and started, which is NOT the default on Windows Server 2003.

There is a series of ItemAttachment events available and as I mentioned before, the documentation for them is not very good. Hint: properties.AfterUrl will indicate the added file. .BeforeUrl will indicate the file being deleted.

BUG: The thing to watch out for is that when using WebDAV, the ItemAttachment events don't fire, but instead, an item event fires with .AfterUrl or .BeforeUrl set, which it wouldn't ordinarily -- you can use this fact to choose to reroute Item events to the appropriate ItemAttachment events in your event code. It would be nice if you could poke in the proper properties.EventType, but it's read-only so you need to make sure that any part of your ItemAttachment event code can handle that.

Public Overrides Sub Item{Whatever}(ByVal properties As Microsoft.SharePoint.SPItemEventProperties)
   ' Reroute for WebDAV event bug
   If properties.AfterUrl IsNot Nothing AndAlso properties.AfterUrl <> "" Then ItemAttachmentAdding(properties) : Exit Sub 'or ..Added( if -ed event.
   If properties.BeforeUrl IsNot Nothing AndAlso properties.BeforeUrl <> "" Then ItemAttachmentDeleting(properties) : Exit Sub 'or ..Deleted( if -ed event

   ' Normal event code follows

End Sub

Thursday, June 12, 2008 4:50:50 PM (US Mountain Standard Time, UTC-07:00)  #    Comments [0] -
SharePoint
# Monday, June 09, 2008

VMware workstation allows a maximum of 950GB. That's quite a bit more than VirtualPC 2007 allows. So what's my advise on sizing? As before, do the max.

Windows Server 2003R2 install makes 1,637,548,032 byte .vmdk. Still under 8% difference.

"But I don't want to pay the extra 117MB." Really? That's pretty cheap compared to what the space required to install a partition resizer later along with your time.

"But I'm only going to use this virt for a couple of things." Great. Then when you are done and delete it, you'll get a full refund of your extra space.

"I don't want my virt blowing up my main machine by causing it to run out of disk space." You could enable disk quotas.

Monday, June 09, 2008 4:55:36 PM (US Mountain Standard Time, UTC-07:00)  #    Comments [0] -
Virtualization
# Friday, June 06, 2008

Don't be a cheapskate when VirtualPC 2007 asks you how much disk space to allocate for your machine. Do the max! I just did a comparison of three identical installs of Windows Server 2003 on a 8GB, 64GB and a 132GB (which is the max) disks. The difference? Less than 2.5%. Here's the numbers:

8GB - 1,514,532,352 bytes
64GB - 1,537,721,344 bytes (22MB more)
132GB - 1,552,535,040 bytes (36MB more)

But why pay that extra space? If you ever had to grow one, you'd know why.

But why 132GB? I don't even had that much space on my drive? Sure, but the beauty of a virtual disk is that you can copy it off to another machine.

That's a key point: Your virtual machine may outlive your real hardware.

I'm gonna guess the difference on VMware is similiar.

Friday, June 06, 2008 6:20:00 PM (US Mountain Standard Time, UTC-07:00)  #    Comments [0] -
Virtualization
# Thursday, June 05, 2008

It's not at all clear from the documentation nor is it logically located in the object model, but when you get a SharePoint attachment event (like ItemAttachmentAdding, ItemAttachmentAdded, ItemAttachmentDeleting, ItemAttachmentDeleted) you get the properties.Attachment collection, but the affected attachment is indicated by the properties.AfterUrl property which gives a web.Url relative url to the attachment being evented on.

Thursday, June 05, 2008 4:09:49 PM (US Mountain Standard Time, UTC-07:00)  #    Comments [0] -
SharePoint
# Sunday, May 18, 2008
Sunday, May 18, 2008 5:36:17 PM (US Mountain Standard Time, UTC-07:00)  #    Comments [1] -

# Friday, May 16, 2008

Not actually supported. You really need to -o backup your SC before you do it. If you didn't, try at least to backup your 12.0/Secure key in regedit and copy the \Windows\SysMSI\*\*.cer. The content is PKI protected. I've dorked up a WSS3 install royally this way.

Friday, May 16, 2008 12:11:30 AM (US Mountain Standard Time, UTC-07:00)  #    Comments [0] -
SharePoint
Archive
<July 2009>
SunMonTueWedThuFriSat
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678
All Content © 2010, Hafthor Stefansson - Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way. - Sign In