サンプル: 有効な状態の遷移を取得する
公開日: 2016年11月
対象: Dynamics CRM 2015
このサンプル コードは、Microsoft Dynamics CRM 2015 および Microsoft Dynamics CRM Online 2015 更新プログラム 向けです。 Microsoft Dynamics CRM SDK パッケージをダウンロードします。 このサンプル コードは、ダウンロード パッケージの次の場所にあります。
SampleCode\CS\Metadata\Attributes\StateModelTransitions.cs
要件
この SDK で提供するサンプル コードを実行するために必要な要件については、「サンプルとヘルパー コードの使用」を参照してください。
使用例
このサンプルは、エンティティのカスタム状態の遷移が定義されているかどうかに関係なく、有効な状態の遷移を取得する方法を示します。
サンプルには、次のタスクがあります:
インシデント エンティティの状態オプションを取得する
各状態のオプションの有効な状態の遷移を取得するサンプルでGetValidStatusOptionsメソッドを使用する
コンソールに有効な遷移オプションを表示する
次の方法で、インシデント エンティティのステータスの遷移が設定されている場合:
有効な状態の遷移はフィルター処理され、次のように、各状態オプションのすべての有効な遷移が表されます。
[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:
このサンプルがインシデント エンティティが適用されたステータスの遷移なしで実行された場合、次のように、各状態のすべての可能な遷移が表されます。
[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
例
サンプルで使用されるGetValidStatusOptions メソッドは、次のようです。
/// <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;
}
例
次は、フル サンプル コードです。
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; }
}
}
関連項目
© 2017 Microsoft. All rights reserved. 著作権