Eksempel: Hente gyldige statusovergange
Udgivet: januar 2017
Gælder for: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online
Denne eksempelkode er for Microsoft Dynamics 365 (online og i det lokale miljø).Hent SDK-pakken til Microsoft Dynamics CRM. Den findes på følgende placering i downloadpakken:
SampleCode\CS\Metadata\Attributes\StateModelTransitions.cs
Krav
Du kan finde flere oplysninger om kravene til kørsel af den eksempelkode, der findes i denne SDK, under Brug eksempel- og hjælpekoden.
Demonstrerer
I dette eksempel vises, hvordan du kan hente gyldige tilstandsovergange, uanset om der er defineret brugerdefinerede tilstandsovergange for objektet.
I eksemplet udføres følgende opgaver:
Henter statusindstillinger for hændelsesobjektet
Bruger en GetValidStatusOptions-metode i til at hente gyldige statusovergange for hver statusindstilling
Viser indstillingerne for gyldig overgang i konsollen
Når statusårsagsovergange for hændelsesobjektet er konfigureret på følgende måde:
Gyldige tilstandsovergange er filtreret, og du kan se følgende, der repræsenterer alle de overgange, der er gyldige for hver statusindstilling.
[In Progress] incident records can transition to:
2 Canceled 1 Canceled
2 Canceled 1 Merged
0 Active 1 On Hold
[On Hold] incident records can transition to:
2 Canceled 2 Canceled
2 Canceled 2 Merged
0 Active 2 Waiting for Details
[Waiting for Details] incident records can transition to:
2 Canceled 3 Canceled
2 Canceled 3 Merged
0 Active 3 Researching
[Researching] incident records can transition to:
2 Canceled 4 Canceled
1 Resolved 4 Information Provided
1 Resolved 4 Problem Solved
2 Canceled 4 Merged
[Problem Solved] incident records can transition to:
2 Canceled 5 Merged
[Information Provided] incident records can transition to:
2 Canceled 1000 Merged
[Canceled] incident records can transition to:
2 Canceled 6 Merged
[Merged] incident records can transition to:
Når dette eksempel køres uden statusårsagsovergange på hændelsesobjektet, kan du se følgende, der repræsenterer alle mulige overgange for hver status.
[Problem Solved] incident records can transition to:
1 Resolved 1000 Information Provided
2 Canceled 6 Canceled
2 Canceled 2000 Merged
0 Active 1 In Progress
0 Active 2 On Hold
0 Active 3 Waiting for Details
0 Active 4 Researching
[Information Provided] incident records can transition to:
1 Resolved 5 Problem Solved
2 Canceled 6 Canceled
2 Canceled 2000 Merged
0 Active 1 In Progress
0 Active 2 On Hold
0 Active 3 Waiting for Details
0 Active 4 Researching
[Canceled] incident records can transition to:
1 Resolved 5 Problem Solved
1 Resolved 1000 Information Provided
2 Canceled 2000 Merged
0 Active 1 In Progress
0 Active 2 On Hold
0 Active 3 Waiting for Details
0 Active 4 Researching
[Merged] incident records can transition to:
1 Resolved 5 Problem Solved
1 Resolved 1000 Information Provided
2 Canceled 6 Canceled
0 Active 1 In Progress
0 Active 2 On Hold
0 Active 3 Waiting for Details
0 Active 4 Researching
[In Progress] incident records can transition to:
1 Resolved 5 Problem Solved
1 Resolved 1000 Information Provided
2 Canceled 6 Canceled
2 Canceled 2000 Merged
0 Active 2 On Hold
0 Active 3 Waiting for Details
0 Active 4 Researching
[On Hold] incident records can transition to:
1 Resolved 5 Problem Solved
1 Resolved 1000 Information Provided
2 Canceled 6 Canceled
2 Canceled 2000 Merged
0 Active 1 In Progress
0 Active 3 Waiting for Details
0 Active 4 Researching
[Waiting for Details] incident records can transition to:
1 Resolved 5 Problem Solved
1 Resolved 1000 Information Provided
2 Canceled 6 Canceled
2 Canceled 2000 Merged
0 Active 1 In Progress
0 Active 2 On Hold
0 Active 4 Researching
[Researching] incident records can transition to:
1 Resolved 5 Problem Solved
1 Resolved 1000 Information Provided
2 Canceled 6 Canceled
2 Canceled 2000 Merged
0 Active 1 In Progress
0 Active 2 On Hold
0 Active 3 Waiting for Details
Eksempel
Følgende er den GetValidStatusOptions-metode, der bruges i eksemplet:
/// <summary>
/// Returns valid status option transitions regardless of whether state transitions are enabled for the entity
/// </summary>
/// <param name="entityLogicalName">The logical name of the entity</param>
/// <param name="currentStatusValue">The current status of the entity instance</param>
/// <returns>A list of StatusOptions that represent the valid transitions</returns>
public List<StatusOption> GetValidStatusOptions(String entityLogicalName, int currentStatusValue)
{
List<StatusOption> validStatusOptions = new List<StatusOption>();
//Check entity Metadata
//Retrieve just one entity definition
MetadataFilterExpression entityFilter = new MetadataFilterExpression(LogicalOperator.And);
entityFilter.Conditions.Add(new MetadataConditionExpression("LogicalName", MetadataConditionOperator.Equals, entityLogicalName));
//Return the attributes and the EnforceStateTransitions property
MetadataPropertiesExpression entityProperties = new MetadataPropertiesExpression(new string[] { "Attributes", "EnforceStateTransitions" });
//Retrieve only State or Status attributes
MetadataFilterExpression attributeFilter = new MetadataFilterExpression(LogicalOperator.Or);
attributeFilter.Conditions.Add(new MetadataConditionExpression("AttributeType", MetadataConditionOperator.Equals, AttributeTypeCode.Status));
attributeFilter.Conditions.Add(new MetadataConditionExpression("AttributeType", MetadataConditionOperator.Equals, AttributeTypeCode.State));
//Retrieve only the OptionSet property of the attributes
MetadataPropertiesExpression attributeProperties = new MetadataPropertiesExpression(new string[] { "OptionSet" });
//Set the query
EntityQueryExpression query = new EntityQueryExpression()
{
Criteria = entityFilter,
Properties = entityProperties,
AttributeQuery = new AttributeQueryExpression() { Criteria = attributeFilter, Properties = attributeProperties }
};
//Retrieve the metadata
RetrieveMetadataChangesRequest request = new RetrieveMetadataChangesRequest() { Query = query };
RetrieveMetadataChangesResponse response = (RetrieveMetadataChangesResponse)_serviceProxy.Execute(request);
//Check the value of EnforceStateTransitions
Boolean? EnforceStateTransitions = response.EntityMetadata[0].EnforceStateTransitions;
//Capture the state and status attributes
StatusAttributeMetadata statusAttribute = new StatusAttributeMetadata();
StateAttributeMetadata stateAttribute = new StateAttributeMetadata();
foreach (AttributeMetadata attributeMetadata in response.EntityMetadata[0].Attributes)
{
switch (attributeMetadata.AttributeType)
{
case AttributeTypeCode.Status:
statusAttribute = (StatusAttributeMetadata)attributeMetadata;
break;
case AttributeTypeCode.State:
stateAttribute = (StateAttributeMetadata)attributeMetadata;
break;
}
}
if (EnforceStateTransitions.HasValue && EnforceStateTransitions.Value == true)
{
//When EnforceStateTransitions is true use the TransitionData to filter the valid options
foreach (StatusOptionMetadata option in statusAttribute.OptionSet.Options)
{
if (option.Value == currentStatusValue)
{
if (option.TransitionData != String.Empty)
{
XDocument transitionData = XDocument.Parse(option.TransitionData);
IEnumerable<XElement> elements = (((XElement)transitionData.FirstNode)).Descendants();
foreach (XElement e in elements)
{
int statusOptionValue = Convert.ToInt32(e.Attribute("tostatusid").Value);
String statusLabel = GetOptionSetLabel(statusAttribute, statusOptionValue);
string stateLabel = String.Empty;
int? stateValue = null;
foreach (StatusOptionMetadata statusOption in statusAttribute.OptionSet.Options)
{
if (statusOption.Value.Value == statusOptionValue)
{
stateValue = statusOption.State.Value;
stateLabel = GetOptionSetLabel(stateAttribute, stateValue.Value);
}
}
validStatusOptions.Add(new StatusOption()
{
StateLabel = stateLabel,
StateValue = stateValue.Value,
StatusLabel = statusLabel,
StatusValue = option.Value.Value
});
}
}
}
}
}
else
{
////When EnforceStateTransitions is false do not filter the available options
foreach (StatusOptionMetadata option in statusAttribute.OptionSet.Options)
{
if (option.Value != currentStatusValue)
{
String statusLabel = "";
try
{
statusLabel = option.Label.UserLocalizedLabel.Label;
}
catch (Exception)
{
statusLabel = option.Label.LocalizedLabels[0].Label;
};
String stateLabel = GetOptionSetLabel(stateAttribute, option.State.Value);
validStatusOptions.Add(new StatusOption()
{
StateLabel = stateLabel,
StateValue = option.State.Value,
StatusLabel = statusLabel,
StatusValue = option.Value.Value
});
}
}
}
return validStatusOptions;
}
Eksempel
Nedenstående er den fulde kode til eksemplet.
using System;
using System.Linq;
using System.Xml.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Xml;
// These namespaces are found in the Microsoft.Xrm.Sdk.dll assembly
// found in the SDK\bin folder.
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Xrm.Sdk.Metadata.Query;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Messages;
// This namespace is found in Microsoft.Crm.Sdk.Proxy.dll assembly
// found in the SDK\bin folder.
using Microsoft.Crm.Sdk.Messages;
namespace Microsoft.Crm.Sdk.Samples
{
class StateModelTransitions
{
#region Class Level Members
/// <summary>
/// Stores the organization service proxy.
/// </summary>
OrganizationServiceProxy _serviceProxy;
#endregion Class Level Members
#region How To Sample Code
/// <summary>
/// Create and configure the organization service proxy.
/// Retrieve status options for the Incident entity
/// Use GetValidStatusOptions to get valid status transitions for each status option
/// </summary>
/// <param name="serverConfig">Contains server connection information.</param>
/// <param name="promptForDelete">When True, the user will be prompted to delete all
/// created entities.</param>
public void Run(ServerConnection.Configuration serverConfig, bool promptForDelete)
{
try
{
// Connect to the Organization service.
// The using statement assures that the service proxy will be properly disposed.
using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri, serverConfig.HomeRealmUri,serverConfig.Credentials, serverConfig.DeviceCredentials))
{
// This statement is required to enable early-bound type support.
_serviceProxy.EnableProxyTypes();
String entityLogicalName = "incident";
// Retrieve status options for the Incident entity
//Retrieve just the incident entity and its attributes
MetadataFilterExpression entityFilter = new MetadataFilterExpression(LogicalOperator.And);
entityFilter.Conditions.Add(new MetadataConditionExpression("LogicalName", MetadataConditionOperator.Equals, entityLogicalName));
MetadataPropertiesExpression entityProperties = new MetadataPropertiesExpression(new string[] { "Attributes" });
//Retrieve just the status attribute and the OptionSet property
MetadataFilterExpression attributeFilter = new MetadataFilterExpression(LogicalOperator.And);
attributeFilter.Conditions.Add(new MetadataConditionExpression("AttributeType", MetadataConditionOperator.Equals, AttributeTypeCode.Status));
MetadataPropertiesExpression attributeProperties = new MetadataPropertiesExpression(new string[] { "OptionSet" });
//Instantiate the entity query
EntityQueryExpression query = new EntityQueryExpression()
{
Criteria = entityFilter,
Properties = entityProperties,
AttributeQuery = new AttributeQueryExpression() { Criteria = attributeFilter, Properties = attributeProperties }
};
//Retrieve the metadata
RetrieveMetadataChangesRequest request = new RetrieveMetadataChangesRequest() { Query = query };
RetrieveMetadataChangesResponse response = (RetrieveMetadataChangesResponse)_serviceProxy.Execute(request);
StatusAttributeMetadata statusAttribute = (StatusAttributeMetadata)response.EntityMetadata[0].Attributes[0];
OptionMetadataCollection statusOptions = statusAttribute.OptionSet.Options;
//Loop through each of the status options
foreach (StatusOptionMetadata option in statusOptions)
{
String StatusOptionLabel = GetOptionSetLabel(statusAttribute, option.Value.Value);
Console.WriteLine("[{0}] {1} records can transition to:", StatusOptionLabel, entityLogicalName);
List<StatusOption> validStatusOptions = GetValidStatusOptions(entityLogicalName, option.Value.Value);
//Loop through each valid transition for the option
foreach (StatusOption opt in validStatusOptions)
{
Console.WriteLine("{0,-3}{1,-10}{2,-5}{3,-10}", opt.StateValue, opt.StateLabel, opt.StatusValue, opt.StatusLabel);
}
Console.WriteLine("");
}
}
}
// Catch any service fault exceptions that Microsoft Dynamics CRM throws.
catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>)
{
// You can handle an exception here or pass it back to the calling method.
throw;
}
}
#endregion How To Sample Code
#region Main
/// <summary>
/// Standard Main() method used by most SDK samples.
/// </summary>
/// <param name="args"></param>
static public void Main(string[] args)
{
try
{
// Obtain the target organization's Web address and client logon
// credentials from the user.
ServerConnection serverConnect = new ServerConnection();
ServerConnection.Configuration config = serverConnect.GetServerConfiguration();
StateModelTransitions app = new StateModelTransitions();
app.Run(config, true);
}
catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine("Timestamp: {0}", ex.Detail.Timestamp);
Console.WriteLine("Code: {0}", ex.Detail.ErrorCode);
Console.WriteLine("Message: {0}", ex.Detail.Message);
Console.WriteLine("Plugin Trace: {0}", ex.Detail.TraceText);
Console.WriteLine("Inner Fault: {0}",
null == ex.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault");
}
catch (System.TimeoutException ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine("Message: {0}", ex.Message);
Console.WriteLine("Stack Trace: {0}", ex.StackTrace);
Console.WriteLine("Inner Fault: {0}",
null == ex.InnerException.Message ? "No Inner Fault" : ex.InnerException.Message);
}
catch (System.Exception ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine(ex.Message);
// Display the details of the inner exception.
if (ex.InnerException != null)
{
Console.WriteLine(ex.InnerException.Message);
FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> fe
= ex.InnerException
as FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>;
if (fe != null)
{
Console.WriteLine("Timestamp: {0}", fe.Detail.Timestamp);
Console.WriteLine("Code: {0}", fe.Detail.ErrorCode);
Console.WriteLine("Message: {0}", fe.Detail.Message);
Console.WriteLine("Plugin Trace: {0}", fe.Detail.TraceText);
Console.WriteLine("Inner Fault: {0}",
null == fe.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault");
}
}
}
// Additional exceptions to catch: SecurityTokenValidationException, ExpiredSecurityTokenException,
// SecurityAccessDeniedException, MessageSecurityException, and SecurityNegotiationException.
finally
{
Console.WriteLine("Press <Enter> to exit.");
Console.ReadLine();
}
}
#endregion Main
#region Methods used in Sample
/// <summary>
/// Returns valid status option transitions regardless of whether state transitions are enabled for the entity
/// </summary>
/// <param name="entityLogicalName">The logical name of the entity</param>
/// <param name="currentStatusValue">The current status of the entity instance</param>
/// <returns>A list of StatusOptions that represent the valid transitions</returns>
public List<StatusOption> GetValidStatusOptions(String entityLogicalName, int currentStatusValue)
{
List<StatusOption> validStatusOptions = new List<StatusOption>();
//Check entity Metadata
//Retrieve just one entity definition
MetadataFilterExpression entityFilter = new MetadataFilterExpression(LogicalOperator.And);
entityFilter.Conditions.Add(new MetadataConditionExpression("LogicalName", MetadataConditionOperator.Equals, entityLogicalName));
//Return the attributes and the EnforceStateTransitions property
MetadataPropertiesExpression entityProperties = new MetadataPropertiesExpression(new string[] { "Attributes", "EnforceStateTransitions" });
//Retrieve only State or Status attributes
MetadataFilterExpression attributeFilter = new MetadataFilterExpression(LogicalOperator.Or);
attributeFilter.Conditions.Add(new MetadataConditionExpression("AttributeType", MetadataConditionOperator.Equals, AttributeTypeCode.Status));
attributeFilter.Conditions.Add(new MetadataConditionExpression("AttributeType", MetadataConditionOperator.Equals, AttributeTypeCode.State));
//Retrieve only the OptionSet property of the attributes
MetadataPropertiesExpression attributeProperties = new MetadataPropertiesExpression(new string[] { "OptionSet" });
//Set the query
EntityQueryExpression query = new EntityQueryExpression()
{
Criteria = entityFilter,
Properties = entityProperties,
AttributeQuery = new AttributeQueryExpression() { Criteria = attributeFilter, Properties = attributeProperties }
};
//Retrieve the metadata
RetrieveMetadataChangesRequest request = new RetrieveMetadataChangesRequest() { Query = query };
RetrieveMetadataChangesResponse response = (RetrieveMetadataChangesResponse)_serviceProxy.Execute(request);
//Check the value of EnforceStateTransitions
Boolean? EnforceStateTransitions = response.EntityMetadata[0].EnforceStateTransitions;
//Capture the state and status attributes
StatusAttributeMetadata statusAttribute = new StatusAttributeMetadata();
StateAttributeMetadata stateAttribute = new StateAttributeMetadata();
foreach (AttributeMetadata attributeMetadata in response.EntityMetadata[0].Attributes)
{
switch (attributeMetadata.AttributeType)
{
case AttributeTypeCode.Status:
statusAttribute = (StatusAttributeMetadata)attributeMetadata;
break;
case AttributeTypeCode.State:
stateAttribute = (StateAttributeMetadata)attributeMetadata;
break;
}
}
if (EnforceStateTransitions.HasValue && EnforceStateTransitions.Value == true)
{
//When EnforceStateTransitions is true use the TransitionData to filter the valid options
foreach (StatusOptionMetadata option in statusAttribute.OptionSet.Options)
{
if (option.Value == currentStatusValue)
{
if (option.TransitionData != String.Empty)
{
XDocument transitionData = XDocument.Parse(option.TransitionData);
IEnumerable<XElement> elements = (((XElement)transitionData.FirstNode)).Descendants();
foreach (XElement e in elements)
{
int statusOptionValue = Convert.ToInt32(e.Attribute("tostatusid").Value);
String statusLabel = GetOptionSetLabel(statusAttribute, statusOptionValue);
string stateLabel = String.Empty;
int? stateValue = null;
foreach (StatusOptionMetadata statusOption in statusAttribute.OptionSet.Options)
{
if (statusOption.Value.Value == statusOptionValue)
{
stateValue = statusOption.State.Value;
stateLabel = GetOptionSetLabel(stateAttribute, stateValue.Value);
}
}
validStatusOptions.Add(new StatusOption()
{
StateLabel = stateLabel,
StateValue = stateValue.Value,
StatusLabel = statusLabel,
StatusValue = option.Value.Value
});
}
}
}
}
}
else
{
////When EnforceStateTransitions is false do not filter the available options
foreach (StatusOptionMetadata option in statusAttribute.OptionSet.Options)
{
if (option.Value != currentStatusValue)
{
String statusLabel = "";
try
{
statusLabel = option.Label.UserLocalizedLabel.Label;
}
catch (Exception)
{
statusLabel = option.Label.LocalizedLabels[0].Label;
};
String stateLabel = GetOptionSetLabel(stateAttribute, option.State.Value);
validStatusOptions.Add(new StatusOption()
{
StateLabel = stateLabel,
StateValue = option.State.Value,
StatusLabel = statusLabel,
StatusValue = option.Value.Value
});
}
}
}
return validStatusOptions;
}
/// <summary>
/// Returns a string representing the label of an option in an optionset
/// </summary>
/// <param name="attribute">The metadata for an an attribute with options</param>
/// <param name="value">The value of the option</param>
/// <returns>The label for the option</returns>
public String GetOptionSetLabel(EnumAttributeMetadata attribute, int value)
{
String label = "";
foreach (OptionMetadata option in attribute.OptionSet.Options)
{
if (option.Value.Value == value)
{
try
{
label = option.Label.UserLocalizedLabel.Label;
}
catch (Exception)
{
label = option.Label.LocalizedLabels[0].Label;
};
}
}
return label;
}
#endregion Methods used in Sample
}
public class StatusOption
{
public int StatusValue { get; set; }
public String StatusLabel { get; set; }
public int StateValue { get; set; }
public String StateLabel { get; set; }
}
}
Se også
Definere brugerdefinerede overgange af tilstandsmodeller
Microsoft Dynamics 365
© 2017 Microsoft. Alle rettigheder forbeholdes. Ophavsret