Partekatu bidez


Lan egin soluzioekin erabilita Dataverse SDK

Garapenetik ekoizpenerako bizi-zikloaren barruan, baliteke zeregin jakin batzuk kudeatzeko automatizazio pertsonalizatua sortu nahi izatea. 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. Eragiketa hauek eta gehiago egin ditzakezu eskuragarri dituzun APIak erabiliz. Hona hemen .NET-erako SDK-a eta kode pertsonalizatua erabiliz lor ditzakezun adibide batzuk. Dataverse

Oharra

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

Artikulu honetako kode-laginak CrmSvcUtil edo PAC CLI erabiliz sortutako entitate mota goiztiarrak erabiltzen ari dira. Informazio gehiago: .NET-erako SDK-a erabiliz berandu lotutako eta goiz lotutako programazioa

Sortu, esportatu edo inportatu kudeatu gabeko soluzio bat

Ikasi C# kodea erabiliz ohiko soluzio-eragiketa batzuk nola egin. Soluzio-eragiketa mota hauek eta gehiago erakusten dituen C# kodearen adibide osoa ikusteko, joan hona: Lagina: Soluzioekin lan egin.

Sortu argitaratzaile bat

Soluzio orok argitaratzaile bat behar du, Argitaratzaile taulak irudikatuta. Argitaratzaile batek propietate hauek behar ditu:

  • Pertsonalizazio-aurrizkia
  • Izen esklusiboa
  • Izen adierazgarria

Oharra

Aplikazioen bizi-zikloaren kudeaketa (ALM) osasuntsu bat lortzeko, erabili beti argitaratzaile eta soluzio pertsonalizatu bat, ez soluzio eta argitaratzaile lehenetsia, zure pertsonalizazioak zabaltzeko.

Hurrengo kode adibideak lehenik argitaratzaile bat definitzen du eta, ondoren, argitaratzaile hori existitzen den egiaztatzen du izen bakarraren arabera. Dagoeneko existitzen bada, pertsonalizazio aurrizkia aldatu egin daiteke. Adibide honek uneko pertsonalizazio aurrizkia jaso 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 taulak soluzio batek dituen deskribapenekin dauden zutabeak zerrendatzen ditu.

Zutabearen etiketa Azalpena
Bistaratze-izena Soluzioaren izena.
Eman 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 bertsio bat formatu hau erabiliz: major.minor.build.revision, 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 zutabe hau zure irtenbideari buruzko xehetasun garrantzitsuak sartzeko.

Hona hemen aurreko atalean sortu dugun argitaratzailea erabiltzen duen kudeatu gabeko soluzio bat sortzeko kode adibide bat.

// 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 soluzio bat sortu ondoren, gehitu soluzio-osagaiak soluzio honen testuinguruan sortuz edo beste soluzio batzuetako 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 taula erabil dezakezu soluzioaren inportazioaren arrakastari buruzko datuak jasotzeko. ImportSolutionRequest ImportJobId -rako bat zehazten duzunean, balio hori erabil dezakezutaulari inportazioaren egoerari buruzko kontsultak egiteko. ImportJob 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. Soluzio-osagaia soluzio zehatz bati lotzen ez badiozu sortzen denean, soluzio lehenetsiari gehituko zaio soilik, eta eskuz edo Gehitu lehendik dagoen soluzio-osagai bat atalean sartutako kodea erabiliz gehitu beharko diozu soluzio bati.

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.

Hurrengo kodeak AddSolutionComponentRequest erabiltzen du Account taula osagai gisa gehitzeko kudeatu gabeko soluzio bati.

// 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 RemoveSolutionComponentRequest erabiltzen du kudeatu gabeko soluzio batetik taula-soluzio osagai bat kentzeko. 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 irtenbidea ezabatzeko metodoa.

// 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 adabakitze irtenbideetarako, erabili CloneAsPatchRequest eta CloneAsSolutionRequest. Klonazioari eta adabakiak ezartzeari buruzko informazioa lortzeko, ikus Sortu soluzioaren adabakiak.

Irtenbide bertsio berritzeko erabiltzen denean StageAndUpgradeRequest eta DeleteAndPromoteRequest. Eszenaratze eta eguneratze prozesuari buruzko informazio gehiago lortzeko, joan Soluzio bat eguneratu edo berritu atalera.

Detektatu soluzioaren menpekotasunak

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

Kode honek eragiketa hauek egiten ditu:

  • 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 component 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 soluzio-osagai bat ezabatu daitekeen ala ez

Erabili RetrieveDependenciesForDeleteRequest Mezua, irtenbide jakin bat ezabatzea eragotziko lukeen beste edozein konponbide osagai identifikatzeko. Hurrengo kode adibideak edozein atributu bilatzen ditu aukera orokor ezagun bat erabiliz. Aukera globala erabiltzen duen edozein atributuak aukera globala ezabatzea eragotziko 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);
  }
 }
}