I was looking through the documentation and I was having trouble finding a good example of how to add features through the API to my Workforce assignments. I figured I would put up a post up on how I was able to do get it to work.
Note: I use googles API to return Lat/Long from Addresses. This comes back in WKID 4326 and the hosted service is in Spatial Reference: 102100 or WKID 3857 so I had to convert these coordinates to import.
I found an error in the documentation when I was looking through this doc @ https://doc.arcgis.com/en/workforce/android-phone/help/workforce-schema.htm
SHAPE | The point location of the assignment. | An x,y coordinate pair. |
This is incorrect, you need to have a geometry field instead of SHAPE.
Libraries used
Esri.ArcGISRuntime v200.3.0
Newtonsoft.Json v13.0.3
RestSharp v110.2.0
Code to Convert 4326 to 3857
//Convert EPSG:4326 WGS 84 to EPSG:3857 WGS 84 / Pseudo-Mercator
private double[] ConvertTo3857(double[] coords)
{
double smRadius = 6378136.98;
double smRange = smRadius * Math.PI * 2.0;
double smLonToX = smRange / 360.0;
double smRadiansOverDegrees = Math.PI / 180.0;
double[] newCoords = new double[2];
newCoords[0] = coords[0];
newCoords[1] = coords[1];
newCoords[0] *= smLonToX;
double y = newCoords[1];
if (y > 86.0)
{
newCoords[1] = smRange;
}
else if (y < -86.0)
{
newCoords[1] = -smRange;
}
else
{
y *= smRadiansOverDegrees;
y = Math.Log(Math.Tan(y) + (1.0 / Math.Cos(y)), Math.E);
newCoords[1] = y * smRadius;
}
return newCoords;
}
This is the class to great the object that is then converted to JSON with Newtonsoft.Json. This will have to be bracketed with [ ] once converted to string to import.
public class Assignments
{
public Attributes attributes { get; set; }
public AttributeGeometry geometry { get; set; }
}
public class Attributes
{
public string description { get; set; }
public int priority { get; set; }
public string assignmenttype { get; set; }
public string workorderid { get; set; }
public long duedate { get; set; }
public string location { get; set; }
public string dispatcherid { get; set; }
public int status { get; set; }
}
public class AttributeGeometry
{
public double x { get; set; }
public double y { get; set; }
}
This class holds the result from importing and will give you the objectID if you need it for further in your code.
public class AddFeaturesResult
{
public Addresult[] addResults { get; set; }
}
public class Addresult
{
public bool success { get; set; }
public string globalId { get; set; }
public int objectId { get; set; }
}
This is calls the portal. I pass in the Service name and the completed JSON String that will be inserted. responseObject has the response.
public async Task UpdateCSUAssignments(string service, string assignment)
{
string ServiceUrl = @"https://enterpriseUrl/server/rest/services/Hosted/" + service + @"/FeatureServer/0/addFeatures"; //Layer 0
// generate an ArcGISTokenCredential using input from the user (username and password)
var cred = await Esri.ArcGISRuntime.Security.AuthenticationManager.Current.GenerateCredentialAsync(
new Uri("https://enterpriseUrl/portal/sharing/rest/generateToken"),
"name",
"password") as ArcGISTokenCredential;
//Build POST request
var client = new RestClient(ServiceUrl);
var request = new RestRequest(ServiceUrl, Method.Post);
//Add Parameters
request.AddParameter("token",cred.Token);
request.AddParameter("f", "json");
request.AddParameter("features", assignment);
request.AddParameter("rollbackOnFailure", "false");
//Execute Request
var response = client.Execute(request);
var responseObject = JsonConvert.DeserializeObject<AddFeaturesResult>(response.Content);
return;
}
//Create Assignment object to hold everything
Assignments assignments = new Assignments();
//Create Attributes object
Attributes attributes = new Attributes();
attributes.status = 0;
attributes.assignmenttype = "{34AA8F52-B5A7-4DF9-9F77-169283027D14}";
attributes.location = "Full Address to import";
attributes.dispatcherid = "{AD2B0E54-FA3A-47AE-B639-95A766752E1D}";
attributes.description = "This is a test";
attributes.priority = 1;
attributes.workorderid = "ID that you want tied to Assignment";
attributes.duedate = 1711980000000; //Date that has to be in UTC format
//Create Geometry object in WKID 3857
AttributeGeometry geometry = new AttributeGeometry();
geometry.x = -10072068.9623985;
geometry.y = 4640672.87246465;
//assign attribute object to the assignment object
assignments.attributes = attributes;
//assign geometry to assignment object
assignments.geometry = geometry;
//convert object to JSON string
var json = JsonConvert.SerializeObject(assignments);
//add brackets for importation
json = "[" + json + "]";
//PortalCode is the class that contains all my API calls.
PortalCode portal = new PortalCode();
//call update assignments method
var t = System.Threading.Tasks.Task.Run(async () => { await portal.UpdateCSUAssignments("This is your hosted service ID.", json); });
t.Wait();
I hope this helps, I am sure if you change your class objects for other feature services you can use the same code to add features to your services!
I wanted to thank you for posting this particular sample. It saved me a bunch of time!