opomba,
Dostop do te strani zahteva pooblastilo. Poskusite se vpisati alispremeniti imenike.
Dostop do te strani zahteva pooblastilo. Poskusite lahko spremeniti imenike.
Kot del življenjskega cikla od razvoja do produkcije boste morda želeli ustvariti avtomatizacijo po meri za obravnavo določenih nalog. Tako lahko na primer pri razvoju projekta DevOps izvedete kodo ali skript po meri, ki ustvari preizkusno okolje, uvozi neupravljano rešitev, izvozi to neupravljano rešitev kot upravljano rešitev in na koncu izbriše okolje. Te in še več operacij lahko izvedete z uporabo API-jev, ki so vam na voljo. Tukaj je nekaj primerov, kaj lahko dosežete z uporabo kompleta SDK za .NET in kode po meri. Dataverse
opomba,
Te postopke lahko izvedete tudi prek spletnega API-ja. Povezana dejanja so: ImportSolution, ExportSolution, CloneAsPatch in CloneAsSolution.
Vzorci kode v tem članku uporabljajo zgodnje vezane tipe entitet, ustvarjene s CrmSvcUtil ali PAC CLI. Več informacij: Pozno vezano in zgodnje vezano programiranje z uporabo SDK-ja za .NET
Ustvarjanje, izvoz ali uvoz neupravljane rešitve
Naučite se izvajati nekatere pogoste operacije reševanja s kodo C#. Če si želite ogledati celoten delujoč primer kode C#, ki prikazuje te vrste operacij z rešitvami in še več, pojdite na Vzorec: Delo z rešitvami.
Ustvarjanje izdajatelja
Vsaka rešitev zahteva založnika, ki ga predstavlja tabela Založnik. ... Založnik zahteva te lastnosti:
- Predpono prilagoditve
- Enolično ime
- Prijazno ime
opomba,
Za zdrav pristop k upravljanju življenjskega cikla aplikacij (ALM) za uvajanje prilagoditev vedno uporabite založnika in rešitev po meri, ne pa privzete rešitve in založnika.
Naslednji primer kode najprej definira založnika in nato na podlagi enoličnega imena preveri, ali založnik že obstaja. Če že obstaja, je bila predpona prilagajanja morda spremenjena. Ta vzorec poskuša zajeti trenutno predpono prilagoditve. Zajame se tudi PublisherId, tako da je zapis izdajatelja mogoče izbrisati. Če izdajatelja ni mogoče najti, se na podlagi metode IOrganizationService.Create.Create ustvari nov izdajatelj.
// 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;
}
Ustvarjanje neupravljane rešitve
Ko imate na voljo izdajatelja po meri, lahko ustvarite neupravljano rešitev. V naslednji tabeli so navedeni stolpci z opisi, ki jih vsebuje rešitev.
| Oznaka stolpca | Opis |
|---|---|
| Prikazano ime | Ime rešitve. |
| Imenu | Microsoft Dataverse ustvari enolično ime na podlagi prikaznega imena. Enolično ime lahko uredite. Enolično ime je lahko sestavljeno le iz alfanumeričnih znakov ali podčrtaja. |
| Izdajatelj | Uporabite iskanje Izdajatelj, da povežete rešitev z izdajateljem. |
| Različica | Različico določite v obliki: večja.manjša.gradnja.revizija, na primer 1.0.0.0. |
| Stran s konfiguracijo | Če v svojo rešitev vključite spletni vir HTML, ga lahko prek tega iskanja dodate kot namensko stran s konfiguracijo rešitve. |
| Description | V ta stolpec vključite vse pomembne podrobnosti o svoji rešitvi. |
Tukaj je vzorčna koda za ustvarjanje neupravljane rešitve, ki uporablja založnika, ki smo ga ustvarili v prejšnjem razdelku.
// 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);
}
Ko ustvarite neupravljano rešitev, dodajte komponente rešitve tako, da jih ustvarite v kontekstu te rešitve ali pa dodate obstoječe komponente iz drugih rešitev. Več informacij: Dodajanje nove komponente rešitve in Dodajanje obstoječe komponente rešitve
Izvoz neupravljane rešitve
Ta vzorec kode ponazarja, kako izvoziti neupravljano rešitev ali zapakirati upravljano rešitev. Koda uporablja razred ExportSolutionRequest za izvoz stisnjene datoteke, ki predstavlja neupravljano rešitev. Možnost za ustvarjanje upravljane rešitve se nastavi z uporabo lastnosti Managed. Ta vzorec shrani datoteko samplesolution.zip v izhodno mapo.
// 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);
Uvoz neupravljane rešitve
Uvoz (ali nadgradnja) rešitve prek kode se izvede na podlagi ImportSolutionRequest.
// Install or upgrade a solution
byte[] fileBytes = File.ReadAllBytes(ManagedSolutionLocation);
ImportSolutionRequest impSolReq = new ImportSolutionRequest()
{
CustomizationFile = fileBytes
};
_serviceProxy.Execute(impSolReq);
Spremljanje uspešnosti uvoza
Tabelo ImportJob lahko uporabite za zajemanje podatkov o uspešnosti uvoza rešitve. Ko za zahtevo ImportSolutionRequest določite vrednost ImportJobId , lahko to vrednost uporabite za poizvedbo v tabeli o stanju uvoza.ImportJob
ImportJobId lahko uporabite tudi za prenos datoteke z dnevnikom uvoza prek sporočila 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);
}
}
Vsebina lastnosti Data je niz, ki predstavlja datoteko XML rešitve.
Dodajanje in odstranjevanje komponent rešitve
Preberite, kako lahko s kodo dodate in odstranite komponente rešitve.
Dodajanje nove komponente rešitve
Ta primer prikazuje, kako ustvarite komponento rešitve, ki je povezana z določeno rešitvijo. Če komponente rešitve ob njenem ustvarjanju ne povežete z določeno rešitvijo, bo dodana le privzeti rešitvi, ki jo morate dodati v rešitev ročno ali z uporabo kode, ki je vključena v razdelku Dodajanje obstoječe komponente rešitve. ...
Ta koda ustvari nov globalni nabor možnosti in ga doda v rešitev z enoličnim imenom, ki je enako _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);
Dodajanje obstoječe komponente rešitve
Ta primer prikazuje, kako dodate obstoječo komponento rešitve v rešitev.
Naslednja koda uporablja AddSolutionComponentRequest za dodajanje tabele Account kot komponente rešitve v neupravljano rešitev.
// 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);
Odstranjevanje komponente rešitve
Ta primer prikazuje, kako odstranite komponento rešitve iz neupravljane rešitve. Naslednja koda uporablja RemoveSolutionComponentRequest za odstranitev komponente rešitve tabele iz neupravljane rešitve.
solution.UniqueName se sklicuje na rešitev, ustvarjeno v koraku Ustvarjanje neupravljane rešitve.
// 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);
Brisanje rešitve
Spodnji primer prikazuje, kako pridobite rešitev z uporabo uniquename rešitve in nato izvlečete solutionid iz rezultatov. Primer nato uporabi solutionid s IOrganizationService.
Delete način za brisanje rešitve.
// 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);
Kloniranje, popravki in nadgradnja
Dodatne postopke rešitve lahko izvedete z API-ji, ki so na voljo. Za rešitve za kloniranje in nameščanje popravkov uporabite CloneAsPatchRequest in CloneAsSolutionRequest. Za informacije o kloniranju in popravkih glejte Ustvarjanje popravkov rešitev.
Pri nadgradnjah rešitve uporabite StageAndUpgradeRequest in DeleteAndPromoteRequest. Za več informacij o postopku priprave in nadgradenj glejte Nadgradnja ali posodobitev rešitve.
Iskanje odvisnosti rešitve
Ta primer prikazuje, kako ustvarite poročilo, ki prikazuje odvisnosti med komponentami rešitve.
Ta koda izvaja te operacije:
pridobi vse komponente za rešitev.
pridobi vse odvisnosti za vsako komponento.
prikaže poročilo, ki opisuje odvisnost, za vsako najdeno odvisnost.
// 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);
}
}
Metoda DependencyReport je v spodnjem primeru kode.
Poročilo o odvisnosti
Metoda DependencyReport ponuja prijaznejše sporočilo na podlagi informacij, najdenih v odvisnosti.
opomba,
V tem primeru je metoda uporabljena le deloma. Sporočila lahko prikaže samo za komponente rešitve atributa in nabora možnosti.
/// <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);
}
Zaznavanje, ali je mogoče komponento rešitve izbrisati
Uporabite sporočilo RetrieveDependenciesForDeleteRequest, da poiščete druge komponente rešitve, ki bi preprečile brisanje določene komponente rešitve. Naslednji primer kode išče atribute z uporabo znanega stolpca globalne izbire. Vsak atribut, ki uporablja globalno izbiro, bi preprečil brisanje globalne izbire.
// 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);
}
}
}