Microsoft InfoPath 2010
The official blog of the Microsoft InfoPath team

Submitting to 'this' document library

Submitting to 'this' document library

Rate This

Have you ever needed to develop an InfoPath form template that submits back to a SharePoint document library but you did not initially know the server or library name when developing the form? Or have a scenario where your InfoPath form template could be published (or added as a content type) to multiple SharePoint document libraries and you need the submit location to be dynamic? Well read on to find out how you can do this!

When you create an InfoPath form template that needs to be able to submit to a SharePoint document library, you need to specify that connection in the initial design of the form template. However, at run time you can use managed code to determine the server and library name where the form was launched and then modify the “FolderUrl” property of the submit data connection so the form is submitted to the appropriate library.

So let’s get started setting up this sample. The C# walkthrough below uses the new InfoPath 2007 managed object model; below, you will find attached the same logic implemented in InfoPath 2003 managed object model and in InfoPath 2003 JScript.

Step 1: Create a sample InfoPath Form Template

Create a browser-compatible form template as following:

  1. Add 3 text box controls, all with a data type of text, named as follows: strFormURL, strLocation and strFolderName
  2. Add a “Submit” data connection named “Main submit”:
    • Set the document library name to a dummy SharePoint document library (i.e. http://server/dummyLib)
    • Use the concat function to concatenate the strFolderName field and _Test for the File Name property: concat(my:strFolderName, "_Test")
    • Enable the Allow overwrite if file exists property
  3. Set the Security Level of the form to Full Trust and sign the form template with a digital certificate
  4. Enable the Submit functionality (Tools | Submit Options) and choose the “Perform custom action using code” option

Now that we have the form, controls and submit functionality, let’s add the code to make this process work:

 

Step 2: Add the code

  • Click the Edit Code button on the Submit Options dialog
  • Create the following FormState Dictionary object – this will be used to store the form’s location when the form is initially opened:

private object _strUri
{
   get { return FormState["_strUri"];
  
set { FormState["_strUri"] = value; }
}

 

  • Add the following code to the Forms Loading event: 

// Get the Uri (or SaveLocation in a browser form) of where
// the form was opened.
// See if the form was opened in the browser

Boolean OpenedInBrowser = Application.Environment.IsBrowser; 

// If so, we will get the "SaveLocation" from the InputParameters

if (OpenedInBrowser)
  
_strUri = e.InputParameters["SaveLocation"].ToString();
else  

   //If it was opened in the client, we will get the Uri
  
_strUri = this.Template.Uri.ToString();

 

// Populate the fields on the form - keep in mind, this

// not necessary - this is simply to see the results

PopulateLibInfo(OpenedInBrowser);

 

  • Add the following procedure to the Forms class: 

private void PopulateLibInfo(Boolean OpenedInBrowser)

{

// Create a Navigator object for the main DOM
XPathNavigator xnDoc = this.MainDataSource.CreateNavigator();

 

// Create Navigator objects for each field

XPathNavigator xnFormURL = xnDoc.SelectSingleNode("my:myFields/my:strFormURL", this.NamespaceManager);
XPathNavigator xnLocation = xnDoc.SelectSingleNode("my:myFields/my:strLocation", this.NamespaceManager);

XPathNavigator xnFolderName = xnDoc.SelectSingleNode("my:myFields/my:strFolderName", this.NamespaceManager);

 

// Get the Uri stored in the FormState Dictionary variable

string strUri = _strUri.ToString();

 

// Create a variable to store the path (URL) to the document library

string strPath = "";

if (OpenedInBrowser == true) {

   //If we are open in the browser, the strUri value is just

   //the server name and library - so we just need to get

   //the URL without the last "/"

   strPath = strUri.Substring(0, strUri.LastIndexOf("/"));

} else {

   // Parse just the path to the document library -

   // this would return something like this:

   //  http://server/library

   strPath = strUri.Substring(0, strUri.IndexOf("Forms") - 1);
}


// Now, parse the URL to where the document library resides;
// this would return something like:

//    http://server or http://server/site
string strLoc = strPath.Substring(0, strPath.LastIndexOf("/"));


// Lastly, parse the URL to return just the document library name -

// in this case,we are looking for the last "/" character

// knowing that what comes after this is the document library name

string strFolder = strPath.Substring(strPath.LastIndexOf("/") + 1);

 

// Populate the fields on the form – we will use these

// values in the Submit process

xnFormURL.SetValue(strUri);

xnLocation.SetValue(strLoc);

xnFolderName.SetValue(strFolder);
}

 

  • Add the following code to the form’s Submit event:

// Create a Navigator object for the main DOM
XPathNavigator xnDoc = this.MainDataSource.CreateNavigator();


// Create Navigator objects for the fields we will

// use to modify the FolderUrl
XPathNavigator xnLocation = xnDoc.SelectSingleNode("my:myFields/my:strLocation", this.NamespaceManager);
XPathNavigator xnFolderName = xnDoc.SelectSingleNode("my:myFields/my:strFolderName", this.NamespaceManager);

 

// Get a reference to the submit data connection

FileSubmitConnection fc = (FileSubmitConnection)this.DataConnections["Main submit"]; 

 

// Modify the URL we want to submit to by concatenating the

// xnLocation and xnFolderName values

fc.FolderUrl = xnLocation.Value + "/" + xnFolderName.Value;

 

// Execute the submit connection

try

{

   fc.Execute();

   e.CancelableArgs.Cancel = false;

}

catch (Exception ex)

{

   e.CancelableArgs.Cancel = true;
}

 

  • Build and save the project
  • Publish and test

And that is it! You now have an InfoPath form template that will submit to whatever document library the form was opened from so you do not need to know this information when designing the template.

 

Scott Heim

Support Engineer

Attachment: submitToThisLibrary.zip
Leave a Comment
  • Please add 3 and 3 and type the answer here:
  • Post
  • Hi SP,

    If you are using InfoPath 2010, then yes - the "dummy" library needs to exist as InfoPath now validates that the submit to library is there. As such, you could just use any default library that would normally be there, such as "Shared Documents".

    Scott

  • I am so new to this. I already created my form. I am not sure how to place the codes. Can you help, please.

    Neetu

  • Scott,

    I am using infopath 2010, I have already deployed my form to sharepoint but having trouble getting it onto my website. Help!

    Neetu

  • Hi Neetu,

    This particular blog post is fairly code intensive...you need to have some idea about programming to be able to maintain your code once you follow these steps. If you don't have that, it's going to be very difficult to implement changes, updates, etc. The post itself documents where to add the code.

    In regard to your question about having trouble getting the InfoPath Form Template to your web site, you are going to need to provide more detail as I don't know what you are referring to. Did you publish the Form Template (XSN file?) Did it produce an error or publish successfully? It sounds like you are new to InfoPath - if so, you may want to go through this training before going any further with this post:

    InfoPath 2007 Training Labs

    office.microsoft.com/.../HA102227501033.aspx

    InfoPath 2010 Training Labs

    msdn.microsoft.com/.../gg180739.aspx

    Scott

  • Hi Scott,

    Great post!  Especially considering that this post is over 5 years old and is still very relevant.  It's gotten me to almost where I want to be.  

    I have a SharePoint 2010 web part which hosts a XmlFormView control.  I use this control to render an Administrator-approved InfoPath 2010 browser-enabled form.  This form has custom code for the Loading and Submit events.  I've verified that they both work if I submit the form using the Submit button from the SharePoint ribbon.

    Now, I need to be able to call the Submit event of the form via an ASP.NET button.  This is because I need to process other information together with the data in the InfoPath form.  This is were I'm having trouble.  Calling the Submit (XmlFormView.XmlForm.Submit()) method yields me an InfoPathFatalException exception.  It doesn't even step into the Submit coe I wrote for the InfoPath form.  Just to test and make sure that the form still works, I've kept the Submit button in the SharePoint ribbon visible.  I can debug and step into the Submit code.

    I've checked various sources in the internet and have yet to find a working sample of calling the InfoPath form's Submit method from an ASP.NET button.  Is this even possible?

    Hope you can help.  Thanks!

    Dino

  • Hi Dino,

    Glad this post has helped! Unfortunately you cannot directly call a "submit" or a submit connection from a hosted page. However, there is a way you can still do this:

    - Create a .NET web service that takes, as a minimum, the name for the "submitted" form and the XML from the form

    - From your custom ASPX page, call that web service passing the information from the form

    Here is some sample code:

    NOTE: THIS IS NOT PRODUCTION READY!! IT IS INTENDED AS A SAMPLE ONLY!! **

    Here is a sample web service:

    //You will need to change the code to reference your library name and your site URL

    [WebMethod]

    public void UploadDocumentToLibrary(string formName, string formXML)

    {

    //NOTE: If running this anonymously, the "RunWithElevatedPrivileges will be

    //needed to allow the process to complete.

    SPSecurity.RunWithElevatedPrivileges(delegate()

    {

    string libraryName = "YourLibraryNameForSubmittedForms";

    SPSite site = new SPSite("http://serverName"); //Or servername/site

    SPWeb web = site.OpenWeb();

    web.AllowUnsafeUpdates = true;

    SPFolder folder = null;

    //See if the library exists - if not, catch the error

    //and create that folder

    try

    {

    folder = web.Folders[libraryName];

    }

    catch (Exception)

    {

    //Library did not exist, so we create it and add it to the Quick Launch

    SPListTemplateType t = new SPListTemplateType();

    t = SPListTemplateType.DocumentLibrary;

    Guid listGuid = web.Lists.Add(libraryName, "", t);

    SPList newList = web.Lists[listGuid];

    newList.OnQuickLaunch = true;

    newList.Update();

    folder = web.Folders[libraryName];

    }

    //Build our URL for the form

    string fileUrl = folder.Url + "/";

    //See if the user added ".xml" to the file name

    //If not, we will want to add it

    if (formName.IndexOf(".xml") > 0)

    fileUrl += formName;

    else

    fileUrl += formName + ".xml";

    //Set the encoding

    System.Text.Encoding e = System.Text.Encoding.UTF8;

    //Create a byte array from the XML string

    byte[] b = e.GetBytes(formXML);

    //Create the file in the specified library

    SPFile file = folder.Files.Add(fileUrl, b, true);

    }); //Closing for RunWithElevatedPrivileges

    }

    Then from my custom ASPX page, I can call this web service like this:

    protected void Button1_Click(object sender, EventArgs e)

    {

    try

    {

    this.DataBind();

    XmlNamespaceManager ns = XmlFormView1.XmlForm.NamespaceManager;

    XPathNavigator xnMain = XmlFormView1.XmlForm.MainDataSource.CreateNavigator();

    //My web service was called: CreateFormFromXML - so this line needs to be whatever

    //the name is for the web service created above

    CreateFormFromXML svc = new CreateFormFromXML();

    //There is just one public method in the web service: UploadDocumentToLibrary - call this

    //passing in whatever you need to create the form name and the "OuterXml" of the loaded form

    svc.UploadDocumentToLibrary(xnMain.SelectSingleNode("/my:myFields/my:field1", ns).Value.ToString(), xnMain.OuterXml.ToString());

    }

    catch (Exception ex)

    {

    Response.Write(ex.Message);

    }

    }

    When I tested this in my environment, the form was created appropriately in the library. :)

    Hope this helps Dino!

    Scott

  • Hi Scott,

    It's been a few days and I haven't seen my post, so I think it might not have gone through when I submitted.

    Anyway, the approach you suggested won't work for my scenario because I need the form's validation to fire.  It won't if I just upload the Xml file into the library.  In fact, this is my current implementation.

    Since I can't call InfoPath's Submit, I'll split my form into 2 pages as a workaround.  1 page for the ASP.NET controls and another for InfoPath.  The user will then access the form as if he/she were running a wizard, with step 1 being the ASP.NET page and step 2 being the InfoPath form.  

    Thanks!

  • Hello!  I think you forgot a brace in your property set:

    private object _strUri

    {

     get { return FormState["_strUri"];   <----should be a brace here, no?

     set { FormState["_strUri"] = value; }

    }

  • There is no need of setting the Security Level of the form to Full Trust and signing the form template with a digital certificate if to convert "Main submit" data connection to UDCX file connection having stored it in a data connection library on the same sharepoint site collection

  • Scott,

    The problem I have is that I am not able to update an existing form (form based not browser enabled). But here is a twist, if I wait for about 15 mins then I open the form I am able to update and Submit.

    Here is the error

    InfoPath cannot submit the form.

    An error occurred while the form was being submitted.

    The form cannot be submitted to the following location: http://salessourcetest/teamsites/ccmtform/Form/123451234123213.xml

    The specified location cannot be accessed. Check that the location you entered is correct and that you have appropriate permissions.

      at Microsoft.Office.InfoPath.Internal.MomExceptionHelper.ExecuteDataConnectionAction(XmlFormHost formHost, OMCall d)

      at Microsoft.Office.InfoPath.Internal.FileSubmitConnectionHost.Execute()

      at CMTInfoPath.Code.FormCode.SaveToSharepoint()

      at CMTInfoPath.Code.FormCode.Button1_Clicked(Object sender, ClickedEventArgs e)

      at Microsoft.Office.InfoPath.Internal.ButtonEventHost.OnButtonClick(DocActionEvent pEvent)

      at Microsoft.Office.Interop.InfoPath.SemiTrust._ButtonEventSink_SinkHelper.OnClick(DocActionEvent pEvent)

    I replace the Submit with "Custom Action" and put in the code you provided. It's not reaching the Submit event handler. But if I wait for 15 mins it works fine. So bottom line its nothing to do with Submit action

    Appreciate your help on the same.

  • Hi Cheemalapati,

    It sounds like the form/data is being locked. Unfortunately this could be any number of things causing this and troubleshooting that in this blog would not be beneficial. I would suggest you enable Verbose logging on the server, reproduce the issue and see if this points you to what may be the underlying cause. If not, then you will want to open a support case to have a support engineer dig into this with you.

    Scott

  • How i can Know if the user open a new form or open existing form?

  • Hi Muayad,

    If you are *not* using code then you would need to check if a field you know would always be empty on a new form and *always* completed on an existing form. If you are using code then you can do this:

    //C# sample

    if (this.New)

    {

    }

    else

    {

    }

    //VB sample

    If Me.[New] Then

    Else

    End If

    Scott

  • Hi Scott,

    It's amazing that your post is still very relevant all of these years now. Thank you for all of the work you've placed into this post and updating it periodically.

    I have implemented your code (in addition to the modifications within the comments for opening existing forms) into my XSN. There was a question asked several years ago about an error dealing with ArgumentOutOfRangeException: Length cannot be less than zero. However, I don't believe the OP ever responded to your queary. And unfortunately, I am having the same issue as the OP. The error I am receiving involves the following line of code:

    string strLoc = strPath.Substring(0, strPath.LastIndexOf("/"));

    I am publishing the form to a content type within my site. I'm not getting any errors during the build. However, when I test the form, the error appears while the form is loading.

    Would you have any direction on how to resolve this issue?

    Thanks!

    Tom

  • Hi Tom,

    What I would do is either add logging to the code or, even easier, just add a new text box to your form and just before the code that fails, set the value of the node the text box is bound to: strPath - this will show you what is in that variable which should point you to what is causing the error.

    Scott

Page 11 of 12 (166 items) «89101112