Lan egin soluzioekin erabilita Dataverse SDK

Bizi-zikloaren garapenaren zati gisa, zenbait zeregin kudeatzeko automatizazio pertsonalizatua sortu nahi duzu. Adibidez, zure DevOps proiektuaren bideratzean, agian sandbox ingurunea sortzen duten kode pertsonalizatu edo script batzuk exekutatu nahi dituzu, kudeatu gabeko soluzio bat inportatu, kudeatu gabeko soluzio hori kudeatutako soluzio gisa esportatzen du eta, azkenik, ingurunea ezabatzen du. Zure eskura dauden APIak erabiliz gero eta gehiago egin dezakezu. Azpian adibide batzuk daude zer egin dezakezun erabilita Dataverse SDK hurrengorako .NET eta pertsonalizatutako kodea.

Oharra

Webaren APIa erabiliz eragiketa berak ere egin ditzakezu. Honi lotutako ekintzak hauek dira: ImportSolution, ExportSolution, CloneAsPatch eta CloneAsSolution.

Sortu, esportatu edo inportatu kudeatu gabeko soluzio bat

Ikus dezagun soluzioaren ohiko eragiketa batzuk C# kodea erabiliz. Soluzio mota hauek (eta gehiago) erakusten dituzten C# kodearen lagina osatzeko ikusteko, ikus Lagina: soluzioekin lan egin.

Sortu argitaratzaile bat

Soluzio bakoitzak argitaratzailea behar dute, ordezkatua Argitaratzailearen entitatea. Argitaratzaile batek hau eskatzen du:

  • Pertsonalizazio-aurrizkia
  • Izen esklusiboa
  • Izen adierazgarria

Oharra

ALM ikuspegi osasuntsu baterako, erabili beti argitaratzaile eta soluzio pertsonalizatuak, eta ez soluzio eta argitaratzaile lehenetsiak, zure pertsonalizazioak ezartzeko.

Hurrengo kode laginak lehenik argitaratzaile bat definitzen du eta, ondoren, argitaratzailea izen bakarra oinarritzat hartuta dagoeneko egiaztatzen du. Lehendik badago, pertsonalizazio aurrizkia aldatu egin liteke, beraz, lagin honek uneko pertsonalizazio aurrizkia harrapatu nahi du. PublisherId ere kapturatzen eta horrela argitaratzailearen erregistroa ezaba daiteke. Argitaratzailea ez bada aurkitzen, argitaratzaile berria sortuko da erabiliz IOrganizationService.Sortu metodoa.

// Define a new publisher
Publisher _myPublisher = new Publisher
{
   UniqueName = "contoso-publisher",
   FriendlyName = "Contoso publisher",
   SupportingWebsiteUrl =
      "https://learn.microsoft.com/powerapps/developer/data-platform/overview",
   CustomizationPrefix = "contoso",
   EMailAddress = "someone@contoso.com",
   Description = "This publisher was created from sample code"
};

// Does the publisher already exist?
QueryExpression querySamplePublisher = new QueryExpression
{
   EntityName = Publisher.EntityLogicalName,
   ColumnSet = new ColumnSet("publisherid", "customizationprefix"),
   Criteria = new FilterExpression()
};

querySamplePublisher.Criteria.AddCondition("uniquename", ConditionOperator.Equal,
   _myPublisher.UniqueName);

EntityCollection querySamplePublisherResults =
   _serviceProxy.RetrieveMultiple(querySamplePublisher);

Publisher SamplePublisherResults = null;

// If the publisher already exists, use it
if (querySamplePublisherResults.Entities.Count > 0)
{
   SamplePublisherResults = (Publisher)querySamplePublisherResults.Entities[0];
   _publisherId = (Guid)SamplePublisherResults.PublisherId;
   _customizationPrefix = SamplePublisherResults.CustomizationPrefix;
}

// If the publisher doesn't exist, create it
if (SamplePublisherResults == null)
{
   _publisherId = _serviceProxy.Create(_myPublisher);

   Console.WriteLine(String.Format("Created publisher: {0}.",
   _myPublisher.FriendlyName));

   _customizationPrefix = _myPublisher.CustomizationPrefix;
}

Kudeatu gabeko soluzioak sortu

Argitaratzaile pertsonalizatu bat eskuragarri eduki ondoren, kudeatu gabeko soluzio bat sor dezakezu. Hurrengo taulan, soluzio bat duten deskribapenak dituzten eremuak agertzen dira.

Eremuaren etiketa Azalpena
Bistaratze-izena Soluzioaren izena.
Izena Microsoft Dataverse izen bakarra sortzen du Bistaratzeko izena oinarritzat hartuta. Izen esklusiboa edita dezakezu. Izen esklusiboak karaktere alfanumerikoak edo beheko marra izan ditzake soilik.
Argitaratzailea Erabili Argitaratzaile bilaketa lotu soluzioa argitaratzailearekin.
Bertsioa Zehaztu honako formatu hau duen bertsio bat: nagusia.bigarren-mailakoa.konpilazioa.berrikuspena adibidez, 1.0.0.0.
Konfigurazio-orria HTML web-baliabidea zure soluzioan sartzen baduzu, bilaketa hau erabil dezakezu zure soluzioaren konfiguratutako orrialde gisa gehitzeko.
Deskribapenak Erabili eremu hau zure soluzioaren inguruko xehetasun garrantzitsuak sartzeko.

Jarraian, adibide-kodea da aurreko atalean sortu genuen editorea erabiltzen duen kudeatu gabeko soluzioa sortzeko.

// Create a solution
Solution solution = new Solution
{
   UniqueName = "sample-solution",
   FriendlyName = "Sample solution",
   PublisherId = new EntityReference(Publisher.EntityLogicalName, _publisherId),
   Description = "This solution was created by sample code.",
   Version = "1.0"
};

// Check whether the solution already exists
QueryExpression queryCheckForSampleSolution = new QueryExpression
{
   EntityName = Solution.EntityLogicalName,
   ColumnSet = new ColumnSet(),
   Criteria = new FilterExpression()
};

queryCheckForSampleSolution.Criteria.AddCondition("uniquename",
   ConditionOperator.Equal, solution.UniqueName);

// Attempt to retrieve the solution
EntityCollection querySampleSolutionResults =
   _serviceProxy.RetrieveMultiple(queryCheckForSampleSolution);

// Create the solution if it doesn't already exist
Solution SampleSolutionResults = null;

if (querySampleSolutionResults.Entities.Count > 0)
{
   SampleSolutionResults = (Solution)querySampleSolutionResults.Entities[0];
   _solutionsSampleSolutionId = (Guid)SampleSolutionResults.SolutionId;
}

if (SampleSolutionResults == null)
{
   _solutionsSampleSolutionId = _serviceProxy.Create(solution);
}

Kudeatu gabeko soluzioa sortu ondoren, soluzioaren osagaiak gehitu ditzakezu, soluzio honen testuinguruan sortuz edo lehendik dauden osagaiak gehituz. Informazio gehiago: Gehitu soluzio-osagai berria eta Gehitu lehendik dagoen soluzio-osagaia

Esportatu kudeatu gabeko soluzio bat

Kode-lagin honek erakusten du nola esportatu kudeatu gabeko soluzio bat edo pakete bat kudeatutako soluzioa. Kodeak erabiltzen du ExportSolutionRequest klasea esportatzeko konprimitutako fitxategia ordezkatuz kudeatu gabeko soluzioa. Aukeratu sortzea kudeatutako soluzioa ezarrita dago erabiliz Kudeatua propietatea. Lagin honek gordetzen du fitxategia izena duena samplesolution.zip irteera-karpeta.

// Export a solution
ExportSolutionRequest exportSolutionRequest = new ExportSolutionRequest();
exportSolutionRequest.Managed = false;
exportSolutionRequest.SolutionName = solution.UniqueName;

ExportSolutionResponse exportSolutionResponse =
   (ExportSolutionResponse)_serviceProxy.Execute(exportSolutionRequest);

byte[] exportXml = exportSolutionResponse.ExportSolutionFile;
string filename = solution.UniqueName + ".zip";

File.WriteAllBytes(outputDir + filename, exportXml);

Console.WriteLine("Solution exported to {0}.", outputDir + filename);

Inportatu kudeatu gabeko soluzio bat

Kodea erabiliz soluzio bat inportatu (edo bertsio-berritzea) lortzen da ImportSolutionRequest balioarekin.

// Install or upgrade a solution
byte[] fileBytes = File.ReadAllBytes(ManagedSolutionLocation);

ImportSolutionRequest impSolReq = new ImportSolutionRequest()
{
   CustomizationFile = fileBytes
};

_serviceProxy.Execute(impSolReq);

Inportazio arrakastaren jarraipena

ImportJob entitatea erabil dezakezu soluzioaren inportazioaren arrakastaren inguruko datuak jasotzeko. ImportJobId balioa zehazten duzunean ImportSolutionRequest balioan, balio hori erabil dezakezu ImportJob entitateak inportazioaren egoerari buruz kontsultatzeko. ImportJobId balioa inportazioko erregistro fitxategia deskargatzeko erabil daiteke RetrieveFormattedImportJobResultsRequest mezua erabiliz.

// Monitor solution import success
byte[] fileBytesWithMonitoring = File.ReadAllBytes(ManagedSolutionLocation);

ImportSolutionRequest impSolReqWithMonitoring = new ImportSolutionRequest()
{
   CustomizationFile = fileBytes,
   ImportJobId = Guid.NewGuid()
};

_serviceProxy.Execute(impSolReqWithMonitoring);

ImportJob job = (ImportJob)_serviceProxy.Retrieve(ImportJob.EntityLogicalName,
   impSolReqWithMonitoring.ImportJobId, new ColumnSet(new System.String[] { "data",
   "solutionname" }));

System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(job.Data);

String ImportedSolutionName =
   doc.SelectSingleNode("//solutionManifest/UniqueName").InnerText;

String SolutionImportResult =
   doc.SelectSingleNode("//solutionManifest/result/\@result").Value;

Console.WriteLine("Report from the ImportJob data");

Console.WriteLine("Solution Unique name: {0}", ImportedSolutionName);

Console.WriteLine("Solution Import Result: {0}", SolutionImportResult);

Console.WriteLine("");

// This code displays the results for Global Option sets installed as part of a
// solution.

System.Xml.XmlNodeList optionSets = doc.SelectNodes("//optionSets/optionSet");

foreach (System.Xml.XmlNode node in optionSets)
{
   string OptionSetName = node.Attributes["LocalizedName"].Value;
   string result = node.FirstChild.Attributes["result"].Value;

   if (result == "success")
   {
      Console.WriteLine("{0} result: {1}",OptionSetName, result);
   }
   else
   {
      string errorCode = node.FirstChild.Attributes["errorcode"].Value;
      string errorText = node.FirstChild.Attributes["errortext"].Value;

      Console.WriteLine("{0} result: {1} Code: {2} Description: {3}",OptionSetName,
      result, errorCode, errorText);
   }
}

Data propietatearen edukia soluzioaren XML fitxategia irudikatzen duen katea da.

Gehitu eta ezabatu edo kendu soluzio-osagaiak

Ikasi irtenbide osagaiak nola gehitu eta kentzen dituzun kodea erabiliz.

Gehitu soluzio-osagai berriak

Lagin honek irtenbide osagai bat nola sortu irtenbide jakin batekin lotzen den erakusten du. Soluzioaren osagaia soluzio zehatz batekin lotzen ez baduzu soluzio lehenetsia baino ez da gehituko, eta soluzio bat eskuz edo erantsi beharko duzu sartutako kodea erabiliz. Gehitu lehendik dagoen irtenbide osagaia.

Kode honek aukera multzo global berria sortzen du eta izen bakarra duen soluzioari eransten dio _primarySolutionName.

OptionSetMetadata optionSetMetadata = new OptionSetMetadata()
{
   Name = _globalOptionSetName,
   DisplayName = new Label("Example Option Set", _languageCode),
   IsGlobal = true,
   OptionSetType = OptionSetType.Picklist,
   Options =
{
   new OptionMetadata(new Label("Option 1", _languageCode), 1),
   new OptionMetadata(new Label("Option 2", _languageCode), 2)
}
};
CreateOptionSetRequest createOptionSetRequest = new CreateOptionSetRequest
{
   OptionSet = optionSetMetadata                
};

createOptionSetRequest.SolutionUniqueName = _primarySolutionName;
_serviceProxy.Execute(createOptionSetRequest);

Gehitu lehendik dagoen soluzio-osagaia

Lagin honek lehendik dagoen irtenbide osagaia nola gehitu irtenbide bati erakusten dio.

Ondorengo kodigoak erabiltzen du AddSolutionComponentRequest gehitzeko Account entitatea kudeatu gabeko irtenbide baten osagai gisa.

// Add an existing Solution Component
// Add the Account entity to the solution
RetrieveEntityRequest retrieveForAddAccountRequest = new RetrieveEntityRequest()
{
   LogicalName = Account.EntityLogicalName
};
RetrieveEntityResponse retrieveForAddAccountResponse = (RetrieveEntityResponse)_serviceProxy.Execute(retrieveForAddAccountRequest);
AddSolutionComponentRequest addReq = new AddSolutionComponentRequest()
{
   ComponentType = (int)componenttype.Entity,
   ComponentId = (Guid)retrieveForAddAccountResponse.EntityMetadata.MetadataId,
   SolutionUniqueName = solution.UniqueName
};
_serviceProxy.Execute(addReq);

Kendu soluzio-osagaia

Lagin horrek erakutsi egiten du nola kendu soluzio-osagai bat kudeatu gabeko soluziotik. Hurrengo kodeak erabili egiten du RemoveSolutionComponentRequest kentzeko entitatearen soluzio-osagai bat kudeatu gabeko soluziotik. solution.UniqueName sortutako irtenbidea aipatzen du Sortu kudeatu gabeko irtenbidea.

// Remove a Solution Component
// Remove the Account entity from the solution
RetrieveEntityRequest retrieveForRemoveAccountRequest = new RetrieveEntityRequest()
{
   LogicalName = Account.EntityLogicalName
};
RetrieveEntityResponse retrieveForRemoveAccountResponse = (RetrieveEntityResponse)_serviceProxy.Execute(retrieveForRemoveAccountRequest);

RemoveSolutionComponentRequest removeReq = new RemoveSolutionComponentRequest()
{
   ComponentId = (Guid)retrieveForRemoveAccountResponse.EntityMetadata.MetadataId,
   ComponentType = (int)componenttype.Entity,
   SolutionUniqueName = solution.UniqueName
};
_serviceProxy.Execute(removeReq);

Soluzioak ezabatu

Hurrengo laginean, irtenbidea nola berreskuratu erakusten da uniquename eta, ondoren, atera ezazu solutionid emaitzetatik. Laginak orduan erabiltzen du solutionid nirekinIOrganizationService. Delete metodoa ezabatzeko soluzioa.

// Delete a solution

QueryExpression queryImportedSolution = new QueryExpression
{
    EntityName = Solution.EntityLogicalName,
    ColumnSet = new ColumnSet(new string[] { "solutionid", "friendlyname" }),
    Criteria = new FilterExpression()
};


queryImportedSolution.Criteria.AddCondition("uniquename", ConditionOperator.Equal, ImportedSolutionName);

Solution ImportedSolution = (Solution)_serviceProxy.RetrieveMultiple(queryImportedSolution).Entities[0];

_serviceProxy.Delete(Solution.EntityLogicalName, (Guid)ImportedSolution.SolutionId);

Console.WriteLine("Deleted the {0} solution.", ImportedSolution.FriendlyName);

Klonazioa, adabakiak ezartzea eta bertsio-berritzea

Eskuragarri dauden APIak erabiliz soluzio eragiketa osagarriak egin ditzakezu. Klonazio eta maketazio soluzioak erabili CloneAsPatchRequest eta CloneAsSolutionRequest. Klonazioari eta adabakiak ezartzeari buruzko informazioa lortzeko, ikus Sortu soluzioaren adabakiak.

Irtenbide bertsio berritzeko erabiltzen denean StageAndUpgradeRequest eta DeleteAndPromoteRequest. Eguneratze eta bertsio berritze prozesuari buruzko informazio gehiago lortzeko, ikus Soluzio bat eguneratu edo eguneratu.

Detektatu soluzioaren menpekotasunak

Lagin honek irtenbide osagaien arteko mendekotasunak erakusten dituen txostena nola sortzen den erakusten du.

Kode honek:

  • Berreskuratu osagai guztiak irtenbide bat lortzeko.

  • Berreskuratu osagai bakoitzeko mendekotasun guztiak.

  • Aurkitu den dependentzia bakoitzerako mendekotasuna deskribatzen duen txostena erakutsi.

// Grab all Solution Components for a solution.
QueryByAttribute componentQuery = new QueryByAttribute
{
    EntityName = SolutionComponent.EntityLogicalName,
    ColumnSet = new ColumnSet("componenttype", "objectid", "solutioncomponentid", "solutionid"),
    Attributes = { "solutionid" },

    // In your code, this value would probably come from another query.
    Values = { _primarySolutionId }
};

IEnumerable<SolutionComponent> allComponents =
    _serviceProxy.RetrieveMultiple(componentQuery).Entities.Cast<SolutionComponent>();

foreach (SolutionComponent component in allComponents)
{
    // For each solution component, retrieve all dependencies for the component.
    RetrieveDependentComponentsRequest dependentComponentsRequest =
        new RetrieveDependentComponentsRequest
        {
            ComponentType = component.ComponentType.Value,
            ObjectId = component.ObjectId.Value
        };
    RetrieveDependentComponentsResponse dependentComponentsResponse =
        (RetrieveDependentComponentsResponse)_serviceProxy.Execute(dependentComponentsRequest);

    // If there are no dependent components, we can ignore this component.
    if (dependentComponentsResponse.EntityCollection.Entities.Any() == false)
        continue;

    // If there are dependencies upon this solution component, and the solution
    // itself is managed, then you will be unable to delete the solution.
    Console.WriteLine("Found {0} dependencies for Component {1} of type {2}",
        dependentComponentsResponse.EntityCollection.Entities.Count,
        component.ObjectId.Value,
        component.ComponentType.Value
        );
    //A more complete report requires more code
    foreach (Dependency d in dependentComponentsResponse.EntityCollection.Entities)
    {
        DependencyReport(d);
    }
}

DependencyReport metodoa honako kode-laginean dago.

Mendekotasun txostena

DependencyReport metodoak lagunarteko mezua eskaintzen du mendekotasunean aurkitutako informazioan oinarrituta.

Oharra

Lagin honetan metodoa partzialki inplementatzen da. Mezuak atributu eta aukera multzo irtenbide osagaietarako soilik bistaratu ditzake.

/// <summary>
/// Shows how to get a more friendly message based on information within the dependency
/// <param name="dependency">A Dependency returned from the RetrieveDependentComponents message</param>
/// </summary> 
public void DependencyReport(Dependency dependency)
{
 // These strings represent parameters for the message.
    String dependentComponentName = "";
    String dependentComponentTypeName = "";
    String dependentComponentSolutionName = "";
    String requiredComponentName = "";
    String requiredComponentTypeName = "";
    String requiredComponentSolutionName = "";

 // The ComponentType global Option Set contains options for each possible component.
    RetrieveOptionSetRequest componentTypeRequest = new RetrieveOptionSetRequest
    {
     Name = "componenttype"
    };

    RetrieveOptionSetResponse componentTypeResponse = (RetrieveOptionSetResponse)_serviceProxy.Execute(componentTypeRequest);
    OptionSetMetadata componentTypeOptionSet = (OptionSetMetadata)componentTypeResponse.OptionSetMetadata;
 // Match the Component type with the option value and get the label value of the option.
    foreach (OptionMetadata opt in componentTypeOptionSet.Options)
    {
     if (dependency.DependentComponentType.Value == opt.Value)
     {
      dependentComponentTypeName = opt.Label.UserLocalizedLabel.Label;
     }
     if (dependency.RequiredComponentType.Value == opt.Value)
     {
      requiredComponentTypeName = opt.Label.UserLocalizedLabel.Label;
     }
    }
 // The name or display name of the compoent is retrieved in different ways depending on the component type
    dependentComponentName = getComponentName(dependency.DependentComponentType.Value, (Guid)dependency.DependentComponentObjectId);
    requiredComponentName = getComponentName(dependency.RequiredComponentType.Value, (Guid)dependency.RequiredComponentObjectId);

 // Retrieve the friendly name for the dependent solution.
    Solution dependentSolution = (Solution)_serviceProxy.Retrieve
     (
      Solution.EntityLogicalName,
      (Guid)dependency.DependentComponentBaseSolutionId,
      new ColumnSet("friendlyname")
     );
    dependentComponentSolutionName = dependentSolution.FriendlyName;
    
 // Retrieve the friendly name for the required solution.
    Solution requiredSolution = (Solution)_serviceProxy.Retrieve
      (
       Solution.EntityLogicalName,
       (Guid)dependency.RequiredComponentBaseSolutionId,
       new ColumnSet("friendlyname")
      );
    requiredComponentSolutionName = requiredSolution.FriendlyName;

 // Display the message
     Console.WriteLine("The {0} {1} in the {2} depends on the {3} {4} in the {5} solution.",
     dependentComponentName,
     dependentComponentTypeName,
     dependentComponentSolutionName,
     requiredComponentName,
     requiredComponentTypeName,
     requiredComponentSolutionName);
}

Detektatu ea soluzio-osagai bat ezaba daitekeen

Erabili RetrieveDependenciesForDeleteRequest Mezua, irtenbide jakin bat ezabatzea eragotziko lukeen beste edozein konponbide osagai identifikatzeko. Hurrengo kodearen laginak, global aukera multzo ezaguna erabiliz atributuak bilatzen ditu. Aukera multzo globala erabiltzen duen edozein atributuak aukera globalaren ezabatzea saihestuko luke.

// Use the RetrieveOptionSetRequest message to retrieve  
// a global option set by it's name.
RetrieveOptionSetRequest retrieveOptionSetRequest =
    new RetrieveOptionSetRequest
    {
     Name = _globalOptionSetName
    };

// Execute the request.
RetrieveOptionSetResponse retrieveOptionSetResponse =
    (RetrieveOptionSetResponse)_serviceProxy.Execute(
    retrieveOptionSetRequest);
_globalOptionSetId = retrieveOptionSetResponse.OptionSetMetadata.MetadataId;
if (_globalOptionSetId != null)
{ 
 // Use the global OptionSet MetadataId with the appropriate componenttype
 // to call RetrieveDependenciesForDeleteRequest
 RetrieveDependenciesForDeleteRequest retrieveDependenciesForDeleteRequest = new RetrieveDependenciesForDeleteRequest 
{ 
 ComponentType = (int)componenttype.OptionSet,
 ObjectId = (Guid)_globalOptionSetId
};

 RetrieveDependenciesForDeleteResponse retrieveDependenciesForDeleteResponse =
  (RetrieveDependenciesForDeleteResponse)_serviceProxy.Execute(retrieveDependenciesForDeleteRequest);
 Console.WriteLine("");
 foreach (Dependency d in retrieveDependenciesForDeleteResponse.EntityCollection.Entities)
 {

  if (d.DependentComponentType.Value == 2)//Just testing for Attributes
  {
   String attributeLabel = "";
   RetrieveAttributeRequest retrieveAttributeRequest = new RetrieveAttributeRequest
   {
    MetadataId = (Guid)d.DependentComponentObjectId
   };
   RetrieveAttributeResponse retrieveAttributeResponse = (RetrieveAttributeResponse)_serviceProxy.Execute(retrieveAttributeRequest);

   AttributeMetadata attmet = retrieveAttributeResponse.AttributeMetadata;

   attributeLabel = attmet.DisplayName.UserLocalizedLabel.Label;
  
    Console.WriteLine("An {0} named {1} will prevent deleting the {2} global option set.", 
   (componenttype)d.DependentComponentType.Value, 
   attributeLabel, 
   _globalOptionSetName);
  }
 }
}