Las personas deben enviar sus elementos de catálogo para su aprobación y un administrador debe aprobarlos antes de que otros puedan usarlos.
Para enviar un artículo al catálogo, necesita:
Un paquete de Package Deployer o soluciones que contiene el elemento que desea enviar.
Un envío de metadatos de documento JSON.
Utilice el comando pac catalog create-submission para obtener un documento JSON de metadatos de envío de ejemplo. Debe editar este documento y se pueden agregar más atributos de envío. Más información: Atributos de envío
Atributos de envío
Antes de poder enviar artículos a un catálogo, debe preparar un documento JSON que describa los artículos que desea enviar.
Los elementos enviados al catálogo deben incluirse en un paquete de Package Deployer. Un paquete del Package Deployer contiene un archivo zip de solución y algunas instrucciones opcionales que se deben aplicar al implementar el paquete. Si no tiene un paquete del Package Deployer, puede crear uno para la solución que contiene sus elementos.
pac catalog submit -p "BuildDemoSubmission.json" -sz "ContosoConference_1_0_0_1_managed.zip"
Creating package for catalog submit request...
Connected to... TestCatalog
Connected as user@domain
Tracking id for this submission is 0e6b119d-80f3-ed11-8849-000d3a0a2d9d
El método estático SubmitCatalogApprovalRequest demuestra el uso del mensaje mspcat_SubmitCatalogApprovalRequest. En este ejemplo se utilizan las clases mspcat_SubmitCatalogApprovalRequestRequest y mspcat_SubmitCatalogApprovalRequestResponse generadas mediante el comando pac modelbuilder build .
Este método de ejemplo devuelve una instancia de la clase mspcat_SubmitCatalogApprovalRequestResponse, que contiene las propiedades CertificationRequestId y AsyncOperationId que puede usar para comprobar el estado del envío.
El mensaje mspcat_SubmitCatalogApprovalRequest requiere que la propiedad packageFile de CatalogItemDefinition del archivo JSON de envío especifique una URL para descargar un archivo de paquete del Package Deployer.
/// <summary>
/// Submits a Catalog item for approval
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance.</param>
/// <param name="pathToSubmissionFile">The location of the submission file</param>
/// <returns>
/// mspcat_SubmitCatalogApprovalRequestResponse contains AsyncOperationId
/// and CertificationRequestId
/// </returns>
static mspcat_SubmitCatalogApprovalRequestResponse SubmitCatalogApprovalRequest(
IOrganizationService service,
FileInfo pathToSubmissionFile)
{
byte[] fileBytes = File.ReadAllBytes(pathToSubmissionFile.FullName);
string encodedSubmissionFile = Convert.ToBase64String(fileBytes);
var request = new mspcat_SubmitCatalogApprovalRequestRequest
{
EncodedApprovalRequest = encodedSubmissionFile
};
return (mspcat_SubmitCatalogApprovalRequestResponse)service.Execute(request);
}
La siguiente función PowerShell SubmitCatalogApprovalRequest muestra cómo utilizar el mensaje mspcat_SubmitCatalogApprovalRequest.
Los resultados devueltos son una instancia del mspcat_SubmitCatalogApprovalRequestResponse tipo complejo, que contiene CertificationRequestId y AsyncOperationId propiedades que puede usar para comprobar el estado del envío.
El mensaje mspcat_SubmitCatalogApprovalRequest requiere que la propiedad packageFile de CatalogItemDefinition del archivo JSON de envío especifique una URL para descargar un archivo de paquete del Package Deployer.
Esta función depende de los valores $baseURI y $baseHeaders establecidos mediante la función Connect, tal y como se describe en Crear una función Connect.
Crear un paquete de Package Deployer a partir de una solución no gestionada
Cuando se utiliza el mensaje mspcat_SubmitCatalogApprovalRequest con el SDK para .NET o Web API como se describe en Enviar elementos al catálogo, el archivo JSON de envío debe incluir una propiedad packageFileCatalogItemDefinition establecida para especificar una URL en el filesaslink para descargar un archivo de paquete de Package Deployer. No necesita hacer esto con el comando pac catalog submit porque lo hace por usted.
Esta dirección URL puede representar cualquier lugar en el que Dataverse pueda descargar un archivo sin ninguna credencial, pero no se recomienda colocar los archivos en una ubicación de descarga pública. En su lugar, puede usar la tabla del almacén de envío de paquetes (mspcat_PackageStore) para generar un paquete de Package Deployer usando una solución no administrada de cualquier ambiente en su inquilino. Este proceso genera un registro en esta tabla que contiene un paquete en la columna de archivo PackageFile (mspcat_PackageFile). A continuación, puede usar el GetFileSasUrl mensaje para obtener una dirección URL de firma de acceso compartido (SAS) para habilitar la descarga anónima del archivo en el plazo de 1 hora. Dado que la dirección URL solo es válida dentro de una hora, este proceso debe automatizarse para que el acceso para descargar el archivo no caduque.
El método estático CatalogItemFromSolution muestra cómo crear un elemento de catálogo a partir de una solución siguiendo los pasos descritos en Proceso. El catalogItemSubmissionJsonString parámetro de esta función no debe tener una packageFile propiedad establecida, ya que esta función la agrega.
/// <summary>
/// Processes a solution and returns the catalog item ID
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance</param>
/// <param name="solutionName">The name of the solution</param>
/// <param name="solutionUniqueName">The unique name of the solution</param>
/// <param name="catalogItemSubmissionJsonString">The string containing the submission json file</param>
/// <returns>Catalog Item ID</returns>
/// <exception cref="Exception"></exception>
static string CatalogItemFromSolution(
IOrganizationService service,
string solutionName,
string solutionUniqueName,
string catalogItemSubmissionJsonString
)
{
Entity packageStoreRecord = new("mspcat_packagestore")
{
Attributes = {
{"mspcat_name", solutionName},
{"mspcat_solutionuniquename", solutionUniqueName},
{"mspcat_intendeddeploymenttype", new OptionSetValue(526430000)}, // Standard
{"mspcat_operation", new OptionSetValue(958090001)} //Create Package
}
};
Guid packageStoreRecordId = service.Create(packageStoreRecord);
Console.WriteLine($"Created package store record with ID {packageStoreRecordId}");
packageStoreRecord.Attributes.Clear(); //Don't send values again
packageStoreRecord.Id = packageStoreRecordId;
int statusCodeValue = 958090004; // Submitted
string statusReason; // Set in the loop
packageStoreRecord["statuscode"] = new OptionSetValue(statusCodeValue);
service.Update(packageStoreRecord); //Set status to Submitted
Console.WriteLine("Updated package store record status to Submitted");
// Columns to retrieve while polling the package store record
ColumnSet packageStoreColumns = new("statuscode");
do
{
Task.Delay(10000).Wait(); //Wait 10 seconds between polling
// Retrieve the record
packageStoreRecord = service.Retrieve(
"mspcat_packagestore",
packageStoreRecord.Id,
packageStoreColumns);
// Get the status code value
statusCodeValue = packageStoreRecord
.GetAttributeValue<OptionSetValue>("statuscode").Value;
statusReason = packageStoreRecord
.FormattedValues["statuscode"];
Console.WriteLine($" - Package store record status is {statusReason}");
// Continue while statusCodeValue is Submitted, Pending, or Running
} while (statusCodeValue.Equals(958090004) ||
statusCodeValue.Equals(1) ||
statusCodeValue.Equals(958090000));
// If it isn't Completed, throw an exception
if (!statusCodeValue.Equals(958090001))
{
statusReason = packageStoreRecord
.FormattedValues["statuscode"];
// 958090002 is 'Failed'
throw new Exception($"Package submission {statusReason}");
}
Console.WriteLine($"Package submission {statusReason}");
// If successful, retrieve the details about the file to download
GetFileSasUrlRequest getFileSasUrlRequest = new()
{
Target = new EntityReference("mspcat_packagestore", packageStoreRecord.Id),
FileAttributeName = "mspcat_packagefile"
};
var getFileSasUrlResponse = (GetFileSasUrlResponse)service
.Execute(getFileSasUrlRequest);
FileSasUrlResponse getFileSasUrlResponseResult = getFileSasUrlResponse.Result;
Console.WriteLine($"Retrieved SAS URL for {getFileSasUrlResponseResult.FileName}");
// Add the packageFile to the catalog item submission
var catalogItemSubmissionJsonObject = JsonNode.Parse(catalogItemSubmissionJsonString).AsObject();
var packageFile = new JsonObject
{
["name"] = getFileSasUrlResponseResult.FileName,
["filesaslink"] = getFileSasUrlResponseResult.SasUrl
};
// Add the packageFile to the catalog item submission
catalogItemSubmissionJsonObject["catalogItemDefinition"]["packageFile"] = packageFile;
catalogItemSubmissionJsonString = catalogItemSubmissionJsonObject.ToJsonString();
string encodedSubmissionJson = Convert
.ToBase64String(Encoding.UTF8.GetBytes(catalogItemSubmissionJsonString));
var submitCatalogApprovalRequest = new mspcat_SubmitCatalogApprovalRequestRequest
{
EncodedApprovalRequest = encodedSubmissionJson
};
var submitCatalogApprovalResponse = (mspcat_SubmitCatalogApprovalRequestResponse)service
.Execute(submitCatalogApprovalRequest);
Guid certificationRequestId = submitCatalogApprovalResponse.CertificationRequestId;
Console.WriteLine($"Submitted catalog approval request with ID {certificationRequestId}");
// Approval must be in either InProgress or Submitted to be processed
// Columns to retrieve while polling the certification request record
ColumnSet certificationRequestColumns = new("statuscode", "mspcat_application");
Entity certificationRequestRecord;
do
{
Task.Delay(10000).Wait(); //Wait 10 seconds between polling
// Retrieve the record
certificationRequestRecord = service.Retrieve(
"mspcat_certificationrequest",
certificationRequestId,
certificationRequestColumns);
// Get the status code value
statusCodeValue = certificationRequestRecord
.GetAttributeValue<OptionSetValue>("statuscode").Value;
statusReason = packageStoreRecord
.FormattedValues["statuscode"];
Console.WriteLine($" - Approval Request status is {statusReason}");
// Continue while statusCodeValue is:
} while (statusCodeValue.Equals(526430002) || // Waiting On Submitter,
statusCodeValue.Equals(526430003) || // Pending Deployment,
statusCodeValue.Equals(526430008) || // Draft
statusCodeValue.Equals(526430009)); // Processing
// If it isn't Submitted or InProgress, throw an exception
if (!(statusCodeValue.Equals(1) || statusCodeValue.Equals(526430001)))
{
string statusreason = certificationRequestRecord
.FormattedValues["statuscode"];
throw new Exception($"Certification request {statusreason}");
}
// Approve the request
mspcat_ResolveApprovalRequest resolveApprovalRequest = new()
{
Target = new EntityReference("mspcat_certificationrequest", certificationRequestId),
requestsuccess = true, //Approve the request
message = "Approved by CatalogItemFromSolution function"
};
// mspcat_ResolveApprovalResponse has no properties to return
service.Execute(resolveApprovalRequest);
Console.WriteLine("Approved the certification request");
// Get the Catalog Item
EntityReference catalogItemReference = certificationRequestRecord
.GetAttributeValue<EntityReference>("mspcat_application");
Entity catalogItem = service.Retrieve(
"mspcat_applications",
catalogItemReference.Id,
new ColumnSet("mspcat_tpsid"));
string tpsid = catalogItem.GetAttributeValue<string>("mspcat_tpsid");
Console.WriteLine($"Returning Catalog Item ID: {tpsid}");
return tpsid;
}
Output
El resultado de esta función deberá ser similar a esto:
Created package store record with ID 46f662aa-2137-ef11-8409-6045bdd3aec3
Updated package store record status to Submitted
- Package store record status is Submitted
- Package store record status is Pending
- Package store record status is Running
- Package store record status is Running
- Package store record status is Completed
Package submission Completed
Retrieved SAS URL for <solutionName>_1_0_0_0.zip
Submitted catalog approval request with ID b932c7c8-2137-ef11-8409-6045bdd3aec3
- Approval Request status is Completed
Approved the certification request
Returning Catalog Item ID: <solutionUniqueName>
Esta New-CatalogItemFromSolution función de PowerShell muestra cómo crear un elemento de catálogo a partir de una solución siguiendo los pasos descritos en Proceso. El catalogItemSubmissionJsonString parámetro de esta función no debe tener una packageFile propiedad establecida, ya que esta función la agrega.
Esta función PowerShell New-CatalogItemFromSolution depende de las variables y funciones siguientes:
Los valores $baseURI y $baseHeaders establecidos mediante la función Connect, tal y como se describe en Crear una función Connect.
.SYNOPSIS
Creates a new catalog item from a solution and submits it for approval.
.DESCRIPTION
The `New-CatalogItemFromSolution` function automates the process of creating a new catalog item from a specified solution and submitting it for approval. It performs the following steps:
1. Validates the existence of the solution.
2. Creates a package store record.
3. Submits the package for approval.
4. Monitors the approval status.
5. Retrieves the SAS URL for the package file.
6. Submits the catalog item for certification.
.PARAMETER solutionName
The name of the solution.
.PARAMETER solutionUniqueName
The unique name of the solution.
.PARAMETER catalogItemSubmissionJsonString
The JSON string containing the catalog item submission details.
.EXAMPLE
New-CatalogItemFromSolution `
-solutionName "MySolution" `
-solutionUniqueName "my_solution" `
-catalogItemSubmissionJsonString '{"catalogItemDefinition":{...}}'
This example creates a new catalog item from the solution named "MySolution" with the unique name "my_solution" and submits it for approval using the provided JSON string.
.NOTES
Ensure that the `Get-Records`, `New-Record`, `Update-Record`, `Get-Record`, and `Get-FileSasUrl` functions are defined and accessible in your environment.
The function uses specific status codes and operations that should be defined in your system.
function New-CatalogItemFromSolution {
param(
[Parameter(Mandatory)]
[string]
$solutionName,
[Parameter(Mandatory)]
[string]
$solutionUniqueName,
[Parameter(Mandatory)]
[string]
$catalogItemSubmissionJsonString
)
$statusCodeLabelName = 'statuscode@OData.Community.Display.V1.FormattedValue'
$solutionQuery = "?`$filter=uniquename eq '$solutionUniqueName'&`$select=solutionid"
$solutionCollection = (Get-Records `
-setName 'solutions' `
-query $solutionQuery).value
if (!$solutionCollection.Count -eq 1) {
throw "Solution with unique name $solutionUniqueName does not exist"
}
$packageStoreRecord = @{
mspcat_name = $solutionName
mspcat_solutionuniquename = $solutionUniqueName
mspcat_intendeddeploymenttype = 526430000 # Standard
mspcat_operation = 958090001 # Create Package
}
$packageId = New-Record `
-setName 'mspcat_packagestores' `
-body $packageStoreRecord
Write-Host ('Created package store record with ID ' + $packageId)
# Set statuscode to Submitted
$packageStoreRecord = @{
statuscode = 958090004
}
Update-Record `
-setName 'mspcat_packagestores' `
-id $packageId `
-body $packageStoreRecord | Out-Null
Write-Host 'Updated package store record status to Submitted'
do {
Start-Sleep -Seconds 10
$packageStore = Get-Record `
-setName 'mspcat_packagestores' `
-id $packageId `
-query '?$select=statuscode,mspcat_processingmessage'
$statusCodeValue = $packageStore.statuscode
$statusCodeLabel = $packageStore.$statusCodeLabelName
Write-Host (' - Package store record status is ' + $statusCodeLabel)
} while ($statusCodeValue -eq 958090004 -or # Submitted
$statusCodeValue -eq 1 -or # Pending
$statusCodeValue -eq 958090000) # Running
if ($statusCodeValue -ne 958090001) {
# 958090002 is 'Failed'
throw "Package submission $statusCodeLabel"
}
# If successful, retrieve the details about the file to download
$fileSasUrlResponse = Get-FileSasUrl `
-setName 'mspcat_packagestores' `
-id $packageId `
-columnName 'mspcat_packagefile'
Write-Host ('Retrieved SAS URL for ' + $fileSasUrlResponse.FileName)
$catalogItemSubmission = $catalogItemSubmissionJsonString | ConvertFrom-Json
$packageFile = @{
name = $fileSasUrlResponse.FileName
filesaslink = $fileSasUrlResponse.SasUrl
}
$catalogItemSubmission.catalogItemDefinition.packageFile = $packageFile
$catalogItemSubmissionJsonString = $catalogItemSubmission | ConvertTo-Json -Depth 10
$encodedCatalogItemSubmission = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($catalogItemSubmissionJsonString))
$body = @{
EncodedApprovalRequest = $encodedCatalogItemSubmission
} | ConvertTo-Json
$postHeaders = $baseHeaders.Clone()
$postHeaders.Add('Content-Type', 'application/json')
$results = Invoke-RestMethod `
-Method Post `
-Uri ($baseURI + 'mspcat_SubmitCatalogApprovalRequest') `
-Headers $postHeaders `
-Body $body
$certificationRequestId = $results.CertificationRequestId
Write-Host ('Submitted catalog approval request with ID ' + $certificationRequestId)
# Approval must be in either InProgress or Submitted to be processed
do {
Start-Sleep -Seconds 10
# Retrieve the record
$approvalRequestRecord = Get-Record `
-setName 'mspcat_certificationrequests' `
-id $certificationRequestId `
-query '?$select=statuscode'
# Get the status code value
$statusCodeValue = $approvalRequestRecord.statuscode
$statusCodeLabel = $approvalRequestRecord.$statusCodeLabelName
Write-Host (' - Approval request status is ' + $statusCodeLabel)
} while ($statusCodeValue -eq 526430002 -or # Waiting On Submitter
$statusCodeValue -eq 526430003 -or # Pending Deployment
$statusCodeValue -eq 526430008 -or # Draft
$statusCodeValue -eq 526430009) # Processing
# If statuscode isn't Submitted or InProgress, throw an exception
if (!($statusCodeValue -eq 1 -or $statusCodeValue -eq 526430001)) {
throw "Certification request $statusCodeLabel"
}
# Approve the request
ResolveApproval `
-certificationRequestId $certificationRequestId `
-requestsuccess $true `
-message 'Approved by script'
Write-Host 'Approved the certification request'
# Get the Catalog Item
$query = '?$select=mspcat_certificationrequestid'
$query += '&$expand=mspcat_Application($select=mspcat_tpsid)'
$approvalRequestRecord = Get-Record `
-setName 'mspcat_certificationrequests' `
-id $certificationRequestId `
-query $query
$tpsid = $approvalRequestRecord.mspcat_Application.mspcat_tpsid
Write-Host ('Returning Catalog Item ID:' + $tpsid)
return $tpsid
}
Output
El resultado de esta función deberá ser similar a esto:
Created package store record with ID 46f662aa-2137-ef11-8409-6045bdd3aec3
Updated package store record status to Submitted
- Package store record status is Submitted
- Package store record status is Pending
- Package store record status is Running
- Package store record status is Running
- Package store record status is Completed
Package submission Completed
Retrieved SAS URL for <solutionName>_1_0_0_0.zip
Submitted catalog approval request with ID b932c7c8-2137-ef11-8409-6045bdd3aec3
- Approval Request status is Completed
Approved the certification request
Returning Catalog Item ID: <solutionUniqueName>
Utilice el comando pac catalog status para comprobar el estado de los envíos de catálogos.
pac catalog status --tracking-id 0e6b119d-80f3-ed11-8849-000d3a0a2d9d --type submit
Connected to... TestCatalog
Connected as user@domain
Status of the Submit request: Submitted
El siguiente método estático GetApprovalRequest recupera las columnas seleccionadas de la tabla Approval Request (mspcat_certificationrequest) para el elemento en el que el parámetro trackingId coincide con la clave principal del registro.
La siguiente Get-ApprovalRequest función de PowerShell recupera las columnas seleccionadas de la tabla Solicitud de aprobación (mspcat_certificationrequest) para el elemento donde el $trackingId parámetro coincide con la clave principal del registro.
No hay ningún comando PAC CLI para esta operación.
Este método estático ResolveApproval muestra cómo resolver una solicitud de envío de un catálogo mediante el mensaje mspcat_ResolveApproval. En este ejemplo se utiliza la clase mspcat_ResolveApprovalRequest generada mediante el comando pac modelbuilder build.
/// <summary>
/// Resolves a catalog submission approval
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance.</param>
/// <param name="certificationRequestId">The ID of the certification request.</param>
/// <param name="requestsuccess">The decision to approve or reject the request.</param>
/// <param name="message">Information for the submitter about the resolution</param>
static void ResolveApproval(
IOrganizationService service,
Guid certificationRequestId,
bool requestsuccess,
string message)
{
mspcat_ResolveApprovalRequest request = new()
{
Target = new EntityReference("mspcat_certificationrequest", certificationRequestId),
requestsuccess = requestsuccess,
message = message
};
// mspcat_ResolveApprovalResponse has no properties to return
service.Execute(request);
}
Esta función PowerShell ResolveApproval muestra cómo resolver una solicitud de envío de catálogo mediante la acción mspcat_ResolveApproval.
Esta función depende de los valores $baseURI y $baseHeaders establecidos mediante la función Connect, tal y como se describe en Crear una función Connect.
<#
.SYNOPSIS
This function resolves an approval request.
.DESCRIPTION
mspcat_ResolveApproval is an action bound to the mspcat_certificationrequests table.
.PARAMETER certificationRequestId
This is a mandatory GUID parameter that represents the ID of the certification request.
.PARAMETER requestsuccess
This is a mandatory Boolean parameter that indicates the decision to approve or reject the request..
.PARAMETER message
This is a mandatory string parameter that contains information for the submitter about the resolution.
.EXAMPLE
ResolveApproval `
-certificationRequestId "<Guid>" `
-requestsuccess $true `
-message "Request processed successfully."
.NOTES
The function does not return any value.
Any output from the Invoke-RestMethod cmdlet is sent to Out-Null.
#>
function ResolveApproval {
param (
[Parameter(Mandatory)]
[guid]
$certificationRequestId,
[Parameter(Mandatory)]
[bool]
$requestsuccess,
[Parameter(Mandatory)]
[string]
$message
)
$uri = $baseURI + "mspcat_certificationrequests($certificationRequestId)"
$uri += "/Microsoft.Dynamics.CRM.mspcat_ResolveApproval"
$body = @{
requestsuccess = $requestsuccess
message = $message
} | ConvertTo-Json
$postHeaders = $baseHeaders.Clone()
$postHeaders.Add('Content-Type', 'application/json')
Invoke-RestMethod `
-Method Post `
-Uri $uri `
-Headers $postHeaders `
-Body $body | Out-Null
}