Monthly Archives: February 2008

Using Web ADF controls in an ASP.NET Web Part and SharePoint 2007

Rex Hansen, a Product Engineer for the .Net Web ADF, contributed this post:

Update: The post below applies to ArcGIS Server 9.2. Click here to see the 9.3 instructions.

The organization of information within a Web site can be challenging, especially
when attempting to accommodate multiple end users with different work habits
and capabilities. To support this situation, many Web sites utilize some form a
portal technology which can provide a framework to modularize information and
personalize its presentation. First introduced in ASP.NET 2.0, the Web Parts
framework fulfills this need by providing an ASP.NET solution for portal
developers. In general, ASP.NET Web Parts are controls that enable developers
to encapsulate related functionality and give end users the ability to modify
the content, appearance, and behavior of Web pages directly in a browser.

There are a number of options for building an ASP.NET Web Part in Visual Studio
2005: drag and drop Web Part controls in a page, build a Web user control, or
create a custom Web Part control. In most cases, Web Parts are supposed to be
addedremoved at runtime during a user session, so dragging and dropping Web
Part controls in a page at design-time does not offer a realistic solution. Web
ADF controls will work in user controls, but not if the user control is in a
Web Part. This problem is rooted in managing state and control ids for
callbacks and cannot be overcome in ArcGIS Server 9.2. This leaves the last option, a custom
Web Part control, which also gives you the most control over how the Web Part
functions. There are two stages to consider here: support for Web ADF controls
in a custom Web Part and deployment of the Web Part. In essence, getting Web
ADF controls to work in a custom Web Part involves building a custom composite
Web control that inherits from System.Web.UI.WebControls.WebParts.WebPart.
Other than the standard pattern for creating a custom composite Web control,
such as adding controls during CreateChildControls(), a number of Web ADF
control specific issues must be considered:

  • In a custom Web Part, Web ADF controls are added dynamically. During a request
    to a page, the page and its controls (including the Web Part) iterate through
    their lifecycle. This becomes important when dealing with resources added to a
    resource manager. Once added, they are maintained in state and retrieved when
    the resource manager is recreated during the control lifecycle. So as not to
    keep re-adding resources every time the resource manager is created during the
    Web Part lifecycle, you need to check session state for the presence of the
    resource items. If present, do not re-add the resources.
  • A set of HTML hidden input elements (fields) are injected in the page at
    runtime if a Web ADF control is present. These fields store information about
    the current tool, map mode, and screen coordinates associated with tool
    interaction in the map, etc. One field, ESRIWebADFHiddenFields, stores a list
    of all the other field names (input values). This list is used to include the
    other field values in a callback request. If the Web ADF controls are added
    after the initial request to the page (such as what happens when a Web Part is
    added during a full postback to the page), the ESRIWebADFHiddenFields value is
    empty. As a result, tool interaction with the map is not functional. To
    workaround this issue, you need to manually set the value of the
    ESRIWebADFHiddenFields element. Note this will only affect Web Parts that are
    added after initial page load. If a Web Part is added during initial page load,
    these fields will be set correctly. Adding more than one Web Part with a Web
    ADF Map and Toolbar will likely cause conflicts and render some tool
    interaction with the map non-functional. There is no easy way to overcome this
    in 9.2. As a result, it is best to add only one Web Part with a Map-Toolbar per
    page.

On to working with SharePoint – Building a portal site which uses Web Parts can
be time consuming; integrating the site into other enterprise systems can be
difficult and inefficient; and lastly, managing the site can be overly complex
and convoluted. In an attempt to manage enterprise content, intelligence and
search systems effectively, Microsoft has created Microsoft Office SharePoint
Server 2007, or MOSS for short. MOSS is good for what it claims to do (be an
all encompassing enterprise system for sharing information), but it is not
simple. Like many software products, more capability means greater complexity.
One option for customizing the presentation of content and providing access to
business logic is developing custom ASP.NET Web Parts and deploying them on a
SharePoint server. An ASP.NET Web Part can be deployed relatively easily with
SharePoint 2007. The SharePoint SDK includes a WebPart class which derives from
the ASP.NET WebPart. The SharePoint WebPart class offers a few benefits, such
as cross-page and non-WebPart connections, which primarily facilitate backward
compatibility with SharePoint 2003. For more information on Web Part
development with SharePoint 2007, Scott Guthrie provides a bevy of valuable
information and links in his blog post
Writing Custom WebParts for SharePoint 2007
. You can use Sahil Malik’s
walkthrough at the beginning of the post to get started creating a custom
ASP.NET Web Part.

There are a few issues to consider when deploying a Web Part that contains Web
ADF controls in SharePoint 2007:

  • SharePoint 2007 was designed to function using the full page postback pattern.
    As a result, tools in a Web ADF Toolbar may need to trigger a full postback
    within a custom Web Part to communicate with other parts in the page.
    Unfortunately the postback event never gets to the tool, so some additional
    code is required to raise the post back event to the correct control (e.g.
    Map). See the sample code for more details.
  • The SharePoint 2007 server may not have session state enabled, which is
    necessary for the Web ADF controls to function. If not enabled, SharePoint will
    return a fairly ambiguous error when attempting to add your custom Web Part to
    the SharePoint server.

The 9.3 Web ADF will resolve many of the limitations and issues encountered when
working with 9.2 Web ADF controls in a Web Part. 9.3 Web ADF controls will be
fully supported for use in custom user and composite controls, both of which
may be deployed as a Web Part. Multiple Web Parts containing multiple Web ADF
controls can function within the same application. The use of
ESRIWebADFHiddenFields will be reduced if not removed. And full postbacks
initiated by toolbar items will be supported internally.

The sample code includes two projects. The class library project contains the
custom Web Part with a MapResourceManager, Map and Toolbar control. The file
system Web application contains a simple aspx page designed to emulate a
runtime scenario where an end user wants to add a Web Part within the current
session. Note, to personalize the page (e.g. add a Web Part at runtime) the
current session must be associated with an authenticated user. By default, a
file system Web site will used integrated authentication. If deploying as a Web
application in IIS, you will need to disable anonymous access to the Web
application in IIS. Enabling integrated authentication may offer the easiest
solution since you do not need to configure or explicitly set authentication
details, instead the authenticated user will be the user account under which
the client (browser) is running.

The default personalization provider for ASP.NET 2.0 is SQL Express. If you do not have SQL Express installed, a personalization store will not be created (upon initial execution of the application) and an error will be returned when attempting to add the custom Web Part to the page at runtime. To alleviate this requirement, I have added a custom personalization provider that uses text files. The code, markup, and discussion for this technique is provided here: http://msdn2.microsoft.com/en-us/library/aa479037.aspx

Download
the sample code

Posted in Services | Tagged , , , , | 4 Comments

Explorer at the FedUC

Last week marked ESRI’s Federal User Conference in Washington, D.C. During the plenary on Tuesday a variety of ESRI software and applications were showcased, including ArcGIS Explorer. We’ve had a few requests to recap what was shown in a little more detail, so here’s the overview of the ArcGIS Explorer plenary presentation.

First, the new Resource Center (introduced with Explorer 440) was highlighted by adding one of the newly published results – State Capitals – and showing the popup links to the USGS Science In Your Backyard Web site for each result. From there the Physical Features layer was added to the map, with a demonstration of the swipe and transparency tools. Shown below is the swipe tool being used with the seamless USGS topographic map layer that is included in the service.

The next part of the presentation showcased Explorer’s ability to connect to and integrate a wide variety of different content services, each published through different servers at locations throughout the US. The layers included:

  • several ArcGIS Online layers
  • an ArcIMS service from the ESRI Geography Network
  • a WMS services found via the FGDC clearinghouse
  • an ArcGIS Server map service (population growth by county)
  • a dynamic weather map service that updates every 15 minutes. The weather data is collected in an enterprise geodatabase (ArcSDE) via a connection to a Meterologix weather service, and published as an ArcGIS Server map service. The Explorer layer properties were set to update every 15 minutes to match the updates on the server.
  • an ArcGIS Server globe service (hurricane tracks)

Added to the map was a stamp of ”confidential.” This was done using the new Display Overlay property added to Explorer 440. Go to File, then Map Properties, and look for the Display Overlay property. The overlay can be placed at a variety of different locations, and is a great way to include your company logo with your map.

Next, Explorer’s ability to add a variety of local data sources was highlighted. Shown in the map below are a raster file (the historical map), a file geodatabase (Oregon county polygons), a shapefile (airport locations), and a KMZ file from the NRCS Web site (Snotel precipitation and snow levels). Also shown is the KML/Z popup window.

The airport symbol is part of Explorer’s new billboarded point symbol set. These are optimized for performance, so even though there are many 10s of thousands of airports worldwide (see below) the navigation speed is not impacted significantly.

The city of Portland was visited next, with a 3D cityscape of the downtown area. The buildings were authored using ArcGlobe, extruding building footprints based on attributes containing elevation. Also shown are tax lots (an ArcGIS Server map service) and a link to a YouTube video showing a walking tour through Portland.

 

Several tasks were demonstrated, including a few of the default tasks (powered by ArcGIS Online) and a Weather Finder task downloaded from the Explorer Resource Center. Finally, a custom service area analysis task was used to determine drive time service areas, shown below as a red polygon. The geoprocessing task was authored using ArcGIS Desktop, and published via ArcGIS Server.

 

Posted in Uncategorized | Tagged , , , | Leave a comment

Map viewing altitude

By Dr. A Jon Kimerling, Professor Emeritus, Oregon State University

Have you ever wondered how you can figure out how far the viewing distance is from the center point of any map?  For example, in my office I have a large map of the world on my wall. It has a scale of 1:9,000,000.  How can you tell the viewing altitude for the map?  This is a very good question that I was asked recently.

Continue reading

Posted in Mapping | Tagged | Leave a comment

A quick, clean method for insetting polygon outlines

By Charlie Frye, Esri Chief Cartographer

Example of inset boundary lines

Quite some time ago we posted a blog entry on creating tint bands, which are bands of color either interior or exterior to polygons along their borders.  You will see this cartographic effect on world atlases, for example, using different colors to distinguish the various counties. The solution we presented was involved and complex, but it did preserve essential characteristics of the polygons better than any other method we tried. Continue reading

Posted in Mapping | Tagged , | 1 Comment

Creating a utility library (Part II): Creating and adding resources

Morten Nielsen, a developer on the .NET Web ADF team, contributed this series:

This post is the second in a series on creating a set of reusable helper methods
that tries to make some of the common developer tasks when working with the
.NET Web ADF easier. This specific article shows how to create a few static
methods that you can use to create, add and initialize resources to your map.

The simplest way of creating resources is by using the resource definition
string. If you use the designer in Visual Studio and add a resource to the
MapResourceManager, then switch to source view, you can see what the resource
definition string looks like:

<esri:MapResourceManager ID="MapResourceManager1" runat="server">
<ResourceItems>
<esri:MapResourceItem Definition="<Definition DataSourceDefinition="http://myserver/arcgis/services" DataSourceType="ArcGIS Server Internet" Identity="" ResourceDefinition="(default)@Counties" DataSourceShared="True" />"
DisplaySettings="visible=True:transparency=0:mime=True:imgFormat=PNG8:height=100:width=100:dpi=96:color=:transbg=False:displayInToc=True:dynamicTiling="
Name="MapResourceItem0" />
</ResourceItems>
</esri:MapResourceManager>

The definition string has been encoded to remove quotes and < and >
characters, so the “real” definition string for the above actually reads:

<Definition DataSourceDefinition="http://myserver/arcgis/services" DataSourceType="ArcGIS Server Internet" Identity"" ResourceDefinition="(default)@Counties" DataSourceShared="True">

We can create a resource based on this string using the constructor on
GISResourceItemDefinition:

MapResourceItem mri = new MapResourceItem();
mri.Definition = new GISResourceItemDefinition(definition);

Let’s take this concept further and create two helper methods for inserting and
adding resources to the MapResourceManager:

public static class Common
{
public static MapResourceItem AddResource(string definition, string name, MapResourceManager mapResourceManager)
{
return InsertResource(definition, name, mapResourceManager, mapResourceManager.ResourceItems.Count);
}
public static MapResourceItem InsertResource(string definition, string name, MapResourceManager mapResourceManager, int index)
{
//Ensure unique name by appending a number to it if it already exists
string uniqueName = name;
int counter = 1;
while (mapResourceManager.ResourceItems.Find(uniqueName) != null)
{
uniqueName = String.Format("{0}_{1}", name, ++counter);
}
//Create resource
MapResourceItem mri = new MapResourceItem();
mri.Definition = new GISResourceItemDefinition(definition);
mri.Name = name;
//Add and initialize resource
mapResourceManager.ResourceItems.Insert(index, mri);
IMapResource mr = mapResourceManager.CreateResource(mri);
mapResourceManager.Initialize(mri);
return mri;
}
}

The library that you can download takes this helper method a little further.
Instead of using the MapResourceManager as a parameter, it takes the map
instead. The method will take care of zooming to the first resource you add,
return error messages if the resource was not available, etc. I also added
several overloads to give you more fine-grained control of the resources you
added.

So this gives us an easy way of adding any kind of map resource to the Map. By
analyzing the definition string we can also create some data source-specific
methods that will create the definition strings based on for instance the
server endpoint and service name. Here are a few for ArcGIS Server Internet,
ArcGIS Server Local and ArcIMS:

public static class ArcGISServer
{
public static MapResourceItem AddLocalResource(string servername, string servicename, MapResourceManager mapResourceManager)
{
return AddLocalResource(servername, servicename, mapResourceManager, string.Empty);
}
public static MapResourceItem AddLocalResource(string servername, string servicename, MapResourceManager mapResourceManager, string identity)
{
string definition = string.Format("<Definition DataSourceDefinition="{0}" DataSourceType="ArcGIS Server Local" Identity="{1}" ResourceDefinition="(default)@{2}" DataSourceShared="True" />",
servername, identity, servicename);

return Common.AddResource(definition, servicename, mapResourceManager);
}
public static MapResourceItem AddHttpResource(string serverURI, string servicename, MapResourceManager mapResourceManager)
{
return AddHttpResource(serverURI, servicename, mapResourceManager, string.Empty);
}
public static MapResourceItem AddHttpResource(string serverURI, string servicename, MapResourceManager mapResourceManager, string identity)
{
string definition = string.Format("<Definition DataSourceDefinition="{0}" DataSourceType="ArcGIS Server Internet" Identity="{1}" ResourceDefinition="(default)@{2}" DataSourceShared="True" />",
serverURI, identity, servicename);

return Common.AddResource(definition, servicename, mapResourceManager);
}
}

public static class ArcIMS
{
public static MapResourceItem AddResource(string servername, int port, string servicename, MapResourceManager mapResourceManager)
{
string definition = string.Format("<Definition DataSourceDefinition="{0}@{1}" DataSourceType="ArcIMS" Identity="" ResourceDefinition="(default){2}" DataSourceShared="True" />",
servername, port, servicename);

return Common.AddResource(definition, servicename, mapResourceManager);
}
}

If we combine this with
the previous post
on how to simplify callback results, we can easily
create a callback button that adds a resource, updates the table of contents
etc.

protected void CallbackButton1_Clicked(object sender, EventArgs args)
{
//Add ArcGIS Server resource
ArcGISServer.AddHttpResource("http://myserver/arcgis/services", "Counties",
Map1);

Toc1.Refresh(); //Refresh TOC

//Disable the CallbackButton so user cannot click the button again
CallbackButton1.CallbackResults.Add(
Callbacks.CreateJavaScript(
String.Format("document.getElementById('{0}').disabled = -1;",
CallbackButton1.ClientID)));

//Ensure CallbackResults from all controls are returned to the client
WebADF.Utilities.Callbacks.AutoMoveCallbackResults();
}

Download
the Web ADF Utility Class

Update: The utility library has since been updated to support 9.3 partial postbacks, and can be found in the Code Gallery.

Posted in Services | Tagged , , | Leave a comment

Creating a utility library (Part I): Simplify working with callback results

Morten Nielsen, a developer on the .NET Web ADF Team, contributed this series:

This post is the first in a series on creating a set of reusable helper methods that tries to make some of the common developer tasks when working with the .NET Web ADF easier.

The AJAX behavior of the .NET Web ADF has been built on top of the ASP.NET Callback Framework. The framework allows us to do a call from the browser to a server-side web control carrying a string as argument, perform some processing on the server based on this argument, and then return a new string to a javascript method on the client. The argument string coming from the browser could for instance be a key/value pair separated by ampersands, but can technically be anything you want, for instance a JSON formatted object that you later deserialize on the server.

Each web control has its own client-side method that can be executed to do the callback to the server-side instance of the control. The Web ADF’s web controls all have a ‘CallbackFunctionString’ property that returns the javascript method needed to do this callback to server.

Most of the Web ADF’s web controls use the ‘CallbackResult’ type to specify what we want to send back to the client. The Callback Result basically consists of a control id if applicable, an argument type and a set of parameters. The ‘ToString()’ method on the ‘CallbackResultCollection’ serializes this to a return string that the client-side method ‘processCallbackResults’ knows how to parse.

An important thing to remember here is that the control that received the callback is the one responsible for returning all the callback results. If you for instance use the CallbackButton to call back to the server page, make some changes to the map, refresh the Table of Contents, etc, you are responsible for picking up all the callback results from the various controls that you changed and return them though the CallbackButton’s CallbackResults collection. The way this usually is done is by copying the callback results from all other modified controls in the ‘GetCallbackResults’ method, or in the case of the CallbackButton in its click handler method. Example:

CallbackButton1.CallbackResults.CopyFrom(Map1.CallbackResults);
CallbackButton1.CallbackResults.CopyFrom(Toc1.CallbackResults);
CallbackButton1.CallbackResults.CopyFrom(TaskResults1.CallbackResults);

Where this can get tricky is that you might not realize that certain controls contain callback results. For instance if you add a new ResourceItem to the MapResourceManager, that Map will contain new CallbackResults, because it automatically listens for the ResourceItemAdded event.

Since it is possible to figure out what control did the callback, and also search for all controls that contain results, why not create a small utility method that does this search and copy them over for you? This way you just do a simple call to a static method instead of doing all the copying.

The first step is finding the control that performed the callback. The page request will contain the unique ID of the control stored in the parameter ‘__CALLBACKID’, and we can use the UniqueID to search for the control in the page:

public static Control GetCallingControl()
{
HttpContext context = HttpContext.Current;
if (context == null) return null;
Page page = context.CurrentHandler as Page;
if (page == null) return null;
else if (page.IsCallback)
{
string controlid = context.Request.Params["__CALLBACKID"];
Control c = page.FindControl(controlid);
return c;
}
else return null; //Not an asyncronous request
}

The next step is to search for all controls in the page that contain callback results. We do this by doing a recursive search through the page tree to find any control that inherits from ESRI.ArcGIS.ADF.Web.UI.WebControls.WebControl or ESRI.ArcGIS.ADF.Web.UI.WebControls.CompositeControl and copy the CallbackResults. The recursive search will clear out any CallbackResults that have been copied over, so you don’t risk copying the same results if you do this search more than once:

/// <summary>
/// Searches for and moves all <see cref="CallbackResults"/> to the
/// calling control's <see cref="CallbackResultCollection"/>.
/// Note that callbackresults on all other controls will be cleared out.
/// </summary>
/// <param name="page">Page where the asyncronous call originated.</param>
public static void AutoMoveCallbackResults()
{
Control callingControl = GetCallingControl();
if (callingControl == null)
return;
CallbackResultCollection results = null;
if (callingControl is WebControl)
{
results = (callingControl as WebControl).CallbackResults;
}
else if (callingControl is CompositeControl)
{
results = (callingControl as CompositeControl).CallbackResults;
}
else return;

autoMoveCallbackresultsRecursive(callingControl.Page.Controls, results, callingControl);
}

private static void autoMoveCallbackresultsRecursive(ControlCollection controls, CallbackResultCollection results, Control callingControl)
{
foreach (Control control in controls)
{
if (control is WebControl && callingControl != control)
{
CallbackResultCollection controlresults = (control as WebControl).CallbackResults;
results.CopyFrom(controlresults);
controlresults.Clear();
}
else if (control is CompositeControl && callingControl != control)
{
CallbackResultCollection controlresults = (control as CompositeControl).CallbackResults;
results.CopyFrom(controlresults);
controlresults.Clear();
}
if (control.Controls.Count > 0)
{
autoMoveCallbackresultsRecursive(control.Controls, results, callingControl);
}
}
}

All you need to do now is call AutoMoveCallbackResults after doing processing and all controls in the page that contains callbackresults will automatically be copied to the calling control’s callbackresult collection:

protected void CallbackButton1_Clicked(object sender, EventArgs args)
{
//Do your processing and generate callback results...
//...

WebADF.Utilities.Callbacks.AutoMoveCallbackResults();
}

You can download the code below. We also included some static helper methods for creating some of the standard callback results. Example:

WebADF.Utilities.Callbacks.CreateJavaScript("alert('Hello World');");
WebADF.Utilities.Callbacks.CreateSetInnerContent(this, "This is the inner content of this control");
WebADF.Utilities.Callbacks.CreateSetImageSource(myImage, "http://www.mydomain.com/images/picture.jpg");

Download the Web ADF Utility Class

Update: The utility library has since been updated to support 9.3 partial postbacks, and can be found in the Code Gallery. Furthermore, the static CallbackResult helper methods mentioned above are now available directly off the CallbackResult class.

Posted in Services | Tagged , , | Leave a comment

Esri Press presents Designed Maps: A sourcebook for GIS users by Cynthia Brewer

By Michael Law, Esri Product Engineer

Link to Esri Press webpage for Design Maps

Cynthia Brewer’s new book titled Designed Maps: A Sourcebook for GIS Users is a companion piece designed to compliment the highly successful Designing Better Maps: A Guide for GIS Users published by Esri Press in 2005. The goal of the book is to offer a graphics-intensive presentation of published maps, providing cartographic details that will prompt GIS users to think about their own maps and how to improve them. Continue reading

Posted in Mapping | Tagged , , , | 1 Comment

Ask the Development Team

In our first year anniversary post, many of you liked the idea of having an “Ask the development team” thread, in which you could post questions about ArcGIS Server and we would post answers. This week we’re giving it a try.

How it works

  • Post your question as a comment to this post.
  • The blog moderators will select relevant questions and send them to the appropriate members of the development team.
  • Development team members will post comments in reply. We’ll try to answer all questions that are appropriate.
  • The thread will be open for questions through Friday, February 22. We’ll continue posting responses after that date.

    Question

Please note

The development team cannot address questions about pricing or licensing. Please contact your ESRI representative if you have a question about that.

Also, we may direct you to ESRI Support if your question is related to a bug or unexpected behavior. They are better equipped to help you troubleshoot the problem.

Update: This post is now closed to new questions but we will attempt to answer all of the questions we received while the thread was open.
 

Posted in Services | Tagged , | 21 Comments

Some Starting Options to Consider

One of the nice things about Explorer is that you can easily customize it to suit the way you work, or perhaps more accurately – the way you want to work. By choosing Tools, then Options, you’ll find a number of settings that will allow you to customize the way Explorer works for you. Here’s some of our favorites.

Which map do you want to open? By default, Explorer opens your most recently saved map. This is great if your workflow involves using the last map you saved, but it won’t be ideal if you do a lot of authoring and want to start with the default map. In that case, you’ll likely want to start with the Server default map, and if your Home Server is ESRI, then that will be the one you’ll want to start with.

To open the default map instead of your last saved map, just go to Tools, then Options, and choose Startup to toggle Open ESRI’s default map. If you are working from your own home server, then your home server’s name will replace “ESRI.”

Another option to consider is how you travel from one place to another, for example when you click on a result. The default action is to Fly To the next location, but you may prefer Move To. Move To is the instantaneous way to travel. Rather than liftoff and navigate, you’ll immediately be at your next location. Especially if you want to navigate to the same set of places over and over, Move To is instantaneous.

Go to Tools > Options > Flight Characteristics to toggle this setting.

Tired of answering all those wizard questions when you open local data sources? Using Tools > Options > Open Content Settings you can tell Explorer to use your last preferences, bypassing all those questions.

These are just a few of the ways to change the way Explorer works for you. For more information, visit the Setting application options Help topic.

Posted in Uncategorized | Tagged | Leave a comment

Integrating markers and dashes on cartographic representation line symbols

By Charlie Frye, Esri Chief Cartographer

Example of a thrust fault line symbol where the teeth are aligned to the dashes of the line

Using cartographic representations to make line symbols like those in the image to the right, where markers are displayed in conjunction with a dash pattern, requires more than just casual knowledge of the geometric effects. In fact, to make a line symbol like the one shown to the right, the default settings won’t work. Continue reading

Posted in Mapping | Tagged , | 3 Comments