Pass in any parameter to an InfoPath form with one piece of code

One thing that’s lacking in Microsoft InfoPath 2007 is the ability to simply map input parameters to the main data source (which is most likely where you want them to go). 

Unfortunately there’s no getting around the need to write code to ‘receive’ your input parameters, but with a thought you’ll be able to pass
in parameters with the same name as the fields in your form and have one block of code to paste into the code behind all forms – that will work for all. 

This includes a couple of utility functions that make life a bit easier when coding around fields in the form.
The ‘DeleteSelf’ line around the nil attribute is something that apparently gets around data type errors if you’ve got fields that aren’t just ‘string’ – e.g. ‘number’ etc.  I found this worked in the InfoPath client, but not in a browser (and had to change my field data type back to string, and add some regexp validation).

        public void FormEvents_Loading(object sender, LoadingEventArgs e)
        {

            //Try and identify any input parameters and put them into their requisite places in the main data source
            foreach (string parameter in e.InputParameters.Keys)
            {

                //Try and find in the main data source, then set the value
                XPathNavigator formNode = SelectSingleNode(String.Format("//my:{0}", parameter));
                if (formNode != null)
                {
                    if (formNode.MoveToAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance"))
                        formNode.DeleteSelf();

                    formNode = SelectSingleNode(String.Format("//my:{0}", parameter));
                    formNode.SetValue(e.InputParameters[parameter]);
                }
            }
        }
        
        /// <summary>
        /// Select a single node from the Main data Source
        /// </summary>
        /// <param name="xpath"></param>
        /// <returns></returns>
        private XPathNavigator SelectSingleNode(string xpath)
        {
            string ns = LookupNamespace("my");
            XPathNavigator navigator = MainDataSource.CreateNavigator();
            return navigator.SelectSingleNode(xpath, NamespaceManager);
        }
 
 
        private string LookupNamespace(string ns)
        {
            return NamespaceManager.LookupNamespace(ns);
        }

Embedding InfoPath forms in SharePoint WebPart pages using the XmlFormView control

I recently needed to take a simple InfoPath form and surface that through a ‘themed’ SharePoint page.  It’s possible to load the form in a browser without needing a specific page, but this effectively eliminates your master page from the equation.

Nick Grattan wrote an excellent paper on using the XmlFormView control to contain InfoPath forms on SharePoint webpart pages.

This is all great until you then need to send in input parameters to the form.  I looked around for quite a while before I found the (rather obvious) Initialize event allows you to set the Input parameters of the form.  All other methods of loading the form (InfoPath client, FormServer.aspx) use a querystring-style format.

The following code should do the trick in the case where you’re passing information from a current ‘list item’ to the form:
 

    private SPList requestList = null;
    private int requestID;
    private SPListItem currentItem = null;

    protected void Page_Load(object sender, EventArgs e)
    {

        XmlformView1.Initialize    += XmlformView1_Initialize;
        //Get ID and List Item information (passed into this page)
        requestList = SPContext.Current.Web.Lists["My List"];        
        if (requestList != null && Request.QueryString["ID"] != null)
        {
            if (int.TryParse(Request.QueryString["ID"].ToString(), out requestID))
            {
                //Get Item
                currentItem = requestList.GetItemById(requestID);

                if (currentItem == null)
                    throw new ArgumentException("The specified ID does not exist");

            }
            
        }
        
    }

    protected void XmlformView1_Initialize(object sender, InitializeEventArgs e)
    {
        //Set input parameters for embedded Form
        e.InputParameters["foo"] = currentItem["foo"].ToString();
        e.InputParameters["bar"] = currentItem["bar"].ToString();

    }

I discovered that in order to write code in a WebPart page (using SharePoint Designer)
you’ll need to add a PageParserPath to the web.config as follows – otherwise you’ll get an error saying something like ‘code not allowed in this page’.  I’ve got a folder called ‘WebPages’ that houses the page.  The standard web.config already has the PageParserPaths element:

    <SafeMode MaxControls="200" CallStack="true" DirectFileDependencies="10" 
TotalFileDependencies="50" AllowPageLevelTrace="false">
<PageParserPaths>
    <PageParserPath VirtualPath="/WebPages/*" CompilationMode="Always"
AllowServerSideScript="true" IncludeSubFolders="true" />
</PageParserPaths>
</SafeMode>


NOTE:
If you’re showing/hiding the form based on a flag/checkbox etc in the page (I’m doing this), then make sure you wrap the XmlFormView in a container Panel/div that you show/hide server-side, rather than showing/hiding the XmlFormView itself.  For some reason this doesn’t seem to work properly (at least in FireFox).

Retrieving User Information in InfoPath without Code – One solution to ‘Value cannot be null. Parameter name: serverContext’

InfoPath, SharePoint and Web Services are becoming sparring partners for me of late. 

In order to retrieve user information in my InfoPath form I followed the instructions at itaysk’s blog, as I wasn’t aware I could use a SharePoint Web Service to get profile information.  Sweet – I thought.

I then immediately got:

The User Profile Manager object could not be loaded. —> Value cannot be null. Parameter name: serverContext

This was an error noted by quite a few people, but with very few solutions.

I then got out Fiddler as I do, to see what was going on, and remembered that InfoPath tends to expand url’s into their fully qualified domain names (FQDN) – so you may have entered http://mylocalnetworkserver/_vti_bin/etc.asmx but if you’re on a corproate network or anywhere with DNS happening then you’ll suddenly find yourself calling http://mylocalnetworkserver.some.other.domain.gumph/_vti_bin/etc.asmx.

Why is this important you ask?  – Well I then thought ‘I’m sure there wouldn’t be anything logged on the server?’  – well SharePoint probably logs a lot more than most realise, but the error in this case was staring me in the face in the Event Log:

A Windows SharePoint Services Error – Event ID 8214.

A request was made for a URL, http://mylocalnetworkserver.some.other.domain.gumph, which has not been configured in Alternate Access Mappings.  Some links may point to the Alternate Access URL for the default zone, http://mylocalnetworkserver.  Review the Alternate Access mappings for this Web application at http://mylocalnetworkserver:1234/_admin/AlternateUrlCollections.aspx and consider adding http://mylocalnetworkserver.some.other.domain.gumph as a Public Alternate Access URL if it will be used frequently.  Help on this error: http://go.microsoft.com/fwlink/?LinkId=114854.

Well blow me down.  All the other web services I call from InfoPath don’t care about this because they’re not hosted in SharePoint, and SharePoint manages the allowed paths into the application. 

Once I went to the Central Admin site –> Operations –> Alternate Access Mappings, and edited ‘Public Zone URLs’ to add the FQDN to the intranet zone (probably could choose any zone), it just started working.