Microsoft Documentation

October 31, 2007

Does anyone else despise Microsoft’s documentation?

I’m used to the help in Notes – it tells you everything you need to know about a given property or method, as well as a sample of the simplest script you would need to use that object.

Microsoft tells you… syntax. And lists methods. No samples… or sometimes HUGE monolithic code samples that they use to illustrate eleventeen methods in one sample, and expect you to spend hours sorting through it to find which part applies to the answer you actually seek.

Well, in this case, the question applies to the SharePoint API — specifically, SPField.TypeAsString. Very simple method, very easy to understand and use. But nowhere can I find a list of the possible return values. I found some sample code that gives me some of the values. And I could go create a list with a field of every type, and see what comes back… but shouldn’t I be able to find this via documentation somewhere?

 Update:

I went ahead and wrote some code to see what would come back. I came up with the following list:

  • Attachments
  • Boolean
  • Calculated
  • Choice
  • Computed
  • ContentTypeID
  • Counter
  • CrossProjectLink
  • DateTime
  • File
  • Guid
  • Integer
  • Lookup
  • ModStat
  • MultiChoice
  • Note
  • Number
  • Recurrence
  • Text
  • ThreadIndex
  • URL
  • User

At the risk of being mocked for my lacking C# skillz, I thought I’d post another code snippet.
(And at the risk of losing traffic, because it seems that whenever I post code, Google stops sending me traffic for a couple days.)

One thing we have encountered as part of our migration is the need to make a change to an entire environment. (Modifying ACLs, etc.) In Notes, AdminP can do some of this for you, but when the change needs some calculated logic, you need to script it. Notes has the NotesDbDirectory object which handles this nicely for you.

But it got me thinking – what if you wanted to traverse your entire SharePoint environment? What would that code look like? So I sat down this morning, and spit out the code below.
It is just a recursive call to each site’s subsites, which gives you an opportunity to do something at each site.

static void Main(string[] args)

{

SPSite rootSite = new SPSite(”http://yourserver”);

SPWeb site;

SPWebCollection children; site = rootSite.OpenWeb();

DoYourStuff(site);

//Traverse SP hierarchy

children = site.GetSubwebsForCurrentUser();

if (children.Count > 0)

{

ProcessChildren(children);

}

}

static void ProcessChildren(SPWebCollection sites)

{

foreach (SPWeb site in sites)

{

DoYourStuff(site);

SPWebCollection children;

children = site.GetSubwebsForCurrentUser();

if (children.Count > 0)

{

ProcessChildren(children);

}

}

}

Business Data Catalog

October 26, 2007

One of the reasons that an organization would want MOSS instead of just the basic SharePoint services is for the Business Data Catalog (BDC). In short, this allows you to use your existing enterprise data as a data source within Sharepoint. No need to synchronize your list of customers or vendors between systems – just use your existing system.

I can see where the BDC would become a critical component of your apps.
But that is also exactly my concern – I can foresee it becoming a maintenance nightmare, as changes to your other systems can now impact your SharePoint environment. So I’m curious – has anyone out there actually been using the BDC long enough to develop any best practices on configuration & maintenance?

Technology Evangelism

October 25, 2007

Just a quick note this morning…
I found the following link (via www.lotusviralmarketing.com):

http://www.allthingsdistributed.com/historical/archives/000141.html

It is a nice first-person, real-world explanation of why postioning yourself as a proponent for one specific technology can actually hurt your credibility and weaken the message you are trying to present.

I’ve been trying to live a balanced life for years, focusing on the problem, not the technology. And today, even as my organization is trying to move away from Notes, I am in a position to stop specific migration decisions if they are… well, to be blunt…. if they are technically stupid. I know other people who are basically ignored in such discussions because people do not believe they have a balanced perspective.

Once again, comments and emails have given me some insight into questions and false assumptions that some Notes people may have.

Namely, they assume that the recommendations given by Microsoft partners will apply to a Notes migration. And while certainly much of their technical advice is valid, the underlying viewpoint of a Microsoft partner is going to miss an extremely important piece of information about a Notes shop:

The current collaboration in a Notes shop is NOT based around Microsoft Office. Notes people do not email spreadsheets back and forth. They do not use Access databases, or share documents via email. They already have a collaboration infrastructure in place, and are not starting from scratch.

Sharepoint was designed to give organizations their first stab at collaboration. Its primary strength is to take Office documents, and share them on the web. While I am sure this is a great help to many organizations, as a Notes professional, it just doesn’t impress me that much.. SharePoint is an immature product. It has flaws and weaknesses, and we have already addressed some of them on this blog.

But those weaknesses get exaggerated when we go out deliberately looking for flaws, and this type of exaggeration is exactly what I want to avoid here. Let’s call out the weaknesses, but lets not spin SharePoint’s faults into something worse than it really is.

With that in mind, lets talk about MOSS. MOSS is the “Microsoft Office SharePoint Server.” It adds functionality to SharePoint. But not as much as people think. the plain old freebie SharePoint install is what gives you most of the programmability of SharePoint. And because a Notes shop is already used to doing a certain level of development for their apps, that is the level of complexity that most Notes shops really need.

So when you see lists of the technologies from Microsoft that you must install and learn to run a SharePoint environment, take them with a grain of salt. Maybe in the future, your organization will reach that level of complexity. But to start a migration, you really just need a few things, most of which you probably already have:

  • Web Server (IIS/ASP.NET, with SharePoint services installed)
  • SQL Server  (technically optional, but realistically you need it to have any scalability.)
  • Exchange Server (and even this is optional)
  • Backups for the above. :)

What I am finding is that because SharePoint has limitations and weakneses on its programmability, most Notes professionals do not accept its built-in functionality. So they step down into C#, and write custom .NET code. And while people will tell you that this is much harder than using the rest of the Microsoft platform, it greatly simplifies your infrastructure needs. (Not to mention costs.)

Again – as your Microsoft platform grows, you probably will add on more tools and end up with a more complex infrastructure. But the assumption  that it takes a  ton of effort to get going on SharePoint just isn’t correct.

What should not migrate?

October 23, 2007

A question has indirectly risen, both in online and offline conversations, of how we would define which applications should NOT be migrated to a new platform. Assuming that a small subset of Notes functionality will remain in the organization, what features or functions would lead you to  not even attempt a migration?

My answer would be the following:

1) Any application that truly needs offline access, and therefore replication. In my particular organization, surprisingly, nothing fits this category.
2) Any app that requires field-level encryption. The other granular levels of Notes security can be emulated with some skilled development efforts, although I acknowledge they are more difficult in Microsoft technologies. But I know of no way to set encryption on individual fields other than through the use of the Notes  client.
3) Any app that is business critical, directly generates the revenue for the company, and also well-loved by the business users. An app that works, that makes the money, and that isn’t a source of pain for people…. it should just be left alone to do its job.

Yesterday I posted some code, and some reasons why it wasn’t quite useful yet.
So this morning, I fixed my main two complaints by adding check to see if the list already exists before creating it, and adding a check for an existing record before creating it. This could now be scheduled nightly, and will maintain your SharePoint version of a Notes catalog for you.
You would, of course, need to create some views to make the resulting list user-friendly. Maybe I’ll tackle that another day, too. But that can be done easily through the browser interface, so it isn’t a high priority on my list.

I included the full program code, as I realized some of the objects wouldn’t be resolved correctly in the IDE unless you saw my ‘using’ statements.

One question, though – I did not find any method in the SharePoint API to check for the existence of a list by using that list’s name. I used a try/catch block instead. Do any SharePoint folks know if that is appropriate, or is there a better method?

On with the updated code:
(Disclaimer – untested code, but it should do the trick.)

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using Microsoft.SharePoint;
using Domino;

namespace NotesInventory
{
    class Program
    {
        static void Main(string[] args)
        {
            SPSite rootSite = new SPSite(“
http://localhost“);
            SPWeb site = rootSite.OpenWeb();
            SPList l;
            SPListItem li;
            StringCollection sc;
            StringBuilder q;
            SPQuery sq = new SPQuery();
            SPListItemCollection items;

            try //to get the list
            {
                l = site.Lists["Notes Inventory"];
            }
            catch (Exception ex)
            { // it isn’t there — make it
                Guid newGuid = site.Lists.Add(“Notes Inventory”, “List of Notes Applications”, SPListTemplateType.GenericList);
                l = site.Lists.GetList(newGuid, false);

                l.Fields.Add(“DB Path”, SPFieldType.Text, true);
                l.Fields.Add(“Business Owner”, SPFieldType.Text, false);
                sc = new StringCollection();
                sc.AddRange(new string[] { “SharePoint”, “Exchange Mailbox”, “InfoPath”, “Domino Web UI”, “.NET Development”, “3rd Party Tool”, “Decommission”, “No Action” });
                l.Fields.Add(“Migration Plan”, SPFieldType.Choice, false, true, sc);
                sc = new StringCollection();
                sc.AddRange(new string[] { “< 10 Hours”, “10-50 Hours”, “50-150 Hours”, “150-300 Hours”, ” >300 Hours” });
                l.Fields.Add(“Scope”, SPFieldType.Choice, false, true, sc);
                l.Fields.Add(“Priority”, SPFieldType.Number, false);

            }
            //OK, we’ve now got a list — let’s fill it with Notes Data.
            NotesSession s = new NotesSession();
            s.Initialize(“password”);
            NotesDbDirectory dbdir =s.GetDbDirectory(“server”);
            NotesDatabase db = dbdir.GetFirstDatabase(DB_TYPES.NOTES_DATABASE);

            while (db != null) {
                try
                {
                    db.Open();

                    //check to see if record exists
                    q = new StringBuilder();
                    q.Append(“<Where>”);
                    q.Append(“<Eq><FieldRef Name=‘DB Path’ />”);
                    q.Append(“<Value Type=‘String’>”);
                    q.Append(db.FilePath);
                    q.Append(“</Value></Eq>”);
                    q.Append(“</Where>”);

                    sq.Query = q.ToString();
                    items = l.GetItems(sq);

                    if (items.Count == 0) { //no record found — create it
                      li = l.Items.Add();
                      li["Title"] = db.Title;
                      li["DB Path"] = db.FilePath;
                      li.Update();
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.StackTrace);
                }
                db = dbdir.GetNextDatabase();
            }
        }
    }
}

I mentioned a while back that you could keep track of your Notes DBs in SharePoint.

Below is  a bare-bones snippet of how you might set that up. I wrote and tested this as a Windows console app. You will need to set up a project in VS.NET, and add references to the SharePoint API and the Domino Objects via COM.

In a real-world scenario, this would need major improvements. Namely, either splitting the list generation into a new script, or checking if it already exists. Also you’d want to update pre-existing list items, not just do a full data dump on each run. However, in SharePoint, there really is no equivalent to GetDocumentByKey, so you cannot just grab and edit a document. Instead, you can write XML code to pass to a Web Service that will do the updates. I’ll put together a code sample of that another day.

SPSite rootSite = new SPSite(“http://localhost“);
SPWeb site = rootSite.OpenWeb();
SPList l;
SPListItem li;
StringCollection sc;

//Create the SharePoint List and add fields.
Guid newGuid = site.Lists.Add(“Notes Inventory”, “List of Notes Applications”, SPListTemplateType.GenericList);
l = site.Lists.GetList(newGuid, false);
l.Fields.Add(“DB Path”, SPFieldType.Text, true);
l.Fields.Add(“Business Owner”, SPFieldType.Text, false);
sc = new StringCollection();
sc.AddRange(new string[]  { “SharePoint”, “Exchange Mailbox”, “InfoPath”, “Domino Web UI”, “.NET Development”, “3rd Party Tool”, “Decommission”, “No Action”  });
l.Fields.Add(“Migration Plan”, SPFieldType.Choice, false, true, sc);
sc = new StringCollection();
sc.AddRange(new string[] {“< 10 Hours”, “10-50 Hours”, “50-150 Hours”, “150-300 Hours”, ” >300 Hours”});
l.Fields.Add(“Scope”, SPFieldType.Choice, false, true, sc);
l.Fields.Add(“Priority”, SPFieldType.Number, false);

//OK, we’ve now got a list — let’s fill it with Notes Data.
NotesSession s = new NotesSession();
s.Initialize(“YourNotesPassword”);
NotesDbDirectory dbdir =s.GetDbDirectory(“YourServerName”);
NotesDatabase db = dbdir.GetFirstDatabase(DB_TYPES.NOTES_DATABASE);
while (db != null) {
try
{
db.Open();
li = l.Items.Add(); //create record
li["Title"] = db.Title;
li["DB Path"] = db.FilePath;
li.Update();
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
db = dbdir.GetNextDatabase();
}

What About agents?

October 19, 2007

One big gap in SharePoint’s functionality is a lack of agents. The concept just doesn’t exist.

So I wanted to take a brief look at what we really did with agents, and how you could achieve the same results with Microsoft technologies. I’m not posting how-to instructions here, just a general direction that can be taken. It should at least be enough to help you know what to search for on Google.

1) Data Updates — If you need to make mass data updates, (or even just small corrections to specific documents), a previous commenter pointed out that one of your best options is actually Microsoft Access. SharePoint can be a data source,  and you can use Access to  update your data.

2) Event-driven scripting — We’re used to our plethora of events — we can and do script to the QuerySave, the PostSave, the POstOpen, the QueryDocumentDelete, etc. We can control just about everything in our system based on an event-driven model. But SharePoint doesn’t have this. ASP.NET does…. somewhat. To take advantage of an event-driven model, you would need to write an ASP.NET application, and either turn it into a Web Part, or just link it from SharePoint.

3) Scheduled Agents — You will need to write a console app and schedule it  at the Operating System level. .

4) Scripted Actions — While SharePoint  doesn’t have  the action bar we are used to, it does have menus. And you can update those menus by writing and deploying custom features.

What it comes down to is that data updates aren’t as difficult as I first feared, and everything else is custom .NET coding. While it is not integrated with SharePoint the way we Notes folks would like, it will serve the same purpose. And who knows? Maybe if enough of us learn the Microsoft side of things, we can start to explain to them what an integrated programming environment actually is. :)

Last Planning Post

October 18, 2007

Based on the stats, you guys care a lot less about planning, and a lot more about technical details.
So be it — one last short post to finish out the plan, then we’ll get more detailed posts coming.

If everything is now scoped out, you have everything you need to prioritize your migration.

Prioritization is going to be based on your business needs, naturally. But let me make just a couple suggestions:

1) Put the apps that require the most maintenance near the front of the list. That will give you an opportunity to correct the problems causing maintenance, as well as leave you with a low-maintenance Notes environment, so you can spend your time on more valuable tasks.

2) Put client-based apps near the front of the list, too. I’ve mentioned before  that simple getting to a 100% web-based environment should offer maintenance and cost benefits to your organization.

The, the final step – do the migration.

I’m not even going to attempt to comment on that. A lot of work to be done. From here on out, I’ll try to continue to post technical issues and techniques. That is where all the fun is to be had anyway. :)