我最近开始在Execute方法中获取CRM对象,并以单独的方法执行插件/工作流业务逻辑。
这种方法可以改进(或丢弃)吗?
使用LINQ获取工作流的目标记录是否可以接受?
它比输入参数更方便;工作流程也是异步的,不会影响用户体验。
对于插件:
public class AddEmailAttachments : IPlugin
{
private void AddAttachments(Entity target, IOrganizationService service, Context linq)
{
// Business logic
}
/*
* Get all the Objects that we need
* and call AddAttachments
* */
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = null;
IOrganizationServiceFactory factory = null;
IOrganizationService service = null;
Entity target = null;
Context linq = null;
try // and get the services we need
{
context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
service = factory.CreateOrganizationService(context.UserId);
target = (Entity)context.InputParameters["Target"];
linq = new Context(service);
if (service != null && target != null && linq != null)
AddAttachments(target, service, linq);
}
catch (Exception) { }; // this is strict because if this plugin fails then the email will not be created in CRM and disrupt the business process
}
}
对于工作流程:
public class SendCaseNotifications : CodeActivity
{
/* Receives the necessary Objects and
* Sends the email
* */
private void SendNotifications(Incident incident, IOrganizationService service, Email email, Context linq)
{
// Perform business logic
}
/* Get the Objects that are required and call
* the method
* */
protected override void Execute(CodeActivityContext context)
{
IWorkflowContext workflowContext = context.GetExtension<IWorkflowContext>();
IOrganizationServiceFactory factory = context.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = factory.CreateOrganizationService(workflowContext.InitiatingUserId);
Entity target = workflowContext.InputParameters["Target"] as Entity;
Incident incident = null;
Email email = null;
Context linq = new Context(service);
IEnumerable<Incident> incidentQuery = from incidents in linq.IncidentSet where incidents.Id.Equals(target.Id) select incidents;
if (incidentQuery.Any())
incident = incidentQuery.First();
if (incident == null)
throw new InvalidPluginExecutionException("Unable to retrieve Case with id: " + target.Id.ToString() + ". Re-try the operation or contact the system administrator.");
IEnumerable<Email> emailQuery = from emails in linq.EmailSet where emails.Id.Equals(incident.mda_originatingemail.Id) select emails;
if (emailQuery.Any())
email = emailQuery.First();
if (email == null)
throw new InvalidPluginExecutionException("Unable to retrieve Email with id: " + incident.mda_originatingemail.Id.ToString() + ". Re-try the operation or contact the system administrator.");
SendNotifications(incident, service, email, linq);
}
}
我在Execute中尽可能多地进行异常处理,然后将对象传递给执行实际工作的方法 我最近了解到,如果同步插件抛出异常,它可能会影响业务流程。
答案 0 :(得分:2)
1 =&gt;这种方法可以改进(或丢弃)吗?
您可以通过几种方式改进这一点。你可以改进的最大方法是为你的插件和工作流活动创建一个基类,它自动完成上下文,orgservice等所有必要的提取。你甚至可以更进一步,并为Create /创建基类更新/删除/ SetState / etc插件适当地提取输入和输出参数。
其次,如果您想要完整的OO设计,您可以将所有业务逻辑放在单独的类而不是函数中。对于复杂的逻辑,它会更少耦合,更有条理,如果你想进行单元测试,那么它是可测试的。
2 =&gt;使用LINQ获取工作流的目标记录是否可以接受?
我认为问题是使用LINQ检索工作流的当前记录是一种好习惯吗?你是怎么做的没有任何问题。您可以使用LINQ扩展方法FirstOrDefault()
而不是Any()
和First()
。
同样一般来说,Crm Retrieves只返回您需要的列是一种好习惯。虽然您可能没有注意到这一点用于检索一条记录,但如果要检索多条记录,则应该这样做。