Darbs ar risinājumiem, izmantojot Dataverse SDK
Kā daļu no jūsu attīstības līdz ražošanas dzīves cikla jūs, iespējams, vēlēsities izveidot pielāgotu automatizāciju noteiktu uzdevumu apstrādei. 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 izdarīt to un vēl vairāk, izmantojot jums pieejamos API. Tālāk sniegti daži piemēri tam, ko varat paveikt, izmantojot . Dataverse SDK programmatūrai .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.
Nepārvaldīta risinājuma izveide,eksportēšana vai importēšana
Apskatīsim, kā izpildīt dažas bieži veicamas risinājuma operācijas, izmantojot C# kodu. Lai skatītu pilnu darba C# koda paraugu, kas demonstrē šāda veida risinājumu operācijas (un vairāk), skatiet sadaļu Paraugs: darbs ar risinājumiem.
Izstrādātāja izveidošana
Katram risinājumam nepieciešams izstrādātājs, ko pārstāv Izstrādātāja entītija. Izstrādātājam ir nepieciešams tālāk minētais.
- Pielāgojuma prefikss
- Unikālais nosaukums
- Draudzīgais nosaukums
Note
Veselīgai ALM pieejai vienmēr izmantojiet pielāgotu izstrādātāju un risinājumu, nevis noklusējuma risinājumu un izstrādātāju pielāgojumu izvietošanai.
Šajā koda paraugā vispirms ir definēts izstrādātājs un pēc tam pārbaudes, lai redzētu, vai izstrādātājs jau pastāv, pamatojoties uz unikālo nosaukumu. Ja tas jau pastāv, pielāgošanas prefikss, iespējams, ir mainīts, tādēļ šī parauga mērķis ir tvert 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. Tabulā zemāk ir uzskaitīti lauki ar aprakstiem, ko ietver risinājums.
Lauka etiķete | Apraksts |
---|---|
Parādāmais nosaukums | Risinājuma nosaukums. |
Nosaukums/vārds, uzvā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 tālāk minēto 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 lauku, lai iekļautu visu nepieciešamo informāciju par risinājumu. |
Zemāk ir parauga kods, lai izveidotu nepārvaldītu risinājumu, kas izmanto izstrādātāju, ko izveidojāt iepriekšējā sadaļā.
// 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);
}
Kad esat izveidojis nepārvaldītu risinājumu, varat pievienot risinājumu 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
ImportJob entītiju var izmantot, lai tvertu datus par risinājuma importēšanas panākumiem. Norādot ImportJobId
opcijai ImportSolutionRequest, varat izmantot šo vērtību, lai vaicātu ImportJob entītijai 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 noteiktu risinājumu, kad tas tiek izveidots, tas tiks pievienots tikai noklusējuma risinājumam, un tas būs jāpievieno risinājumam manuāli, vai arī izmantojot kodu, kas iekļauts Esoša risinājuma komponenta pievienošana.
Š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.
Tālāk minētais kods izmanto AddSolutionComponentRequest, lai pievienotu entītiju 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. Tālāk minētais kods izmanto RemoveSolutionComponentRequest, lai noņemtu entītijas 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 šķīduma dzēšanai.
// 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ēšanai un lāpīšanai risinājumi izmanto 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. Papildinformāciju par izstādīšanas un jaunināšanas procesu skatiet sadaļā Rrisinā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:
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);
}
Noteikt, vai risinājuma komponentus var dzēst
Izmantojiet RetrieveDependenciesForDeleteRequest ziņojumu, lai identificētu jebkurus citus risinājuma komponentus, kas neļauj dzēst konkrētu risinājuma komponentu. Šajā koda paraugā tiek meklēti visi atribūti, kas izmanto zināmu globālo opciju kopu. Jebkurš atribūts, kas izmanto globālo opciju kopu, neļaus dzēst globālo opciju kopu.
// 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);
}
}
}