Basic operations with Domino .NET API for export purposes

This post is a very short guide on how to access a Notes database and read the data with a .NET application using Lotus Notes Interop. The code snippets are not optimized for use in a .NET application for continues access to Notes database. Its more meant for one time execution for export purposes. I’ve used the code presented here in a migration process from Lotus Notes document management solution to a custom SharePoint document management solution. Of course in that process I’ve developed other tools as needed to manipulate the data and documents before uploading to SharePoint as well as tools to upload and for post-upload data manipulation. As the title states this post is only for the first part, getting information out of Lotus Notes.

The code samples are tested and used on a PC with Windows 7 and Notes 7 client installed.
There is some Lotus Script presented too. For that part Domino Designer 7 is used.

Short Introduction to Notes databases

It’s important to know that Notes database is not a relational database but a document-centric database.
For people with SQL Server background it may be helpful to make a loose parallel between Notes database and a SQL database table.
A Notes database contains views.
Think of a view in Notes database as a SQL database table.
A document in a Lotus Notes database is similar to a row in a SQL table.
Documents in Notes database contain items which are similar to fields in a table in SQL with one big difference being that an item in Notes DB can have one or more objects (array of objects).
As mentioned before this is a very rough comparison between Notes database and SQL database and its meant just for getting an idea what is what in Notes DB in case you have never worked with Lotus Notes before.

Initialize Lotus Notes session

Reference to Interop.Domino.dll is required to be added in the project.

using Domino;

NotesSession lotusNotesSession = new NotesSession();
lotusNotesSession.Initialize("yourPassword");

Get and Open a Notes database

NotesDatabase localDatabase = lotusNotesSession.GetDatabase("ServerName", "DatabaseName.nsf", false);
localDatabase.Open();

In some cases this didn’t work for me and I had to loop through all the databases to get the DB I needed

NotesDbDirectory dbDict = lotusNotesSession.GetDbDirectory("ServerName");
NotesDatabase localDatabase = dbDict.GetFirstDatabase(DB_TYPES.NOTES_DATABASE);
while (localDatabase != null)
{
	if (localDatabase.Title == "DatabaseName")
		break;
	else
		localDatabase = dbDict.GetNextDatabase();
}

localDatabase.Open();

Get all the views of a database

public List<NotesView> GetAllViews(NotesDatabase localDatabase)
{
   object[] viewsArray = localDatabase.Views;
   List<NotesView> views = new List<NotesView>();

   foreach (object viewObject in viewsArray)
   {
      NotesView oneView = oneObject as NotesView;
      views.Add(oneView);
   }
   return views;
}

Get a view with a given name

NotesView view = localDatabase.GetView("ViewName");

Get the items names for a document

		
public List<string>	GetItemNames(int id)
{
	NotesDocument document = view.GetNthDocument(id);
	object items = document.Items;
	Array itemArray = (System.Array)items;
	List<string> itemNames = new List<string>();

	for (int icount = 0; icount < itemArray.Length; icount++)
	{
		NotesItem item = (Domino.NotesItem)itemArray.GetValue(icount);
		itemNames.Add(item.Name);
	}
	return itemNames;
}

Get items value for all documents in a view

For simplicity this method returns list of strings, every string containing metadata for a document. Values of the items are separated with the characters combination “;;;###”. If an item has more than one object in the object array then they are all added by separating them with the characters combination “;###”.
Also for simplicity this method takes all the items values as string. It can be modified as needed to deal with other types.

public List<string> GetDocumentsMetadata(NotesView view, List<string> itemNames)
{
	List<string> metadata = new List<String>();
	
	NotesDocument document = view.GetFirstDocument();
			
	while (document != null)
	{
        string itemsString = string.Empty;
		foreach (string itemName in itemNames)
		{
            string value = string.Empty;
			try
			{
				object[] valueArrey = document.GetItemValue(itemName);
				for (int icount = 0; icount < valueArrey.Length; icount++)
				{
					value += valueArrey[icount] == null ? string.Empty : valueArrey[icount].ToString() + ";###";
				}
			}
			catch
			{
				value = "N/A";
			}
			itemsString += value + ";;;###";
	   }

		document = view.GetNextDocument(document);

		metadata.Add(itemsString);
	}
	
	return metadata;
}

After getting the metadata it can be saved in a file and later processed for Notes-to-SharePoint migration.

Exporting Notes documents as RTF files

I had troubles exporting the document content as rich text file (RTF) using the .NET API for Notes. Its possible to export the text of the document which is stored in an item of type IT_TYPE.RICHTEXT but that doesn’t include the formatting nor the images of the documents. All what it returns is the plain text content of the document.
To export the document content as RTF I had to create an agent with Domino Designer. A great help was Rtftest.zip.
The agent loops through all the documents in a specified view and exports the documents as RTF. The resulting RTF files were not perfect (look and feel wise) but were very close to the original. Some of the problems I noticed were: Styling may not be the same 100 % as when viewed with Notes, some tables may be with no visible borders, and similar small problems. In any case the result was more than acceptable although the users had to inspect the documents quickly and make small changes after the files were converted to .docx files and uploaded to SharePoint.

Exporting Notes document’s embedded files (attachments)

There are two ways to export all the attachments from all Notes Documents in a view using LotusScript:

Using NotesRichTextNavigator

	Dim doc As NotesDocument
	Set doc = view.GetFirstDocument
	Dim title As String
	Do Until doc Is Nothing
		Dim body As NotesRichTextItem
		Set body = doc.GetFirstItem("YourDocBodyFieldName")

		Dim attachment As NotesEmbeddedObject
		Dim rtnav As NotesRichTextNavigator
		Set rtnav = body.CreateNavigator
		If rtnav.FindFirstElement(RTELEM_TYPE_FILEATTACHMENT) Then
			Do
				Set attachment = rtnav.GetElement()
				filepath$ = "C:\YourFolder\" & attachment.Source
				Call attachment.ExtractFile(filepath$)
			Loop While rtnav.FindNextElement()
		End If
		
		Set doc = view.GetNextDocument(doc)
	Loop

By getting EmbeddedObjects from NotesRichTextItem

	Dim doc As NotesDocument
	Set doc = view.GetFirstDocument
	Dim title As String
	Do Until doc Is Nothing
		Dim body As NotesRichTextItem
		Set body = doc.GetFirstItem("YourBodyFieldName")
		
		If Not Isempty (body.EmbeddedObjects) Then
			Forall att In body.EmbeddedObjects
				If att.Type = EMBED_ATTACHMENT Then
					filepath = "fullPathWhereToSaveTheFile"
					Call att.ExtractFile(filepath)
				End If
			End Forall
		End If
				
		Set doc = view.GetNextDocument(doc)
	Loop

This method with EmbeddedObjects is useful if you want to keep track which attachment belongs to which document. You can include that information in the filepath variable, or write a string with more information on the fly as the files are being extracted and than save it as a csv file.

Advertisements

Get Active Directory Groups and Users programmatically

To get Active Directory groups and users we need to reference System.DirectoryServices.AccountManagement in the project.

Get Groups from Active Directory

The method listed below will return list of all group names from Active Directory.
ServerName of the domain controller should be provided as well as UserName and Password for an account with sufficient rights to list the Active Directory groups.

public List<String> GetADGroups()
{
	List<String> result = new List<String>();

	PrincipalContext ctx = new PrincipalContext(ContextType.Domain, ServerName, UserName, Password);
	GroupPrincipal findAllGroups = new GroupPrincipal(ctx, "*");
	PrincipalSearcher ps = new PrincipalSearcher(findAllGroups);
	foreach (Principal group in ps.FindAll())
	{
		result.Add(group.Name);
	}

	return result;
}

Get Users from Active Directory

The method listed below will return list of all users members of a given Active Directory group including the members of all nested subgroups.
ServerName of the domain controlled should be provided as well as UserName and Password for an account with sufficient rights to list the Active Directory groups and users.

public List<String> getGroupUsers(String strGroup)
{
	List<String> groupMembers = new List<String>();

	PrincipalContext ctx = new PrincipalContext(ContextType.Domain, ServerName, UserName, Password);

	GroupPrincipal myGroup = GroupPrincipal.FindByIdentity(ctx, strGroup);

	if (myGroup != null)
	{
		//calling GetMembers with 'true' flag will get all users including members of nested groups
		PrincipalSearchResult<Principal> allMembers = myGroup.GetMembers(true);

		foreach (Principal principal in allMembers)
		{
			//get properties you need from Principal object
			String loginName = principal.SamAccountName;
			groupMembers.Add(loginName);
		}
	}
	else
	{
		throw new Exception("AD group not found.");
	}

	return groupMembers;
}

%d bloggers like this: