I am connection to a Map Service that requires a token and this code works to get the list of layers (where url is something like http://myhost/arcgis/rest/services/MapServer?token=abcdefg😞
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(url + "&f=pjson");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client.GetAsync("").Result;
}
I then want to go through each layer and add it as a feature layer to a map (where layerUrl looks like http://myhost/arcgis/rest/services/MapServer/5?token=abcdefg)
Uri serviceUri = new Uri(layerUrl);
FeatureLayer layer = new FeatureLayer(serviceUri);
await layer.LoadAsync();
Map.OperationalLayers.Add(layer);
This does not seem to be working. I am getting no errors, but the layer is also showing no features. Is it obvious what I am doing wrong?
Solved! Go to Solution.
The recommended way to authenticate is to generate tokens using the AuthenticationManager as done above. But if you already have a token, you can add it to the outgoing request by doing something like this
ArcGISHttpClientHandler.HttpRequestBegin += (a, b) =>
{
if (b.RequestUri.OriginalString.Contains(mapserverUrl))
{
b.RequestUri = new Uri(b.RequestUri + "token=abcdefg");
}
//OR try adding the token as part of the header
if (b.RequestUri.OriginalString.Contains(mapserverUrl))
{
b.Headers.Add("X-Esri-Authorization", "My Custom Header");
}
};
ArcGISHttpClientHandler.HttpResponseEnd += (a, b) =>
{
// Check for response codes here
};
If you use the authentication code mentioned in my previous reply then every time a request is made to the requestUri, the Clienthandler will kick in and add the token/authorization header to the outgoing request.
Hello,
Is this a custom token parameter that is specific to your environment?
No, this would be a security token created for a 'secure' map service. I am actually simulating the existence of this token parameter (this is a customer environment I do not have access to) by putting '?blah=blah' at the end of the REST url.
Do you have the credentials for the user's ArcGIS Server (username and password)?
If yes, then you can try using the following code to generate tokens
MyView1.Map = new Map(Basemap.CreateImagery());
Esri.ArcGISRuntime.Security.AuthenticationManager.Current.ChallengeHandler = new ChallengeHandler(
async info => await Esri.ArcGISRuntime.Security.AuthenticationManager.Current.GenerateCredentialAsync
(info.ServiceUri,
"username",
"password", info.GenerateTokenOptions));
var featureURL = "http://myhost/arcgis/rest/services/MapServer/5";
var layer = new FeatureLayer(new Uri(wms));
await layer.LoadAsync();
MyView1.Map.OperationalLayers.Add(layer);
I do not have a username/password (which is why I am using a generated token).
The recommended way to authenticate is to generate tokens using the AuthenticationManager as done above. But if you already have a token, you can add it to the outgoing request by doing something like this
ArcGISHttpClientHandler.HttpRequestBegin += (a, b) =>
{
if (b.RequestUri.OriginalString.Contains(mapserverUrl))
{
b.RequestUri = new Uri(b.RequestUri + "token=abcdefg");
}
//OR try adding the token as part of the header
if (b.RequestUri.OriginalString.Contains(mapserverUrl))
{
b.Headers.Add("X-Esri-Authorization", "My Custom Header");
}
};
ArcGISHttpClientHandler.HttpResponseEnd += (a, b) =>
{
// Check for response codes here
};
Thanks this is how I've done !
Just using an UriBuilder to not mess with other get parameters.
var uriBuilder = new UriBuilder(b.RequestUri.AbsoluteUri);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
//apply token
query["token"] = "<add your token here>";
uriBuilder.Query = query.ToString();
//update uri
b.RequestUri = uriBuilder.Uri;
Checking the layerViewState for errors is a good way to debug your code. The spatial reference of the features and that of the map should be the same for the features to be displayed on the map. Also, if you want to parse the MapServer to get the layer ids, you can try doing something like this (using ServiceGeoDatabase instead)
var sgdb = new ServiceGeodatabase(new Uri(mapserverUrl));
await sgdb.LoadAsync();
var map = new Map(Basemap.CreateTopographic());
MyMapView.LayerViewStateChanged += (a, b) =>
{
var error = b.LayerViewState.Error ?? b.Layer.LoadError;
if (error != null)
MessageBox.Show(error.Message, error.GetType().Name);
};
MyMapView.Map = map;
foreach(var info in sgdb.ServiceInfo.LayerInfos)
{
var layer = new FeatureLayer(new Uri($"{mapserverUrl}/{info.Id}"));
await layer.LoadAsync();
map.OperationalLayers.Add(layer);
}
In this code snippet, how are you giving the FeatureLayer the security token (line 17)?
If you use the authentication code mentioned in my previous reply then every time a request is made to the requestUri, the Clienthandler will kick in and add the token/authorization header to the outgoing request.