Dataverse SDK арқылы шешімдермен жұмыс істеу
Өндірістің жарамдылық кезеңінің әзірлеу бөлігі ретінде белгілі тапсырмаларды өңдеу үшін реттелмелі автоматтандыруды жасағыңыз келуі мүмкін. Мысалы, DevOps жобасының үдерістер тізбегінде сынақ ортасын жасайтын, басқарылмайтын шешімді импорттайтын, басқарылмайтын шешімді басқарылатын шешім ретінде экспорттайтын және соңында ортаны жоятын кейбір реттелетін кодты немесе сценарийді орындағыңыз келуі мүмкін. Осы әрекетті және басқаларын өзіңізге қолжетімді болатын API интерфейстерінің көмегімен орындауға болады. Төменде Dataverse SDK for .NET және реттелетін код арқылы орындауға болатын мысалдар келтірілген.
Ескерім
Сондай-ақ, осы бірдей әрекеттерді Web API интерфейсінің көмегімен орындауға болады. Қатысты әрекеттер: ImportSolution, ExportSolution, CloneAsPatch және CloneAsSolution.
C # кодының көмегімен кейбір жалпы шешім жұмыстарын орындау жолын қарастырайық. Шешім жұмыстарының (және бірнеше) осы түрлерін көрсететін толық жұмыс істейтін C# кодының үлгісін қарау үшін, Үлгі: шешімдермен жұмыс бөлімін қараңыз.
Әр шешім Жариялаушы нысан арқылы ұсынылған жариялаушыны талап етеді. Жариялаушы келесілерді талап етеді:
- Реттеу префиксі
- Бірегей атауы
- Оңай ат
Ескерім
Қалыпты ALM әдісін алу үшін, реттеулерді орналастыруға арналған әдепкі шешім мен жариялаушыны емес, реттелетін жариялаушы мен шешімді әрқашан пайдаланыңыз.
Келесі код үлгісі алдымен жариялаушыны анықтайды, содан кейін жариялаушының бірегей атау негізінде бар-жоғын тексереді. Егер ол бұрыннан бар болса, реттеу префиксі өзгертілген болуы мүмкін, сондықтан бұл үлгі ағымдағы реттеу префиксін түсіруге тырысады. Сондай-ақ PublisherId
жариялаушы жазбаны жоятындай етіп түсіріледі. Егер жариялаушы табылмаса, жаңа жариялаушы IOrganizationService.Жасау әдісінің көмегімен жасалады.
// 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;
}
Жеке жариялаушы қолжетімді болғаннан кейін, басқарылмайтын шешімді жасауға болады. Келесі кестеде шешімді қамтитын сипаттамалары бар өрістер берілген.
Өріс белгісі | Сипаттамасы |
---|---|
Атауды көрсету | Шешімнің атауы. |
Аты | Microsoft Dataverse бағдарламасы Көрсетілетін атау негізіндегі бірегей атауды жасайды. Бірегей атауды өңдеуге болады. Бірегей атауда тек алфавиттік-сандық таңбалар немесе астын сызу таңбасы болуы тиіс. |
Жариялаушы | Шешімді жариялаушымен байланыстыру үшін Жариялаушы іздеу өрісін пайдаланыңыз. |
Нұсқа | Нұсқаны мына пішімді пайдалану арқылы көрсетіңіз: негізгі.қосымша.құрастыру.редакция, (мысалы, 1.0.0.0. |
Конфигурация беті | Егер шешіміңізге HTML веб-ресурсын қоссаңыз, оны белгіленген шешім конфигурациясының беті ретінде қосу үшін осы іздеуді пайдалануға болады. |
Сипаттама | Шешім туралы кез келген қатысты мәліметтерді қосу үшін осы өрісті пайдаланыңыз. |
Төменде алдыңғы бөлімде жасаған жариялаушыны пайдаланатын басқарылмайтын шешімді жасауға арналған код үлгісі берілген.
// 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);
}
Басқарылмайтын шешімді жасағаннан кейін, шешім құрамдастарын осы шешім контекстінде жасау арқылы немесе басқа шешімдердің бұрыннан бар құрамдастарын қосу арқылы оларды қосуға болады. Қосымша ақпарат: Жаңа шешім құрамдасын қосу және Бұрыннан бар шешім құрамдасын қосу
Бұл код үлгісі басқарылмайтын шешімді экспорттау немесе басқарылатын шешімді жинақтау жолын көрсетеді. Код басқарылмайтын шешімді ұсынатын сығымдалған файлды экспорттау үшін ExportSolutionRequest сыныбын пайдаланады. Басқарылатын шешім жасау параметрі Басқарылған сипат көмегімен орнатылады. Бұл samplesolution.zip деп аталған файлды шығыс қалтаға сақтайды.
// 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);
Шешімді кодтың көмегімен импорттау (немесе жаңарту) ImportSolutionRequest арқылы орындалады.
// Install or upgrade a solution
byte[] fileBytes = File.ReadAllBytes(ManagedSolutionLocation);
ImportSolutionRequest impSolReq = new ImportSolutionRequest()
{
CustomizationFile = fileBytes
};
_serviceProxy.Execute(impSolReq);
ImportJob нысанын импорт шешімді импорттаудың сәтті аяқталуы туралы деректерді түсіру үшін пайдалануға болады. ImportSolutionRequest үшін ImportJobId
параметрін көрсеткен кезде, сол мәнді импорттау күйі туралы ImportJob нысанын сұрау үшін пайдалануға болады. Сондай-ақ ImportJobId
параметрін импорт журналы файлын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
сипатының мазмұны – XML файлының шешімін көрсететін жол.
Код арқылы шешім құрамдастарын қосу және жою жолы туралы қосымша ақпарат.
Бұл үлгі нақты шешіммен байланысты шешім құрамдасын құру жолын көрсетеді. Егер сіз шешім құрамдасын жасау кезінде оны нақты шешіммен байланыстырмасаңыз, ол тек әдепкі шешімге қосылады және оны шешімге қолмен немесе Бұрыннан бар шешім құрамдасын қосу бөліміне енгізілген код арқылы қосу керек болады.
Бұл код жаңа глобалдық параметрлер жиынын жасайды және оны _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);
Бұл үлгі бұрыннан бар шешім құрамдасын шешімге қосу жолын көрсетеді.
Келесі код Account
нысанын шешім құрамдасы ретінде басқарылмайтын шешімге қосу үшін AddSolutionComponentRequest пайдаланады.
// 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);
Бұл үлгі шешім құрамдасын басқарылмайтын шешімнен алып тастау жолын көрсетеді. Келесі код нысанның шешім құрамдасын басқарылмайтын шешімнен алып тастау үшін RemoveSolutionComponentRequest пайдаланады. solution.UniqueName
Басқарылмайтын шешім жасау бөлімінде жасалған шешімге сілтеме жасайды.
// 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);
Төмендегі үлгі шешімді uniquename
шешімі арқылы алу, содан кейін solutionid
шешімін нәтижелерден шығарып алу жолын көрсетеді. Содан кейін, үлгі IOrganizationService бірге solutionid
пайдаланады. Delete шешімді жою әдісі.
// 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);
Қолжетімді API интерфейстері арқылы қосымша шешім операцияларын орындауға болады. Шешімдерді клондау және түзету үшін CloneAsPatchRequest және CloneAsSolutionRequest пайдаланыңыз. Көшіру және түзету туралы ақпаратты Шешім түзетулерін жасау бөлімінен қараңыз.
Шешім жаңартуларын орындау кезінде StageAndUpgradeRequest және DeleteAndPromoteRequest пайдаланыңыз. Аралық сақтау мен жетілдіру процестері туралы қосымша ақпарат алу үшін Шешімді жетілдіру немесе жаңарту бөлімін қараңыз.
Бұл үлгі шешім құрамдастары арасындағы тәуелділіктерді көрсететін есепті құру жолын көрсетеді.
Бұл код:
Шешім үшін барлық құрамдастарды алады.
Әр құрамдас үшін барлық тәуелділіктерді алады.
Табылған тәуелділік үшін тәуелділікті сипаттайтын есепті көрсетеді.
// 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
әдісі келесі код үлгісінде.
DependencyReport
әдісі тәуелділік шеңберінде табылған ақпарат негізінде достық хабарлама ұсынады.
Ескерім
Бұл үлгіде әдіс жартылай ғана жүзеге асырылады. Ол хабарламаларды төлсипат және параметрлер жиынының шешім құрамдастары үшін ғана көрсете алады.
/// <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);
}
Берілген шешім құрамдастарының жойылуына жол бермейтін кез келген басқа шешім құрамдастарын анықтау үшін RetrieveDependenciesForDeleteRequest хабарламасын пайдаланыңыз. Келесі код үлгісі белгілі глобалдық параметрлер жиыны арқылы кез келген төлсипаттарды іздейді. Глобалдық параметрлер жиынын пайдаланатын кез келген төлсипат глобалдық параметрлер жиынының жойылуына жол бермейді.
// 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);
}
}
}