Kopīgot, izmantojot


Darbs ar risinājumiem, izmantojot Dataverse SDK

Izstrādes un ražošanas dzīves cikla ietvaros, iespējams, vēlēsities izveidot pielāgotu automatizāciju, lai apstrādātu noteiktus uzdevumus. Piemēram, savā DevOps projektu konveijerā, iespējams, vēlaties izpildīt kādu pielāgotu kodu vai skriptu, kas veido smilškastes vidi, importē nepārvaldītu risinājumu, eksportē šo nepārvaldīto risinājumu kā pārvaldītu risinājumu, un visbeidzot izdzēš attiecīgo vidi. Varat veikt šīs un citas darbības, izmantojot jums pieejamos API. Tālāk ir sniegti daži piemēri, ko varat paveikt, izmantojot Dataverse SDK .NET un pielāgotu kodu.

Note

Šīs pašas operācijas varat arī veikt, izmantojot tīmekļa API. Saistītās darbības ir šādas: ImportSolution, ExportSolution, CloneAsPatch un CloneAsSolution.

Šajā rakstā sniegtajos koda paraugos tiek izmantoti agrīni saistītie entītiju tipi, kas ģenerēti, izmantojot CrmSvcUtil vai PAC CLI. Papildinformācija: Vēlīnā un agrīnā saistītā programmēšana, izmantojot .NET SDK

Nepārvaldīta risinājuma izveide,eksportēšana vai importēšana

Uzziniet, kā veikt dažas bieži sastopamās risinājuma darbības, izmantojot C# kodu. Lai skatītu pilnu darba C# koda paraugu, kas parāda šāda veida risinājumu operācijas un daudz ko citu, dodieties uz Paraugs: darbs ar risinājumiem.

Izstrādātāja izveidošana

Katram risinājumam ir nepieciešams izdevējs, ko attēlo tabula Publisher. Izdevējam ir nepieciešami šādi rekvizīti:

  • Pielāgojuma prefikss
  • Unikālais nosaukums
  • Draudzīgais nosaukums

Note

Lai nodrošinātu veselīgu lietojumprogrammu dzīves cikla pārvaldības (ALM) pieeju, pielāgojumu izvietošanai vienmēr izmantojiet pielāgotu izdevēju un risinājumu, nevis noklusējuma risinājumu un izdevēju.

Tālāk sniegtajā koda piemērā vispirms tiek definēts izdevējs un pēc tam tiek pārbaudīts, vai izdevējs jau pastāv, pamatojoties uz unikālo nosaukumu. Ja tas jau pastāv, iespējams, pielāgošanas prefikss ir mainīts. Šī parauga mērķis ir uztvert pašreizējo pielāgošanas prefiksu. PublisherId tiek tverts arī tā, lai varētu dzēst izstrādātāja ierakstu. Ja izstrādātājs nav atrasts, tiek izveidots jauns izstrādātājs, izmantojot metodi IOrganizationService.Izveidot.

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

Nepārvaldīta risinājuma izveide

Kad ir pieejams pielāgots izstrādātājs, varat izveidot nepārvaldītu risinājumu. Šajā tabulā ir uzskaitītas kolonnas ar aprakstiem, kas satur risinājumu.

Kolonnas etiķete Apraksts
Parādāmais vārds Risinājuma nosaukums.
Nosaukums/vārds Microsoft Dataverse ģenerē unikālu nosaukumu, pamatojoties uz Parādāmo nosaukumu. Varat rediģēt unikālo nosaukumu. Unikālajam nosaukumam jāietver tikai burtciparu vai pasvītrojuma rakstzīmes.
Publicētājs Izmantojiet Izstrādātāja uzmeklēšanu, lai risinājumu saistītu ar izstrādātāju.
Versija Norādiet versiju, izmantojot formātu: major.minor.build.revision, piemēram, 1.0.0.0.
Konfigurācijas lapa Ja risinājumā iekļaujat HTML tīmekļa resursu, varat izmantot šo uzmeklēšanu, lai to pievienotu kā norādīto risinājuma konfigurācijas lapu.
Apraksts Izmantojiet šo sleju, lai iekļautu visu atbilstošo informāciju par savu risinājumu.

Tālāk ir sniegts koda paraugs, lai izveidotu nepārvaldītu risinājumu, kurā tiek izmantots iepriekšējā sadaļā izveidotais izdevējs.

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

Pēc nepārvaldīta risinājuma izveides pievienojiet risinājuma komponentus, izveidojot tos šī risinājuma kontekstā vai pievienojot esošus komponentus no citiem risinājumiem. Papildinformācija: Jauna risinājuma komponenta pievienošana un Esoša risinājuma komponenta pievienošana

Nepārvaldīta risinājuma eksportēšana

Šajā koda piemērā ir parādīts, kā eksportēt nepārvaldītu risinājumu vai pakotni pārvaldītam risinājumam. Kods izmanto klasi ExportSolutionRequest, lai eksportētu saspiestu failu, kas pārstāv nepārvaldītu risinājumu. Pārvaldīta risinājuma izveides opcija ir iestatīta, izmantojot rekvizītu Pārvaldīts. Šajā paraugā tiek saglabāts fails ar nosaukumu samplesolution.zip uz izvades mapi.

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

Nepārvaldīta risinājuma importēšana

Risinājuma importēšana (vai jaunināšana), izmantojot kodu, tiek izpildīta ar ImportSolutionRequest.

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

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

_serviceProxy.Execute(impSolReq);

Importēšanas panākumu izsekošana

Tabulu ImportJob var izmantot, lai iegūtu datus par risinājuma importēšanas panākumiem. Norādot ImportJobIdImportSolutionRequest vērtību, šo vērtību var izmantot, lai vaicātu tabulā ImportJob par importēšanas statusu. ImportJobId var izmantot arī, lai lejupielādētu importēšanas žurnālfailu, izmantojot ziņojumu RetrieveFormattedImportJobResultsRequest.

// 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 rekvizīta saturs ir virkne, kas pārstāv risinājuma XML failu.

Risinājuma komponentu pievienošana un noņemšana

Informācija par to, kā pievienot un noņemt risinājuma komponentus, izmantojot kodu.

Jauna risinājuma komponenta pievienošana

Šajā paraugā ir parādīts, kā izveidot risinājuma komponentu, kas saistīts ar noteiktu risinājumu. Ja risinājuma komponentu nesaistāt ar konkrētu risinājumu, kad tas tiek izveidots, tas tiks pievienots tikai noklusējuma risinājumam, un jums tas ir jāpievieno risinājumam manuāli vai izmantojot kodu, kas iekļauts sadaļā Pievienot esošu risinājumu.

Šis kods izveido jaunu globālo opciju kopu un pievieno to risinājumam, kam ir unikāls nosaukums, kas vienāds ar _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);

Esoša risinājuma komponenta pievienošana

Šajā paraugā ir parādīts, kā risinājumam pievienot esošu risinājuma komponentu.

Šis kods tiek izmantots AddSolutionComponentRequest , lai pievienotu tabulu Account kā risinājuma komponentu nepārvaldītam risinājumam.

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

Risinājuma komponentu noņemšana

Šajā paraugā ir parādīts, kā noņemt risinājuma komponentu no nepārvaldīta risinājuma. Šis kods tiek izmantots RemoveSolutionComponentRequest , lai noņemtu tabulas risinājuma komponentu no nepārvaldīta risinājuma. solution.UniqueName attiecas uz risinājumu, kas izveidots Nepārvaldīta risinājuma izveide.

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

Risinājuma dzēšana

Šajā piemērā ir parādīts, kā izgūt risinājumu, izmantojot risinājumu uniquename, un pēc tam iegūt solutionid no rezultātiem. Piemērā pēc tam ir izmantots lauks solutionid arIOrganizationService. Delete metode, lai izdzēstu risinājumu.

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

Klonēšana, lāpīšana un jaunināšana

Varat veikt papildu risinājumu operācijas, izmantojot pieejamos API. Klonēšanas un ielāpīšanas risinājumiem, izmantojiet CloneAsPatchRequest un CloneAsSolutionRequest. Informāciju par klonēšanu un lāpīšanu skatiet sadaļā Risinājuma ielāpu izveide.

Veicot risinājumu jaunināšanu, izmantojiet līdzekli StageAndUpgradeRequest un DeleteAndPromoteRequest. Lai iegūtu papildinformāciju par iestāšanās un jaunināšanas procesu, dodieties uz Risinājuma jaunināšana vai atjaunināšana.

Risinājumu atkarību noteikšana

Šajā piemērā ir parādīts, kā izveidot atskaiti, kurā parādītas dažādu risinājuma komponentu atkarības.

Šis kods veic šādas darbības:

  • izgūs visus risinājuma komponentus;

  • izgūs visas katra komponenta atkarības;

  • par katru atrasto atkarību parādīs atskaiti, kas apraksta šo atkarību.

// 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 metode ir tālāk parādītajā koda paraugā.

Atskaite par atkarībām

Metode DependencyReport nodrošina draudzīgāku ziņojumu, pamatojoties uz informāciju, kas ir atrodama atkarībā.

Note

Šajā paraugā metode tiek īstenota tikai daļēji. Tā ziņojumus var parādīt tikai par atribūta un opciju kopas risinājuma komponentiem.

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

Nosakiet, vai risinājuma komponentu var izdzēst

Izmantojiet RetrieveDependenciesForDeleteRequest ziņojumu, lai identificētu jebkurus citus risinājuma komponentus, kas neļauj dzēst konkrētu risinājuma komponentu. Tālāk sniegtajā koda piemērā tiek meklēti visi atribūti, izmantojot zināmu globālās izvēles kolonnu. Jebkurš atribūts, kas izmanto globālo izvēli, neļautu dzēst globālo izvēli.

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