Migrating Wiki Pages Remotely – Part 01
I was doing some work recently where I needed to move a large volume (thousands) of Wiki Pages from one server to another. The problem was that while if I begged and pleaded, I probably could have gotten local admin access to the farms, I didn’t really want to go through that if I didn’t have to. I wanted to be able to manage the relocation of my Wiki Libraries from my client machine and not have to touch the server locally if I could help it. How do you do this kind of thing? Web Services of course… sounds simple right? Well, that’s what I thought until I gave it a try. As it turns out, it is very easy to use lists.asmx to pull all the data you want. You can do it for Wiki Libraries just like you would for any other list type.
In case you didn’t already figure this out, lucky you, I’ve done all the work for you already. If you are an adventurous or savvy developer, you could stop reading right here and go give it a shot. Otherwise keep reading and see how I made this all go. I have split up a much longer document into a series of posts where I will step through the different parts of the code and talk about the logic/etc behind them. I did this so that I was more reasonable on your RSS readers (my docx is 19 pages long). I will finish the final piece with a single post providing all of the code together.
I will say that some of the scenarios I had to deal with are not ones that I would expect many people to encounter. Some of the source servers I was working with had databases that had been around since Beta, even Alpha stages of SharePoint 2007. This situation led to a few things that just wouldn’t work using conventional methods. I don’t expect many readers will have to deal with these same things I ran into that I had to code around. I’ll be the first to say it—my code is a bit bloated as a result. However, I did want to share it in its entirety so you could benefit from seeing how I dealt with various problems. I would encourage you to hunt and peck my code any try the different code paths separately in your environment until you find what works for you instead of throwing everything at it at once.
Before I dig in, here are a few notes you should know and a screenshot of my final UI so that some of the object names will make a little more sense:
Note 1: I only cared about the current version of the Wiki Pages—so none of my code or methodologies will include handling history. This should be accessible though, and I see no reason why wouldn’t be able to migrate if you felt like writing the extra code.
I was too lazy It was out of spec :) to make this a multithreaded application, so I put all my logging on the TraceListener. You can use DbgView from sysinternals to watch the Trace.Write statement output fly by.
Note 3: When I use the lists.asmx GetListItems method, I am passing in the value in txtNumberRows because, otherwise we will use the number of rows configured in the view on the list. By default this is 100. If you have less than 100 Wiki Pages, this isn’t a problem. Otherwise it is. A workaround would be to alter the default view to return more rows and continue to pass null instead of txtNumberRows value.
Note 4: In the posts with commentary, I’ve removed all the action in the catch blocks—if you want to see my error tracing/etc, you can look in the final post. You also may notice that most of these code snippets aren’t full methods and don’t close out all of the braces/etc.
Note 5: Server1WS points to lists.asmx. Server1CopyWS points to copy.asmx. I created separate Server2 versions of these because at times I was using multiple at the same time and wanted them to be separate live objects in memory. This could be cleaned up—I thought it made it easier to follow the code if you were seeing it for the first time.
Note 6: Just as a generic disclaimer, as you might imagine this code and resulting tool is not considered production worthy. It was not tested and as a tool would be “unsupported” by Microsoft Product Support. I am sharing it simply to help save you some time in your own development efforts.
We will dive into some of the code with the next post.