Wednesday 11 April 2012

User Controls and Server Controls in SharePoint

User Controls

A user control is a control that is associated with a .ASCX extension and was originally intended for a developer to re-use within a single project.  ASP.NET developers know it is really easy to create a new user control, drag and drop some controls onto a visual designer, put some logic in the control’s code-behind, and re-use the control within a single project.  This is because the .ASCX file associated with the control enables you to create markup for your control:
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Control Language="C#" 
        AutoEventWireup="true" 
        CodeBehind="EchoControl.ascx.cs" 
        Inherits="ControlsDemo.ControlTemplates.ControlsDemo.EchoControl" %>


Enter some text:
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" />
<asp:Label ID="Label1" runat="server" Visible="false"></asp:Label>
Because you can add markup for your control, you get the nice WYSIWYG designers for your control.  This allows you to drag items from the toolbox, such as a button, a label, and a text box. 
image
Another nice feature of user controls is that you can quickly add event handlers for your control.  For instance, I double-click the button to add some code-behind, and Visual Studio pops up the code editor to allow me to add some code.
using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ControlsDemo.ControlTemplates.ControlsDemo
{
    public partial class EchoControl : UserControl
    {     
        protected void Button1_Click(object sender, EventArgs e)
        {
            Label1.Text = "You entered: " + 
                TextBox1.Text + " at " + 
                System.DateTime.Now.ToLongTimeString();
            Label1.Visible = true;
        }
    }
}
Notice that our code-behind derives from System.Web.UI.UserControl.  For existing ASP.NET developers, you will be happy to see that it’s the same old UserControl class that’s been there since ASP.NET was introduced.  By using the .ASCX, Visual Studio 2010 provides the same WYSIWYG, drag-and-drop features that you have with ASP.NET development.  In your SharePoint 2010 project, add a new User Control to your project, add the markup to the .ASCX file, and put some code in the code-behind.  The project structure will look like this:
image
When the solution is compiled, the code (the .cs classes) are compiled into an assembly that is deployed to the GAC.  The ASCX file points to our assembly, which SharePoint deploys to the global assembly cache.  SharePoint deploys your .ASCX file to a special location: 
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\CONTROLTEMPLATES
If you open that directory, you will see lots of out-of-box controls, such as Welcome.ascx, the control that is registered in the v4.master master page in SharePoint 2010.  Once the control is deployed to the ControlTemplates directory structure, an end user can then use the control in their master page or page.  For instance, we’ll use SharePoint Designer 2010 to edit a master page to use our control.  At the top of the file, register the control:
<%@ Register TagPrefix="demo" TagName="EchoControl"  
src="~/_controltemplates/ControlsDemo/EchoControl.ascx" %>
You can see where to do that in this screen shot:
image
Once our control is registered, we use it in our page, and the visual design is used in SharePoint Designer 2010 to give a WYSIWYG rendering to the end user.
image
We save the master page and then look at the final product:
image
User controls are a great way to add functionality to a SharePoint site for end users without requiring a web part.  You might have noticed that Visual Studio 2010 includes a new project item template called “Visual Web Part”.  This project simply creates a .ASCX control that is loaded by your web part.

 

Server Controls

A server control is a compiled control that renders on the server.  Where user controls derive from System.Web.UI.UserControl, a server control (also known as a custom control) typically derives from System.Web.UI.WebControl.  The main difference is that server controls do not have a corresponding .ASCX control.  For some scenarios, this can be highly beneficial because the page parser does not need to parse the .ASCX control.
Creating a server control is very easy.  In Visual Studio 2010, add a new ASP.NET Server Control item to your project from the Web group.
image
The generated template is just a suggestion, you can edit the class to suit your needs.  Here is a useful control for SharePoint developers that simply shows the name of the server that is currently processing the request.
using System;
using System.Web.UI.WebControls;
using System.Web.UI;

namespace ControlsDemo
{
    [ToolboxData("<{0}:ServerNameControl runat=server></{0}:ServerNameControl>")]
    public class ServerNameControl : WebControl
    {
        protected override void CreateChildControls()
        {
            Label l = new Label();
            l.Text = System.Environment.MachineName;
            Controls.Add(l);   
        }
    }
}
This can be useful for troubleshooting inconsistent behavior among web front end servers in a load-balanced farm.  When Visual Studio builds the project, the class is compiled into our assembly and deployed to the GAC.  Once the control is registered in the GAC, we can use it in our master page similar to our previous example.  The syntax is different, because before we could point the Src attribute to the .ASCX file, this time we need to register the control and import the namespace.
<%@ Register 
    TagPrefix="demo2" 
    Namespace="ControlsDemo" 
    Assembly="ControlsDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=01374ea14aa626aa" %>
<%@ Import Namespace="ControlsDemo" %>
Once we register the control, we can now use it in our page.
<demo:ServerNameControl runat="server" id="serverNameControl"/>
Only this time, instead of seeing the nice WYSIWYG UI in SharePoint Designer 2010, we see an error message, “The type is not registered as safe.”
image
WTF?!?!
To understand what’s going on, you need to understand how the page is processed:
When a page with a user control is requested, the following occurs:
  • The page parser parses the .ascx file specified in the Src attribute in the @ Register directive and generates a class that derives from the System.Web.UI.UserControl class.
  • The parser then dynamically compiles the class into an assembly.
  • If you are using Visual Studio, then at design time only, Visual Studio creates a code behind file for the user control, and the file is precompiled by the designer itself.
  • Finally, the class for the user control, which is generated through the process of dynamic code generation and compilation, includes the code for the code behind file (.ascx.cs) as well as the code written inside the .ascx file.
[via http://support.microsoft.com/kb/893667]
The page parser will parse the page and determine if the page uses code-behind or includes in-line script.  I have blogged about the impact of marking your controls as safe for pages here and here, which gives some insight to the problem.  The reason that our user control example worked is because it was deployed to the ControlTemplates directory, an action that only a farm administrator would have privileges to do.  Thus, any control in the ControlTemplates directory structure is marked as safe out of the box:
<SafeControl Src="~/_controltemplates/*"
                   IncludeSubFolders="True"
                   Safe="True"
                   AllowRemoteDesigner="True"
                   SafeAgainstScript="True" />
The server control does not have a corresponding .ASCX file, so we need to explicitly mark it as safe.   Visual Studio 2010 makes this very easy.  Add a new Module to your project and give it a name.
image
Click the module in the Solution Explorer pane, and edit the Safe Controls property.  Add a new safe control, taking care to add the right namespace.  You can use an asterisk for the typename if any type in the namespace is safe, or you can use the class name of a specific class that is safe as I did here:
image
You can delete the sample text file that is generated.  Now, when we look at the web.config file, we see a SafeControl entry for our control:
<SafeControl Assembly="ControlsDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=01374ea14aa626aa"
                   Namespace="ControlsDemo"
                   TypeName="ServerNameControl"
                   Safe="True"
                   SafeAgainstScript="False" />
Now, when we use the control in SharePoint Designer 2010, we have the markup correct but see nothing in the WYSIWYG view:
image
If we view the page in the browser, we can see the effect of the control being rendered (highlighted in yellow to show you where the server name is rendered).
image
You can do some amazing things with ASP.NET controls, and you can bring many of your existing controls forward so that end users can take advantage of them in their pages and master pages.

No comments:

Post a Comment

Note: only a member of this blog may post a comment.