Creating a custom server task


Summary
This topic provides a simple and instructive guide to creating a custom server task. At design time, the custom task can modify properties exposed via a custom verb on the control in Web page design view. At run time, the custom task contains a button and a text box in a floating panel. When you type text in the text box and click the button, the text box content is added to a TaskResults control with the current time on the Web server. The custom task can also be used and configured in ArcGIS Manager (Manager).

Click here to get the sample associated with this walkthrough.

In this topic


Create the custom server control task

Do the following steps to create a custom server control task:
  1. Start Visual Studio 2008 and create a project of type class library.
  2. Add a reference to System.Web, System.Web.Extensions, System.Drawing, and ESRI.ArcGIS.ADF.Web.UI.WebControls.
  3. In <Classname>.cs, add the using statements defined in the following code example.
  4. Start with the FloatingPanelTask abstract class. This class provides a floating panel container at run time, in which you can add your task controls and client-side logic. The out-of-the-box controls also extend the FloatingPanelTask. In the following code example, the SimpleServerTask_CSharp namespace contains the SimpleServerTask_CSharp class that extends FloatingPanelTask.
  5. Provide information on how the Web control will appear in a Web page at design time. Use the ToolboxData attribute to define the content written to the page when the control is dragged onto it. In the following code example, {0} indicates a dynamically defined control tag prefix when added to a Web page. Other attributes define that this control will run on the server and other design-time display properties (width is 100 pixels, border width is 1 pixel).

    Steps 3 through 5 are reflected in the following code example:
[C#]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using ESRI.ArcGIS.ADF.Web.UI.WebControls;
namespace SimpleServerTask_CSharp
{
    [System.Web.UI.ToolboxData(
        "<{0}:SimpleServerTask_CSharp runat=\"server\" Width=\"100px\" BorderWidth=\"1px\"><TaskResultsContainers><esri:BuddyControl Name=\"TaskResults1\" /></TaskResultsContainers> </{0}:SimpleServerTask_CSharp>")]

    public class SimpleServerTask_CSharp: FloatingPanelTask
    {
  1. Add member variables to reference the controls rendered at run time as shown in the following code example:
[C#]
private System.Web.UI.HtmlControls.HtmlInputText m_textBox = null;
private System.Web.UI.HtmlControls.HtmlInputButton m_executeButton = null;
  1. Override the CreateChildControls() method. This method constructs the visual interface of the task at run time. As a result, the output must work within a browser client (for example, contain Hypertext Markup Language [HTML] or JavaScript). This process must be done programmatically. Use .NET HTML control classes or render the contents of an ASP.NET control to create the interface. In the following code example, the task dialog box contains a text box and a button. The Controls property inherited from the System.Web.UI.WebControls.CompositeControl class is used to add content to the task dialog box.
It is not possible to add controls (drag and drop from a toolbox) to a server task control at design time.
[C#]
protected override void CreateChildControls()
{
    Controls.Clear();
    base.CreateChildControls();
    m_textBox = new System.Web.UI.HtmlControls.HtmlInputText();
    m_textBox.ID = "txtTaskText";
    Controls.Add(m_textBox);
    m_executeButton = new System.Web.UI.HtmlControls.HtmlInputButton();
    m_executeButton.ID = "executetask";
    m_executeButton.Value = "Execute Task";
    string jsGetTaskCallbackArgument = string.Format(
        "'{0}=' + document.getElementById('{1}').value", m_taskTextKey,
        m_textBox.ClientID);
    string jsOnClick = string.Format("executeTask({0},\"{1}\");",
        jsGetTaskCallbackArgument, CallbackFunctionString);
    m_executeButton.Attributes.Add("onclick", jsOnClick);
    Controls.Add(m_executeButton);
}
  1. Override the GetCallbackResult() method from the FloatingPanelTask to set the Input property to the value being submitted by the task at run time as shown in the following code example. The Input property is implemented in the FloatingPanelTask. It is of type object, but is often a string. It modifies the input member variable used in the ExecuteTask() method to process data provided when a user interacts with the control at run time.
[C#]
public override string GetCallbackResult()
{
    // Set the task's Input member to the value of the task's text box. 
    System.Collections.Specialized.NameValueCollection keyValColl =
        ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(CallbackEventArgument);
    Input = keyValColl[m_taskTextKey]; //Value in the text box.
    return base.GetCallbackResult();
}
  1. Add the execution logic for the custom task as shown in the following code example. Get the input value provided by the user (if any) via the Input property or input member variable. Populate the Results property with something to display in the TaskResults control. The DisplayResult() method in TaskResults processes the Results object. The type should be ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResultNode, ESRI.ArcGIS.ADF.Web.UI.WebControls.SimpleResultTask, or System.Data.DataSet. The TaskResults control renders the contents in a TreeView structure. In the following code example, a custom SimpleTaskResult is used to return the input value and time on the Web server. The heading property is the parent node and the detail property defines the child node content.
[C#]
public override void ExecuteTask()
{
    Results = null;
    if (Input == null)
        return ;
    string textBoxValue = input as string;
    string heading = string.Format("The time on the server is {0}",
        DateTime.Now.ToShortTimeString());
    string detail = string.Format("The value in the text box is: {0}", textBoxValue);
    SimpleTaskResult str = new SimpleTaskResult(heading, detail);
    Results = str;
}
  1. Override the Refresh() method to run the task again and refresh the task in the TaskResult control at run time as shown in the following code example. Both options are available as a context menu from the task result nodes.
[C#]
public override void Refresh()
{
    string tmp = Input as string;
    if (!string.IsNullOrEmpty(tmp))
        textBox.Text = tmp;
    base.Refresh();
}
  1. If a dependency exists, include a mandatory override to maintain a list of dependent resource items. In the following code example, no dependencies are defined:
[C#]
public override List < GISResourceItemDependency > GetGISResourceItemDependencies()
{
    List < GISResourceItemDependency > list = new List < GISResourceItemDependency >
        ();
    return list;
}

}

}
  1. In preparation for deployment, add a custom tag prefix to uniquely identify this task from other items in a Web page (such as Web controls, tasks, and so on). By convention, this information is stored in a separate file compiled with the control. The file is named AssemblyInfo.<language> (for example, AssemblyInfo.cs for C# class library projects). The TagPrefix attribute associates a Web control namespace and assembly with a suggested tag prefix. If the Web control is not already registered to a tag prefix in a Web.config file or via the Register directive, the suggested tag prefix is used to register the assembly in the page. In this topic, use the following definition:
[C#]
[assembly: System.Web.UI.TagPrefix("SimpleServerTask_CSharp", "simpleServerTaskCS")]
At this point, the custom task can be used in Visual Studio at design time.
  1. Build the custom task class library and add the assembly to the Visual Studio toolbox as described in the following steps:
    1. In a Web project, with a Web page active, right-click the toolbox and select Add Tab.
    2. Type a name for the new tab, for example, Custom Task Controls.
    3. Right-click the new tab and select Choose Items. The Choose Items dialog box appears.
    4. Click the Browse button, navigate to the location of the SimpleTask_CSharp.dll file, and click Open. The new control is added to and selected in the Choose Items dialog box.
    5. Select the SimpleTask_CSharp check box and click OK to close the dialog box. The new tab contains the custom task control.
    6. Drag the task control and a Web Application Developer Framework (ADF) TaskResults control onto a Web page. See the following screen shot:


    7. Using the verbs from the custom task control, buddy the TaskResults control to the custom task. The custom task will also function with an ASP.NET navigation control, the same way as out-of-the-box tasks. See the following screen shot:


    8. At run time, the same Web page is rendered as shown in the following screen shot:



      In the preceding screen shot, the Hello World!, Hello California!, and Hello Redlands! text has been typed into the text box and the Execute button has been clicked.

Visual Studio integration

To enhance the Visual Studio design-time configuration of the custom task, extend the ESRI.ArcGIS.ADF.Web.UI.WebControls.Design.Designers.TaskDesigner class included with the Web ADF. This class provides the framework for exposing custom verbs off a task control when setting properties of the control in design view. The following are the broad-level steps:
  • Expose properties in the custom task that need to be changed via a custom verb.
  • Create a Windows form for a Visual Studio developer to set and change the property at design time.
  • Extend TaskDesigner and associate it with the custom task.
Until now, you have covered steps to create a simple custom server task control. This section further enhances the simple server task by adding design-time configuration functionality.
This section is built on standard .NET practices for enhancing custom Web controls in the Visual Studio integrated development environment (IDE).
  1. In the SimpleTask_CSharp.cs custom task class, add a public property to modify the text on the button as shown in the following code example. The attributes before the property define how TaskDesigner works with characteristics and defaults of the property.
[C#]
#region Instance Properties
[System.ComponentModel.Browsable(true)][System.ComponentModel.Category("Appearance")
    ][System.ComponentModel.DefaultValue("Execute")][System.Web.UI.PersistenceMode
    (System.Web.UI.PersistenceMode.Attribute)]
public string ButtonText
{
    get
    {
        object buttonTextObject = StateManager.GetProperty("buttonText");
        return (buttonTextObject == null) ? "Execute" : buttonTextObject as string;
    }
    set
    {
        StateManager.SetProperty("buttonText", value);
    }
}

#endregion
  1. Create a Windows form in the same custom task library project. The name of the custom form class is ButtonTextEditorForm. Include it with the project so when you distribute the custom task assembly, a Visual Studio developer can use the form to set properties on the task at design-time. The following screen shot shows the form:
 
See the following code example for the form (ButtonTextEditorForm.cs):
The form contains a text box named txtButtonText.
[C#]
namespace SimpleServerTask_CSharp
{
    public partial class ButtonTextEditorForm: System.Windows.Forms.Form
    {
        public ButtonTextEditorForm(string value)
        {
            InitializeComponent();
            Value = value;
        }
        public string Value
        {
            get
            {
                return txtButtonText.Text;
            }
            set
            {
                if (value != null)
                    txtButtonText.Text = value;
            }
        }

        private void cmdOK_Click(object sender, System.EventArgs e)
        {
            DialogResult = System.Windows.Forms.DialogResult.OK;
            Hide();
        }
        private void cmdCancel_Click(object sender, System.EventArgs e)
        {
            DialogResult = System.Windows.Forms.DialogResult.Cancel;
            Hide();
        }
    }
}
  1. The form is initialized by a custom class that extends the System.Drawing.Design.UITypeEditor class. This class provides a base class to implement a custom type editor for a Web control in the Visual Studio IDE at design time. The custom class, ButtonTextEditor, initializes the Windows form to add a value, in this case, the value of the text on the button in the custom task. The returned value is available to the custom task. See the following code example:
[C#]
namespace SimpleServerTask_CSharp
{

    public class ButtonTextEditor: System.Drawing.Design.UITypeEditor
    {
        public override object EditValue
            (System.ComponentModel.ITypeDescriptorContext typeDescriptorContext,
            System.IServiceProvider serviceProvider, object value)
        {
            if ((typeDescriptorContext != null) && (serviceProvider != null))
            {
                if (typeDescriptorContext.Instance == null)
                    return value;
                ButtonTextEditorForm buttonTextEditorForm = new ButtonTextEditorForm
                    (value as string);

                if (buttonTextEditorForm.ShowDialog() ==
                    System.Windows.Forms.DialogResult.OK)
                    value = buttonTextEditorForm.Value;
            }
            return value;
        }
        public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle
            (System.ComponentModel.ITypeDescriptorContext typeDescriptorContext)
        {
            if (typeDescriptorContext != null)
            {
                return System.Drawing.Design.UITypeEditorEditStyle.Modal;
            }
            return base.GetEditStyle(typeDescriptorContext);
        }
    }
}
  1. Create the class that links input from the Windows form to the custom task in Visual Studio at design time. Create a class, called SimpleServerTaskDesigner_CSharp, that extends the Web ADF TaskDesigner class. In the constructor, add a new DesignerVerb to the custom task control to initiate the ButtonTextEditorForm Windows form. When initiated, get a description of the ButtonText property in the custom task, create a ButtonTextEditor instance that opens the Windows form, capture the input value, and update the ButtonText property as shown in the following code example:
[C#]
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Design;
using System.ComponentModel;
using System.ComponentModel.Design;
using ESRI.ArcGIS.ADF.Web.UI.WebControls.Design.Designers;
namespace SimpleServerTask_CSharp
{
    public class SimpleServerTaskDesigner_CSharp: TaskDesigner
    {
        public SimpleTaskDesigner_CSharp(): base()
        {
            verbs.Add(new DesignerVerb("Edit the button text", new EventHandler
                (OnEditButtonText)));
        }
        protected void OnEditButtonText(object sender, EventArgs args)
        {

            SimpleServerTask_CSharp simpleTask = this.Component as
                SimpleServerTask_CSharp;
            PropertyDescriptor propertyDescriptor = TypeDescriptor.GetProperties
                (simpleTask)["ButtonText"];
            UITypeEditor uiTypeEditor = new ButtonTextEditor();
            object newValue = uiTypeEditor.EditValue(new
                TaskControlDesignerTypeDescriptorContext(this, propertyDescriptor), 
                (IServiceProvider)this, propertyDescriptor.GetValue(simpleTask));
            propertyDescriptor.SetValue(simpleTask, newValue);
        }
    }
}
  1. Associate this functionality with the custom task. At the top of the custom task class, add the Designer attribute to define that a custom TaskDesigner is associated with the task. The attribute associates the custom task with the TaskDesigner (the SimpleTaskDesigner_CSharp class) previously created. In the following code example, only one new line referencing the Designer attribute has been added to the existing content:
[C#]
[System.Web.UI.ToolboxData(
    "<{0}:SimpleServerTask_CSharp runat=\"server\" Width=\"100px\" BorderWidth=\"1px\"><TaskResultsContainers><esri:BuddyControl Name=\"TaskResults1\" /></TaskResultsContainers> </{0}:SimpleServerTask_CSharp>")][Designer(typeof(SimpleServerTaskDesigner_CSharp))]

public class SimpleServerTask_CSharp: FloatingPanelTask
{
  1. When the custom task control is added to a Web page, a new verb becomes available to change the text of the button on the task. Click the verb, Edit the button text. The Edit Button Text dialog box appears as shown in the following screen shot:


  2. When the application runs and the Web page loads, the button on the custom task shows the changed text. See the following screen shot:



See Also:

Working with the Task Framework
Task runtime workflow
Server task Manager integration
Walkthrough: Creating a custom UserControlTask