Writing your own custom DataFormWebPart with C#
I believe that the DataFormWebPart class is a very powerful, often overlooked, piece of functionality available to SharePoint Developers that deserves some serious attention. The DataFormWebPart (DFWP) is nothing new, and many have blogged about creating one through SharePoint designer (SPD), but what I want to discuss is the possibilities that exist when creating one through C# (or VB).
The Story…
Imagine a WebPart that you can just drop on a page, set some web part properties, and SHAZAM – you’re displaying enterprise data from any source – configurable at RUN TIME. You may be thinking I’m talking about the Business Data Catalog (BDC) that comes with MOSS, and I have to admit, I am. However, what if you don’t feel like paying for MOSS and you still want similar functionality? Even for people that have MOSS – the DFWP is still a great means to get data on the page with minimal effort, and you can take advantage of the sorting, grouping, and filtering functionality that comes with the DFWP – saving coding time.
In this post, I am going to cover
1. Demonstrate how to bind the DFWP to XML returned from a web service through C# - rather than through SPD.
2. Tips to help you with your DFWP’s XSL
3. Real world scenarios why this is a great idea.
What to think about when overriding…
In my opinion, there are only 2 main components to the DFWP that a developer needs to think about, the Data Source, and the XSL that is used to format that data. I started by creating a new class that inherits from Microsoft.SharePoint.WebPartPages.DataFormWebPart. Then, I overrode the OnInit method in my web part. At a minimum, there are only 2 properties you will have to set to get your DFWP to work, the DataSourcesString or DataSource(s) properties, along with the XslLink or the Xsl properties. Following the setting of these properties you would call the DataBind method and you’ll be done:
However, if this is all you do, you might as well just use SPD because you haven’t gained anything. The thing to keep in mind here is that we want to set our data sources at run time, giving our end users the ability to target any data they desire.
The DataSource property accepts an IDataSource object. A good example of an appropriate object here would be to use the SqlDataSource object that is bound to a SQL stored procedure. As long as the procedure returns the Data in a format that your XSL expects, this is a great option.
I however chose to get my data through a web service (simply to comply with company standards). You see the DataSourcesString that I used above, that is basically a string that contains the SOAP envelope and the location and name of my web service. In that string there are 6 web service settings that need to be set. Example of these settings:
Here’s the string in its entirety:
this.DataSourcesString = String.Format("<%@ Register TagPrefix=\"sharepoint\" Namespace=\"Microsoft.SharePoint.WebControls\" Assembly=\"Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c\" %><sharepoint:SoapDataSource runat=\"server\" SelectPort=\"ServiceSoap\" WsdlPath=\"{0}\" ID=\"Service_x0020_on_x0020_jobstatus1\" SelectAction=\"{1}\" SelectServiceName=\"{2}\" SelectUrl=\"{3}\" AuthType=\"{4}\"><SelectCommand><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><{5} xmlns=\"{6}\"/></soap:Body></soap:Envelope></SelectCommand></sharepoint:SoapDataSource>", wsdlPath, selectAction, selectServiceName, selectUrl, authType, webServiceMethodName, webServiceMethodNamespace);
A great tip that makes this web part very dynamic is to create a web part property for each of these settings. That way, the user can just drop the DFWP on the page, set the properties, and they’ll be off to the races. Additionally, I check the Form Post and the Query String for the variables, giving my users and developers 3 options to get these settings set.
Tips for your Xsl…
The best way to build your Xsl for your new DFWP is to let SPD do it for you. This won’t work unfortunately if you want to bind to a SQL data source because that is disabled in SPD, so you’ll have to start with my code.
Once you have the Xsl, you can either put it in a file on a URL and set the “XslLink” property, or you can set the Xsl string itself to the “Xsl” property. I do the latter by putting my Xsl file as an embedded resource in my assembly. I do this simply because it makes deploying easier.
If you do find yourself playing in the Xsl, there’s one area that is particularly worth mentioning. In the “dvt_1.body” template – there’s a line as follows:
<xsl:variable name="Rows" select="/soap:Envelope/soap:Body/ddw1:ReturnJobStatusResponse/ddw1:ReturnJobStatusResult/Rows/row"/>
This variable “Rows” is set to the response to the “ReturnJobStatus” web service method. You will need to alter this to reflect your web service method name. A better way to do this would be to get this variable from the query string, and then the web part would be more generic.
If you examine the above line carefully – you should know that the expected format of the XML is of the following raw format:
You can change this to another format by altering the “/Rows/row” in the variable assignment. Rows-Row is the default configuration that SPD expects to see when it tries to generate the DFWP. If the xml is not in this configuration – SPD will error out when you try to add the DFWP into a zone.
Here’s a screen shot of my DFWP in action:
In summary, why this is cool…
By writing your own DFWP – the sky is the limit as to how far you can customize and reuse the DFWP’s functionality. Imagine a business that requires your end users to be able toggle the data sources of your DFWP at run time. All you would have to do is override CreateChildControls and add three buttons to your DFWP. When the user clicks each button, you could toggle the DFWP to another data source. Try doing that with SPD (without writing 3 DFWP’s that is)!
Please email me at - phil [dot] wicklund [at] mindsharp [dot] com - if you would like the source.
Phil Wicklund