我正在关注this文章,以更改c#插件中的业务流程流程阶段。我可以将舞台移到下一个阶段,但是当我尝试移回到上一个阶段时收到错误。以下错误是我在Dynamics的UI中收到的。调试插件时,我收到一个FaultException<OrganizationServiceFault>
异常,其中不包含任何信息。为什么会收到错误,如何修改代码以成功返回到业务流程的上一个阶段?
Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: An unexpected error occurred.
Detail: <OrganizationServiceFault xmlns="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ActivityId>5df51362-b7c1-4817-a8d0-de2d63b15c17</ActivityId>
<ErrorCode>-2147220970</ErrorCode>
<ErrorDetails xmlns:a="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<Message>An unexpected error occurred.</Message>
<Timestamp>2018-07-19T18:55:42.6625925Z</Timestamp>
<ExceptionSource i:nil="true" />
<InnerFault>
<ActivityId>5df51362-b7c1-4817-a8d0-de2d63b15c17</ActivityId>
<ErrorCode>-2147220970</ErrorCode>
<ErrorDetails xmlns:a="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<Message>System.NullReferenceException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #0D309052</Message>
<Timestamp>2018-07-19T18:55:42.6625925Z</Timestamp>
<ExceptionSource i:nil="true" />
<InnerFault i:nil="true" />
<OriginalException i:nil="true" />
<TraceText i:nil="true" />
</InnerFault>
<OriginalException i:nil="true" />
<TraceText i:nil="true" />
</OrganizationServiceFault>
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;
Client client = (Client)service.Retrieve(
Client.LogicalName,
new Guid("75FE165F-848B-E811-80F3-005056B33317"),
new ColumnSet(new String[]{
Client.Properties.ClientId
})
);
client.ChangeStage(service);
public void ChangeStage(IOrganizationService service)
{
// Get Process Instances
RetrieveProcessInstancesRequest processInstanceRequest = new RetrieveProcessInstancesRequest
{
EntityId = this.Id,
EntityLogicalName = this.LogicalName
};
RetrieveProcessInstancesResponse processInstanceResponse = (RetrieveProcessInstancesResponse)service.Execute(processInstanceRequest);
// Declare variables to store values returned in response
int processCount = processInstanceResponse.Processes.Entities.Count;
Entity activeProcessInstance = processInstanceResponse.Processes.Entities[0]; // First record is the active process instance
Guid activeProcessInstanceID = activeProcessInstance.Id; // Id of the active process instance, which will be used later to retrieve the active path of the process instance
// Retrieve the active stage ID of in the active process instance
Guid activeStageID = new Guid(activeProcessInstance.Attributes["processstageid"].ToString());
// Retrieve the process stages in the active path of the current process instance
RetrieveActivePathRequest pathReq = new RetrieveActivePathRequest
{
ProcessInstanceId = activeProcessInstanceID
};
RetrieveActivePathResponse pathResp = (RetrieveActivePathResponse)service.Execute(pathReq);
string activeStageName = "";
int activeStagePosition = -1;
Console.WriteLine("\nRetrieved stages in the active path of the process instance:");
for (int i = 0; i < pathResp.ProcessStages.Entities.Count; i++)
{
// Retrieve the active stage name and active stage position based on the activeStageId for the process instance
if (pathResp.ProcessStages.Entities[i].Attributes["processstageid"].ToString() == activeStageID.ToString())
{
activeStageName = pathResp.ProcessStages.Entities[i].Attributes["stagename"].ToString();
activeStagePosition = i;
}
}
// Retrieve the stage ID of the next stage that you want to set as active
activeStageID = (Guid)pathResp.ProcessStages.Entities[activeStagePosition - 1].Attributes["processstageid"];
// Retrieve the process instance record to update its active stage
ColumnSet cols1 = new ColumnSet();
cols1.AddColumn("activestageid");
Entity retrievedProcessInstance = service.Retrieve("ccseq_bpf_clientsetup", activeProcessInstanceID, cols1);
// Set the next stage as the active stage
retrievedProcessInstance["activestageid"] = new EntityReference(ProcessStage.LogicalName, activeStageID);
service.Update(retrievedProcessInstance);
}
我发现了this文章,该文章解释了如何使用Web API更新舞台。当我尝试此方法时,出现错误:
未声明的属性“ activestageid”,仅在负载中具有属性注释,而在负载中未找到属性值。在OData中,只有声明的导航属性和声明的命名流可以表示为没有值的属性。
我尝试了几种“ activestageid”,但都没有成功(ActiveStageId,_activestageid_value)。
根据Arun的反馈,我尝试了以下Web API调用,但均未成功。我从ccseq_bpf_clientsetups表上的BusinessProcessFlowInstanceId中提取的网址(ccseq_bpf_clientsetups(###))中括号内的ID。我从ProcessStageBase表中的ProcessStageId中提取的流程阶段ID
// Attempt 1
PATCH /COHEN/api/data/v8.2/ccseq_bpf_clientsetups(bc892aec-2594-e811-80f4-005056b33317) HTTP/1.1
{ "ActiveStageID@odata.bind": "/processstages(70018854-db7c-4612-915b-2ad7870a8574)"}
// Attempt 2
PATCH /COHEN/api/data/v8.2/ccseq_bpf_clientsetups(bc892aec-2594-e811-80f4-005056b33317) HTTP/1.1
{ "activestageid@odata.bind": "/processstages(70018854-db7c-4612-915b-2ad7870a8574)"}
// Attempt 3
PATCH /COHEN/api/data/v8.2/ccseq_bpf_clientsetups(bc892aec-2594-e811-80f4-005056b33317) HTTP/1.1
{ "ActiveStageId@odata.bind": "/processstages(70018854-db7c-4612-915b-2ad7870a8574)"}
我下载了jLattimer的CRM Rest Builder,并尝试运行他生成的工具中的JavaScript。该代码与我之前编写的代码相同,但不幸的是,该代码无法正常工作。目前,我非常有信心Web API v8.2不支持更改阶段。
答案 0 :(得分:0)
我有一些代码尝试将业务流程流阶段前进,作为自定义工作流步骤(而不是插件)。我已将其张贴在下面。
我看到的区别是:
active path
,我只是获得了该过程的所有可用阶段TraversedPath
属性代码:
var activeInstancesRequest = new RetrieveProcessInstancesRequest
{
EntityId = TargetEntity.Id,
EntityLogicalName = TargetEntity.LogicalName
};
var activeInstancesResponse = (RetrieveProcessInstancesResponse)base.OrgService.Execute(activeInstancesRequest);
var process = activeInstancesResponse.Processes.Entities.Select(x => x.ToEntity<BusinessProcessFlowInstance>()).ToList();
var stages = base.XrmContext.ProcessStageSet
.Where(s => s.ProcessId.Id == process.FirstOrDefault().ProcessId.Id)
.Select(s => new ProcessStage
{
ProcessStageId = s.ProcessStageId,
StageName = s.StageName
})
.ToList();
var targetStage = stages.Where(stage => stage.StageName == targetStageName).FirstOrDefault();
if (targetStage != null)
{
crmWorkflowContext.Trace($"BPF contains target stage (\"{targetStageName}\"). Attempting to update BPF");
// Setting the Traversed Path is necessary for the Business Process Flow to show the active Stage
// If this is not updated then although the new Stage is set as current, the previous Stage remains actively selected
var traversedPath = $"{bpf.TraversedPath},{targetStage.ProcessStageId.Value}";
var update = new BusinessProcessFlowInstance()
{
BusinessProcessFlowInstanceId = bpf.BusinessProcessFlowInstanceId,
ProcessStageId = targetStage.ProcessStageId,
TraversedPath = traversedPath
};
xrmContext.Attach(update);
xrmContext.UpdateObject(update);
}
答案 1 :(得分:0)
我进行了快速测试,能够在香草v9在线组织的Lead to Opportunity Sales Process
中前进/后退。
我只是成功地通过CRM REST构建器的Web API PATCH
请求进行了测试。
发展为提议(向前)
var entity = {};
entity["activestageid@odata.bind"] = "/processstages(3A275C22-FC45-4E89-97FC-41E5EC578743)";
var req = new XMLHttpRequest();
req.open("PATCH", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/leadtoopportunitysalesprocesses(1674DB10-1994-E811-A969-000D3A1A9FA9)", true);
建议发展(向后)
var entity = {};
entity["activestageid@odata.bind"] = "/processstages(BFC9108C-8389-406B-9166-2C3298A2E41F)";
var req = new XMLHttpRequest();
req.open("PATCH", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/leadtoopportunitysalesprocesses(1674DB10-1994-E811-A969-000D3A1A9FA9)", true);
除了在下面需要标记以外,没有其他用途。
不需要
1574DB10-1994-E811-A969-000D3A1A9FA9-leadid
919E14D1-6489-4852-ABD0-A63A6ECAAC5D-processid
f99b4d48-7aad-456e-864a-8e7d543f7495,bfc9108c-8389-406b-9166-2c3298a2e41f-traversedpath
需要
1674DB10-1994-E811-A969-000D3A1A9FA9-businessprocessflowinstanceid
BFC9108C-8389-406B-9166-2C3298A2E41F-activestageid
开发
3A275C22-FC45-4E89-97FC-41E5EC578743-activestageid
建议
更新:
我也在v8中成功测试了以下代码段[在线版本<12>版本1612(8.2.2.2160)(DB 8.2.2.2160)]
实际上,它在没有 traversedpath
的情况下向后/向前移动。
var entity = {};
entity["activestageid@odata.bind"] = "/processstages(BFC9108C-8389-406B-9166-2C3298A2E41F)";
entity.traversedpath = "f99b4d48-7aad-456e-864a-8e7d543f7495,bfc9108c-8389-406b-9166-2c3298a2e41f";
var req = new XMLHttpRequest();
req.open("PATCH", Xrm.Page.context.getClientUrl() + "/api/data/v8.0/leadtoopportunitysalesprocesses(E5B70E69-2094-E811-8145-C4346BDCF2F1)", true);
但是出现Bad request
错误,如下:
entity.activestageid = {
Id: "3A275C22-FC45-4E89-97FC-41E5EC578743",
LogicalName: "processstage"
};
答案 2 :(得分:0)
我遇到了同样的问题。它比您想象的要简单得多。 确定,打开高级查找,选择{您的BPF}。 添加两列查询:{您的实体} {遍历的路径}。
好,因此,请查看实际处于上一阶段(您想返回的阶段)的实体的遍历路径。
使用您的代码,您需要动态分解遍历的路径(.Split(','))或类似的内容...删除最后一个阶段(您当前所在的那个阶段),瞧!您正在用汽油做饭。
如果当前遍历的路径是数组:
string[] currentPath = {"A", "B", "C", "D"};
您之前的路径必须为:
string[] previousPath = {"A", "B", "C"};
在这里,假设“实体”是您检索到的实体,您将可以在代码中完成此操作:
string traversedPath = (string) entity["traversedpath"];
string[] stages = traversedPath.Split(',');
string newPath = "";
//use length - 1 to omit last stage (your current stage)
for (int i = 0; i < stages.Length - 1; i++)
{
if (i != stages.Length - 1)
newPath += stages[i] + ",";
else
newPath += stages[i];
}
entity["processid"] = new Guid("BPF Guid") //may be optional
entity["stageid"] = new Guid("previous stage guid");
entity["traversedpath"] = newPath;
service.Update(entity);
基本上,所遍历的路径不会+ =“您的前一阶段”到所遍历的路径的末尾。它想将遍历路径设置为“您的上一阶段”的原始遍历路径。找出所需阶段的遍历路径是什么,然后将吸盘硬编码成字符串(如果永远都只能进入那个阶段)..或通过.Split(',')方法以编程方式完成代码中的Entity [“ traversedpath”]属性。
请记住,您是从中减去而不是向...添加经过的路径。我花了很多无效的遍历路径错误才能得出这个结论……而且行之有效。祝你好运!