C# SerializationException in Office 2013/2016 VSTO add-ins with CSLA

125 views Asked by At

I first asked for help on the CSLA forum, but I haven't been able to solve this yet. I have created a test VS2015 solution which demonstrates the issues I am experiencing.

I am using CSLA 4.6.603 in Outlook, Word, Excel and PowerPoint. After setting Csla.ApplicationContext.User, a SerializationException can be thrown when displaying a Form or MessageBox, or even reading XML.

The simplest example of the problem is the following:

private void MessageThrows(object sender, EventArgs e)
{
    // This message displays correctly
    MessageBox.Show("About to set user to UnauthenticatedPrincipal. " +
                    "Check Debug Output to see exception.",
                    "Before UnauthenticatedPrincipal");

    // The user is set correctly with no exception
    Csla.ApplicationContext.User = new Csla.Security.UnauthenticatedPrincipal();

    try
    {
        // The following message throws:

        // System.Runtime.Serialization.SerializationException:
        // Type is not resolved for member 'Csla.Security.UnauthenticatedPrincipal,Csla,
        // Version =4.6.603.0,
        // Culture =neutral,
        // PublicKeyToken =93be5fdc093e4c30'.

        MessageBox.Show("The user has been set to UnauthenticatedPrincipal.",
                        "After UnauthenticatedPrincipal");
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex);
    }
}

In the test solution there is another example which throws the same SerializationException when attempting to read XML via dataSet.ReadXml(tempFileName, XmlReadMode.InferSchema);

I am handling the AppDomain.CurrentDomain.AssemblyResolve event, and CSLA is listed in AppDomain.CurrentDomain.GetAssemblies() right before the exception is thrown.

The test solution has a very basic custom identity, a basic business object which reads from a generated XML file, and a form with three buttons.

If you set the WindowsUI project as the StartUp project and run it, each button in the main form should succeed, with no exceptions being thrown.

Set the WordAddIn project as the StartUp project and run it. Word starts and the same form is displayed as the add-in loads. The first button succeeds, but the next two buttons throw exceptions. See the Debug Output for details, or set a breakpoint. The same is true for the OutlookAddIn project.

As others have pointed out earlier in the CSLA forum thread, this is caused by or related to .NET failing to resolve assemblies. The AssemblyResolve event may be the answer, I just haven't been able to figure it out.

Any help would be greatly appreciated.

1

There are 1 answers

1
Michael Csikos On

With help from Ingo on the CSLA forum, I think we have found a workaround.

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
    Csla.ApplicationContext.PropertyChangedMode = Csla.ApplicationContext.PropertyChangedModes.Windows;

    Csla.ApplicationContext.ContextManager      = new Csla.Windows.ApplicationContextManager();

    // Workaround to prevent 'SerializationException' in VSTO add-in

    // 1. Force initialisation of ConfigurationManager
    System.Configuration.ConfigurationManager.GetSection("Dummy");

    // 2. Set UnauthenticatedPrincipal explicitly after
    // setting the Csla.ApplicationContextManager
    Csla.ApplicationContext.User = new Csla.Security.UnauthenticatedPrincipal();
}

What I've found is that before any UI is displayed by any ribbon control event handler, we need to re-run the workaround code, and reassigning the current user is sufficient. It looks ridiculous, but it works.

/// <summary>
/// Microsoft Office add-ins can experience
/// <code>System.Runtime.Serialization.SerializationException</code> 
/// "Type is not resolved for member Csla.Security.UnauthenticatedPrincipal".
/// Calling this method before showing any UI works around the problem.
/// </summary>
public static void ExceptionWorkaround(bool setUnauthenticatedPrincipal = false)
{
    // 1. Force initialisation of ConfigurationManager
    ConfigurationManager.GetSection("Dummy");

    // 2. Set User explicitly
    if (setUnauthenticatedPrincipal)
        Csla.ApplicationContext.User = new UnauthenticatedPrincipal();
    else
        Csla.ApplicationContext.User = Csla.ApplicationContext.User;
}

UPDATE
I found other scenarios where this workaround failed. Installing Csla.dll in the GAC solves the problem. No workarounds are required at all. It's a bit of a last resort, but so far it looks like the only reliable solution.