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.
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.
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;
}
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
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);
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);
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.
Siit saate teada, kuidas koodi abil lahenduse komponente lisada ja eemaldada.
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);
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);
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);
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 lahuse kustutamise meetod.
// 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);
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.
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.
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);
}
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);
}
}
}