Ok, it seemed like a good idea to make myself a MailService class as a singleton to work with the Outlook class (which itself is a singleton afaik).
It worked great at first, but as soon as I tried setting up unit tests (MS Unit Testing) for this class from my appservice layer all hell broke loose and I get Runtime Callable Wrapper errors..
Was I wrong setting up a MailService class as a singleton or am I doing something wrong in wrapping Outlook as singleton class?
This is my Mailservice class with one of the methods shown:
public class MailService : IDisposable
{
private static MailService _instance;
private Outlook.ApplicationClass _app;
private Outlook.NameSpace _olNS;
private MailService()
{
_app = new Outlook.ApplicationClass();
_olNS = _app.GetNamespace("MAPI");
}
public static MailService Instance
{
get
{
if (_instance == null)
_instance = new MailService();
return _instance;
}
}
public void Dispose()
{
_app.Quit();
Marshal.ReleaseComObject(_app);
GC.Collect();
GC.WaitForPendingFinalizers();
}
public Outlook.Folder getFolderByPath(string sFolderPath)
{
Outlook.Folder olFolder = null;
if (sFolderPath.StartsWith(@"\\"))
{
sFolderPath = sFolderPath.Remove(0, 2);
}
string[] sFolders = sFolderPath.Split('\\');
try
{
olFolder = _app.Session.Folders[sFolders[0]] as Outlook.Folder;
if (olFolder != null)
{
for (int i = 1; i <= sFolders.GetUpperBound(0); i++)
{
Outlook.Folders subFolders = olFolder.Folders;
olFolder = subFolders[sFolders[i]] as Outlook.Folder;
if (olFolder == null)
{
return null;
}
}
}
return olFolder;
}
catch (Exception e)
{
LogHelper.MyLogger.Error("Error retrieving " + sFolderPath, e);
return null;
}
}
}
My MS Unit tests are working separately but not when running all in a test list. In the latter condition only the first Test passed…
[TestMethod]
public void TestMonitorForCleanUpDone()
{
Assert.IsNotNull(MailService.Instance.getFolderByPath(olFolderDone));
}
[TestMethod]
public void TestMonitorForCleanUpIn()
{
Assert.IsNotNull(MailService.Instance.getFolderByPath(olFolderIn));
}
As usual it turns out someone else has faced this problem before and wrote a blog post about it:
http://blogs.msdn.com/b/martijnh/archive/2009/12/31/unit-testing-com-object-that-has-been-separated-from-its-underlying-rcw-cannot-be-used.aspx
Just in case the blogpost ever goes away, the resolution in short is to run Unit Tests in MTA mode.
“the way to solve this issue is to open up your testrunconfig file using the XML editor and adding the <ExecutionThread apartmentState=”MTA” /> element to it”