InfoPath forms can be configured with cascading dropdowns using a variety of data sources. If you’re a developer you know it’s not a highly complex programming task but certainly more complicated than should be necessary. You can’t just pull list data in such a way that makes a cascading drop-down work from within InfoPath, some fuss is always involved. Now, what about multiple forms within various sites or even multiple cascading drop-downs on a single form? Like any project you realize whatever solution you have in the initial case will likely need refactoring later.
It’s not my intention to rehash the details of programming cascading dropdowns, suffice it to say that you can use web services (asmx specifically) as a means to populate form elements. Of course, web services are global within MOSS (Web App or Farm) and are usually installed in physical directories (generally a folder within ISAPI, LAYOUTS, or the physical directory representing port 80 for example) on the server and automatically mapped to all sites within the chosen scope.
Given the global nature of MOSS web services you can easily run into several issues; in particular, if your web service depends on site specific data or other site specific configurations. A poor way to handle this situation is to pass site specific data back via your web service parameters. The obvious down side here is that the primary role of the service is not to manage configuration data but help with a business need. Even worse, a scenario where the configuration data tells the service how it connects with a site list or table directly. In that case the configuration data must necessarily be stored in a separate place altogether. You could choose to store configuration data in the web.config file of the web application but that would not provide any site specific context and is not considered a good practice, generally.
The example I’m eluding to here is a service that needs to operate on different sites and connect to site specific lists to perform the same function. This seems like a tall order but the technical solution is rather simple.
The steps to solve this are as follows:
1. Develop a web service that reads configuration parameters from .AllProperties of SPWeb which can hold site specific data entered by site owners or administrators. One caveat in testing this approach is to understand that when Invoking the service be sure to POST back to the full site path. You’ll notice that the OTB default test page endpoint only Invokes back to the web application root (usually in ISAPI or LAYOUTS) of the top level web application.
Here is example code for reading these configurations (in this case 4 site specific parameters are defined):
SPWeb web = SPContext.Current.Web;
this.m_ListName = web.AllProperties["CascadeList"].ToString() ;
this.m_DropDownID = web.AllProperties["DropDownIDColumn"].ToString();
this.m_Parent = web.AllProperties["ParentColumn"].ToString();
this.m_Child = web.AllProperties["ChildColumn"].ToString();
2. Once deployed site owners or administrators can add these four properties to each site individually via SharePoint Designer. The steps are as follows:
a. Open SharePoint Designer to a specific site or subsite
b. From the top meny choose Site => Site Settings
c. On the site settings panel choose Parameters as shown
d. Simply add the parameters that define how the service will operate on the site. This information would be provided as documentation to site owners.
In this case I enter the list name for the service to connect with a list called “Rooms”. I further enter the name of the two columns, “Building” and “Room” (remember the use case here is a cascading dropdown usable from any site containing a similar list). I use “Rooms”, “Building”, and “Room” only as example names. Any kind of naming can be used.
Here is an example of how the list looks on /Site1 (ignore the Ddparam column, that is used to identify specific drop-downs on a form)
Keep in mind the same service can be used from any site with this approach as long as the site specific parameters are entered and each site has its own version of the list above (for this example).
3. If the service happens to be feeding an InfoPath form (as this one is) then one other configuration needs to happen. In InfoPath, when you add your data connections, you will see a button that allows you to convert the connection to a udx file and have it saved within a data connection library on the site. You need to perform this step. Once the udx file is saved then open it up and modify the site specific path for the ServiceURL element to include the full path of the subsite. This will create the correct postback URL required. Here is a sample using /Site1
That’s it, the service can now be managed purely from an administrative standpoint from any number of sites or subsites. Very cool indeed.