다음을 통해 공유


솔루션 작업

 

게시 날짜: 2016년 11월

적용 대상: Dynamics CRM 2015

이 항목에서는 샘플: 솔루션 작업샘플: 솔루션 종속성 검색에 포함된 특정 프로그래밍 작업을 소개합니다.

이 항목의 내용

게시자 만들기

기본 게시자 검색

솔루션 만들기

솔루션 검색

새 솔루션 구성 요소 추가

기존 솔루션 구성 요소 추가

솔루션 구성 요소 제거

솔루션 내보내기 또는 패키지

솔루션 설치 또는 업그레이드

솔루션 삭제

솔루션 종속성 검색

게시자 만들기

각 솔루션에는 Publisher 엔터티로 나타내는 게시자가 필요합니다. 솔루션은 Microsoft Corporation 게시자를 사용할 수 없지만 조직 또는 새 게시자에 대한 Default 게시자를 사용할 수 있습니다.

게시자는 다음 항목이 필요합니다.

  • 사용자 지정 접두사

  • 고유 이름

  • 대화명

다음 샘플에서는 먼저 게시자를 정의한 후 고유 이름에 따라 게시자가 이미 있는지 여부를 확인합니다. 이미 있는 경우 사용자 지정 접두사가 바뀌었을 수 있으므로 이 샘플은 현재 사용자 지정 접두사를 캡처하기 위해 찾습니다. 게시자 레코드를 삭제할 수 있도록 PublisherId도 캡처됩니다. 게시자가 발견되지 않으면 IOrganizationService을 사용하여 새 게시자가 생성됩니다.Create 메서드




//Define a new publisher
Publisher _crmSdkPublisher = new Publisher
{
    UniqueName = "sdksamples",
    FriendlyName = "Microsoft CRM SDK Samples",
    SupportingWebsiteUrl = "https://msdn.microsoft.com/en-us/dynamics/crm/default.aspx",
    CustomizationPrefix = "sample",
    EMailAddress = "someone@microsoft.com",
    Description = "This publisher was created with samples from the Microsoft Dynamics CRM SDK"
};

//Does publisher already exist?
QueryExpression querySDKSamplePublisher = new QueryExpression
{
    EntityName = Publisher.EntityLogicalName,
    ColumnSet = new ColumnSet("publisherid", "customizationprefix"),
    Criteria = new FilterExpression()
};

querySDKSamplePublisher.Criteria.AddCondition("uniquename", ConditionOperator.Equal, _crmSdkPublisher.UniqueName);
EntityCollection querySDKSamplePublisherResults = _serviceProxy.RetrieveMultiple(querySDKSamplePublisher);
Publisher SDKSamplePublisherResults = null;

//If it already exists, use it
if (querySDKSamplePublisherResults.Entities.Count > 0)
{
    SDKSamplePublisherResults = (Publisher)querySDKSamplePublisherResults.Entities[0];
    _crmSdkPublisherId = (Guid)SDKSamplePublisherResults.PublisherId;
    _customizationPrefix = SDKSamplePublisherResults.CustomizationPrefix;
}
//If it doesn't exist, create it
if (SDKSamplePublisherResults == null)
{
    _crmSdkPublisherId = _serviceProxy.Create(_crmSdkPublisher);
    Console.WriteLine(String.Format("Created publisher: {0}.", _crmSdkPublisher.FriendlyName));
    _customizationPrefix = _crmSdkPublisher.CustomizationPrefix;
}



'Define a new publisher
Dim _crmSdkPublisher As Publisher =
 New Publisher With {
  .UniqueName = "sdksamples",
  .FriendlyName = "Microsoft CRM SDK Samples",
  .SupportingWebsiteUrl = "https://msdn.microsoft.com/en-us/dynamics/crm/default.aspx",
  .CustomizationPrefix = "sample",
  .EMailAddress = "someone@microsoft.com",
  .Description = "This publisher was created with samples from the Microsoft Dynamics CRM SDK"
 }

'Does publisher already exist?
Dim querySDKSamplePublisher As QueryExpression =
 New QueryExpression With {
  .EntityName = Publisher.EntityLogicalName,
  .ColumnSet = New ColumnSet("publisherid", "customizationprefix"),
  .Criteria = New FilterExpression()
 }

querySDKSamplePublisher.Criteria.AddCondition("uniquename",
                                              ConditionOperator.Equal,
                                              _crmSdkPublisher.UniqueName)
Dim querySDKSamplePublisherResults As EntityCollection =
 _serviceProxy.RetrieveMultiple(querySDKSamplePublisher)
Dim SDKSamplePublisherResults As Publisher = Nothing

'If it already exists, use it
If querySDKSamplePublisherResults.Entities.Count > 0 Then
 SDKSamplePublisherResults = CType(querySDKSamplePublisherResults.Entities(0), Publisher)
 _crmSdkPublisherId = CType(SDKSamplePublisherResults.PublisherId, Guid)
 _customizationPrefix = SDKSamplePublisherResults.CustomizationPrefix
End If
'If it doesn't exist, create it
If SDKSamplePublisherResults Is Nothing Then
 _crmSdkPublisherId = _serviceProxy.Create(_crmSdkPublisher)
 Console.WriteLine(String.Format("Created publisher: {0}.", _crmSdkPublisher.FriendlyName))
 _customizationPrefix = _crmSdkPublisher.CustomizationPrefix
End If

기본 게시자 검색

이 샘플에서는 기본 게시자를 검색하는 방법을 보여 줍니다. 기본 게시자의 상수 GUID 값은: d21aab71-79e7-11dd-8874-00188b01e34f입니다.


// Retrieve the Default Publisher

//The default publisher has a constant GUID value;
Guid DefaultPublisherId = new Guid("{d21aab71-79e7-11dd-8874-00188b01e34f}");

Publisher DefaultPublisher = (Publisher)_serviceProxy.Retrieve(Publisher.EntityLogicalName, DefaultPublisherId, new ColumnSet(new string[] {"friendlyname" }));

EntityReference DefaultPublisherReference = new EntityReference
{
    Id = DefaultPublisher.Id,
    LogicalName = Publisher.EntityLogicalName,
    Name = DefaultPublisher.FriendlyName
};
Console.WriteLine("Retrieved the {0}.", DefaultPublisherReference.Name);

' Retrieve the Default Publisher

'The default publisher has a constant GUID value;
Dim DefaultPublisherId As New Guid("{d21aab71-79e7-11dd-8874-00188b01e34f}")

Dim DefaultPublisher As Publisher =
 CType(_serviceProxy.Retrieve(Publisher.EntityLogicalName,
                              DefaultPublisherId,
                              New ColumnSet(New String() {"friendlyname"})), 
                             Publisher)

Dim DefaultPublisherReference As EntityReference = New EntityReference With {
 .Id = DefaultPublisher.Id,
 .LogicalName = Publisher.EntityLogicalName,
 .Name = DefaultPublisher.FriendlyName
}
Console.WriteLine("Retrieved the {0}.", DefaultPublisherReference.Name)

솔루션 만들기

다음 샘플에서는 게시자 만들기에서 만든 Microsoft Dynamics CRM SDK 샘플 게시자를 사용하여 비관리형 솔루션을 만드는 방법을 보여 줍니다.

솔루션에는 다음 항목이 필요합니다.

  • 게시자

  • 대화명

  • 고유 이름

  • 버전 번호

변수 _crmSdkPublisherId는 publisherid를 나타내는 GUID 값입니다.

이 샘플에서는 솔루션이 고유 이름을 기반으로 하는 조직에 이미 있는지 여부를 확인합니다. 솔루션이 없는 경우 만들어집니다.SolutionId 값은 솔루션에서 삭제할 수 있도록 캡처됩니다.


// Create a Solution
//Define a solution
Solution solution = new Solution
{
    UniqueName = "samplesolution",
    FriendlyName = "Sample Solution",
    PublisherId = new EntityReference(Publisher.EntityLogicalName, _crmSdkPublisherId),
    Description = "This solution was created by the WorkWithSolutions sample code in the Microsoft Dynamics CRM SDK samples.",
    Version = "1.0"
};

//Check whether it already exists
QueryExpression queryCheckForSampleSolution = new QueryExpression
{
    EntityName = Solution.EntityLogicalName,
    ColumnSet = new ColumnSet(),
    Criteria = new FilterExpression()
};
queryCheckForSampleSolution.Criteria.AddCondition("uniquename", ConditionOperator.Equal, solution.UniqueName);

//Create the solution if it does not already exist.
EntityCollection querySampleSolutionResults = _serviceProxy.RetrieveMultiple(queryCheckForSampleSolution);
Solution SampleSolutionResults = null;
if (querySampleSolutionResults.Entities.Count > 0)
{
    SampleSolutionResults = (Solution)querySampleSolutionResults.Entities[0];
    _solutionsSampleSolutionId = (Guid)SampleSolutionResults.SolutionId;
}
if (SampleSolutionResults == null)
{
    _solutionsSampleSolutionId = _serviceProxy.Create(solution);
}

' Create a Solution
'Define a solution
Dim solution As Solution =
 New Solution With {
  .UniqueName = "samplesolution",
  .FriendlyName = "Sample Solution",
  .PublisherId = New EntityReference(Publisher.EntityLogicalName, _crmSdkPublisherId),
  .Description = "This solution was created by the WorkWithSolutions sample code in the Microsoft Dynamics CRM SDK samples.",
  .Version = "1.0"
 }

'Check whether it already exists
Dim queryCheckForSampleSolution As QueryExpression =
 New QueryExpression With {
  .EntityName = solution.EntityLogicalName,
  .ColumnSet = New ColumnSet(),
  .Criteria = New FilterExpression()
 }
queryCheckForSampleSolution.Criteria.AddCondition("uniquename",
                                                  ConditionOperator.Equal,
                                                  solution.UniqueName)

'Create the solution if it does not already exist.
Dim querySampleSolutionResults As EntityCollection =
 _serviceProxy.RetrieveMultiple(queryCheckForSampleSolution)
Dim SampleSolutionResults As Solution = Nothing
If querySampleSolutionResults.Entities.Count > 0 Then
 SampleSolutionResults = CType(querySampleSolutionResults.Entities(0), Solution)
 _solutionsSampleSolutionId = CType(SampleSolutionResults.SolutionId, Guid)
End If
If SampleSolutionResults Is Nothing Then
 _solutionsSampleSolutionId = _serviceProxy.Create(solution)
End If

솔루션 검색

특정 솔루션을 검색하려면 솔루션의 UniqueName을 사용할 수 있습니다. 각 조직에는 상수 GUID 값이 FD140AAF-4DF4-11DD-BD17-0019B9312238인 기본 솔루션이 있습니다.

이 샘플에서는 고유 이름이 ”samplesolution”인 솔루션의 데이터를 검색하는 방법을 보여 줍니다. 이 이름의 솔루션이 솔루션 만들기에 만들어집니다.


// Retrieve a solution
String solutionUniqueName = "samplesolution";
QueryExpression querySampleSolution = new QueryExpression
{
    EntityName = Solution.EntityLogicalName,
    ColumnSet = new ColumnSet(new string[] { "publisherid", "installedon", "version", "versionnumber", "friendlyname" }),
    Criteria = new FilterExpression()
};

querySampleSolution.Criteria.AddCondition("uniquename", ConditionOperator.Equal, solutionUniqueName);
Solution SampleSolution = (Solution)_serviceProxy.RetrieveMultiple(querySampleSolution).Entities[0];

' Retrieve a solution
Dim solutionUniqueName As String = "samplesolution"
Dim querySampleSolution As QueryExpression =
 New QueryExpression With {
  .EntityName = solution.EntityLogicalName,
  .ColumnSet = New ColumnSet(New String() {"publisherid",
                                           "installedon",
                                           "version",
                                           "versionnumber",
                                           "friendlyname"}),
  .Criteria = New FilterExpression()
 }

querySampleSolution.Criteria.AddCondition("uniquename", ConditionOperator.Equal, solutionUniqueName)
Dim SampleSolution As Solution =
 CType(_serviceProxy.RetrieveMultiple(querySampleSolution).Entities(0), Solution)

새 솔루션 구성 요소 추가

이 샘플에서는 특정 솔루션에 연결된 솔루션 구성 요소를 만드는 방법을 보여 줍니다. 솔루션 구성 요소를 만들 때 특정 솔루션에 솔루션 구성 요소를 연결하지 않으면 기본 솔루션에만 추가되므로 수동으로 솔루션을 추가하거나 기존 솔루션 구성 요소 추가에 포함된 코드를 사용하여 추가해야 합니다.

이 코드는 새 전역 옵션 집합을 만들고 고유 이름이 _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);

Dim optionSetMetadata As New OptionSetMetadata() With {
 .Name = _globalOptionSetName,
 .DisplayName = New Label("Example Option Set", _languageCode),
 .IsGlobal = True,
 .OptionSetType = OptionSetType.Picklist
}
optionSetMetadata.Options.AddRange(
 {
  New OptionMetadata(New Label("Option 1", _languageCode), 1),
  New OptionMetadata(New Label("Option 2", _languageCode), 2)
 }
)
Dim createOptionSetRequest As CreateOptionSetRequest =
 New CreateOptionSetRequest With {
  .OptionSet = optionSetMetadata
 }

createOptionSetRequest.SolutionUniqueName = _primarySolutionName
_serviceProxy.Execute(createOptionSetRequest)

기존 솔루션 구성 요소 추가

이 샘플에서는 솔루션에 기존 솔루션 구성 요소를 추가하는 방법을 보여 줍니다.

다음 코드는 AddSolutionComponentRequest를 사용하여 Account 엔터티를 솔루션 구성 요소로 비관리형 솔루션에 추가합니다.


// 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);

' Add an existing Solution Component
'Add the Account entity to the solution
Dim retrieveForAddAccountRequest As New RetrieveEntityRequest() With {
 .LogicalName = Account.EntityLogicalName
}
Dim retrieveForAddAccountResponse As RetrieveEntityResponse =
 CType(_serviceProxy.Execute(retrieveForAddAccountRequest), 
  RetrieveEntityResponse)
Dim addReq As New AddSolutionComponentRequest() With {
 .ComponentType = componenttype.Entity,
 .ComponentId = CType(retrieveForAddAccountResponse.EntityMetadata.MetadataId, Guid),
 .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);

' Remove a Solution Component
'Remove the Account entity from the solution
Dim retrieveForRemoveAccountRequest As New RetrieveEntityRequest() With {
 .LogicalName = Account.EntityLogicalName
}
Dim retrieveForRemoveAccountResponse As RetrieveEntityResponse =
 CType(_serviceProxy.Execute(retrieveForRemoveAccountRequest), RetrieveEntityResponse)

Dim removeReq As New RemoveSolutionComponentRequest() With {
 .ComponentId = CType(retrieveForRemoveAccountResponse.EntityMetadata.MetadataId, Guid),
 .ComponentType = componenttype.Entity,
 .SolutionUniqueName = solution.UniqueName
}
_serviceProxy.Execute(removeReq)

솔루션 내보내기 또는 패키지

이 샘플에서는 비관리형 솔루션을 내보내거나 관리형 솔루션을 패키지하는 방법을 보여 줍니다. 코드는 ExportSolutionRequest를 사용하여 비관리형 솔루션을 나타내는 압축 파일을 내보냅니다. 관리형 솔루션을 만드는 옵션은 Managed 속성을 사용하여 설정됩니다. 이 샘플에서는 이름이 samplesolution.zip인 파일을 c:\temp\ 폴더에 저장합니다.


// Export or package a solution
//Export an 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);

' Export or package a solution
'Export an a solution
Dim outputDir As String = "C:\temp\"

Dim exportSolutionRequest As New ExportSolutionRequest()
exportSolutionRequest.Managed = False
exportSolutionRequest.SolutionName = solution.UniqueName

Dim exportSolutionResponse As ExportSolutionResponse =
 CType(_serviceProxy.Execute(exportSolutionRequest), ExportSolutionResponse)

Dim exportXml() As Byte = exportSolutionResponse.ExportSolutionFile
Dim filename As String = solution.UniqueName & ".zip"
File.WriteAllBytes(outputDir & filename, exportXml)

Console.WriteLine("Solution exported to {0}.", outputDir & filename)

솔루션 설치 또는 업그레이드

이 샘플에서는 ImportSolutionRequest 메시지를 사용하여 솔루션을 설치하거나 업그레이드하는 방법을 보여 줍니다.

ImportJob 엔터티를 사용하여 가져오기 성공에 대한 데이터를 캡처할 수 있습니다.

다음 샘플에서는 성공을 추적하지 않고 솔루션을 가져오는 방법을 보여 줍니다.


// Install or Upgrade a Solution                  

byte[] fileBytes = File.ReadAllBytes(ManagedSolutionLocation);

ImportSolutionRequest impSolReq = new ImportSolutionRequest()
{
    CustomizationFile = fileBytes
};

_serviceProxy.Execute(impSolReq);

Console.WriteLine("Imported Solution from {0}", ManagedSolutionLocation);

' Install or Upgrade a Solution                  

Dim fileBytes() As Byte = File.ReadAllBytes(ManagedSolutionLocation)

Dim impSolReq As New ImportSolutionRequest() With {
 .CustomizationFile = fileBytes
}

_serviceProxy.Execute(impSolReq)

Console.WriteLine("Imported Solution from {0}", ManagedSolutionLocation)

가져오기 성공 추적

ImportSolutionRequest에 대해 ImportJobId를 지정할 때 해당 값을 사용하여 가져오기 상태에 대해 ImportJob 엔터티에 쿼리할 수 있습니다.

ImportJobIdRetrieveFormattedImportJobResultsRequest 메시지를 사용하여 가져오기 파일을 다운로드하는 데도 사용할 수 있습니다.

가져오기 작업 데이터 검색

다음 샘플에서는 가져오기 작업 레코드와 ImportJob.Data 특성의 콘텐츠를 검색하는 방법을 보여 줍니다.


// Monitor import success
byte[] fileBytesWithMonitoring = File.ReadAllBytes(ManagedSolutionLocation);

ImportSolutionRequest impSolReqWithMonitoring = new ImportSolutionRequest()
{
    CustomizationFile = fileBytes,
    ImportJobId = Guid.NewGuid()
};

_serviceProxy.Execute(impSolReqWithMonitoring);
Console.WriteLine("Imported Solution with Monitoring from {0}", ManagedSolutionLocation);

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);
    }
}

' Monitor import success
Dim fileBytesWithMonitoring() As Byte = File.ReadAllBytes(ManagedSolutionLocation)

Dim impSolReqWithMonitoring As New ImportSolutionRequest() With {
 .CustomizationFile = fileBytes,
 .ImportJobId = Guid.NewGuid()
}

_serviceProxy.Execute(impSolReqWithMonitoring)
Console.WriteLine("Imported Solution with Monitoring from {0}", ManagedSolutionLocation)

Dim job As ImportJob =
 CType(_serviceProxy.Retrieve(ImportJob.EntityLogicalName,
                              impSolReqWithMonitoring.ImportJobId,
                              New ColumnSet(New String() {"data", "solutionname"})), 
                             ImportJob)


Dim doc As New System.Xml.XmlDocument()
doc.LoadXml(job.Data)

Dim ImportedSolutionName As String = doc.SelectSingleNode("//solutionManifest/UniqueName").InnerText
Dim SolutionImportResult As String = 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.
Dim optionSets As System.Xml.XmlNodeList = doc.SelectNodes("//optionSets/optionSet")
For Each node As System.Xml.XmlNode In optionSets
 Dim OptionSetName As String = node.Attributes("LocalizedName").Value
 Dim result As String = node.FirstChild.Attributes("result").Value

 If result = "success" Then
  Console.WriteLine("{0} result: {1}", OptionSetName, result)
 Else
  Dim errorCode As String = node.FirstChild.Attributes("errorcode").Value
  Dim errorText As String = node.FirstChild.Attributes("errortext").Value

  Console.WriteLine("{0} result: {1} Code: {2} Description: {3}", OptionSetName, result, errorCode, errorText)
 End If
Next node

Data 속성의 콘텐츠는 XML 파일을 나타내는 문자열입니다. 다음은 이 샘플의 코드를 사용하여 캡처한 샘플입니다. 이 관리형 솔루션에는 sample_tempsampleglobaloptionsetname이라는 단일 전역 옵션 집합이 들어 있습니다.

<importexportxml start="634224017519682730"
                 stop="634224017609764033"
                 progress="80"
                 processed="true">
 <solutionManifests>
  <solutionManifest languagecode="1033"
                    id="samplesolutionforImport"
                    LocalizedName="Sample Solution for Import"
                    processed="true">
   <UniqueName>samplesolutionforImport</UniqueName>
   <LocalizedNames>
    <LocalizedName description="Sample Solution for Import"
                   languagecode="1033" />
   </LocalizedNames>
   <Descriptions>
    <Description description="This solution was created by the WorkWithSolutions sample code in the Microsoft Dynamics CRM SDK samples."
                 languagecode="1033" />
   </Descriptions>
   <Version>1.0</Version>
   <Managed>1</Managed>
   <Publisher>
    <UniqueName>sdksamples</UniqueName>
    <LocalizedNames>
     <LocalizedName description="Microsoft CRM SDK Samples"
                    languagecode="1033" />
    </LocalizedNames>
    <Descriptions>
     <Description description="This publisher was created with samples from the Microsoft Dynamics CRM SDK"
                  languagecode="1033" />
    </Descriptions>
    <EMailAddress>someone@microsoft.com</EMailAddress>
    <SupportingWebsiteUrl>https://msdn.microsoft.com/en-us/dynamics/crm/default.aspx</SupportingWebsiteUrl>
    <Addresses>
     <Address>
      <City />
      <Country />
      <Line1 />
      <Line2 />
      <PostalCode />
      <StateOrProvince />
      <Telephone1 />
     </Address>
    </Addresses>
   </Publisher>
   <results />
   <result result="success"
           errorcode="0"
           errortext=""
           datetime="20:49:12.08"
           datetimeticks="634224269520845122" />
  </solutionManifest>
 </solutionManifests>
 <upgradeSolutionPackageInformation>
  <upgradeRequired>0</upgradeRequired>
  <upgradeValid>1</upgradeValid>
  <fileVersion>5.0.9669.0</fileVersion>
  <currentVersion>5.0.9669.0</currentVersion>
  <fileSku>OnPremise</fileSku>
  <currentSku>OnPremise</currentSku>
 </upgradeSolutionPackageInformation>
 <entities />
 <nodes />
 <settings />
 <dashboards />
 <securityroles />
 <workflows />
 <templates />
 <optionSets>
  <optionSet id="sample_tempsampleglobaloptionsetname"
             LocalizedName="Example Option Set"
             Description=""
             processed="true">
   <result result="success"
           errorcode="0"
           errortext=""
           datetime="20:49:16.10"
           datetimeticks="634224269561025400" />
  </optionSet>
 </optionSets>
 <ConnectionRoles />
 <SolutionPluginAssemblies />
 <SdkMessageProcessingSteps />
 <ServiceEndpoints />
 <webResources />
 <reports />
 <FieldSecurityProfiles />
 <languages>
  <language>
   <result result="success"
           errorcode="0"
           errortext=""
           datetime="20:49:12.00"
           datetimeticks="634224269520092986" />
  </language>
 </languages>
 <entitySubhandlers />
 <publishes>
  <publish processed="false" />
 </publishes>
 <rootComponents>
  <rootComponent processed="true">
   <result result="success"
           errorcode="0"
           errortext=""
           datetime="20:49:20.83"
           datetimeticks="634224269608387238" />
  </rootComponent>
 </rootComponents>
 <dependencies>
  <dependency processed="true">
   <result result="success"
           errorcode="0"
           errortext=""
           datetime="20:49:20.97"
           datetimeticks="634224269609715208" />
  </dependency>
 </dependencies>
</importexportxml>

솔루션 삭제

이 샘플에서는 솔루션을 삭제하는 방법을 보여 줍니다. 다음 샘플에서는 솔루션 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);

' Delete a solution

Dim queryImportedSolution As QueryExpression =
 New QueryExpression With {
  .EntityName = solution.EntityLogicalName,
  .ColumnSet = New ColumnSet(New String() {"solutionid", "friendlyname"}),
  .Criteria = New FilterExpression()
 }


queryImportedSolution.Criteria.AddCondition("uniquename", ConditionOperator.Equal, ImportedSolutionName)

Dim ImportedSolution As Solution =
 CType(_serviceProxy.RetrieveMultiple(queryImportedSolution).Entities(0), Solution)

_serviceProxy.Delete(solution.EntityLogicalName, CType(ImportedSolution.SolutionId, Guid))

Console.WriteLine("Deleted the {0} solution.", ImportedSolution.FriendlyName)

솔루션 종속성 검색

이 샘플에서는 솔루션 구성 요소 간의 종속성을 보여 주는 보고서를 만드는 방법을 보여 줍니다.

이 코드는 다음 작업을 수행합니다.

  • 솔루션의 모든 구성 요소를 검색합니다.

  • 각 구성 요소에 대한 모든 종속성을 검색합니다.

  • 찾은 각 종속성은 종속성을 설명하는 보고서를 표시합니다.



// 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);
    }
}


' Grab all Solution Components for a solution.
Dim componentQuery As QueryByAttribute =
 New QueryByAttribute With {
  .EntityName = SolutionComponent.EntityLogicalName,
  .ColumnSet = New ColumnSet("componenttype", "objectid",
                             "solutioncomponentid", "solutionid")
 }
componentQuery.Attributes.Add("solutionid")
componentQuery.Values.Add(_primarySolutionId)
' In your code, this value would probably come from another query.

Dim allComponents As IEnumerable(Of SolutionComponent) =
 _serviceProxy.RetrieveMultiple(componentQuery).Entities.Cast(Of SolutionComponent)()

For Each component As SolutionComponent In allComponents
    ' For each solution component, retrieve all dependencies for the component.
    Dim dependentComponentsRequest As RetrieveDependentComponentsRequest =
     New RetrieveDependentComponentsRequest With {
      .ComponentType = component.ComponentType.Value,
      .ObjectId = component.ObjectId.Value
     }
    Dim dependentComponentsResponse As RetrieveDependentComponentsResponse =
     CType(_serviceProxy.Execute(dependentComponentsRequest), 
         RetrieveDependentComponentsResponse)

    ' If there are no dependent components, we can ignore this component.
    If dependentComponentsResponse.EntityCollection.Entities.Any() = False Then
        Continue For
    End If

    ' 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
    For Each d As Dependency In dependentComponentsResponse.EntityCollection.Entities
        DependencyReport(d)
    Next d
Next component

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 compoent 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);
   }

''' <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 Sub DependencyReport(ByVal dependency As Dependency)
    'These strings represent parameters for the message.
    Dim dependentComponentName As String = ""
    Dim dependentComponentTypeName As String = ""
    Dim dependentComponentSolutionName As String = ""
    Dim requiredComponentName As String = ""
    Dim requiredComponentTypeName As String = ""
    Dim requiredComponentSolutionName As String = ""

    'The ComponentType global Option Set contains options for each possible component.
    Dim componentTypeRequest As RetrieveOptionSetRequest =
     New RetrieveOptionSetRequest With {
      .Name = "componenttype"
     }

    Dim componentTypeResponse As RetrieveOptionSetResponse =
     CType(_serviceProxy.Execute(componentTypeRequest), RetrieveOptionSetResponse)
    Dim componentTypeOptionSet As OptionSetMetadata =
     CType(componentTypeResponse.OptionSetMetadata, OptionSetMetadata)
    ' Match the Component type with the option value and get the label value of the option.
    For Each opt As OptionMetadata In componentTypeOptionSet.Options
        If dependency.DependentComponentType.Value = opt.Value Then
            dependentComponentTypeName = opt.Label.UserLocalizedLabel.Label
        End If
        If dependency.RequiredComponentType.Value = opt.Value Then
            requiredComponentTypeName = opt.Label.UserLocalizedLabel.Label
        End If
    Next opt
    'The name or display name of the compoent is retrieved in different ways depending on the component type
    dependentComponentName = getComponentName(dependency.DependentComponentType.Value,
                                              CType(dependency.DependentComponentObjectId, 
                                               Guid))
    requiredComponentName = getComponentName(dependency.RequiredComponentType.Value,
                                             CType(dependency.RequiredComponentObjectId, 
                                              Guid))

    ' Retrieve the friendly name for the dependent solution.
    Dim dependentSolution As Solution =
     CType(_serviceProxy.Retrieve(Solution.EntityLogicalName,
                                  CType(dependency.DependentComponentBaseSolutionId, Guid),
                                  New ColumnSet("friendlyname")), 
                                 Solution)
    dependentComponentSolutionName = dependentSolution.FriendlyName

    ' Retrieve the friendly name for the required solution.
    Dim requiredSolution As Solution =
     CType(_serviceProxy.Retrieve(Solution.EntityLogicalName,
                                  CType(dependency.RequiredComponentBaseSolutionId, 
                                   Guid),
                                  New ColumnSet("friendlyname")), 
                                 Solution)
    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)
End Sub

솔루션 구성 요소 삭제 가능 여부 검색

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);
  }
 }                 
}

' Use the RetrieveOptionSetRequest message to retrieve  
' a global option set by it's name.
Dim retrieveOptionSetRequest_Renamed As RetrieveOptionSetRequest =
    New RetrieveOptionSetRequest With {.Name = _globalOptionSetName}

' Execute the request.
Dim retrieveOptionSetResponse_Renamed As RetrieveOptionSetResponse =
    CType(_serviceProxy.Execute(retrieveOptionSetRequest_Renamed), RetrieveOptionSetResponse)
_globalOptionSetId = retrieveOptionSetResponse_Renamed.OptionSetMetadata.MetadataId
If _globalOptionSetId IsNot Nothing Then
    'Use the global OptionSet MetadataId with the appropriate componenttype
    ' to call RetrieveDependenciesForDeleteRequest
    Dim retrieveDependenciesForDeleteRequest_Renamed As RetrieveDependenciesForDeleteRequest =
        New RetrieveDependenciesForDeleteRequest With
        {
            .ComponentType = CInt(Fix(componenttype.OptionSet)),
            .ObjectId = CType(_globalOptionSetId, Guid)
        }

    Dim retrieveDependenciesForDeleteResponse_Renamed As RetrieveDependenciesForDeleteResponse =
        CType(_serviceProxy.Execute(retrieveDependenciesForDeleteRequest_Renamed), 
            RetrieveDependenciesForDeleteResponse)
    Console.WriteLine("")
    For Each d As Dependency In retrieveDependenciesForDeleteResponse_Renamed _
        .EntityCollection.Entities

        If d.DependentComponentType.Value = 2 Then 'Just testing for Attributes
            Dim attributeLabel As String = ""
            Dim retrieveAttributeRequest_Renamed As RetrieveAttributeRequest =
                New RetrieveAttributeRequest With
                {
                    .MetadataId = CType(d.DependentComponentObjectId, Guid)
                }
            Dim retrieveAttributeResponse_Renamed As RetrieveAttributeResponse =
                CType(_serviceProxy.Execute(retrieveAttributeRequest_Renamed), 
                    RetrieveAttributeResponse)

            Dim attmet As AttributeMetadata = retrieveAttributeResponse_Renamed.AttributeMetadata

            attributeLabel = attmet.DisplayName.UserLocalizedLabel.Label

            Console.WriteLine("An {0} named {1} will prevent deleting the {2} global option set.",
                              CType(d.DependentComponentType.Value, componenttype),
                              attributeLabel, _globalOptionSetName)
        End If
    Next d
End If

참고 항목

솔루션을 사용하여 확장 패키지 및 배포
솔루션 소개
솔루션 개발 계획
솔루션 구성 요소에 대해 종속성 추적
비관리형 솔루션 만들기, 내보내기 또는 가져오기
관리형 솔루션 만들기, 설치 및 업데이트
솔루션 제거 또는 삭제
솔루션 엔터티
샘플: 솔루션 작업
샘플: 솔루션 종속성 검색

© 2017 Microsoft. All rights reserved. 저작권 정보