Dalintis per


Darbas su sprendimais naudojant „Dataverse“ SDK

Kurdami gamybos ciklą, galbūt norėsite sukurti pasirinktinį automatizavimą tam tikroms užduotims atlikti. Pavyzdžiui, jūsų „DevOps“ projekto sraute gali prireikti vykdyti tam tikrą pasirinktinį kodą arba scenarijų, kuris sukuria smėlio dėžės aplinką, importuoja nevaldomąjį sprendimą, eksportuoja šį nevaldomąjį sprendimą kaip valdomąjį sprendimą ir, galiausiai, panaikina aplinką. Šias ir kitas operacijas galite atlikti naudodami jums prieinamas API. Štai keletas pavyzdžių, ką galite pasiekti naudodami Dataverse .NET ir pasirinktinio kodo SDK.

Pastaba.

Taip pat galite atlikti tas pačias operacijas naudodami žiniatinklio API. Susiję veiksmai: Importuoti sprendimą, Eksportuoti sprendimą, Klonuoti kaip pataisą ir Klonuoti kaip sprendimą.

Šiame straipsnyje pateiktuose kodo pavyzdžiuose naudojami anksti susietų objektų tipai, sugeneruoti naudojant CrmSvcUtil arba PAC CLI. Daugiau informacijos: Vėlyvasis ir ankstyvasis susietasis programavimas naudojant .NET skirtą SDK

Kurkite, eksportuokite arba importuokite nevaldomąjį sprendimą

Sužinokite, kaip atlikti kai kurias įprastas sprendimo operacijas naudojant C# kodą. Norėdami peržiūrėti visą veikiantį C# kodo pavyzdį, kuris parodo šių tipų sprendimų operacijas ir dar daugiau, eikite į Pavyzdys: darbas su sprendimais.

Kurkite leidėją

Kiekvienam sprendimui reikia leidėjo, kurį pateikia lentelė Publisher. Leidėjui reikia šių ypatybių:

  • Tinkinimo priešvardžio
  • Unikalaus pavadinimo
  • Paprasto pavadinimo

Pastaba.

Jei naudojate sveiką programos gyvavimo ciklo valdymo (ALM) metodą, tinkinimams diegti visada naudokite pasirinktinį leidėją ir sprendimą, o ne numatytąjį sprendimą ir leidėją.

Šis kodo pavyzdys pirmiausia apibrėžia leidėją, o tada patikrina, ar leidėjas jau yra pagal unikalų pavadinimą. Jei jis jau yra, tinkinimo priešvardis galėjo būti pakeistas. Šiame pavyzdyje siekiama užfiksuoti dabartinį tinkinimo priešdėlį. Taip pat užfiksuojamas PublisherId tam, kad leidėjo įrašą būtų galima panaikinti. Jei leidėjo rasti nepavyksta, sukuriamas naujas leidėjas naudojant Organizacijos Aptarnavimą.Kūrimas metodą.

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

Nevaldomojo sprendimo kūrimas

Kai jau turite pasirinktinį leidėją, galite kurti nevaldomąjį sprendimą. Šioje lentelėje išvardyti stulpeliai su aprašais, kurie yra sprendime.

Stulpelio etiketė Aprašas
Rodomas vardas Sprendimo pavadinimas.
Pavadinimą „Microsoft Dataverse” sugeneruoja unikalų pavadinimą pagal Rodomą pavadinimą. Unikalų pavadinimą galite redaguoti. Unikaliame pavadinime turi būti tik raidiniai ir skaitiniai simboliai arba pabraukimo simbolis.
Leidėjas Galite susieti sprendimą su leidėju naudodami Leidėjo peržvalgą.
Versija Nurodykite versiją naudodami formatą: major.minor.build.revision, pvz., 1.0.0.0.
Konfigūravimo puslapis Jei į sprendimą įtrauksite HTML žiniatinklio išteklių, šios peržvalgos pagalba galite jį įtraukti kaip paskirtąjį sprendimo konfigūracijos puslapį.
Aprašą Naudokite šį stulpelį, kad įtrauktumėte visą susijusią informaciją apie savo sprendimą.

Toliau pateikiamas kodo pavyzdys, skirtas nevaldomajam sprendimui, kuris naudoja leidėją, kurį sukūrėme ankstesniame skyriuje, sukurti.

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

Sukūrę nevaldomąjį sprendimą, įtraukite sprendimo komponentų sukurdami juos šio sprendimo kontekste arba įtraukdami esamus komponentus iš kitų sprendimų. Daugiau informacijos: Naujo sprendimo komponento įtraukimas ir Esamo sprendimo komponento įtraukimas

Nevaldomojo sprendimo eksportavimas

Šis kodo pavyzdys rodo, kaip eksportuoti nevaldomąjį sprendimą arba supakuoti valdomąjį sprendimą. Kodas naudoja Eksportavimo Sprendimo Užklausos klasę suglaudintam failui eksportuoti, kuris reprezentuoja nevaldomąjį sprendimą. Parinktis kurti valdomąjį sprendimą nustatoma naudojant Valdomąją ypatybę. Šis pavyzdys įrašo failą pavadinimu samplesolution.zip į išvesties aplanką.

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

Nevaldomojo sprendimo importavimas

Sprendimo importavimas (arba atnaujinimas) naudojant kodą yra atliekamas su ImportSolutionRequest.

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

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

_serviceProxy.Execute(impSolReq);

Sėkmingo importavimo sekimas

Lentelę ImportJob galite naudoti norėdami užfiksuoti duomenis apie sprendimo importavimo sėkmę. Kai nurodote ImportJobId ImportSolutionRequest an, galite naudoti šią reikšmę, kad pateiktumėte ImportJob užklausą lentelėje apie importavimo būseną. ImportJobId pagalba taip pat galima atsisiųsti importavimo žurnalo failą naudojant pranešimą 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 ypatybės turinys yra eilutė, reprezentuojanti sprendimo XML failą.

Sprendimo komponentų įtraukimas arba šalinimas

Sužinokite, kaip įtraukti ir pašalinti sprendimo komponentus naudojant kodą.

Naujo sprendimo komponento įtraukimas

Šis pavyzdys rodo, kaip sukurti sprendimo komponentą, susietą su konkrečiu sprendimu. Jei sukūrę sprendimo komponento nesusiejate su konkrečiu sprendimu, jis bus įtrauktas tik į numatytąjį sprendimą ir turėsite įtraukti jį į sprendimą rankiniu būdu arba naudodami kodą, įtrauktą į Įtraukti esamą sprendimo komponentą.

Šis kodas sukuria naują visuotinį parinkčių rinkinį ir įtraukia jį į sprendimą, kurio unikalus pavadinimas yra _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);

Esamo sprendimo komponento įtraukimas

Šis pavyzdys rodo, kaip į sprendimą įtraukti esamą sprendimo komponentą.

Toliau pateiktas kodas naudoja AddSolutionComponentRequest, kad pridėtų Account lentelę kaip sprendimo komponentą į nevaldomąjį sprendimą.

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

Sprendimo komponento šalinimas

Šis pavyzdys rodo, kaip iš nevaldomojo sprendimo pašalinti sprendimo komponentą. Šis kodas naudoja RemoveSolutionComponentRequest lentelės sprendimo komponentą pašalinti iš nevaldomojo sprendimo. solution.UniqueNameyra nuoroda į sprendimą, sukurtą Nevaldomojo sprendimo kūrimas.

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

Sprendimo naikinimas

Toliau pateikiamas pavyzdys rodo, kaip gauti sprendimą naudojant sprendimo uniquename ir tada išskleisti solutionid iš rezultatų. Tada pavyzdys naudoja solutionid suIOrganizationService. Delete Sprendimo naikinimo metodas.

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

Klonavimas, pataisos ir atnaujinimas

Galite atlikti papildomas sprendimų operacijas naudodami galimus API. Klonavimo ir pataisymo sprendimams naudokite CloneAsPatchRequest ir CloneAsSolutionRequest. Daugiau informacijos apie klonavimą ir pataisas rasite skyriuje Sprendimų pataisų kūrimas.

Vykdydami sprendimų atnaujinimus, naudokite StageAndUpgradeRequest ir DeleteAndPromoteRequest. Norėdami gauti daugiau informacijos apie išdėstymo ir versijos naujinimo procesą, eikite į Sprendimo versijos naujinimas arba naujinimas.

Sprendimų priklausomybių aptikimas

Šiame pavyzdyje rodoma, kaip sukurti priklausomybių tarp sprendimo komponentų ataskaitą.

Šis kodas atlieka šias operacijas:

  • Nuskaitys visus sprendimo komponentus.

  • Nuskaitys visas kiekvieno komponento priklausomybes.

  • Kiekvienai rastai priklausomybei parodys ataskaitą, apibūdinančią priklausomybę.

// 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 metodas yra šiame kodo pavyzdyje.

Priklausomybės ataskaita

DependencyReport metodas suteikia palankesnį pranešimą pagal priklausomybės informaciją.

Pastaba.

Šiame pavyzdyje metodas yra įgyvendinamas tik iš dalies. Jis gali rodyti tik atributo ir parinkčių rinkinio sprendimo komponentų pranešimus.

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

Nustatymas, ar sprendimo komponentas gali būti panaikintas

Naudokite RetrieveDependenciesForDeleteRequest pranešimą, kad nustatytumėte kitus sprendimo komponentus, kurie neleistų panaikinti tam tikro sprendimo komponento. Toliau pateiktame kodo pavyzdyje ieškoma bet kokių atributų naudojant žinomą visuotinio pasirinkimo stulpelį. Bet koks atributas, naudojantis visuotinį pasirinkimą, neleistų ištrinti visuotinio pasirinkimo.

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