Trabajar con soluciones

 

Publicado: enero de 2017

Se aplica a: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online

Este tema muestra las tareas de programación específicas incluidas en Ejemplo: trabajar con soluciones y Ejemplo: detectar las dependencias de solución.

En este tema

Crear un editor

Recuperar el editor predeterminado.

Crear una solución

Recuperar una solución

Agregar un nuevo componente de la solución

Agregar un componente de la solución existente

Quitar un componente de la solución

Exportar o empaquetar una solución

Instalar o actualizar una solución

Eliminar una solución

Detectar dependencias de soluciones

Crear un editor

Cada solución necesita un editor, representado por la entidad Publisher. Una solución no puede usar el editor de Microsoft Corporation pero puede usar el editor Default de la organización o un nuevo editor

Un editor requiere lo siguiente:

  • Un prefijo de personalización

  • Un nombre único

  • Un nombre descriptivo

El siguiente ejemplo primero define un editor y después se asegura de que el editor exista según el nombre único. Si ya existe, puede que el prefijo de personalización haya cambiado, por lo que este ejemplo busca capturar el prefijo actual de personalización. El PublisherId también se captura para poder eliminar el registro del editor. Si no encuentra el editor, se creará un nuevo editor mediante el método IOrganizationService. Método de 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

Recuperar el editor predeterminado.

Este ejemplo muestra cómo recuperar el editor predeterminado. El editor predeterminado tiene un valor de GUID constante: 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)

Crear una solución

El siguiente ejemplo muestra cómo crear una solución no administrada mediante los SDK de Microsoft Dynamics 365 Ejemplos creados en el editor Crear un editor.

Una solución requiere lo siguiente:

  • Un editor

  • Un nombre descriptivo

  • Un nombre único

  • Un número de versión

La variable _crmSdkPublisherId es un valor GUID que representa el valor de publisherid.

Este ejemplo comprueba si la solución ya existe en la organización en función del nombre único. Si la solución no existe, se crea. El valor de SolutionId se captura para que la solución se pueda eliminar.


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

Recuperar una solución

Para recuperar una solución específica puede usar el UniqueName de la solución. Cada organización tendrá una solución predeterminada con un valor de GUID constante: FD140AAF-4DF4-11DD-BD17-0019B9312238.

Este ejemplo muestra cómo recuperar los datos para una solución con el nombre único ”samplesolution”. Se creará una solución con este nombre en Crear una solución.


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

Agregar un nuevo componente de la solución

Este ejemplo muestra cómo crear un componente de la solución que está asociado con una solución específica. Si no asocia el componente de la solución a una solución específica cuando se crea solo se agregará a la solución predeterminada y necesitará agregarlo a una solución manualmente o mediante el código incluido en Agregar un componente de la solución existente.

Este código crea un nuevo conjunto de opciones globales y lo agrega a la solución con un nombre único igual a _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)

Agregar un componente de la solución existente

Este ejemplo muestra cómo agregar un componente de la solución existente a una solución.

El siguiente código usa AddSolutionComponentRequest para agregar la entidad Account como componente de la solución a una solución no administrada.


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

Quitar un componente de la solución

Este ejemplo muestra cómo quitar un componente de la solución de una solución no administrada. El siguiente código usa RemoveSolutionComponentRequest para quitar un componente de la solución de entidad de una solución no administrada. El solution.UniqueName hace referencia a la solución creada en Crear una solución.


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

Exportar o empaquetar una solución

Este ejemplo muestra cómo exportar una solución no administrada o empaquetar una solución administrada. El código usa ExportSolutionRequest para exportar un archivo comprimido que representa una solución no administrada. La opción para crear una solución administrada se configura mediante la propiedad de Managed. Este ejemplo guarda un archivo llamado samplesolution.zip en la carpeta 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)

Instalar o actualizar una solución

Este ejemplo muestra cómo instalar o actualizar una solución con el mensaje de ImportSolutionRequest.

Puede usar la entidad ImportJob para capturar datos acerca del éxito de la importación.

El siguiente ejemplo muestra cómo importar una solución sin hacer seguimiento del éxito.


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

Seguir el éxito de la importación

Cuando especifica un ImportJobId para ImportSolutionRequest, puede usar ese valor para consultar la entidad ImportJob sobre el estado de la importación.

ImportJobId también puede usarse para descargar un archivo de registro de importación mediante el mensaje de RetrieveFormattedImportJobResultsRequest.

Recuperar datos del trabajo de importación

El siguiente ejemplo muestra cómo recuperar el registro del trabajo de importación y el contenido del atributo de 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

El contenido de la propiedad de Data es una cadena que representa un archivo XML. Lo siguiente es un ejemplo capturado mediante el código en este ejemplo. Esta solución administrada contenía un único conjunto de opciones globales llamado 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 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 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>

Eliminar una solución

Este ejemplo muestra cómo eliminar una solución. El siguiente ejemplo muestra cómo recuperar una solución con el uniquename de la solución y después extraer el solutionid de los resultados. Use el solutionid con el método IOrganizationService.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)

Detectar dependencias de soluciones

Este ejemplo muestra cómo crear un informe que muestre las dependencias entre los componentes de la solución.

Este código:

  • Recuperará todos los componentes de una solución.

  • Recuperará todas las dependencias para cada componente.

  • Para cada dependencia encontrada mostrará un informe describiendo la dependencia.



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

El método DependencyReport se encuentra en el siguiente ejemplo de código.

Informe de dependencia

El método de DependencyReport proporciona un mensaje más fácil de usar basándose en la información encontrada en la dependencia.

Nota

En este ejemplo el método se implementa solo parcialmente. Puede enviar mensajes solo para los componentes de la solución de atributo y de conjunto de opciones.


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

Detectar si un componente de la solución se puede eliminar

Use el mensaje de RetrieveDependenciesForDeleteRequest para identificar cualquier otro componente de la solución que pueda evitar que un determinado componente de la solución se elimine. El siguiente ejemplo de código busca atributos que utilicen un conjunto de opciones global conocido. Cualquier atributo que utilice el conjunto de opciones global evitará que el conjunto de opciones global se elimine.


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

Ver también

Empaquetar y distribuir las extensiones con soluciones
Introducción a soluciones
Planear el desarrollo de la solución
Seguimiento de las dependencias de los componentes de la solución
Crear, exportar o importar una solución no administrada
Crear, instalar y actualizar una solución administrada
Desinstalar o eliminar una solución
Entidades de solución
Ejemplo: trabajar con soluciones
Ejemplo: detectar las dependencias de solución

Microsoft Dynamics 365

© 2017 Microsoft. Todos los derechos reservados. Copyright