I've created an Add-In to ArcGIS Pro to facilitate importing and publishing a web map. I have a map package that I'm importing. I need to change the data source in the map to a hosted feature service in ArcGIS Online. In the Add-In code, I have this method:
private static void ResetFeatureServiceDataConnection(Layer dataConnectionLayer, string newConnectionString)
{
CIMStandardDataConnection dataConnection = dataConnectionLayer.GetDataConnection() as CIMStandardDataConnection;
dataConnection.WorkspaceConnectionString = newConnectionString;
dataConnectionLayer.SetDataConnection(dataConnection);
}
The parameters to this method are a map layer and the URL for the hosted feature service. This method changes the data source in the layer, but it doesn't change the ItemID.The ItemID is referencing the original data source (from the map package I imported). When I publish the map, the datasource is based on the ItemID, not the Url that I've set in the code.
I've tried changing the data source from the Layer Properties in ArcGIS Pro. When I click the Set Data Source button and select the layer in my hosted feature service, the URL changes, but not the ItemID.
Is there a way to change the Item ID to match the ItemID of the hosted feature service?
Solved! Go to Solution.
It turns out that the ItemID is stored in the layer's underlying Cartographic Information Model (CIM). More specifically the ItemID value is stored in the SourceURI property of the CIMFeatureLayer class. The SourceURI property is only populated when the layer is first added to a map, but the property is not updated when the data connection is changed. To update the SourceURI you can use the following pattern (from within QueuedTask.Run):
var dcLyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
QueuedTask.Run(() =>
{
if (!(dcLyr.GetDataConnection() is CIMStandardDataConnection dc))
{
MessageBox.Show("Layer doesn't have CIMStandardDataConnection");
return;
}
// make changes to the data connection
dcLyr.SetDataConnection(dc);
// update SourceURI
var lyrDef = dcLyr.GetDefinition();
lyrDef.SourceURI = string.Empty;
dcLyr.SetDefinition(lyrDef);
});
In the snippet above the SourceURI is cleared, but it can also be replaced with the ItemID matching the new data connection.
I have a web map with two feature layers. The first layer in my Map references the first feature layer of my web map. Below is the code for a button's 'OnClick' method, that changes the data connection for this first layer from a feature service ID of '0' to '1' and vice versa. Not sure if this is what you need:
protected override void OnClick()
{
try
{
var dcLyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
if (dcLyr == null)
{
MessageBox.Show("No Layer found");
return;
}
QueuedTask.Run(() =>
{
CIMStandardDataConnection dc = dcLyr.GetDataConnection() as CIMStandardDataConnection;
if (dc == null)
{
MessageBox.Show("Layer doesn't have CIMStandardDataConnection");
return;
}
if (dc.Dataset == "0")
dc.Dataset = "1";
else
dc.Dataset = "0";
dcLyr.SetDataConnection(dc);
});
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Thanks for the reply but I'm trying to change the ItemID for every layer in the map to the correct hosted feature service. I can change the URL, but I need to change the ItemID to the hosted feature service. The datasource is based on the ItemID, not the URL.
To change the URL to the hosted feature service you have to change the Url, to change the ID you have to change the Dataset property as shown in the sample below. When you say you have to change the 'ItemID' to the hosted feature service do you mean the ID? As shown here:
If so then, my sample applies to your question. in the sample I change this (note that the ID is shown under the Name line item):
To this:
In this sample snippet the datasource for the layer is changed from FeatureSerive to MapService and vice versa, and in addition the ID is also changed from '0' to '2' and vice versa.
protected override void OnClick()
{
try
{
var dcLyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
if (dcLyr == null)
{
MessageBox.Show("No Layer found");
return;
}
QueuedTask.Run(() =>
{
if (!(dcLyr.GetDataConnection() is CIMStandardDataConnection dc))
{
MessageBox.Show("Layer doesn't have CIMStandardDataConnection");
return;
}
if (dc.WorkspaceConnectionString.Contains(@"/FeatureServer"))
dc.WorkspaceConnectionString = dc.WorkspaceConnectionString.Replace(@"/FeatureServer", @"/MapServer");
else
dc.WorkspaceConnectionString = dc.WorkspaceConnectionString.Replace(@"/MapServer", @"/FeatureServer");
if (dc.Dataset == "0")
dc.Dataset = "2";
else
dc.Dataset = "0";
dcLyr.SetDataConnection(dc);
});
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I am not trying to change the ID of the layer. I am trying to change the itemId -- which is the reference to the hosted feature service. I've changed the data source as you've indicated above, but that does not change the itemId. Using ArcGIS Online Assistant, I can see the ItemID is "330dbdc986f34ebd884b42171ff165ae". This is not the ID for the feature service 'SeabrookeFieldSeeker' as you can see from the second image. This is causing the map layers to reference a hosted feature service that is not the one in the URL.
My bad, I guess I overlooked the 'ArcGIS Online' part. The actual 'Feature Service' is hosted on ArcGIS Server referenced the the "url" attribute of the "operationallayer" json from your previous reply. I only looked at the ArcGIS Server datassource, not a Portal (ArcGIS Online) connection. I will try a Portal datasource now and let you know what i find.
It turns out that the ItemID is stored in the layer's underlying Cartographic Information Model (CIM). More specifically the ItemID value is stored in the SourceURI property of the CIMFeatureLayer class. The SourceURI property is only populated when the layer is first added to a map, but the property is not updated when the data connection is changed. To update the SourceURI you can use the following pattern (from within QueuedTask.Run):
var dcLyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
QueuedTask.Run(() =>
{
if (!(dcLyr.GetDataConnection() is CIMStandardDataConnection dc))
{
MessageBox.Show("Layer doesn't have CIMStandardDataConnection");
return;
}
// make changes to the data connection
dcLyr.SetDataConnection(dc);
// update SourceURI
var lyrDef = dcLyr.GetDefinition();
lyrDef.SourceURI = string.Empty;
dcLyr.SetDefinition(lyrDef);
});
In the snippet above the SourceURI is cleared, but it can also be replaced with the ItemID matching the new data connection.
Wolf, thank you. That was exactly what I needed.