This blog post is a contribution from Aaron Miao, an engineer with the SharePoint Developer Support team.
This is not a new issue. Ronald Widha’s blog post addresses this issue for SharePoint 2010. But with SharePoint 2012 and Visual Studio 2012 releases, the issue still remains and gets more complicated.
If you create a SharePoint 2013 application page project with Visual Studio 2012 by following the steps below, then drag and drop a user control to your application page Test.aspx, it will generate a mark up shown below.
1. Create SharePoint 2013 Farm solution.
2. Add a new User Control called TestControl.ascx with a public string property called Name.
3. Add an application page called Test.aspx. Your project will look like this.
And the mark up
In Test.aspx.cs, if you access the user control object like this:
You will run into 2 issues.
First, VS intellisense does not work.
Second, you cannot compile the project because VS 2012 does not recognize the Name property (as seen marked with red waved line).
Casting the user control explicitly could do the trick. But you do not want to do that every time!
If you check the Test.aspx.designer.cs file, your user control will be declared like this:
The TestControl is declared as base type of System.Web.UI.UserControl. This is the problem with SharePoint 2013 Visual Studio templates and VS2012. Look closer at your Test.aspx page, your control is registered like this:
Note that the source is _controltemplates rather than ControlTemplates. In addition, it has folder called “15”. This should be mapped to SharePoint 2013 installation 15 hive folder. However, VS2012 generated project does not even have 15 folder. You would hope that VS2012 understands what SharePoint 2013 means here.
If you look closer and hover mouse over the Name property, VS2012 does not seem to like your user control registration.
The user control registration does not match the project folder structure. It’s suggesting that it cannot find the control and decided to put the base System.Web.UI.UserControl in the page designer class (*.ascx.designer.cs). This is the culprit as to why we cannot get the public properties/methods without explicit casting.
It seems that this problem is caused by VS2012 not having the same assumptions as SharePoint 2013. It happens for VS2010 with SharePoint 2010 and still true for VS2012 with SharePoint 2013.
VS2012 should have generated \_controltemplates\15 in the first place when we create user control for SharePoint 2013. Please be aware that SharePoint 2013 installation now includes both 14 and 15 hives. Alternatively, VS2010 should simply accept that controltemplates as a mere string token that will be converted to _controltemplates/15 by SharePoint 2013 runtime and take this into account when generating the designer classes.
The solution is simple. But what I figured is that it depends on the site URL property of the project in question. Typically, site URL could either be http://yourserverurl or http://yourserverurl/sites/yoursiteurl. The key is to make the project folder structure that matches the URL path.
Here’s what we need to do. Continue the steps of creating the project.
4. Add a new folder to the project called “_controltemplates”.
If your site URL looks like http://yourserverurl/sites/yoursiteurl, you need to add folder “sites” and then add folder “yoursiteurl” inside of the folder “sites”. Then add folder “_controltemplates” under “yoursiteurl” folder.
5. Add a new folder called “15” inside of “_controltemplates” folder.
6. In file explorer, copy all files from “ControlTemplates” to “15” folder.
7. In Solution, include all files in “15” folder.
8. Delete “ControlTemplates” from solution.
9. Then you could drag and drop the user control to the application page and starting coding.
As long as you do this, VS2012 behaves properly and casts the user controls to the proper type in designer class (*.ascx.designer.cs).
After all this changes, your project should look like this.
Your control registration now looks like this:
If your project references the site like this: http://yourserverurl/sites/yoursiteurl, it should look like the below. Note that the folder structure matches the site URL.
And your control registration looks like this: