Jagamisviis:


Lahendustega töötamine Dataverse SDK abil

Oma arendusest tootmiseni elutsükli osana võite soovida luua teatud ülesannetele kohandatud automatiseerimist. Näiteks kui soovite oma DevOpsi projekti konveieril käivitada mõne kohandatud koodi või skripti, mis loob liivakastikeskkonna, impordib mittehallatava lahenduse, ekspordib mittehallatava lahenduse hallatava lahendusena ja lõpuks kustutab keskkonna. Saate teha seda ja palju muudki teile saadaolevate API-de abil. Allpool on toodud mõned näited selle kohta, mida on võimalik saavutada Dataverse .NET SDK ja kohandatud koodi abil.

Märkus.

Samu toiminguid saate teha ka veebi API abil. Seostuvad toimingud on järgmised: ImportSolution, ExportSolution, CloneAsPatch ja CloneAsSolution.

Mittehallatava lahenduse loomine, eksportimine või importimine

Vaatame, kuidas teha mõningaid levinud lahenduse toiminguid C# koodi abil. Kui soovite vaadata täielikku näidet C# koodiga töötamisest, mis illustreerib seda tüüpi lahenduse toiminguid (ja muud), vaadake jaotist Näide: lahendustega töötamine.

Väljastaja loomine

Iga lahendus nõuab väljastajat, keda esindabVäljastaja olem. Väljastaja nõuab järgmist.

  • Kohandamise eesliide
  • Kordumatu nimetus
  • Sõbralik nimi

Märkus.

Heas seisundis ALM-i lähenemise puhul kasutage oma kohanduste juurutamiseks vaikelahenduse ja väljastaja asemel alati kohandatud väljastajat ja lahendust.

Järgnev koodi näide määratleb esmalt väljastaja ja seejärel kontrollib kordumatu nimetuse põhjal, ega väljastajat juba olemas pole. Kui see on juba olemas, võidakse kohandamise eesliidet muuta, nii et selle näite eesmärk on hõivata praeguse kohanduse eesliide. Samuti hõivatakse PublisherId nii, et väljastaja kirjet saaks kustutada. Kui väljastajat ei leita, luuakse uus väljastajaIOrganizationService.Loo meetodi abil.

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

Mittehallatava lahenduse loomine

Kui teie kohandatud väljastaja on saadaval, saate luua mittehallatava lahenduse. Järgmises tabelis on toodud väljad, kus on kirjeldatud mida lahendus sisaldab.

Välja silt Kirjeldus
Kuvatav nimetus Lahenduse nimi.
Nimi Microsoft Dataverse loob kordumatu nimeKuvatava nime põhjal. Saate kordumatut nime redigeerida. Kordumatu nimi peab sisaldama ainult tähe- ja numbrimärke ning allkriipse.
Väljaandja Lahenduse seostamiseks väljastajaga kasutage otsingut Väljastaja.
Versioon Määrake versioon järgmise vormingu abil: major.minor.build.revision (nt 1.0.0.0).
Konfiguratsiooni leht Kui lisate lahendusse HTML-i veebiressursi, saate selle otsingu abil lisada selle teie määratud lahenduse konfiguratsiooni lehele.
Kirjeldus Selle välja abil saate kaasata kõik olulised üksikasjad oma lahenduse kohta.

Altpoolt leiate näidiskoodi mittehallatava lahenduse loomiseks, mis kasutab eelmises jaotises loodud väljastajat.

// 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ärast mittehallatava lahenduse loomist saate lisada lahenduse komponente, luues need selle lahenduse raames või lisades muude lahenduste olemasolevaid komponente. Lisateave. Uue lahenduse komponendi lisamine ja Olemasoleva lahenduse komponendi lisamine

Mittehallatava lahenduse eksportimine

Selle koodi näidise abil näete, kuidas mittehallatavat lahendust eksportida või hallatavat lahendust pakkida. Kood kasutab klassi ExportSolutionRequest mittehallatavat lahendust tähistava tihendatud faili eksportimiseks. Hallatava lahenduse loomise suvand määratakse atribuudi Hallatav abil. Selles näites salvesttakse faili nimega samplesolution.zip väljund kausta.

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

Mittehallatava lahenduse importimine

Koodi abil lahenduse importimine (või täiendamine) toimub üksuse ImportSolutionRequest abil.

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

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

_serviceProxy.Execute(impSolReq);

Impordi õnnestumise jälgimine

Olemi ImportJob abil saate hõivata lahenduse importimise õnnestumise kohta käivaid andmeid. Kui määrate ImportJobId jaoks suvandi ImportSolutionRequest, saate selle väärtuse abil esitada päringu olemi ImportJob importimise oleku kohta. Üksust ImportJobId saab kasutada ka impordi logifaili allalaadimiseks sõnumi RetrieveFormattedImportJobResultsRequest abil.

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

Atribuudi Data sisuks on string, mis tähistab lahenduse XML-faili.

Lahendusekomponentide lisamine või eemaldamine

Siit saate teada, kuidas koodi abil lahenduse komponente lisada ja eemaldada.

Uue lahendusekomponendi lisamine

See näide selgitab, kuidas luua kindla lahendusega seostatud lahenduse komponenti. Kui te ei seosta lahenduse komponenti kindla lahendusega selle loomisel, lisatakse see ainult vaikelahendusele ja te peate selle lisama lahendusele käsitsi või kasutades koodi, mis on toodud jaotises Olemasoleva lahenduse komponendi lisamine.

See kood loob uue globaalse suvandikomplekti ja lisab selle lahendusele, mille kordumatu nimi on _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);

Olemasoleva lahenduse komponendi lisamine lahendusele

See näide selgitab, kuidas lisada lahendusele olemasolevat lahenduse komponenti.

Järgmine kood kasutab sõnumit AddSolutionComponentRequest olemi Account lahenduse komponendina lisamiseks mittehallatavasse lahendusse.

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

Lahenduse komponendi eemaldamine

See näide selgitab, kuidas eemaldada lahenduse komponent mittehallatavast lahendusest. Järgmine kood kasutab sõnumit RemoveSolutionComponentRequest olemi lahenduse komponendi eemaldamiseks mittehallatavast lahendusest. solution.UniqueName viitab jaotises Mittehallatava lahenduse loomine loodud lahendusele.

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

Lahenduse kustutamine

Järgmine näide selgitab, kuidas tuua lahendus, kasutades lahendust uniquename, ja seejärel ekstraktida tulemitest solutionid. Seejärel kasutatakse näites lahenduse ID-d solutionid ja sõnumit IOrganizationService. Delete meetod lahenduse kustutamiseks.

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

Kloonimine, paikamine ja täiendamine

Saadaolevate API-de abil saate teha täiendavaid lahenduse toiminguid. Kloonimise ja paikamise lahenduste korral kasutage järgmisi: CloneAsPatchRequest ja CloneAsSolutionRequest. Teavet kloonimise ja paikamise kohta leiate teemast Lahenduse paikade loomine.

Lahenduse versiooni täiendamiseks kasutage järgmisi: StageAndUpgradeRequest ja DeleteAndPromoteRequest. Lisateavet koondamise ja versiooniuuenduste protsessi kohta leiate teemast Lahenduse värskendamine või täiendamine.

Lahendusesõltuvuste tuvastamine

See näide selgitab, kuidas luua aruanne, mis näitab lahenduse komponentide vahelisi sõltuvussuhteid.

See kood teeb järgmist.

  • Toob lahenduse kõik komponendid.

  • Toob iga komponendi kõik sõltuvused.

  • Kuvab sõltuvussuhet kirjeldava aruande iga leitud sõltuvuse kohta.

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

Meetod DependencyReport on järgmises koodi näites.

Sõltuvussuhte aruanne

Meetod DependencyReport pakub sõbralikumat sõnumit, mis põhineb sõltuvuse teabel.

Märkus.

Selles näites rakendatakse seda meetodit ainult osaliselt. Selles saab kuvada ainult atribuutide ja suvandikomplekti lahenduse komponentide sõnumeid.

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

Tuvastab kas lahenduse komponent võidakse kustutada

Kasutage sõnumit RetrieveDependenciesForDeleteRequest, et tuvastada kõik muud lahenduse komponendid, mis võivad takistada konkreetse lahenduse komponendi kustutamist. Järgmises koodi näites otsitakse kõiki atribuute, mis kasutavad teadaolevat üldist suvandikomplekti. Iga üldist suvandikomplekti kasutav atribuut võib takistada üldise suvandikomplekti kustutamist.

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