sharepointsharepoint-2010xmlformview

XmlForm.Submit() "hides" the validation result message?


I'm using the XmlFormView control on a custom aspx page hosted in a SharePoint site. Recently our SharePoint was upgraded to 2010 and afterwards I've been having problems with the form validation triggered by the XmlForm.Submit().

The custom page is actually relying on the exception thrown by SharePoint, if the validation of the submitted form fails. The validation message is formatted and the shown to the user in a friendly way.

When a form containing an invalid user supplied data is submitted, a "Microsoft.Office.InfoPath.Server.Util.InfoPathFatalException" is returned. This exception doesn't contain information about witch fields contains invalid data. Actually I was expecting an "Microsoft.Office.InfoPath.Server.SolutionLifetime.DataAdapterException". (The submit is successful and no exception is thrown if the form contains no validation errors)

If I uncheck the "Enable Just My Code (Managed only)" option in Visual Studio and debug the form submit, I get the following exception(contains Danish texts):

Microsoft.Office.InfoPath.Server.SolutionLifetime.DataAdapterException occurred
Message=Formularen kan ikke afsendes, fordi den indeholder valideringsfejl. Fejlene er angivet med en rød stjerne (obligatoriske felter) eller omgivet af en rød, stiplet streg (ugyldige værdier).

Felt eller gruppe: MunicipalRealPropertyIdentifier
Fejl: Der må kun angives et bestemt mønster

Source=Microsoft.Office.InfoPath.Server
BypassWatson=true
LogId=5567
SaveUserSession=false
UserMessage=Formularen kan ikke afsendes, fordi den indeholder valideringsfejl. Fejlene er angivet med en rød stjerne (obligatoriske felter) eller omgivet af en rød, stiplet streg (ugyldige værdier).

Felt eller gruppe: MunicipalRealPropertyIdentifier
Fejl: Der må kun angives et bestemt mønster

OverrideTopLevelMessage=true
StackTrace:
at
Microsoft.Office.InfoPath.Server.SolutionLifetime.DatabaseHelper.CheckErrorBoard(Document document, DataAdapter adapter, XPathNavigator subtreeToCheck, Boolean schemaErrorOnly)
InnerException:

This is good! The exception contains information about the validation errors. I Continue the debug. The desired exception is re-thrown and the output reads:

Step into: Stepping over method without symbols 'Microsoft.Office.InfoPath.Server.SolutionLifetime.DatabaseHelper.CheckErrorBoard' Step into: Stepping over method without symbols 'Microsoft.Office.InfoPath.Server.DocumentLifetime.Document.ExecuteDefaultSubmitAction'

This is still good! I continue the debug, but now the original exception is lost and the InfoPathFatalException is returned.

Microsoft.Office.InfoPath.Server.Util.InfoPathFatalException occurred
Message=Exception of type 'Microsoft.Office.InfoPath.Server.Util.InfoPathFatalException' was thrown.
Source=Microsoft.Office.InfoPath.Server
BypassWatson=false
SaveUserSession=false
UserMessage=Der opstod en alvorlig fejl under behandlingen af formularen.
StackTrace:
at Microsoft.Office.InfoPath.Server.Util.GlobalStorage.get_CurrentFormId()
InnerException:

The VS output now reads:

Step into: Stepping over method without symbols 'Microsoft.Office.InfoPath.Server.SolutionLifetime.DatabaseHelper.CheckErrorBoard' Step into: Stepping over method without symbols 'Microsoft.Office.InfoPath.Server.DocumentLifetime.Document.ExecuteDefaultSubmitAction' Step into: Stepping over method without symbols 'Microsoft.Office.InfoPath.Server.DocumentLifetime.OMExceptionManager.ExecuteOMCallWithExceptions'

I'm quite a novice when it comes to SharePoint, but I think this smells a bit like a security issue? It seems the original exception is not "allowed" to bubble back to the caller.

I've tried to enable full logging in SharePoint, but when I look at the logs in "..\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\LOGS" I can only see the "original" exception, not why it is overwritten?

Additional information: The site currently runs with the config setting:

<trust level="Full" originUrl="" />

Anybody got any ideas about this issue?

On SharePoint 2007 the desired exception is returned back to the caller.


Solution

  • Think this question has been open long enough :-)

    The problem was with the way we used the XMLFormView control. Instead of changing our code logic I chose to implement a workaround.

    In short: I read this Microsoft documentation: http://msdn.microsoft.com/en-us/library/microsoft.office.infopath.server.controls.xmlformview.xmlform

    One of the sections read:

    The XmlForm property can only be accessed during one of the following events:

    • Initialize
    • NotifyHost
    • SubmitToHost
    • Close

    Our code does neither of these!

    Basically we do a postback from a standard button on the aspx page, and from the code behind try to call XmlFormView1.XmlForm.Submit();

    I found out, using .NET Reflector on the Microsoft.Office.Infopath assembly, that when trying to submit HttpContext.Current.Items["__GlobalStorage.FormIds"] is expected to contain at least one Id form the current form, but at this time it has not yet been set!

    So I did the following little “dirty hack” to make the code work again:

            /// <summary>
        /// Dirty hack to fix issue after update to InfoPath 2010 
        /// </summary>
        private static void InfoPath2010Hack()
        {
            if (HttpContext.Current != null)
            {
                if (HttpContext.Current.Items["__GlobalStorage.FormIds"] == null)
                {
                    var formIds = new Stack<string>();
                    formIds.Push("XmlFormView1");
                    HttpContext.Current.Items["__GlobalStorage.FormIds"] = formIds;
                }
                else
                {
                    var formIds = ((Stack<string>)HttpContext.Current.Items["__GlobalStorage.FormIds"]);
                    if (formIds.Count <= 0)
                    {
                        formIds.Push("XmlFormView1");
                        HttpContext.Current.Items["__GlobalStorage.FormIds"] = formIds;
                    }
                }
            }
        }
    

    Anywhere in the code behind, before I try to access XmlFormView1.XmlForm, I just call InfoPath2010Hack();

    Not a pretty solution, but it works without changing any other logic.