Legend problems with secured services when migrating to 3.0/3.1

1630
6
Jump to solution
08-24-2012 04:41 AM
BenFousek
Occasional Contributor III
I add dynamic and feature layers when the application loads by iterating through an object literal like such:
var config = {     token: SOME_TOKEN,     layers: [         {             type: 'dynamic',             url: 'http://MY_URL/ArcGIS/rest/services/Slope/MapServer',             token: true,             name: 'Slope',             id: 'slope',             visible: false,             opacity: 0.5,             imageFormat: 'png32',             dpi: 96,             legend: true,             parcelLabelControl: false,             subLayerControl: false,             info: true,             infoHtml: 'This layer displays slopes.'         },         {             type: 'feature',             url: 'http://MY_URL/ArcGIS/rest/services/Fire_Hydrants/MapServer/0',             token: true,             name: 'Fire Hydrants',             id: 'firehydrants',             visible: false,             opacity: 1,             imageFormat: 'png32',             dpi: 96,             legend: true,             itTitle: 'Fire Hydrant',             itContentType: 'function',             itContentText: '',             itContentFunction: 'config.featureFunctions.hydrants.infoTemplate'         }     ] }

If a token is required it's added to the url when the layer object is created. Layers are pushed to the legend when legend is set to true. Through 2.8 this worked fine, but not in 3.0+. I did some digging and discovered that in 2.8 the legend widget makes calls to the map service's legend REST like so:
http://MY_URL/ArcGIS/rest/services/Slope/MapServer/legend?token=SOME_TOKEN&f=json&callback=dojo.io.script.jsonp_dojoIoScript23._jsonpCallback

In 3.0+ the call is:
http://MY_URL/ArcGIS/rest/services/Slope/MapServer/legend?token=SOME_TOKEN?token=SOME_TOKEN&f=json&callback=dojo.io.script.jsonp_dojoIoScript23._jsonpCallback

Notice the token query string is represented twice with two ?. AGS returns a 'invalid token' error. Seems to me there's an error forming the url for the legend REST call. Perhaps getting the service's base url from SOME_LAYER.url instead of SOME_LAYER._url.path.

Any help would be appreciated as this is a roadblock as I migrate to 3.0+. Thanks.
0 Kudos
1 Solution

Accepted Solutions
BenFousek
Occasional Contributor III
app.map.addLayer(layer);  layer.url = l.url;  if (l.legend == true) {     app.mapParams.legendLayers.push({         layer: layer,         title: l.name     }) }


I add the layer to the map; then set the LAYER.url string back to the token free url; finally push the layer to the legend. This doesn't affect the layer's ability to retrieve images for the map because those request urls use the LAYER._getToken() function to add the token as a content pair for future requests.

View solution in original post

0 Kudos
6 Replies
JeffPace
MVP Alum
Can you post your legend creation code? Are you manually appending the token?
0 Kudos
BenFousek
Occasional Contributor III
Here's the pertinent parts of function that adds a dynamic layer. Same concept for feature layers.

var url;
if (l.token == true) {
    url = l.url + '?token=' + config.token
} else {
    url = l.url
}
var layer = new esri.layers.ArcGISDynamicMapServiceLayer(url, {
    id: l.id,
    visible: l.visible,
    opacity: l.opacity
});
layer.setImageFormat(l.imageFormat);
layer.setDPI(l.dpi);

if (l.legend == true) {
    app.mapParams.legendLayers.push({
        layer: layer,
        title: l.name
    })
}
app.map.addLayer(layer);


As you can see I'm manually appending the token. When the page loads the first javascript file is php that returns "var token = THE_TOKEN;" based on the referrer or I include the token in my config object as above. It's a little archaic, but that's how I've done it since the beginning. I can see where this going; probably time to get acquainted with IdentityManagerBase.
0 Kudos
JeffPace
MVP Alum
Here's the pertinent parts of function that adds a dynamic layer. Same concept for feature layers.

var url;
if (l.token == true) {
    url = l.url + '?token=' + config.token
} else {
    url = l.url
}
var layer = new esri.layers.ArcGISDynamicMapServiceLayer(url, {
    id: l.id,
    visible: l.visible,
    opacity: l.opacity
});
layer.setImageFormat(l.imageFormat);
layer.setDPI(l.dpi);

if (l.legend == true) {
    app.mapParams.legendLayers.push({
        layer: layer,
        title: l.name
    })
}
app.map.addLayer(layer);


As you can see I'm manually appending the token. When the page loads the first javascript file is php that returns "var token = THE_TOKEN;" based on the referrer or I include the token in my config object as above. It's a little archaic, but that's how I've done it since the beginning. I can see where this going; probably time to get acquainted with IdentityManagerBase.



yes, however in the short term,

on your

if (l.token == true) {

you could just change it to check and see if a token is already in the url.

since there is no indexof for string in dojo (grr)

function oc(a){
 var o = {};
            for(var i=0;i<a.length;i++)
            {
                o[a]='';
            }
            return o;
}


if (l.token == true && "token=" in oc(l.url))
0 Kudos
BenFousek
Occasional Contributor III
I figured it out. When adding a dynamic layer to the legend the code in 2.8 doesn't check to see if the LAYER.url string has a token, nor does it run LAYER._getToken(). It assumes that if it is a valid secured service a token will be present. In 3.0 a small change was made, which runs LAYER._getToken() and if it returns true it adds a token querystring to the url. The problem is, it doesn't check to see if a token querystring is already present in the url and adds another regardless. The result is a failed request. This was a small oversight on the recode. This could easily be fixed in a local API install, but the JSAPI Team needs to look at this. I assume they look through the forum for this kind of thing. I'll repost for them if they don't acknowledge this in a day or two. Thanks in advance guys. Keep up the good work! Thanks for your input too Jeff.

Here's v2.8
_legendRequestServer: function(_27) {
    var url = _27.url;
    var pos = url.indexOf("?");
    if (pos > -1) {
        url = url.substring(0, pos) + "/legend" + url.substring(pos);
    } else {
        url += "/legend";
    }
    var _28 = _4.hitch(this, "_processLegendResponse");
    var _29 = {};
    _29.f = "json";
    if (_27._params.dynamicLayers) {
        _29.dynamicLayers = _27._params.dynamicLayers;
        if (_29.dynamicLayers === "[{}]") {
            _29.dynamicLayers = "[]";
        }
    }
    var _2a = esri.request({
        url: url,
        content: _29,
        callbackParamName: "callback",
        load: function(_2b, _2c) {
            _28(_27, _2b, _2c);
        },
        error: esriConfig.defaults.io.errorHandler
    });
    return _2a;
}


and 3.0+
_legendRequestServer: function(_24) {
    var url = _24.url;
    var pos = url.indexOf("?");
    if (pos > -1) {
        url = url.substring(0, pos) + "/legend" + url.substring(pos);
    } else {
        url += "/legend";
    }
    var _25 = _24._getToken();
    if (_25) {
        url += "?token=" + _25;
    }
    var _26 = _2.hitch(this, "_processLegendResponse");
    var _27 = {};
    _27.f = "json";
    if (_24._params.dynamicLayers) {
        _27.dynamicLayers = _24._params.dynamicLayers;
        if (_27.dynamicLayers === "[{}]") {
            _27.dynamicLayers = "[]";
        }
    }
    var _28 = esri.request({
        url: url,
        content: _27,
        callbackParamName: "callback",
        load: function(_29, _2a) {
            _26(_24, _29, _2a);
        },
        error: esriConfig.defaults.io.errorHandler
    });
    return _28;
}
0 Kudos
BenFousek
Occasional Contributor III
app.map.addLayer(layer);  layer.url = l.url;  if (l.legend == true) {     app.mapParams.legendLayers.push({         layer: layer,         title: l.name     }) }


I add the layer to the map; then set the LAYER.url string back to the token free url; finally push the layer to the legend. This doesn't affect the layer's ability to retrieve images for the map because those request urls use the LAYER._getToken() function to add the token as a content pair for future requests.
0 Kudos
JoepRonde
New Contributor

Ben, your solution works partially.

I remove the token from the layer url after I've added the layers to the map.

this.map.addLayers(layers);
array.forEach(layers, function (l) {
    l.url = l.url.split('?token')[0];
 }, this);

The layer gets added to the map and loads image request succesfully. The legend also works fine, but identifying on a layers fails. The identify request doesn't contain a token anymore after I removed the token from the layer.url. It seems that an identify request doesn't add the token as a legend request does.

Do you have a solution for this as well?

Regards,

Joep Ronde

0 Kudos