Darbas su sprendimais naudojant „Dataverse“ SDK
Vykdant kūrimo-gamybos ciklą jums gali prireikti sukurti pasirinktinį automatizavimo procesą tam tikroms užduotims apdoroti. 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ą. Tai ir daugiau funkcijų galite naudoti jums prieinamose API. Toliau pateikiami keli pavyzdžiai, ką galite atlikti naudodami „Dataverse“ SDK .NET ir pasirinktinį kodą.
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ą.
Pažiūrėkime, kaip atlikti kai kurių įprastų sprendimų operacijas naudojant C# kodą. Norėdami peržiūrėti visą darbinį C# kodo pavyzdį, kuriame demonstruojamas tokio tipo (ir kitų tipų) sprendimų operacijos, žr Pavyzdys: darbas su sprendimais.
Kiekvienam sprendimui reikia leidėjo, kurį atstovauja Leidėjo objektas. Leidėjui reikia:
- Tinkinimo priešvardžio
- Unikalaus pavadinimo
- Paprasto pavadinimo
Pastaba
Siekdami užtikrinti subalansuotą ALM metodą, diegdami tinkinimus visada naudokite pasirinktinį (o ne numatytąjį) leidėją ir sprendimą.
Toliau nurodytas kodo pavyzdys pirmiausia apibrėžia leidėją, o tuomet pagal unikalų pavadinimą patikrina, ar toks leidėjas jau egzistuoja. Jei toks jau yra, tinkinimo priešdėlis galėjo būti pakeistas, todėl šis pavyzdys siekia 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;
}
Kai jau turite pasirinktinį leidėją, galite kurti nevaldomąjį sprendimą. Šioje lentelėje išvardyti laukai su aprašymais, kuriuos apima sprendimas.
Lauko etiketė | Aprašas |
---|---|
Rodomas pavadinimas | Sprendimo pavadinimas. |
Pavadinimas/vardas ir pavardė | „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 tokį formatą: major.minor.build.revision (pavyzdžiui, 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šas | Šiame lauke galite įtraukti visą svarbią informaciją apie savo sprendimą. |
Toliau pateiktas kodo pavyzdys, kuriuo sukuriamas nevaldomasis sprendimas, naudojantis ankstesniame skyriuje sukurtą leidėją.
// 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ą, galite įtraukti sprendimo komponentus juos sukurdami šio sprendimo kontekste arba įtraukdami esamus komponentus iš kitų sprendimų. Daugiau informacijos: Naujo sprendimo komponento įtraukimas ir Esamo sprendimo komponento įtraukimas
Š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);
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);
Galite naudoti importavimo užduoties objektą, jei norite užfiksuoti duomenis apie sprendimo importavimo sėkmę. Nurodę ImportSolutionRequest ImportJobId
, galite panaudoti šią reikšmę, kad pateiktumėte užklausą importavimo užduoties objektui 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ą.
Sužinokite, kaip įtraukti ir pašalinti sprendimo komponentus naudojant kodą.
Šis pavyzdys rodo, kaip sukurti sprendimo komponentą, susietą su konkrečiu sprendimu. Jei sprendimo komponento nesusiejate su konkrečiu sprendimu jį sukūrus, jis bus įtrauktas tik į numatytąjį sprendimą ir turėsite jį įtraukti į sprendimą rankiniu būdu arba naudodami kodą, įtrauktą į Esamo sprendimo komponento įtraukimas.
Š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);
Šis pavyzdys rodo, kaip į sprendimą įtraukti esamą sprendimo komponentą.
Šis kodas naudoja AddSolutionComponentRequest objekto Account
įtraukimui kaip sprendimo komponentui į 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);
Šis pavyzdys rodo, kaip iš nevaldomojo sprendimo pašalinti sprendimo komponentą. Šis kodas naudoja RemoveSolutionComponentRequest objekto sprendimo komponento šalinimui iš nevaldomojo sprendimo. solution.UniqueName
yra 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);
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);
Galite atlikti papildomas sprendimų operacijas naudodami galimus API. Klonavimo ir pataisų sprendimams naudokite CloneAsPatchRequest ir CloneAsSolutionRequest. Daugiau informacijos apie klonavimą ir pataisas rasite skyriuje Sprendimų pataisų kūrimas.
Vykdydami sprendimų atnaujinimus, naudokite StageAndUpgradeRequest ir DeleteAndPromoteRequest. Daugiau informacijos apie paruošimo ir naujinimo procesus žr. Sprendimo plėtojimui arba naujinimui.
Šiame pavyzdyje rodoma, kaip sukurti priklausomybių tarp sprendimo komponentų ataskaitą.
Šis kodas:
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.
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);
}
Naudokite RetrieveDependenciesForDeleteRequest pranešimą, kad nustatytumėte kitus sprendimo komponentus, kurie neleistų panaikinti tam tikro sprendimo komponento. Šis kodo pavyzdys ieško atributų, naudojančių žinomą visuotinį OptionSet. Bet kuris atributas, naudojantis OptionSet, neleistų panaikinti visuotinio OptionSet.
// 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);
}
}
}