แชร์ผ่าน


สร้างปลั๊กอินแบบกำหนดเองที่จะใช้ตัวให้บริการข้อมูล geospatial ที่ต้องการของคุณ

บทความนี้แสดงข้อมูลเกี่ยวกับการดำเนินการเชิงพื้นที่สองรายการใน Universal Resource Scheduling วิธีการสร้างปลั๊กอินสำหรับการดำเนินการเชิงพื้นที่สองรายการ และแสดงตัวอย่างจากปลั๊กอินแบบกำหนดเองที่เป็นตัวอย่างโดยใช้ Google Maps API สำหรับข้อมูลเชิงพื้นที่

พารามิเตอร์อินพุทและเอาท์พุทสำหรับการดำเนินการ geospatial

ในขณะที่กำลังเขียนปลั๊กอินแบบกำหนดเองของคุณ คุณจะต้องคำนึงถึงพารามิเตอร์อินพุทและเอาท์พุทสำหรับการดำเนินการ geospatial เพื่อให้คุณทราบว่าข้อมูลใดที่จะส่งผ่าน และข้อมูลผลลัพธ์ที่คาดไว้ในโค้ดปลั๊กอินของคุณ

มีสองวิธีที่คุณสามารถดูพารามิเตอร์อินพุทและเอาท์พุทสำหรับการดำเนินการที่ geospatial สองรายการ:

  • เนื้อหาการอ้างอิงของการดำเนินการ Web API: ดูข้อมูลอ้างอิงเกี่ยวกับการดำเนินการ geospatial ใน Universal Resource Scheduling
    • Microsoft.Dynamics.CRM.msdyn_RetrieveDistanceMatrix
  • ข้อกำหนดของการดำเนินการ: คุณสามารถดูข้อกำหนดของการดำเนินการได้ใน Dynamics 365 สำหรับข้อมูลเกี่ยวกับพารามิเตอร์ข้อมูลป้อนเข้า/ผลผลิต ซึ่งรวมถึงข้อมูลที่ว่าพารามิเตอร์จำเป็นหรือไม่จำเป็น

หมายเหตุ

ชนิดและการทำงานของ Web API ที่กล่าวถึงในบทความ/ตารางนี้มีอยู่ในสภาพแวดล้อมของคุณ และคุณสามารถใช้เอกสารการบริการของสภาพแวดล้อมของคุณหรือ Postman เพื่อสำรวจชนิดและการดำเนินการเหล่านี้ ข้อมูลเพิ่มเติม: เอกสารบริการ Web API และ ใช้ Postman กับ Microsoft Dataverse Web API

เมื่อต้องการดูข้อกำหนดของการดำเนินการ เลือก การตั้งค่า>กระบวนการ ถัดไป ค้นหาชื่อการดำเนินการ: การจัดกำหนดการทรัพยากร - ที่อยู่พิกัดทางภูมิศาสตร์ หรือ การจัดกำหนดการทรัพยากร - เรียกเมทริกซ์ระยะห่าง แล้วจากนั้น เลือกการดำเนินการในกริดที่จะแสดงคำนิยาม ตัวอย่างเช่น ต่อไปนี้เป็นคำนิยามของการดำเนินการ การจัดกำหนดการทรัพยากร - ที่อยู่พิกัดทางภูมิศาสตร์ (msdyn_GeocodeAddress) ที่ซึ่งพื้นที่ที่เน้นแสดงข้อมูลเกี่ยวกับพารามิเตอร์อินพุทและเอาท์พุท:

Action definition.

เขียนปลั๊กอินแบบกำหนดเองของคุณ

ปลั๊กอินเป็นคลาสที่กำหนดเองที่นำอินเทอร์เฟซ IPlugin ไปใช้ สำหรับข้อมูลโดยละเอียดเกี่ยวกับการสร้างปลั๊กอิน ดู การพัฒนาปลั๊กอิน

ตัวอย่างปลั๊กอินแบบกำหนดเองมีไว้ให้สำหรับการอ้างอิงของคุณที่สาธิตวิธีการใช้ Google Maps API เพื่อให้ข้อมูล geospatial สำหรับการดำเนินงานของฟิลด์ แทนที่จะเป็น Bing Maps API ค่าเริ่มต้น ข้อมูลเพิ่มเติม: ตัวอย่าง: ปลั๊กอินแบบกำหนดเองจะใช้ Google Maps API เป็นผู้ให้บริการข้อมูล geospatial

รหัสต่อไปนี้ในปลั๊กอินตัวอย่างแต่ละรายการใช้ข้อมูลจาก Google API:

วิธีการ ExecuteGeocodeAddress ในไฟล์ปลั๊กอิน msdyn_GeocodeAddress.cs

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 ในไฟล์ปลั๊กอิน msdyn_RetrieveDistanceMatrix.cs

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);
}

หลังจากที่คุณได้เขียนโค้ดปลั๊กอินแบบกำหนดเองของคุณ สร้างโครงการที่จะสร้างแอสเซมบลีปลั๊กอิน (.dll) ซึ่งจะถูกใช้เพื่อลงทะเบียนปลั๊กอินในการดำเนินการ geospatial ของ Universal Resource Scheduling ด้วย