Mukautetun laajennuksen luominen käyttämään ensisijaista geospatiaalista tietopalvelua
Tässä artikkelissa on tietoja kahdesta geospatiaalisesta toiminnosta Universal Resource Schedulingissa ja mukautetun laajennuksen luomisesta kahdelle geospatiaaliselle toiminnolle. Artikkeli sisältää myös esimerkkejä mukautetusta näytelaajennuksesta käyttämällä Google Mapsin ohjelmointirajapintaa geospatiaalisissa tiedoissa.
Geospatiaalisten toimintojen syöte- ja tulosparametrit
Mukautettua laajennusta kirjoitettaessa geospatiaalisten toimintojen syöte- ja tulosparametrit on otettava huomioon, jotta tiedät, mitä tietoja välitetään sisään ja mitä tulostustietoja odotetaan laajennuskoodissa.
Kahden geospatiaalisen toiminnan syöte- ja tulosparametreja voi tarkastella kahdella tavalla:
- Verkon ohjelmointirajapinnan toiminnon viitesisältö: Universal Resource Schedulingin geospatiaalisten toimintojen viitetietojen tarkasteleminen.
Microsoft.Dynamics.CRM.msdyn_RetrieveDistanceMatrix
- Toiminnon määritelmä: tarkastelemalla Dynamics 365:n toiminnon määritelmää saat tietoja syöte-ja tulosparametreista ja siitä, onko parametri pakollinen vai valinnainen.
Muistiinpano
Tässä artikkelissa/taulukossa mainitut WWW-ohjelmointirajapinnan tyypit ja toiminnot ovat käytettävissä ympäristössäsi, ja voit tutkia näitä tyyppejä ja toimintoja ympäristön palveluasiakirjan tai Postmanin avulla. Lisätietoja: WWW-ohjelmointirajapinnan palveluasiakirjat ja Postmanin käyttäminen Microsoft Dataversen WWW-ohjelmointirajapinnan kanssa.
Voit tarkastella toiminnon määritelmää valitsemalla Asetukset>Prosessit. Etsi seuraavaksi toiminnon nimi: Resurssien aikataulutus – maantieteellisten koordinaattien osoite tai Resurssien aikataulutus – etäisyysmatriisin noutaminen. Valitse sitten ruudukossa toiminto, jolloin sen määritelmä avautuu. Tämä on esimerkiksi Resurssien aikataulutus – maantieteellisten koordinaattien osoite (msdyn_GeocodeAddress) -toiminnon määritelmä, jossa korostettu alue sisältää tietoja syöte- ja tulosparametreista:
Mukautetun laajennuksen kirjoittaminen
Laajennukset ovat mukautettuja luokkia, jotka toteuttavat IPlugin-liittymän. Lisätietoja laajennuksen luomisesta on kohdassa Laajennuskehitys
Viitteenä on mukautettu näytelaajennus, joka näyttää, miten Google Mapsin ohjelmointirajapintaa voi käyttää tuottamaan geospatiaalisia tietoja kenttätoimintoja varten oletusarvoisen Bing Mapsin ohjelmointirajapinnan sijaan. Lisätietoja: Näyte: Mukautettu laajennus Google Maps -ohjelmointirajapinnan käyttämiseen geospatiaalisena tietopalveluna.
Seuraava kummankin näytelaajennuksen koodi käyttää Googlen ohjelmointirajapinnan tietoja:
ExecuteGeocodeAddress-menetelmä msdyn_GeocodeAddress.cs-laajennustiedostossa
public void ExecuteGeocodeAddress(IPluginExecutionContext pluginExecutionContext, IOrganizationService organizationService, ITracingService tracingService)
{
//Contains 5 fields (string) for individual parts of an address
ParameterCollection InputParameters = pluginExecutionContext.InputParameters;
// Contains 2 fields (double) for resultant geolocation
ParameterCollection OutputParameters = pluginExecutionContext.OutputParameters;
//Contains 1 field (int) for status of previous and this plugin
ParameterCollection SharedVariables = pluginExecutionContext.SharedVariables;
tracingService.Trace("ExecuteGeocodeAddress started. InputParameters = {0}, OutputParameters = {1}", InputParameters.Count().ToString(), OutputParameters.Count().ToString());
try
{
// If a plugin earlier in the pipeline has already geocoded successfully, quit
if ((double)OutputParameters[LatitudeKey] != 0d || (double)OutputParameters[LongitudeKey] != 0d) return;
// Get user Lcid if request did not include it
int Lcid = (int)InputParameters[LcidKey];
string _address = string.Empty;
if (Lcid == 0)
{
var userSettingsQuery = new QueryExpression("usersettings");
userSettingsQuery.ColumnSet.AddColumns("uilanguageid", "systemuserid");
userSettingsQuery.Criteria.AddCondition("systemuserid", ConditionOperator.Equal, pluginExecutionContext.InitiatingUserId);
var userSettings = organizationService.RetrieveMultiple(userSettingsQuery);
if (userSettings.Entities.Count > 0)
Lcid = (int)userSettings.Entities[0]["uilanguageid"];
}
// Arrange the address components in a single comma-separated string, according to LCID
_address = GisUtility.FormatInternationalAddress(Lcid,
(string)InputParameters[Address1Key],
(string)InputParameters[PostalCodeKey],
(string)InputParameters[CityKey],
(string)InputParameters[StateKey],
(string)InputParameters[CountryKey]);
// Make Geocoding call to Google API
WebClient client = new WebClient();
var url = $"https://{GoogleConstants.GoogleApiServer}{GoogleConstants.GoogleGeocodePath}/json?address={_address}&key={GoogleConstants.GoogleApiKey}";
tracingService.Trace($"Calling {url}\n");
string response = client.DownloadString(url); // Post ...
tracingService.Trace("Parsing response ...\n");
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(GeocodeResponse)); // Deserialize response json
object objResponse = jsonSerializer.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(response))); // Get response as an object
GeocodeResponse geocodeResponse = objResponse as GeocodeResponse; // Unbox into our data contracted class for response
tracingService.Trace("Response Status = " + geocodeResponse.Status + "\n");
if (geocodeResponse.Status != "OK")
throw new ApplicationException($"Server {GoogleConstants.GoogleApiServer} application error (Status {geocodeResponse.Status}).");
tracingService.Trace("Checking geocodeResponse.Result...\n");
if (geocodeResponse.Results != null)
{
if (geocodeResponse.Results.Count() == 1)
{
tracingService.Trace("Checking geocodeResponse.Result.Geometry.Location...\n");
if (geocodeResponse.Results.First()?.Geometry?.Location != null)
{
tracingService.Trace("Setting Latitude, Longitude in OutputParameters...\n");
// update output parameters
OutputParameters[LatitudeKey] = geocodeResponse.Results.First().Geometry.Location.Lat;
OutputParameters[LongitudeKey] = geocodeResponse.Results.First().Geometry.Location.Lng;
}
else throw new ApplicationException($"Server {GoogleConstants.GoogleApiServer} application error (missing Results[0].Geometry.Location)");
}
else throw new ApplicationException($"Server {GoogleConstants.GoogleApiServer} application error (more than 1 result returned)");
}
else throw new ApplicationException($"Server {GoogleConstants.GoogleApiServer} application error (missing Results)");
}
catch (Exception ex)
{
// Signal to subsequent plugins in this message pipeline that geocoding failed here.
OutputParameters[LatitudeKey] = 0d;
OutputParameters[LongitudeKey] = 0d;
//TODO: You may need to decide which caught exceptions will rethrow and which ones will simply signal geocoding did not complete.
throw new InvalidPluginExecutionException(string.Format("Geocoding failed at {0} with exception -- {1}: {2}"
, GoogleConstants.GoogleApiServer, ex.GetType().ToString(), ex.Message), ex);
}
}
ExecuteDistanceMatrix-menetelmä msdyn_RetrieveDistanceMatrix.cs-laajennustiedostossa
public void ExecuteDistanceMatrix(IPluginExecutionContext pluginExecutionContext, IOrganizationService organizationService, ITracingService tracingService)
{
//Contains 2 fields (EntityCollection) for sources and targets
ParameterCollection InputParameters = pluginExecutionContext.InputParameters;
// Contains 1 field (EntityCollection) for results
ParameterCollection OutputParameters = pluginExecutionContext.OutputParameters;
//Contains 1 field (int) for status of previous and this plugin
ParameterCollection SharedVariables = pluginExecutionContext.SharedVariables;
tracingService.Trace("ExecuteDistanceMatrix started. InputParameters = {0},OutputParameters = {1}", InputParameters.Count().ToString(), OutputParameters.Count().ToString());
try
{
// If a plugin earlier in the pipeline has already retrieved a distance matrix successfully, quit
if (OutputParameters[MatrixKey] != null)
if (((EntityCollection)OutputParameters[MatrixKey]).Entities != null)
if (((EntityCollection)OutputParameters[MatrixKey]).Entities.Count > 0) return;
// Make Distance Matrix call to Google API
WebClient client = new WebClient();
var url = String.Format($"https://{GoogleConstants.GoogleApiServer}{GoogleConstants.GoogleDistanceMatrixPath}/json"
+ "?units=imperial"
+ $"&origins={string.Join("|", ((EntityCollection)InputParameters[SourcesKey]).Entities.Select(e => e.GetAttributeValue<double?>("latitude") + "," + e.GetAttributeValue<double?>("longitude")))}"
+ $"&destinations={string.Join("|", ((EntityCollection)InputParameters[TargetsKey]).Entities.Select(e => e.GetAttributeValue<double?>("latitude") + "," + e.GetAttributeValue<double?>("longitude")))}"
+ $"&key={GoogleConstants.GoogleApiKey}");
tracingService.Trace($"Calling {url}\n");
string response = client.DownloadString(url); // Post ...
tracingService.Trace("Parsing response ...\n");
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(DistanceMatrixResponse)); // Deserialize response json
object objResponse = jsonSerializer.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(response))); // Get response as an object
DistanceMatrixResponse distancematrixResponse = objResponse as DistanceMatrixResponse; // Unbox as our data contracted class for response
tracingService.Trace("Response Status = " + distancematrixResponse.Status + "\n");
if (distancematrixResponse.Status != "OK")
throw new ApplicationException($"Server {GoogleConstants.GoogleApiServer} application error (Status={distancematrixResponse.Status}). {distancematrixResponse.ErrorMessage}");
tracingService.Trace("Checking distancematrixResponse.Results...\n");
if (distancematrixResponse.Rows != null)
{
tracingService.Trace("Parsing distancematrixResponse.Results.Elements...\n");
// build and update output parameter
var result = new EntityCollection();
result.Entities.AddRange(distancematrixResponse.Rows.Select(r => ToEntity(r.Columns.Select(c => ToEntity(c.Status, c.Duration, c.Distance)).ToArray())));
OutputParameters[MatrixKey] = result;
}
else throw new ApplicationException($"Server {GoogleConstants.GoogleApiServer} application error (missing Rows)");
}
catch (Exception ex)
{
// Signal to subsequent plugins in this message pipeline that retrieval of distance matrix failed here.
OutputParameters[MatrixKey] = null;
//TODO: You may need to decide which caught exceptions will rethrow and which ones will simply signal geocoding did not complete.
throw new InvalidPluginExecutionException(string.Format("Geocoding failed at {0} with exception -- {1}: {2}"
, GoogleConstants.GoogleApiServer, ex.GetType().ToString(), ex.Message), ex);
}
// For debugging purposes, throw an exception to see the details of the parameters
CreateExceptionWithDetails("Debugging...", InputParameters, OutputParameters, SharedVariables);
}
Kun olet kirjoittanut mukautetun laajennuskoodin, muodosta projekti laajennuskokoonpanon (.dll) luontia varten, sillä tarvitse sitä laajennuksen rekisteröimiseen Universal Resource Schedulingin geospatiaalisiin toimintoihin.