Sunday, September 27, 2009

User Control Error In SharePoint

Background

I was getting the following error when trying to build a simple hello world user control (ascx) and then load it into a web part.

Error

The file '/_controltemplates/XXX/MyWebUserControl.ascx' does not exist.

at System.Web.UI.Util.CheckVirtualFileExists(VirtualPath virtualPath)

at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile)

at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile)

at System.Web.UI.TemplateControl.LoadControl(VirtualPath virtualPath)

at System.Web.UI.TemplateControl.LoadControl(String virtualPath)

at MOSSDistillery.UserControl.WebPart.MySmartPart.CreateChildControls()

Symptoms

What was frustrating was that I could point to any existing user controls provided in SharePoint and they load in fine. Here is the code:

protected override void Render(HtmlTextWriter writer) {
base.Render(writer);
writer.WriteLine(loadControlError);
}
protected override void CreateChildControls()
{
try
{
base.CreateChildControls();

System.Web.UI.UserControl control = (System.Web.UI.UserControl)Page.LoadControl("~/_controltemplates/MyWebUserControl/MyWebUserControl.ascx");
Controls.Add(control);
}
catch (Exception ex)
{
loadControlError = ex.Message + " " + ex.InnerException;
}
}

This error was pretty tough to figure out because:

  • The ascx file was in the correct place.
  • I had entered a safe controls entry.
  • If I changed the web.config to Full trust, everything would work.

I did a significant amount of investigation to understand why I was getting this error. From what I was able to find out, you will get this error in the following scenarios.

  • If you have the ascx file in a location where it cannot be found.
  • If you place the web part dll in the web bin directory and do not place that ascx control in the ~/_controltemplates/ directory. Specifically if you place the web control in a custom folder within the control templates folder in the 12 hive folder. Even with all the correct CAS permissions, it will not work. However if the web part dll in the GAC, it will work.
  • If you place the web part dll in the web bin directory, the error will go away if you move the code from the CreateChildControls() to the OnInit().

Resolution

When research the solution, I saw that many people would just change the permissions levels to full which is a completely unacceptable solution. The following are some deployment options for a web part that will show an ASP.net user control. I have ordered them in the most secure to least secure:

  • Deploy the web part dll to the bin. Add the code to load the user control in the OnInit() method. Place the user control (ascx) directly into the control templates folder in the 12 hive. Make sure you have a safe controls entry in the web.config. Only disadvantage is that you cannot place the user control into a custom folder to separate your user control from SharePoint's user controls. However this is the most secure.
  • Deploy the web part dll to the GAC. Place the loading of the user control into the CreateChildControls method. Place the user control (ascx) where ever you want within the control templates folder in the 12 hive directory. I suggest putting the user control into a custom folder. Make sure you have a safe controls entry in the web.config. The disadvantage is that the dll is not accessible to any running process on the web server. I know many developers have become accustomed to putting dlls in the GAC but again you should always strive to deploy to the web bin and run under minimal trust.
  • I found this option - http://blogs.msdn.com/chandru/archive/2009/03/02/cas-in-sharepoint.aspx. It does work however what you are basically doing is allowing the custom CAS permission you have created for your web part to run in full trust. There are several major issues with doing this. First, the stsadm addsolution command will fail if Unrestricted="true" is added to the PermissionSet within the manifest.xml file – it is not allowed. Second, you decided to do this, will have to manually make the change to each front end web server in the farm which is a deployment problem. Third, you are allowing all dlls running under the CAS permission to run with full trust.
  • Run SharePoint in full trust – please do not do this – it is highly unrecommended.

6 comments:

Mark Attridge said...

Jason,
Great article...
I am currently experiencing the same exact problems as you outline in your post, but I cannot seem to get things resolved using your suggestions. I tried both your first and second solutions to no avail (and didn't even want to go as far as the third/fourth for obvious reasons).

The one main difference that I am noticing with my problem is that when I reference the SharePoint user controls (such as Toolbar.ascx) in the usercontrols folder, I cannot get them to load either.

Is there anything else that I should try troubleshooting or tweaking to get me past my issue?

I've also got this posted on MSDN (if you want to see the full thread details), but that hasn't helped me much so far... http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/thread/bd2626ae-cdb3-4aa5-b428-c66002ffee87

Appreciate the help you can provide... thanks!
-mark

Jason Apergis said...

Matt,

Well it has been some time since I worked on this specifically. I recall that I was having tons of issues trying to embed custom users controls in a sharepoint web part. I eventually get it figured out and wrote this blog - http://www.astaticstate.com/2009/10/embed-and-deploy-user-control-in.html

Maybe this will help.

Jason

Mark Attridge said...

Coincidentally, I was already viewing that blog post. :)

And indeed it did help! I noticed that I was missing the "Assembly" tag at the top of the ascx file. Once I added this tag, my webpart began working. I can't believe it was that simple. Moreso, I can't believe no other resource I looked at recently gave me that clue as to what to troubleshoot.

Thanks so much for your speedy (and helpful) response!

Have a great day!
-mark

Jason Apergis said...

Well I have to say it took me forever to do that blog posting on my spare time. Everyone was like it is so easy but everything I read fell short of telling you how to do it. Glad it worked.

Jason

Suresh said...

Jason/Matt ,

I am also currently experiencing the same problem for Visual webpart in VS2010. I am using sharepoint empty project template. Is this approach works for sharepoint 2010?

Thanks,
Suresh

Jason Apergis said...

Suresh,

Cannot say for sure as I ran into this back on SharePoint 2007. This has nothing to do with Visual Studio.

Jason