Dedicated to development, configuration, and tips and tricks for both WSS 3.0 and MOSS

Posted by Aaron Varga on Saturday, 14 Feb 2009 10:40

Lately we’ve been getting a number of requests for solutions that will require the use of forms, and the first reaction is usually “let’s use InfoPath”.  InfoPath is great for what it does, and is horrible for what it doesn’t.  This post will attempt to offer pros and cons for both InfoPath and ASP.NET ASPX forms, and hopefully will allow you to recommend the correct approach for an electronic forms solution.  This post assumes you’re considering InfoPath Forms Services (browser-enabled forms), as opposed to using the InfoPath client.


InfoPath Forms

Let’s begin by taking a look at InfoPath.  InfoPath is a great tool for creating simple data-entry forms, and for retrieving data from a variety of data sources.  In addition, it’s great when you need to submit data to a SharePoint form library for the purposes of leveraging a SharePoint workflow.  Where InfoPath breaks down is when we need to submit data to other sources, or when we need to provide a rich user-interface with robust controls and data validation.  Let’s take a look at some pros and cons of InfoPath:

Pros

  • Great for submitting data to SharePoint or a SharePoint workflow
    Most of the time when we’re using electronic forms, it is to support a workflow process.  As you [should] know, a SharePoint workflow runs for a specific list item, and data needed for the workflow needs to be entered into the fields for that particular list item in order for the workflow to see it.  Because of this fact that the data actually needs to be a list item, InfoPath is a great choice, because you can effortless promote form fields as columns in your list, which the workflow can then use.
  • Great for retrieving data
    InfoPath provides a very simple wizard interface for selecting a data source for data retrieval.  You can easily select a web service, and XML document, or a SharePoint list and have that data appear in your form pretty easily.  You can also connect to a SQL database and retrieve data from tables, views, or stored procedures.
  • Great for simple end-user form development
    InfoPath is great for creating a simple form with a few fields and simple rules and simple data validation.  I keep emphasizing simple because once you introduce complex business rules, data validation, conditional formatting, or complex data presentation that pushes the limitations of InfoPath, you will be forced to get very creative which often involves some sort of custom coding.
  • Most of the time only requires SharePoint site permissions
    Unless you are creating a browser-enabled form with .NET code-behind, or your form requires Full Trust and uses the InfoPath client, it’s relatively easy to deploy a form to SharePoint.  Simply publish the form to the desired form library and you’re good to go.  However, as soon as you introduce .NET code in a browser-enabled form, you need to install and activate the form to Central Administration and activate the newly-created feature at the site collection level.  You will need to have access to Central Administration and to the site collection in order to activate these features.

Cons

  • Difficult to submit data to non-SharePoint data sources
    Like I mentioned, InfoPath is great for submitting data to a SharePoint form library.  It is not so great for submitting the data to anything else.  If your form is submitting data to a single (single being the operative word here), then you could potentially configure the form to submit directly to a table.  However if the data needs scrubbed or manipulated, chances are you will need to submit the data via a stored procedure, which InfoPath cannot do.  For this, you will be forced to develop a custom web service that accepts the data either field-by-field, or as a giant blob of XML that you have to parse through, which you then have to submit to the database by writing traditional ADO.NET code.  Not too simple anymore, huh?
  • Limited user-interface
    InfoPath allows you to create forms with a variety of standard controls, such as textboxes, date pickers, radio buttons, checkboxes, buttons, drop-down lists, repeating tables, etc..  Unfortunately, it is pretty much limited to those items (you get a few more with the rich client, but that’s beyond the scope of this post).  You don’t have any type of tree view control, no multi-select list box, no tab control, no image buttons, and no grid view control. The lack of a grid view control is a deal breaker in many cases, because we often have to present long lists of data, and the built-in repeating table doesn’t support sorting, grouping, or paging.  Yuck.  Finally, there’s no way to add HTML or CSS to your form, meaning that it can’t inherit any SharePoint styles, and you’re limited to what you can design in the form.  This frequently gives an inconsistent look and feel for a SharePoint process.  Again, yuck.
  • Difficult to secure sensitive data
    Assuming the InfoPath form is being submitted to a SharePoint form library, any data the form contains is inherently insecure.  The form is just saved to the form library like any other document, except as an XML document.  This means if your form contains social security numbers, salary information, or any other type of sensitive data, a user could download the XML file and open it in Notepad.  Even if the data isn’t visible through InfoPath, the data is still stored in the form and can be viewed by any user that knows how to download.
  • Difficult to integrate with Forms-Based Authentication
    Although browser-enabled forms will work with forms-based authentication, the useful username() function no longer works.  This means that even if you’re logged into your SharePoint site as a valid FBA user, InfoPath will have no idea who you are.
  • Not developer-friendly
    If you’ve made it this far in this post, you’ll have already read that while simple things are easy to accomplish in InfoPath, complicated things aren’t and often requires .NET code.  While you can definitely add .NET code to a form, it’s not the same type of form coding a typical developer is used to.  You have to parse XML to retrieve field values, you have to parse XML to set field values, and you’re still pretty much limited to the functionality that you have through the designer.  You can just write more complex business rules and logic, you can’t make the form or the field controls behave any differently.
  • Licensing
    Obviously your users need to be licensed for InfoPath Forms Services before they’re able to use it. Even if you have licenses for the InfoPath client, separate licenses are required for browser forms. If the users are internal and members of your domain, you must be licensed for InfoPath Forms Services, which is available either through the MOSS Enterprise CAL or the standalone InfoPath Forms Services CAL.  If the forms are going to be available externally to non-domain users or anonymous users, then you must be licensed for either Office Forms Services for Internet Sites or be licensed for SharePoint for Internet Sites, which is the external connector that provides the ability for an unlimited number of users to access and use InfoPath through a browser.

ASP.NET ASPX Forms
Creating ASP.NET ASPX forms offer the most in terms of flexibility, as you can do anything that you can do in a traditional ASP.NET web site, including HTML, CSS, JavaScript, and even AJAX.  A lesser-known technique is integrating these pages into the SharePoint “shell” to give users a seamless experience.  It doesn’t take much effort to have SharePoint host these pages and have the master page and styles applied to your custom forms.  Let’s take a look at some pros and cons associated with ASP.NET forms:

Pros

  • Great for submitting data to non-SharePoint data sources
    While InfoPath is great at submitting data to a SharePoint form library, ASP.NET forms are great for submitting data to everything else.  You can easily write your ADO.NET code or whatever-you-like code to submit to your data source, and not have to worry about parsing a bunch of InfoPath XML first in order to pull out the values.  It’s a lot less work to get the data into your data source.
  • Great for providing a rich user interface
    Unlike InfoPath, you aren’t limited to a tiny set of field controls.  You can use whatever an ASP.NET web site supports, including tree view, tab controls, grid views, AJAX – even Silverlight if you really really want.  You can also provide any type of business rules and validation you like as well, including summaries, friendly pop ups, etc.  Also, since the pages are inheriting the SharePoint styles and master page, your forms will automatically pick these styles up, and will also use the master page.  This gives the appearance that they’re actually built-in SharePoint pages.  It’s slick. There are plenty more options for developing a rich and clean user interface if you’re developing ASP.NET forms.
  • Developer friendly
    This one’s a no-brainer.  Obviously if you’re familiar with ASP.NET and .NET programming, creating data-entry forms are a cinch.  There’s no learning curve with learning how to code an InfoPath form, and you don’t have to learn the ins and outs of the InfoPath object model.  This opens up the development work to a wider audience of our developers, as not many have hands-on experience with writing .NET code behind an InfoPath form.  In addition, should any future updates be required to the form or the code, finding resources on ASP.NET online or hiring someone with ASP.NET skills will not be a difficult task.  It’s a widely practiced technology, and there are a ton of resources.
  • Can provide secure means of sensitive data access
    Since no data is actually stored in the ASP.NET form, it provides a much more secure way of viewing sensitive data, as it will have to be retrieved and submitted to the database directly.  A user can’t download an ASP.NET form and see the data like they can with an InfoPath form.
  • Integrates well with Forms-Based Authentication
    By using an ASP.NET form in an FBA-enabled site, we are able to see the user that is currently logged in, unlike with an InfoPath form.
  • Access to the SharePoint Object Model
    Since the ASP.NET forms are running under the context of the SharePoint site they’re accessed from, we can use the SharePoint Object Model to do whatever we wanted.  We could very easily access SharePoint list or site data, user profile information, etc., and bind that information to controls on the form.  To do this in InfoPath, you’d have to use the unfriendly out-of-the-box SharePoint web services, or write your own.
  • Licensing
    Not required! There aren’t any licensing headaches when exposing ASP.NET forms to users, even externally.  Obviously since they’re going to be integrated into SharePoint, you’ll have to have the appropriate licenses for that, but nothing specific to the forms themselves.

Cons

  • Potential additional development overhead
    Obviously writing custom ASP.NET forms requires a competent ASP.NET developer, which may not always be available (though I’d argue that in order to develop some of the complex forms that we have had to do in the past – you will still need a very competent .NET developer).  In addition, changes to simple business rules or data validation is more difficult to accomplish in ASP.NET than in an InfoPath form.  If the form is simple and doesn’t require data going to SQL, then an end-user is probably better of just using InfoPath.
  • Requires file system access on SharePoint server
    To deploy custom ASP.NET forms to SharePoint, they need to be placed onto each web front-end’s file system.  In addition, the assembly must be deployed to the GAC or to the web site root’s BIN directory.  Either way, the developer must have access to the file system, or to someone that has access to the file system.
  • Not business-user friendly
    One good thing about InfoPath is that business users can even build simple forms.  They will probably not be able to develop an ASP.NET form in .NET.  If the form is truly that simple, then creating ASP.NET forms is probably overkill anyways, and InfoPath should be the recommended solution.

 

So, How Do I Choose?
Great question! The answer should be easy -- do the simplest thing possible that will result in a clean solution.  If you can implement the desired functionality quickly and painlessly in an InfoPath form, then by all means do that.  If developing an InfoPath will actually be prohibitive to functionality and future maintainability, then consider building custom ASP.NET forms.

To make your decision even easier, I built a flowchart that should help guide you.  It does not include every scenario, but does include most scenarios that we deal with:

 image

 

Conclusion
Hopefully this post ironed out some of the confusion surrounding what solution to offer clients for their electronic forms requirements.  In no way should we suggest InfoPath just because “it’s an Office app that integrates nicely with SharePoint”.  In some cases it does, it many cases it does not.  The actual requirements need to be evaluated before jumping on the InfoPath bandwagon.  Trust me, I’ve had my hands in enough complex InfoPath forms, and I know that after a certain point of complexity, doing something in InfoPath is more difficult, more expensive, and plenty more aggravating. InfoPath is merely a mechanism to get data into SharePoint. It should not be used to develop complex data entry forms when the data is going to a non-SharePoint data source.  It’s like trying to make a spoon behave like a Swiss Army knife.  Understand what it does well, and more importantly understand what it does not.

Posted by Aaron Varga on Monday, 2 Feb 2009 01:14

Any time you deploy custom development artifacts (style sheets, assemblies, web parts, etc.), it is best practice to package everything up into one or more features, then wrap them up into a SharePoint solution (.wsp) file.  The only problem with creating features is actually defining the feature definition files – the syntax and nuances of each manifest type is difficult to remember, and there are so many that writing these from scratch is next to impossible.  Personally I’ve done enough that I have templates I always use, but occasionally I’ll need to create a new type of feature and I find myself search MSDN for documentation on what to throw into the XML files.  Enter CAML.NET IntelliSense.

John Holliday recently introduced CAML.NET IntelliSense, which is a Visual Studio add-in that provides IntelliSense support for each type of file that requires to to sling around CAML.  This add-in adds the necessary XML schema files to Visual Studio for you. 

Now when I create a feature.xml file, I have full IntelliSense support:

image


This works for all types of feature manifest files too, such as your elements manifest:

image


It even allows you to pick a specific value if there are only a limited set of valid values:

image


As I’ve reiterated in multiple blog posts, you should absolutely be deploying your custom development artifacts as features and solution packages.  Hopefully this makes it a little easier!

Posted by Aaron Varga on Saturday, 31 Jan 2009 01:38

I’ve been waiting for this for a couple months after an announcement was made that it was going to be released, and finally today the SPDisposeCheck tool has been released!  The tool reviews a .NET Assembly (DLL or EXE) and evaluates SharePoint API's used in that assembly. It will produce a report identifying where code doesn't follow best practices for memory management in SharePoint.

To test this out, I created a simple console application that contains undisposed SharePoint objects:

static void Main(string[] args) {
    SPSite siteCollection = new SPSite("http://server");
    SPWeb site = siteCollection.OpenWeb();

    // do something
}


As you know, you must always be sure to dispose of your SPSite and SPWeb objects, as this can lead to expensive memory leaks.  If you’re not a seasoned SharePoint developer, this may not be obvious to you, and for this the SPDisposeCheck tool is a huge asset.  I ran the following command after downloading the tool:

SPDisposeCheck.exe C:\Projects\Test\Aaron.TestApp\bin\Aaron.TestApp.exe

Which produced the following:

image


You can see that 2 errors were found.  Specifically, this tool points out the following for the first error:

Disposable type not disposed: Microsoft.SharePoint.SPSite
***This may be a false positive depending on how the type was created or if it is disposed outside the current scope


This tells me that my SPSite object needs disposed. The second error is exactly the same thing, except in reference to SPWeb.  Let’s clean up the code, this time disposing of our objects:

using (SPSite siteCollection = new SPSite("http://server")) {
    using (SPWeb site = siteCollection.OpenWeb()) {
        // do something
    }
}


Now, when I run this tool I get the following:

image

 

There’s a pretty good chance that if you’ve even made it this far in this post, that you’ve written SharePoint code before, and already know to always dispose of your SPSite/SPWeb objects.  However, what about the less obvious examples.  I ran this tool on an assembly I’m currently developing for a client, and I got an error:

Notes: Dispose/Close was not called on SPLimitedWebPartManager.Web


I went back through my code, and found this line:

SPLimitedWebPartManager manager = defaultPage.GetLimitedWebPartManager(PersonalizationScope.Shared);

Basically this gets the web part manager for a specific page, so you can add/delete/modify the web parts that are on it.  Why is this throwing an error?  I’m not using an SPSite OR an SPWeb anywhere!  It’s because there’s a very non-obvious memory leak in this that creates its own SPWeb object, and this object needs to be disposed.  The correct usage of this is:

using (SPLimitedWebPartManager manager = 
defaultPage.GetLimitedWebPartManager(PersonalizationScope.Shared)) { // do something if (manager.Web != null) manager.Web.Dispose(); }


Not at all obvious, but I’m glad this tool caught it!  PLEASE, if you are writing Object Model code, run this tool.  For a ton more information on SharePoint Dispose() patterns, Roger Lamb’s post is by far the best one out there.  Also check out this MSDN article.

You can (and really should) download this tool here.

Posted by Brian LaSitis on Tuesday, 27 Jan 2009 02:10

For most production SharePoint deployments that involve custom .NET code, such as custom developed web parts, controls, event handlers, etc., best practice dictates that any shared assemblies should be deployed to the Global Assembly Cache (GAC).  While this is a great practice, the GAC location (e.g. %WINDIR%\Assembly) does not behave like a typical folder, or at least doesn’t appear to, and for most .NET developers, the GAC in general is somewhat of a mystery.  One of the biggest perplexities with the GAC is that upon first glace, there does not seem to be a means for retrieving a copy of an assembly that is deployed to the GAC.  While all of us have probably dragged a .NET assembly into the %WINDIR%\Assembly folder to add it to the GAC, if you try dragging an item out of the GAC, it does nothing, and the familiar Cut/Copy/Paste operations that are standard on any Windows Explorer folder view are grayed-out.  How dare you do this to us Microsoft?!

In the sections below I will explain how you can retrieve the actual DLL for an assembly that is only deployed within the GAC, and in the process, we will make some sense out of how the GAC actually works and see how it really is just a specialized folder hierarchy for storing .NET assemblies.

The Uniqueness of the %WINDIR%\Assembly Path Location

If you open a Windows Explorer to the %WINDIR%\Assembly path location, you are presented with a specialized view of this folder, as shown below:

image

This unique view is the result of a Windows Shell extension called SHFusion.dll (as an aside, the reason for this name is the original codename for the GAC, when the .NET Framework was first being developed, was Fusion).  However, if you open a Command Prompt and switch to the %WINDIR%\Assembly path, you see a slightly different listing:

image

The reason for the Command Prompt displaying this view, as opposed to what Windows Explorer shows, is that Windows Shell extensions are not applied to file operations performed from the Command Prompt.  Here we are presented with seven (7) folders, each of which is explained below:

  • GAC – stores .NET 1.x assemblies
  • GAC_32 – stores .NET 2.x+ assemblies that are built specifically for 32-bit architecture.
  • GAC_MSIL – stores .NET 2.x+ assemblies that are architecture independent, meaning they can be used on 32- or 64-bit systems.
  • NativeImages_Vx_Architecture – there can be multiple folders of this format, specific to each version of the .NET Framework present on the system, with possible 32 and 64 bit flavors of each.  Each of these folders is used for storing native images of .NET assemblies that have been pre-compiled using NGen, to eliminate the need to run the MSIL code through the JIT compiler at execution time.
  • temp, tmp – temporary folders.

Additionally, on a 64-bit system, one additional folder would be present:

  • GAC_64 – stores .NET 2.x+ assemblies that are built specifically for 64-bit architecture.

To determine which folder the assembly you seek is within (e.g. GAC, GAC_32, or GAC_64), refer to the Processor Architecture column within the Fusion-based Windows Explorer view.  Let us consider an example:

Assume we would like to retrieve the DLL for the Contoso.Website.Controls assembly, shown in the Explorer view above.  As we can see, the Processer Architecture indicated is MSIL, indicating that this assembly will be within the GAC_MSIL subfolder, if we proceed to descend into that level, we see the following:

image

At this level, we have a subfolder for each assembly, so let us descend into the Contoso.Website.Controls subfolder, to see the following:

image

At this level, we see folders with names based upon the version of the assembly, culture (if not invariant), and public key token.  It is this exact folder structure the enables the GAC to store multiple versions of the same assembly without one overwriting or conflicting with the other.  Since there is only one subfolder present at this level, let us proceed to descend into it, to see the following:

image

Voila!  At this level, we are able to take a copy of the exact DLL file that was deployed to the GAC.  What was a pleasant surprise to me is that the GAC does not in any way mangle the original name of the DLL that was deployed.

Disabling the SHFusion.dll Shell Extension

There is another option of seeing the actual folder structure of the GAC that does not involve the command-line, but I would not recommend doing this on a production system.  To view the same folder structure within Windows Explorer that we were able to navigate through using the Command Prompt, we can disable the SHFusion.dll shell extension using one of three possible methods:

  1. Rename %WINDIR%\Assembly\Desktop.ini – within %WINDIR%\Assembly, a hidden, read-only, system attributed file named Desktop.ini is present.  By renaming this file to something else, such as Desktop.ini.bak, we effectively prevent SHFusion.dll from loading for this folder.
  2. Add the DisableCacheViewer Registry Value – within the HKLM\Software\Microsoft\Fusion registry path, a new DWORD value can be created with the name DisableCacheViewer and a value of 1 to prevent SHFusion.dll from being loaded.
  3. Rename SHFusion.dll – the SHFusion.dll itself can be found within %WINDIR%\Microsoft.NET\Framework\v.XX, and if this file is renamed, it will not be loaded when Windows Explorer is pointed at the %WINDIR%\Assembly path.

By performing any one of the above steps, upon opening %WINDIR%\Assembly the next time, you will be presented with the following view, similar to what we saw within the Command Prompt dir listing above:

image

So there you have it – the biggest mysteries of the GAC have all been dispelled:  how its path location works within Windows, its unique rendering method within Windows Explorer, how it actually stores DLLs you deploy to it, and how you can retrieve them later.  So in reality, all the GAC truly is made up of is a specialized folder hierarchy for tracking multiple versions of assemblies, independent of processor architecture, that has special .NET CAS policies defined for it to allow assemblies deployed to this location to have Full Trust permissions.  Now go forth, fire up your compilers, and start deploying code to the GAC!