Tag Archives: .NET

Using ASP.NET AJAX with the Web ADF

Bryan Baker of the .NET SDK team wrote this great article on integration ASP.NET AJAX with the Web ADF.   

 

Microsoft’s new ASP.NET AJAX enables developers to refresh portions of a Web page in a relatively simple way. To enable a control to use AJAX, the developer can put the control inside an UpdatePanel. Then any events on the control are automatically handled via AJAX, and updates are passed back without refreshing the entire page. For example, a page might have two drop-down lists. The first lists types of features, such as Cities and Countries. When the user picks a value in the first drop-down, the second list is populated with new values corresponding to the first list’s value, such as a list of cities.

Web ADF developers might want to use this approach to update the Map or other ADF controls. For example, when the user selects a city in the second drop-down list, the Map would zoom to the selected city. The problem is that ASP.NET AJAX was released after the 9.2 version of the Web ADF, and these new features were not available to be incorporated. Putting Web ADF controls inside an UpdatePanel will not work correctly, and is not supported. At 9.3 ESRI does plan to support Web ADF controls with ASP.NET AJAX.

You can have both Web ADF and ASP.NET AJAX controls on the page. The challenge is doing something like the example above, where controls in an UpdatePanel communicate with Web ADF controls. This post shows one approach for this. It turns out that it takes less than a dozen lines of code beyond what would have been needed had the Map been inside the UpdatePanel! You can follow along if you have installed Visual Studio 2005, the Web ADF, and the ASP.NET AJAX 1.0 extensions.

Note that the use of ASP.NET AJAX is not supported by ESRI for version 9.2 of the Web ADF. If you use ASP.NET AJAX, you must be prepared to resolve any issues you encounter with using the Web ADF. You may find help at the ESRI Forums, but ESRI Support will not be able to assist with development issues.

Add the controls

I first created a new website using the “ASP.NET AJAX-Enabled Web Site” template in Visual Studio. This creates a website and adds some extra items to support AJAX into both the Default.aspx page and the web.config file. You’ll notice the ScriptManager control already added to the Default.aspx page, which is a non-visual control that handles the AJAX functionality. If you wanted to add ASP.NET AJAX into an existing page or website, you’d need to add these same items that the template adds in. See the ASP.NET AJAX documentation for details.

ASP.NET AJAX and Web ADF controls on the page On the Default.aspx page, I added an UpdatePanel from the AJAX Extensions toolbox tab. I dragged two standard DropDownList controls into the UpdatePanel. The first DropDownList will display a list of layers. We could obtain these from the Web ADF controls on page startup, but I just added them manually for now to the Items property. I added two items: Cities and Countries. I also set the AutoPostBack property for both DropDownList controls to True. We need to do this to trigger a postback (actually a “partial postback” as ASP.NET AJAX calls it) when the user changes the selection.

Next I added a Map control and a MapResourceManager control from the ArcGIS Web Controls. Tip: having a drop-down list just above the map inteferes with the drop-down’s functioning, so I put the map above the drop-down lists for this demo. I set the MapResourceManager property of the Map, and I added a resource item (map service) to the MapResourceManager as required to enable the map to display the service. In my case I used a world map with cities and countries. My simple page looks like the example here.

Update DropDownList items with ASP.NET AJAX

When the user changes the first drop-down list, the second list should display a list of cities or countries. Using ASP.NET AJAX allows us to treat this like a standard postback event. Behind the scenes, ASP.NET AJAX handles the request using AJAX methods rather than a full postback. Fortunately we don’t have to deal with those details here.

I double-clicked on the DropDownList1 on the design page, which creates the method to handle the user selection in the code-behind page. We need to also fill the second DropDownList at startup, so we’ll create a separate method and call it from both the drop-down’s change method and the Page load method (which we can create by double-clicking on the design page). The UpdatePlaceList method fills the second DropDownList with locations and coordinates that we’ll use later for zooming the map. The code below is in VB; both C# and VB versions are available in the download link at the end of this post.

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

If Not Page.IsPostBack Then

UpdatePlaceList()

End If

End Sub





Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)

UpdatePlaceList()

End Sub



Sub UpdatePlaceList()

DropDownList2.Items.Clear()

If DropDownList1.SelectedValue = "Cities" Then

DropDownList2.Items.Add(New ListItem("Cape Town", "17|-36|21|-32"))

DropDownList2.Items.Add(New ListItem("Oslo", "9|58|13|62"))

DropDownList2.Items.Add(New ListItem("Washington", "-79|37|-75|41"))

ElseIf DropDownList1.SelectedValue = "Countries" Then

DropDownList2.Items.Add(New ListItem("Australia", "112|-43|157|-10"))

DropDownList2.Items.Add(New ListItem("Brazil", "-73|-33|-31|6"))

DropDownList2.Items.Add(New ListItem("China", "75|16|136|55"))

End If



End Sub



Zoom the Map when user selects a place

When the user selects a place in the second DropDownList, we need to zoom the map to the coordinates of that place. The challenge is to have the map’s new extent be communicated to the client. Since the Map control cannot be in the UpdatePanel, we have to use another approach to communicate the results of the extent change to the Map.

The user selection in DropDownList2 triggers another partial postback. To set up the code for this, I double-clicked on DropDownList2 in design mode to create the method to handle the selected-index change. Inside this new method, I obtained the coordinates to zoom to from the DropDownList2.SelectedValue property. I parsed this value into an array of coordinate values, created a new envelope, and set the envelope’s extent to these coordinates. I then set the Map’s extent to this new envelope. This changes the map extent on the server. However, the client won’t be aware of the change and won’t obtain a new map unless we tell it to.

To get the client to update the map, we use a feature in ASP.NET AJAX to pass information to the client. The ScriptManager.RegisterDataItem method adds information that will be passed back and evaluated on the client.

The Map’s CallbackResults will have the information required to update the map on the client. We pass this information to the client using the RegisterDataItem method. We’ll see shortly how the client uses this information to update the map.

The code below obtains the callback results and registers them with the ASP.NET AJAX RegisterDataItem method. The ScriptManager1.IsInAsyncPostBack property ensures that we’re doing an AJAX partial postback rather than a full page postback.

Protected Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs)



Dim zoomString As String = DropDownList2.SelectedValue

Dim coordArr() As String = zoomString.Split("|")



Dim new_extent As New ESRI.ArcGIS.ADF.Web.Geometry.Envelope

new_extent.XMin = Double.Parse(coordArr(0))

new_extent.YMin = Double.Parse(coordArr(1))

new_extent.XMax = Double.Parse(coordArr(2))

new_extent.YMax = Double.Parse(coordArr(3))

Map1.Extent = new_extent



If ScriptManager1.IsInAsyncPostBack Then

Dim callbackString As String = Map1.CallbackResults.ToString()

ScriptManager1.RegisterDataItem(Map1, callbackString)

End If



End Sub



Handle the results on the client

The results that we just registered with ScriptManager need to be handled on the client. ASP.NET AJAX has a handler approach to process items passed back to the client. I inserted the code below into the .aspx page, at a point below the asp:ScriptManager tag. This code registers a client-side handler, the PageLoadingHandler function, that will run when the page loads. This handler obtains the items registered on the server with RegisterDataItem, and checks whether any items for the map control are present.  Since our server-side code added an item for the map, the code runs the next line.

This next line calls processCallbackResult and passes it the callback results we registered on the server. The processCallbackResult function is part of the Web ADF JavaScript library, which is automatically downloaded when the page uses Web ADF controls. The processCallbackResult function applies the callback results on the client by retrieving a new map. One caveat: the objects and methods in the client-side library can change, so this method could change with future versions of the Web ADF.

<asp:ScriptManager ID="ScriptManager1" runat="server" />



<script type="text/javascript" language="javascript">



Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(PageLoadingHandler);





function PageLoadingHandler(sender, args) {

var dataItems = args.get_dataItems();

if (dataItems['Map1'] != null)

processCallbackResult(dataItems['Map1'], 'Map1');

}



</script>



With this code in place, when the user selects an item in the places drop-down list, the server sets the map extent to that place, and the map on the client gets notified to retrieve a new map.

Tip: be careful about dragging controls around the page in Design mode when script blocks are within the page body. Doing so caused Visual Studio to remove my script block, which disabled the map update since no handler was available on the client!

Conclusion

We’ve seen how you can use controls in an ASP.NET AJAX UpdatePanel to control a Map in the Web ADF. Although it takes more work than if the Web ADF controls were embedded in the UpdatePanel, it is possible to do these tasks now. In our case it required less than a dozen lines of additional code compared to when the controls are all inside the UpdatePanel.

Download the code for this demo (includes C# and VB)

Try it out here

Posted in Services | Tagged , | 3 Comments

Working with the Web ADF resources in a custom task at run-time

Rex Hansen of the .NET SDK team wrote this very useful post on accessing the Web ADF components at run-time.

 

When creating a custom task, you may often find it necessary to access Web ADF components (controls, resources, etc.) that share the same Web page with the task.  How the task will be used will dictate the technique for accessing Web ADF components.  There are three situations to consider:

1) Task run-time

2) Visual Studio design-time

3) Manager run-time

“Task run-time” defines the technique for working with Web ADF components in a Web application at run-time.  “Visual Studio design-time” uses custom verbs on the custom task control to access to Web ADF components during task configuration in Visual Studio.  “Manager run-time” defines a situation where a custom task must utilize Web ADF components when configuring the task in the Manager Web application.  

This discussion and walkthrough will focus on working with Web ADF resources in a custom task at run-time (situation 1).  The custom task will do the following:

  • Extend FloatingPanelTask
  • Expose a public property to buddy the task with a MapResourceManager
  • Use a DropDownList control to list the map resources in the MapResourceManager control
  • Populate the DropDownList upon initial load of the task

1) Create a custom task control that extends FloatingPanelTask.  As a composite control, the custom task will contain multiple controls.  Define two private member variables to store references to controls that will be used in the custom task.  In this case, a Label will be used to display the MapResourceManager id and a DropDownList will display a list of map resources.

namespace TestTask_CSharp

{

    public class TestTask_Demo : FloatingPanelTask

    {

        private Label label = null;

        private DropDownList dropDownListResources = null;

2) Create a property on the custom task control to store a reference to the unique id of a MapResourceManager control.  The property will be maintained in state for the duration of a user session.  The property can be set declaratively in the aspx page using the MapResourceManagerID attribute (source view). 

        [Browsable(true)]

        [DefaultValue("")]

        [PersistenceMode(PersistenceMode.Attribute)]

        public string MapResourceManagerID

        {

            get

            {

                object obj = StateManager.GetProperty("mapResourceManagerID");

                if (obj == null) return "";

                return obj as string;

            }

            set

            {

                StateManager.SetProperty("mapResourceManagerID", value);

            }

        }

3) As with other composite Web controls, override the CreateChildControls method to construct the custom task control at runt
ime.  The Label and DropDownList are created and added to the custom task.  Note the DropDownList is empty.  The Controls property is inherited from the System.Web.UI.WebControls.CompositeControl class and maintains a collection of controls to be rendered at runtime.   

        protected override void CreateChildControls()

        {

            Controls.Clear();

            base.CreateChildControls();

            label = new Label();

            label.Text = MapResourceManagerID;

            label.ID = "label_mrm";

            dropDownListResources = new DropDownList();

            dropDownListResources.ID = "dropdownlist_resources";

            Controls.Add(label);

            Controls.Add(dropDownListResources);

        }

4) At this time we only need to populate the DropDownList (dropDownListResources) with a list of map resources upon initial load of the custom task.  Since interrogating the MapResourceManager to get a list of resources during every callback is not necessary and can be expensive, we only want it to occur during a full page postback.  The PreRender step in the page lifecycle offers a good location to modify page or control content before the final rendering step, and it's only called during a full page postback.  Override the OnPreRender event of the custom task control and call the UpdateResourceDropDownList() method.  The method will contain the logic to update the dropDownListResources control.  This logic was placed in a separate method so it can be called from other locations in the custom task code, if necessary in the future.        

        protected override void OnPreRender(EventArgs e)

        {

            base.OnPreRender(e);

            UpdateResourceDropDownList();

        }

       

5) The UpdateResourceDropDownList() method uses the MapResourceManagerID property to find a MapResourceManager control on the page and get a list of map resources.  The GetMapResourcesFromMRM() method returns a collection of resources from the MapResourceManager.  If the MapResourceManager has not been initialized, it will be explicitly initialized. Including code to return a collection of resources from a MapResourceManager was placed in a separate method so it can be called from other locations in the custom task that do not involve the dropDownListResources control.  Once a list of resources is returned to the UpdateResourceDropDownList method, only those that are an ArcGIS Server map resource are added to the dropDownListResources control.           

        protected void UpdateResourceDropDownList()

        {

            if (!string.IsNullOrEmpty(MapResourceManagerID))

            {

                GISResourceCollection grcoll = GetMapResourcesFromMRM(MapResourceManagerID);

                foreach (IGISResource gr in grcoll)

                {

 &
nbsp;                  if (gr is ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceBase)

                    {

                        dropDownListResources.Items.Add(gr.Name);

                    }

                }

            }

        }

        protected GISResourceCollection GetMapResourcesFromMRM(string mrmID)

        {

            GISResourceCollection gisRC = new GISResourceCollection();

            MapResourceManager rm = (MapResourceManager)Page.FindControl(mrmID);

            if (rm == null)

                return null;

            if (!rm.Initialized)

                rm.Initialize();

            foreach (MapResourceItem mri in rm.ResourceItems)

            {

                gisRC.Add(mri.Resource);

            }

            return gisRC;

        }

6) Override a set of methods associated with task implementation to complete the custom task control.  Further details on these methods will be provided in future blog posts.

        public override string GetCallbackResult()

        {

            return base.GetCallbackResult();

        }

        public override void ExecuteTask()

        {}

        public override List<GISResourceItemDependency> GetGISResourceItemDependencies()

        {

            List<GISResourceItemDependency> list = new List<GISResourceItemDependency>();

            return list;

        }

    }

}

7) Build the custom task in Visual Studio and add a reference to it in a Web page.  Add the custom task and a MapResourceManager control to the page.  Add one or more ArcGIS Server resources to the MapResourceManager.  Run the Web app and you should see a drop down list containing the name of each ArcGIS Server map resource item in the MapResourceManager.    It should look similar to the following screenshot:

 

 

 

You can download the sample here.

 

Posted in Services | Tagged , , | 1 Comment

Extending the QueryAttributesTask to highlight selected features

Bryan Baker of the .NET SDK team wrote the following great post on extending a task to modify its behavior and then adding that task to the .NET Global Assembly Cache so it can be reused across applications. 

Note: Also see the follow-up to this post from May 3, 2007.

Highlighting all task results

 

With the Web ADF at 9.2, a website can have one or more tasks to allow users to find features or locations on the map. For example, you might add a QueryAttributesTask to the website to allow users to find cities by name, by typing the first few characters in the name.

 

The out-of-the-box tasks at 9.2 do not automatically highlight found features on the map. Instead, the user can highlight features by clicking individual check-boxes of features in the task results (see graphic, with two cities selected).

 

 

What if you want to have all features highlighted immediately when the task runs? There is currently no setting to enable this. But such immediate highlighting is possible through customization. Let’s look at one relatively easy approach for someone with modest programming skills. We’re looking specifically at the Web ADF for the Microsoft .NET Framework here, by the way.

 

We will extend a task control to modify its behavior. The object-oriented nature of .NET allows us to create a new class (a task, in this case) that inherits all of the behavior and properties of the original class. We only need to add or modify the original class where we need it to act differently from the original class (task). Some aspects of tasks may be difficult or impossible to change, but modifying the task results output is not difficult.

 

The approach we’ll look at can apply to any task that produces a task result in the form of a graphics layer, where users can click on feature check-boxes to highlight them on the map. This includes the SearchAttributesTask, FindAddressTask, FindPlaceTask and QueryAttributesTask. We’ll look specifically at the QueryAttributesTask in this example.

Extending an out-of-the-box task

 

First, I open Visual Studio 2005 and create a new project (not a new website), a Class Library project to be specific. One great thing about .NET is that even though the original class was written in C#, we can extend it in any language—we’ll use VB to show this here. We can put our new class library anywhere; it doesn’t have to go into a web folder. I’ll call my project QuerySelectTaskVB. By the way, we could also use either Visual Basic Express or Visual C# Express, but it’s more difficult to debug with a linked web application.

 

Visual Studio creates the project and adds a new class called Class1.vb. I right-clicked on it in the Solution Explorer and renamed it QuerySelectTaskVB. This also renames the class in the code view—nice.

 

We need to add some references to the project to the libraries we’ll be using. I right-click on the project in Solution Explorer, and chose Add Reference, and in the pop up dialog I select these libraries and then click OK:

  • ESRI.ArcGIS.ADF.Tasks
  • ESRI.ArcGIS.ADF.Web
  • ESRI.ArcGIS.ADF.Web.DataSources
  • ESRI.ArcGIS.ADF.Web.UI.WebControls
  • System.Web

 

To start creating our class, we add some Imports statements at the top of the class file so we can use classes without having to type the full path. We’ll also add a Namespace around our class to better identify it.

 

Imports System
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Data
Imports System.Web
imports System.Web.UI
Imports ESRI.ArcGIS.ADF.Tasks
Imports ESRI.ArcGIS.ADF.Web.Display.Graphics
Imports ESRI.ArcGIS.ADF.Web.UI.WebControls

 

Namespace QuerySelect
  Public Class QuerySelectTaskVB
  End Class
End Namespace

 

We tell the class to extend (inherit) the existing QueryAttributesTask by adding to the class declaration we’ve already created:

 

Public Class QuerySelectTaskVB
    Inherits QueryAttributesTask

End Class

 

The only thing we want to change in the task is how it outputs the results to the TaskResults control. The task creates this output in the standard task method called ExecuteTask(). We want the QueryAttributesTask to create its output as usual, but we will modify the results once they’re created. So we create our own version of ExecuteTask() that overrides the original. Our version will call the base (parent) class version of the method, then modify the results that have been created. The following code goes inside the Class definition we saw above:

 

    Public Overrides Sub ExecuteTask()
        ' QueryAttributesTask creates its results
  &nbs
p;    
MyBase.ExecuteTask()
        ' We'll modify the Results next
    End Sub

 

Once the parent class has run its ExecuteTask, we can modify the results. The results are stored in a task property object called Results (makes sense, eh?). If the query finds features, those get stored in Results as a standard .NET DataSet, which contains one or more DataTable objects. But if nothing was found, the Results contains a different type, a SimpleTaskResult. Also, if the map service isn’t working right, the results might have a DataSet, but the name (caption) just has an error message. Let’s make sure we have valid results:

 

        ' We'll modify the Results next
        ' Make sure features were found

        If TypeOf Results Is DataSet Then

            Dim resultsDS As DataSet = CType(Results, DataSet)
            ' Check for errors during query

            If resultsDS.DataSetName.IndexOf("Error") > 0 Then
               
Return
           
End If

             ' Next we can get the table of results
       
End If

 

Now we can get the table from the DataSet. With the QueryAttributesTask, only one DataTable will be in the DataSet (other tasks may have multiple tables). One more error check: after the task performs its query using the Web ADF common API, it converts the data table to a GraphicsLayer object, so that it contains rendering (symbology) information. If it had any problems making that conversion, then features can’t be selected on the map.

 

            ' Next we can get the table of results
           
' Get the one table in the QueryAttributesTask result
           
Dim resultsTable As DataTable = resultsDS.Tables(0)
 

            ' Make sure no problems creating a GraphicsLayer from the results
           
If resultsTable Is Nothing OrElse Not TypeOf resultsTable Is GraphicsLayer Then

                Return

            End If

            ' Now we can modify the table results

 

Now we can actually set the selection for the features found! The GraphicsLayer, which extends the DataTable type, will have a Boolean-type column indicating whether the row (map feature) is selected. We can get this column, and use it when looping through the features to set all features as selected:

 

            ' Now we can modify the table results
           
Dim graphicsLayer As GraphicsLayer = _
              CType
(resultsTable, GraphicsLayer)
 

            ' Get the column that holds the selection attribute
           
Dim selectedCol As DataColumn = graphicsLayer.IsSelectedColumn
 

            ' Set each feature to selected
           
For Each row As DataRow In graphicsLayer.Rows
                row(selectedCol) = True

            Next

 

That’s it! Now each feature will be selected in the TaskResults tree and also on the map….that is, once our task is inside a website, which we’ll show shortly.

 

We compile the code by choosing Build—Build Solution f
rom the menu (no errors, of course!). This puts a compiled .dll file into the Bin directory of the project (you can see that by looking at the project folder with Windows Explorer).

 

Adding the task to Visual Studio

The easiest way to add the task to a website is when it’s in the Visual Studio toolbox. It can be added manually to an individual website, but requires more editing of the source of the page. Let’s get the task into Visual Studio. There’s more on this in the Developer Help for ArcGIS Server and ArcIMS, so we’ll go over this quickly.

 

First, in the code for the task itself, we add some information so Visual Studio sets properties for task when we drag it onto the page from the toolbox. This goes just above the class declaration:

 

<ToolboxData("<{0}:QuerySelectTaskVB runat=""server"" Width=""200px"" Transparency=""35""" _

        + "BackColor=""White"" TitleBarColor=""WhiteSmoke"" TitleBarSeparatorLine=""False""" _

        + "TitleBarHeight=""20px"" BorderColor=""LightSteelBlue"" BorderStyle=”Outset”’ _

        + "BorderWidth=""1px"" Font-Names=""Verdana"" Font-Size=""8pt"" ForeColor=""Black"">" _

        + "</{0}: QuerySelectTaskVB >")> _

Public Class QuerySelectTaskVB

    Inherits QueryAttributesTask

 

Next we will add the task to .NET’s Global Assembly Cache. This makes it easier to add the task to various websites. Before we can do this, we must create a strong name to sign the task. We open the .NET command prompt and type:

 

sn –k QuerySelectVB.snk

 

This creates a key file (QuerySelectVB.snk) in the folder indicated by the command prompt (probably C:Program FilesMicrosoft Visual Studio 8SDKv2.0). I moved that file using Windows Explorer to the project directory where my task .vb file is located. I then added that to my project by right-clicking on the project in Visual Studio’s Solution Explorer, choosing Add-Existing Item, changing the type to All Files, and clicking on the .snk file. I used the keypair to sign the assembly by right-clicking on the project and choosing Properties. In the Properties page, I clicked the Signing tab. I checked the box Sign the assembly and clicked my .snk file in the drop-down list. Finally, I recompiled the code (Build-Build Solution).

 

Now we can add the task to the Global Assembly Cache. Here’s the easy way: I opened two Windows Explorer windows, one to my project folder’s bin directory where the .dll is located, the other to C:WindowsAssembly. I dragged the QuerySelectTaskVB.dll into the C:WindowsAssembly window. This doesn’t actually move the file. It just registers the assembly so it’s available to all applications on the system.

 

Finally let’s add the task to Visual Studio. Open Visual Studio and then any .aspx page (you can create a website and page if necessary). Open the toolbox if necessary. Right-click where you want to add the task and click Choose Items (you can also create a new tab with New Tab).  In the Choose Toolbox Items dialog, click Browse, and navigate to your DLL’s location. Highlight it and click Open. This adds the task to the list of available assemblies. Make sure its check box is checked, and click OK. This adds the task to the Visual Studio toolbox.

 

Now the task is available whenever you design an ASP.NET web page. Notice it has an icon—the same one as the QueryAttributesTask. It inherits this along with other properties of the parent task.

Using the custom task in a website

 

We can use the task in any website. I created a new website using the Web Mapping Application template. I could have added this website to the same solution as my task code if I’m using Visual Studio (useful for debugging the task), or in a new instance of Visual Studio. I could also open a website created with ArcGIS Server Manager or ArcIMS Web Manager, and add the task to it.

 

Once we have our web page open in Visual Studio, we can drag our new task from the toolbox into the Task Manager. Once it’s there, we can click its “smart tag” in its upper right to set the task’s properties.

 

 

 

Yet another great thing about extending an existing task: we get its designer tools with no coding required. We can set the Task Results container and use Edit the Query to create the query, exactly the same as with the standard QueryAttributesTask (see the Developer Help for tips on that).

 

The demo site for this page uses this custom task to query a water-well point layer for estimated yield. Choose a value from the drop-down list, and up to 50 features will be found. Notice that all features are immediately highlighted. Our custom task acts like the standard QueryAttributesTask, except that it highlights all features returned.

 

Try it out: http://serverx.esri.com/QuerySelectTaskDemo/.

Discussion

 

You can do other interesting things with the Results of the task. For instance, you could add a hyperlink to the task results output by adding the <a href…> tag to the DataSet’s DataSetName property, or to the DataTable.TableName. The hyperlink is displayed in the tree of the task results. You can also modify the DataTable itself, such as by hiding columns you don’t want displayed. Another example would be to display the results as a table, by creating a GridView from the DataTable and getting the HTML output from the GridView. You’d then create a new TaskResultsNode, add the output to that, and set it as the Results instead of the DataSet.

 

You might be tempted to customize other aspects of tasks, such as modifying
the task’s user interface. Although some customizations are possible, you’ll probably find that in many cases it would be easier to author your own task from scratch. The Developer Help has a good discussion of writing tasks, and the Web ADF has a couple of samples that can help get you started.

 

You might have noticed that the task user interface does not have the look-and-feel of other tasks—the colors, fonts, etc. The standard tasks have properties defined in the Theme of the website, specifically in the Default.skin file. If you want the same look-and-feel of the standard tasks, you can create your own control skin by copying properties from one of the standard tasks in Default.skin.

 

We haven’t discussed how to make our custom task available within Manager, so that non-programmers could use your task. This is a much more complex chore than adding the task to Visual Studio. Tasks are configured in Manager using a separate class called a web configurator. The standard task’s web configurators are hard-coded to output information specifically for that task. It is not possible to easily modify them to instead output tags and properties for tasks that extend them. It would be necessary to rewrite most or all of the web configurator in order for it to properly output your task from Manager. The Developer Help has information on writing web configurators, if you are ambitious.

 

Download the code for this sample:

 

 

 

Posted in Services | Tagged , , | 7 Comments

ArcGIS Server for the Microsoft .Net Framework 9.2 Service Pack 1

Anne Reuland of the Server Development team has contributed the following excellent detailed writeup on what is in service pack 1 for ArcGIS Server for the Microsoft .Net Framework 9.2.

 

There’s a very good overview of
what’s new in ArcGIS Server 9.2 on the ArcGIS
Server Product Documentation
page. Open the
Whats
New In ArcGIS Desktop 9.2
document; you’ll need to enter your ESRI global
account. The Table of Contents has a listing for ArcGIS Server and ArcIMS.

I’ve had several folks
ask for an overview on what’s included in our Service Pack 1 release.
The main purpose of the ArcGIS
Server for the Microsoft .Net Framework 9.2 Service Pack 1 release was to
address support issues with Internet Explorer 7. The problems we saw with ArcGIS
Server 9.2 Final and Internet Explorer 7 were display problems with the map or
Web Mapping Application related to certain tools and changes to the application
layout. We also found formatting problems with buttons and panels in the Web
Mapping Application, Manager, and several samples in our Software Developer Kit.
Here is the full list of bug fixes for Internet Explorer 7 support:

  • NIM005055 – Samples: In IE7, HTML buttons without a
    defined width will span the width of the browser.
  • NIM005056 – Samples: In IE7, resizable divs should not
    define a width or height.
  • NIM005539 – When using the Web Mapping Application in
    Internet Explorer 7, clicking the FullExtent or Magnifier tool causes the
    page to go blank.
  • NIM005540 – When using the Web Mapping Application in
    Internet Explorer 7, docking a floating panel causes the page to go blank.
  • NIM005564 – When running Manager in an Internet
    Explorer 7 browser, the Apply button on the Preview Layers tab may be
    partially obscured or missing completely.
  • NIM005565 – When running Manager in an Internet
    Explorer 7 browser, the ‘Preview Map Service’ panel is excessively wide.
  • NIM005566 – When running Manager in an Internet
    Explorer 7 browser and configuring a task, the message informing the user
    that a supporting service is required does not display.
  • NIM005567 – When running Manager in an Internet
    Explorer 7 browser and editing an existing application, the Configure
    button on the Tasks panel is partially obscured.
  • NIM005569 – After digitizing a new feature with the
    Geoprocessing Task in Internet Explorer 7, the Help button, Submit button
    and selection of features will not work until clicked twice.
  • NIM005602 – Visual Studio 2005 SDK help system
    displays with incorrect style and formatting when viewed on a machine
    with Internet Explorer 7 installed.

Once you install Service Pack 1,
newly created web applications will take advantage of these fixes for Internet
Explorer 7. If you have already built applications with Manager or the Web
Mapping Application template that you would like to update with these fixes, we
have written a migration utility that will make these changes to your Web
Mapping applications. You can download the migration
utility
from our support site.

 

We’re always looking to improve
performance for the web applications and web services. Jeremy has already
posted about the changes to with map cache image formats to support JGP, PNG8,
and PNG32. These changes allow you to choose the image format that works best
for your application’s functionality and performance needs. 

 

Other performance improvements made
at Service Pack 1 affect web service authentication and geocoding with ArcWeb
Services. In the Web Mapping Application, we made improvements on how fast the
map and task results are initialized. These bug fixes are:

  • NIM005590 – Improve Web services authentication
    performance.
  • NIM005598 – Optimize the display of task results when
    using ArcGIS Server Internet resources.
  • NIM005623 – Optimize initialization within the Map
    control
  • NIM005619 – Optimize geocoding with ArcWeb Services
    resources.  

When using caches map services, if
you have secured both your map service and the cache directories that hold your
map tiles, Service Pack 1 includes a fix to allow the Web Mapping Application
to access those secured tile directories without prompting the end-user of the
application for a username and password. Once a username and password has been
specified during creation of the Web Mapping Application, that account will be
used to access the secured map service and the secured tile directories. The
bug fix for this change is:

  • NIM005541 – Use the Identity information provided when
    defining a map resource to access cache directories that have
    been secured.

If you are using ArcWeb Services in
your Web Mapping Application, you may have been affected by this bug fixed at
Service Pack 1:

  • NIM005593 – ArcWeb services randomly return the error
    ‘The underlying connection was closed: A connection that was expected to
    be kept alive was closed by the server’.

We also fixed problems with some of
the query operators for the Query Attributes task at Service Pack 1. :

  • NIM005323 – Web applications containing a Query Task
    expression using either the < or <= operators will fail to build.
  • NIM005571 – Web applications published from Manager
    containing a Query Task expression using the LIKE operator do not return
    the correct results.
  • NIM005572 – Web applications containing a Query Task
    expression using the != operator do not return the correct results.

In the Web Mapping Application,
after running a task to get a list of results, the Zoom To option for point
features was not zooming in far enough. This problem was addressed at Service
Pack 1 by adding a property named ZoomToPointFactor to the Task Results control
to allow you to control the zooming:

  • NIM005594 – Add a ZoomToPointFactor property to the
    TaskResults control to specify the scale change when using the ZoomTo
    context menu option.

Also in the Web Mapping Application,
fixes were made to ensure the scale bar displays in the expected location:

  • NIM005622 – Fix cases where the Scalebar is displayed
    outside the Map control on initial startup of the Web Mapping
    Application.

You can get the full list
of issues
that were addressed on the Service Pack page.

 

Posted in Services | Tagged , | 1 Comment

Antialiasing with multiple cached resources

Combining multiple cached map services is one of the more powerful aspects of the ADF for ArcGIS Server.  High performance mapping applications can be built off of multiple fused cached map services combined within the ADF.  Lets build on the cached aerial photography example from the other day and add a cached dataset of a street network.  In order to get the best performance when combining cached datasets in the Web ADF for the Microsoft .NET Framework you need to ensure that your cache configurations are identical (same scales, projection, tile size, etc) and that the map services share similar dataframe extents.  When building a map cache you have the option of taking advantage of Antialiasing to smooth the edges of labels and lines for improved display quality).  Of course you want to have smooth lines and labels!  So what does antialiasing really do?  Let's look at some comparisons of similar tiles with and without antialiasing.

   

The image on the left is without antialiasing enabled.  The image to the right has been built using antialiasing.  See the difference?  The image with antialiasing of the 2000 Census Roadways dataset looks crisper, not as choppy.   Antialiasing is designed to minimize jagged, blocky aliasing when representing higher resolution data at a lower resolution.  So let's see what happens when we publish the data on top of our ortho cache…

 

 Wait a minute…where did my roads go?  Let's look at the same area without antialiasing…

 

 

That is what I get for implementing something without understanding the logic behind the process!  The way we have implemented antialiasing from ArcGIS server is to generate tiles four times as large as the specified tile size so that we can average the RGB color of the four pixels that intersect the feature or label.   So instead of a tiled pixel being completely black or not, it will be an average of the subpixels contained by the pixel.  What does it average if it is just a line that is either black or not black?  It uses the background color of the dataframe to compute the average pixel value.  The background color is used as the transparent color by cache generation process and if you don't set the background color of your map the default is to set the background equal to 253,253,253 or almost white.  So in my example I have ended up with gray roads (which don't show up well on a dark image) instead of what I originally designed as black roads.  If I rebuild my map cache of my road dataset with a background color set to an average color within the image of the ortho tile (RGB: 129,129,116–pulled from this slick freeware tool) I end up with a tile that looks like this…

  

 

Try the application with each of the antialiasing options here:   http://serverx.esri.com/antialiasingexamples/

Jeremy 

Posted in Services | Tagged , | Leave a comment

ArcGIS Server Service Pack 1

ArcGIS Server Service Pack 1 is out and available for download.  It has many fixes along with some very key enhancements.  One of the biggest enhancements is the ability to create map caches in different image type formats.  At 9.2 final you only had the option of creating PNG24 images for you map cache.  While PNG24 images are visually appealing and work well with images with a lot of vector data they are inefficient for continuous raster images like aerial photography or satellite imagery.  For example here are two tiles of orthophotography in both png (on the left) and jpeg (on the right):

PNG    JPG

 

The JPEG tile is 16.39kb.  The PNG tile is 85.93kb.  That makes the JPEG in this case 1/5 the size of the PNG.  While that does not really make that much difference while you are on an internal network, it makes a big difference for web applications.  It is important to note that JPEGs do not support transparency so PNG images would be ideal for map caches that need to be transparent (a roads cache on top of an ortho cache for example). 

Try out a demo here:  http://serverx.esri.com/dgaerialsws

This example uses 2 meter FSA NAIP color imagery and six inch black and white orthophotos courtesy of the City of Lawrence, Kansas

Jeremy 

 


 

Posted in Services | Tagged , , | 8 Comments

Using the Callback control framework with a map resource

Let's build on the sample that Ryan put together and use the callback control framework to refresh a map control.  In this case we need to send back callback results of the map control to the control being called back to (the callback button).  To illustrate this lets add a map, map control, and a couple of Callback Button controls to the map design time in Microsoft's Visual Studio 2005.  We want to give the user the ability to add and remove a dynamic dataset via the CallbackButtonCustomControl.
 

To do this we need a method that adds a dynamic resource to the MapResourceManagerInstance.
 

private void createAndAddResource(string resourceName, GISResourceItemDefinition definition, bool insertIntoBeginning)

    {

        MapResourceItem resourceItem = new MapResourceItem();

        resourceItem.Definition = definition;

        resourceItem.Name = resourceName;

        resourceItem.DisplaySettings = new ESRI.ArcGIS.ADF.Web.DisplaySettings();

        resourceItem.DisplaySettings.Visible = true;

        resourceItem.DisplaySettings.Transparency = 20;

        resourceItem.DisplaySettings.DisplayInTableOfContents = false;

        resourceItem.DisplaySettings.ImageDescriptor.TransparentBackground = true;

        resourceItem.DisplaySettings.ImageDescriptor.TransparentColor = System.Drawing.Color.FromArgb(1, 2, 3);

        if (insertIntoBeginning)

        {

            Map1.MapResourceManagerInstance.ResourceItems.Insert(0, resourceItem);

        }

        else

        {

            Map1.MapResourceManagerInstance.ResourceItems.Add(resourceItem);

        }

        resourceItem.CreateResource();

        Map1.InitializeFunctionalities();

    }

 

 

Within the CallbackButton1_Clicked event we call the method to create and display the dynamic resource and then use the callback control framework to pass the CallbackResults from the map to the control.
 

  string resourceName = "Dynamic Data";

        GISResourceItemDefinition definition = null;

        definition = new GISResourceItemDefinition();

        definition.ResourceDefinition = "(default)@DGCountyAerialPhotos";

        definition.DataSourceDefinition = "http://localhost/arcgis/services";

        definition.DataSourceType = "ArcGIS Server Internet";

        definition.DataSourceShared = true;

        createAndAddResource(resourceName, definition, false);

        if (Map1.ImageBlendingMode == ImageBlendingMode.WebTier)

        {

            Map1.Refresh();

        }

        else

        {

            Map1.RefreshResource(resourceName);

        }

        CallbackButton1.CallbackResults.CopyFrom(Map1.CallbackResults);

 

So now we can add dynamic data to a map on a callback.

Try the sample app out here:  http://serverx.esri.com/callbackbuttonsample/map.aspx 

Jeremy 

Posted in Services | Tagged , | 2 Comments

Using the Callback control framework

Ryan Olson of the Web ADF development team contributed the following code sample that demonstrates how to use the callback framework from within the ESRI Web ADF for the Microsoft .NET Framework. 

This control is very useful for testing things during the context of a callback.  When called, it fires a server-side event in the context of a page callback so that you can attach to that event at design time or programmatically and act on the event.  You can return "javascript" as the event argument to execute a JavaScript function or you can refresh the contents of a non-AJAX-enabled control (like the Gridview) without having to write a line of JavaScript.  

The code is extremely simple and yet it shows how to use the Web ADF CallbackResults and the WebControl base class Callback implementation.

 

Here is some sample code to execute some javascript

    protected void CallbackButton1_Clicked(object sender, EventArgs args)

    {

        CallbackButton1.CallbackResults.Add(new ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult(CallbackButton1, "javascript", "alert('hello');"));

    }

Here is some sample code to refresh a control that doesn’t inherit from our webcontrols with the CallbackButton (like a gridview):

    protected void CallbackButton1_Clicked(object sender, EventArgs args)

    {

        CallbackButton1.CallbackResults.Add(RefreshControlHtml(GridView1));

    }

    private CallbackResult RefreshControlHtml(Control control)

    {

        System.IO.StringWriter sw = new System.IO.StringWriter();

        HtmlTextWriter writer = new HtmlTextWriter(sw);

        control.RenderControl(writer);

        string htmlContent = sw.ToString();

        sw.Close();

        return new CallbackResult(control, "content", htmlContent);

    }

 

Try out a sample application illustrating the usage here:  http://serverx.esri.com/callbackbuttonSample/ 

 

Posted in Services | Tagged , | 2 Comments

Querying ArcGIS Server Web Services

One of the ways to connect to ArcGIS Server is through Web services.  When you make an Internet connection to the server, you will use a URL in this format:  http://<server name>/<instance name>/services 

This is an endpoint to your ArcGIS Server service catalog url. 

Where <server name> is the name of your server, which can be an IP address, a domain name (serverx.esri.com), or simply “localhost”.  The <instance name> is the name of your ArcGIS Server instance.  The instance gets defined when you install ArcGIS server.  You can review it by looking at server properties at your root folder in ArcCatalog.
 

So what can I do with this services catalog URL?  This URL can be used to establish an Internet connection to an ArcGIS Server instance in ArcCatalog.  It can be used as a connection in the ArcGIS Server Web ADF.  It can also be used in custom applications that work with Web services.  Today I am going to build a simple web application using the Microsoft .NET Framework in ASP.NET that consumes the catalog URL for my ArcGIS Server instance and lists the services, types, and service URL in a simple web page.

The first step after creating your new web site is to register the services catalog URL for your ArcGIS Server Web service.  To do this you need to add a web reference to your project (in VS2005 right click on the project name and Add Web Reference).  In the web reference dialog enter your server catalog URL. 


 

Once we have registered the Web service we just need to use it. 
 

//Create an instance of the service catalog web service

WebCatalog.Catalog webCat = new WebCatalog.Catalog();

//Set the url to your ArcGIS Server services url

String serverUrl = “http://localhost/arcgis/services”;

webCat.Url = serverUrl;

//Get the all the service descriptions from the Catalog

WebCatalog.ServiceDescription[] sds = webCat.GetServiceDescriptions();

//extract the name, type, and URL for each service in the

//servicedescriptions array

foreach (WebCatalog.ServiceDescription sd in sds)

{

  Response.Write(“<b>Service Name</b> = “ + sd.Name + “<br>”);

  Response.Write(“<b>Service Type = </b>” + sd.Type + “<br>”);

  Response.Write(“<b>Service URL  = </b>” + sd.Name + “<br>”);

  Response.Write(“<br><hr>”);

}

So try it out here:  http://serverx.esri.com/InterrorgateServer 

You can download the Visual Studio project here

Over the next few weeks I will explore working with the Web services for some of the ArcGIS Server service types (MapServer, GPServer).

Jeremy
 

 

 

Posted in Services | Tagged , , | 6 Comments

Publishing and using a geoprocessing model within a map document

One of the exciting new aspects of ArcGIS Server 9.2 is the ability to publish geoprocessing models and scripts to the server.  A model can be published either as a tool that can be used directly on top of any map service, or it can be published with an associated map service so that you can control the symbology of the generated layer. 

 

To illustrate the power of geoprocessing on the server, I built an example that uses a map service and an embedded model that allows users to execute an interpolation on the server and view those results in the web mapping application.  The map service contains a point dataset describing the potential water yield from water wells drilled in Douglas County, Kansas (data courtesy of the Kansas Geological Survey and the Kansas Geospatial Community Commons).  The model takes in the water well dataset and a user-defined cell size.  This information is passed as input parameters to the Natural Neighbors GP tool.  The output is a raster dataset.  The output is then rendered using a predefined layer symbology file (a layer file).

 

 

If you looked closely, you may have noticed that the model includes an embedded Python script.  This script allows me to put a limit on the input cell size parameter.  I want to allow the user to set the cell size (in meters) of the output raster dataset from within the web application.  However, I want to make sure that the user does not enter so small of a cell size that it will negatively affect the speed of the web application.  The script ensures that if the user enters anything less than 30 meters, the application will default to a cell size of 30 meters.  I will have more on this in a future post. 

 

Here are some key steps to remember when publishing a geoprocessing tool embedded in a map service.

 

  • Create an MXD with the input layer and any other background layers that you want in your map service.
  • Create a toolbox in your project directory.
  • Add a new model to your new toolbox.
  • The model should use one of the layers in the map document as an input parameter.
  • Ensure that your map document and input map layers are at the same projection.
  • Your output dataset should be written to the scratch workspace.
  • Set your toolbox scratch workspace environment variable equal to a directory that is visible to your ArcGIS Server Object Container (SOC) account.
  • Move your finished model to your ArcMap table of contents. This is called a tool layer.
  • Execute the model from within ArcMap and verify the results.
  • Turn off the output layer in ArcMap and publish to the server.

 

The easiest way to publish a map service with an embedded geoprocessing service is to publish the map document (using the right-click option on the map document, “Publish to ArcGIS Server”).  ArcGIS Server will see that the map service has a tool layer and will load that tool as a geoprocessing service. 

 

Once deployed to the server, it is relatively straightforward to deploy the map service and associated geoprocessing task as a web application using ArcGIS Server Manager. 

 

Check it out here:  http://serverx.esri.com/interpolationexample

 

Try building and publishing your own models.

 

What do you think?

Jeremy

Posted in Services | Tagged , , | 6 Comments