/// <summary> /// Executes the WorkFlow. /// </summary> /// <param name="crmWorkflowContext">The <see cref="LocalWorkflowContext"/> which contains the /// <param name="executionContext" > <see cref="CodeActivityContext"/> /// </param> /// <remarks> /// For improved performance, Microsoft Dynamics 365 caches WorkFlow instances. /// The WorkFlow's Execute method should be written to be stateless as the constructor /// is not called for every invocation of the WorkFlow. Also, multiple system threads /// could execute the WorkFlow at the same time. All per invocation state information /// is stored in the context. This means that you should not use global variables in WorkFlows. /// </remarks> public override void ExecuteCRMWorkFlowActivity(CodeActivityContext executionContext, LocalWorkflowContext crmWorkflowContext) { if (crmWorkflowContext == null) { throw new ArgumentNullException("crmWorkflowContext"); } try { var tracingService = executionContext.GetExtension <ITracingService>(); var serviceFactory = executionContext.GetExtension <IOrganizationServiceFactory>(); var service = crmWorkflowContext.OrganizationService; var adminService = serviceFactory.CreateOrganizationService(null); tracingService.Trace("In ApplicationCreateFolderInSharePoint with Application Name"); var application = this.Application.Get(executionContext); var azureInterface = new AzureInterface(adminService, service, tracingService); azureInterface.CreateFolder(application); } catch (Exception ex) { throw new InvalidPluginExecutionException("An error occurred in Workflow assembly.", ex); } }
// This custom code activity is no longer used because we found that for files larger than 22MB // calling the custom code activity caused errors. Smaller files work ok. public override void ExecuteCRMWorkFlowActivity(CodeActivityContext executionContext, LocalWorkflowContext crmWorkflowContext) { if (crmWorkflowContext == null) { throw new ArgumentNullException(nameof(crmWorkflowContext)); } try { var tracingService = executionContext.GetExtension <ITracingService>(); var context = executionContext.GetExtension <IWorkflowContext>(); var serviceFactory = executionContext.GetExtension <IOrganizationServiceFactory>(); var service = crmWorkflowContext.OrganizationService; var adminService = serviceFactory.CreateOrganizationService(null); tracingService.Trace("In UploadIndividualAttachmentToSharePoint."); var parentEntityName = Parent_Entity_Name.Get(executionContext); var parentLookupName = Parent_Lookup_Name.Get(executionContext); tracingService.Trace(string.Format("Parent Entity = {0}; Parent Lookup = {1}", parentEntityName, parentLookupName)); var azureInterface = new AzureInterface(adminService, service, tracingService); azureInterface.UploadFile(new EntityReference(context.PrimaryEntityName, context.PrimaryEntityId), parentEntityName, parentLookupName); } catch (Exception ex) { throw new InvalidPluginExecutionException("An error occurred in Workflow assembly.", ex); } }
/// <summary> /// Main entry point for he business logic that the plug-in is to execute. /// </summary> /// <param name="localContext">The <see cref="LocalPluginContext"/> which contains the /// <see cref="IPluginExecutionContext"/>, /// <see cref="IOrganizationService"/> /// and <see cref="ITracingService"/> /// </param> /// <remarks> /// For improved performance, Microsoft Dynamics 365 caches plug-in instances. /// The plug-in's Execute method should be written to be stateless as the constructor /// is not called for every invocation of the plug-in. Also, multiple system threads /// could execute the plug-in at the same time. All per invocation state information /// is stored in the context. This means that you should not use global variables in plug-ins. /// </remarks> protected override void ExecuteCrmPlugin(LocalPluginContext localContext) { if (localContext == null) { throw new InvalidPluginExecutionException("localContext"); } var tracingService = localContext.TracingService; var context = localContext.PluginExecutionContext; var service = localContext.OrganizationService; var serviceFactory = (IOrganizationServiceFactory)localContext.ServiceProvider.GetService(typeof(IOrganizationServiceFactory)); var adminService = serviceFactory.CreateOrganizationService(null); tracingService.Trace("Message = {0}", context.MessageName); // If its a standard Create or Update then we should have an Entity in Target. EntityReference entityReference = null; if (context.InputParameters.Contains(PluginInputParams.Target) && context.InputParameters[PluginInputParams.Target] is Entity) { entityReference = ((Entity)context.InputParameters[PluginInputParams.Target]).ToEntityReference(); } // If plugin is triggered from the Custom Action Message , then we have some custom input parameters. if (context.InputParameters.Contains(PluginInputParams.TargetEntityName) && context.InputParameters.Contains(PluginInputParams.TargetEntityId)) { entityReference = new EntityReference((string)context.InputParameters[PluginInputParams.TargetEntityName], new Guid((string)context.InputParameters[PluginInputParams.TargetEntityId])); } tracingService.Trace("Execution depth = {0};", context.Depth.ToString()); if (entityReference != null) { //var entity = (Entity)context.InputParameters["Target"]; var azureInterface = new AzureInterface(adminService, service, tracingService); // Process the attachment depending on the target entity tracingService.Trace("Start of UploadFile for entity {0}", entityReference.LogicalName); if (entityReference.LogicalName == Annotation.EntityLogicalName || entityReference.LogicalName == ActivityMimeAttachment.EntityLogicalName || entityReference.LogicalName == Email.EntityLogicalName) { // Triggered for Notes if (context.MessageName == PluginMessages.SendFileToSharePoint || context.MessageName == PluginMessages.Update || context.MessageName == PluginMessages.Create) { // Send file to SharePoint azureInterface.UploadFile(entityReference); } } tracingService.Trace("{0} processed successfully", entityReference.LogicalName); } else { tracingService.Trace("No entity or entity reference found in Target"); } }
private void ProcessAttachments() { var azureInterface = new AzureInterface(AdminService, Service, TracingService); var results = Service.GetEmailAndAttachmentsForId(Context.PrimaryEntityId); // Call the plugin to upload the email and all its attachments as files to SharePoint. if (results != null && results.Entities.Count > 0) { var emailUploaded = false; if (results.Entities[0].Contains(Email.Fields.defra_uploadedtosharepoint)) { // annotation and email emailUploaded = results.Entities[0].GetAttributeValue <bool>(Email.Fields.defra_uploadedtosharepoint); } if (!emailUploaded) { TracingService.Trace("Requesting action for Email upload."); azureInterface.SendFileToSharePointActionRequest(Context.PrimaryEntityName, Context.PrimaryEntityId); } else { TracingService.Trace("Email already uploaded to SharePoint"); } // Now process the attachments TracingService.Trace("Processing {0} attachments.", results.Entities.Count.ToString()); foreach (Entity attachment in results.Entities) { var filesize = 0; if (attachment.Contains("attachment.filesize")) { filesize = (int)((AliasedValue)attachment.Attributes["attachment.filesize"]).Value; } var filename = string.Empty; if (attachment.Contains("attachment.filename")) { filename = (string)((AliasedValue)attachment.Attributes["attachment.filename"]).Value; } TracingService.Trace("Attachment Id={0}, filename={1}, size={2}.", attachment.Id.ToString(), filename, filesize.ToString()); if (filesize > 0) { var attachmentId = (Guid)((AliasedValue)attachment.Attributes["attachment.activitymimeattachmentid"]).Value; // Using an action because we don't know how many attachments we'll have. Could take more than process // limit of 2 minutes so using action trigger async plugin. azureInterface.SendFileToSharePointActionRequest(ActivityMimeAttachment.EntityLogicalName, attachmentId); TracingService.Trace("{0} request sent", PluginMessages.SendFileToSharePoint); } else { TracingService.Trace("Attachment has zero filesize. Do not upload.", PluginMessages.SendFileToSharePoint, attachment.Id.ToString()); } } } }
/// <summary> /// Executes the WorkFlow. /// </summary> /// <param name="crmWorkflowContext">The <see cref="LocalWorkflowContext"/> which contains the /// <param name="executionContext" > <see cref="CodeActivityContext"/> /// </param> /// <remarks> /// For improved performance, Microsoft Dynamics 365 caches WorkFlow instances. /// The WorkFlow's Execute method should be written to be stateless as the constructor /// is not called for every invocation of the WorkFlow. Also, multiple system threads /// could execute the WorkFlow at the same time. All per invocation state information /// is stored in the context. This means that you should not use global variables in WorkFlows. /// </remarks> public override void ExecuteCRMWorkFlowActivity(CodeActivityContext executionContext, LocalWorkflowContext crmWorkflowContext) { if (crmWorkflowContext == null) { throw new ArgumentNullException(nameof(crmWorkflowContext)); } try { var tracingService = executionContext.GetExtension <ITracingService>(); var context = executionContext.GetExtension <IWorkflowContext>(); var serviceFactory = executionContext.GetExtension <IOrganizationServiceFactory>(); var service = crmWorkflowContext.OrganizationService; var adminService = serviceFactory.CreateOrganizationService(null); tracingService.Trace("In UpdateSharePointMetadata."); var parentEntityName = Parent_Entity_Name.Get(executionContext); var parentLookupName = Parent_Lookup_Name.Get(executionContext); tracingService.Trace("Parent Entity = {0}; Parent Lookup = {1}", parentEntityName, parentLookupName); var customer = Customer.Get(executionContext); if (string.IsNullOrEmpty(customer)) { customer = string.Empty; tracingService.Trace("No customer details passed to workflow"); } var siteDetails = SiteDetails.Get(executionContext); if (string.IsNullOrEmpty(siteDetails)) { siteDetails = string.Empty; tracingService.Trace("No site details details passed to workflow"); } var permitDetails = PermitDetails.Get(executionContext); if (string.IsNullOrEmpty(permitDetails)) { permitDetails = string.Empty; tracingService.Trace("No permit details passed to workflow"); } tracingService.Trace("Customer = {0}; Site = {1}; Permit = {2}", customer, siteDetails, permitDetails); var azureInterface = new AzureInterface(adminService, service, tracingService); azureInterface.UpdateMetaData(new EntityReference(context.PrimaryEntityName, context.PrimaryEntityId), customer, siteDetails, permitDetails); } catch (Exception ex) { throw new InvalidPluginExecutionException("An error occurred in Workflow assembly.", ex); } }
protected override void Execute(CodeActivityContext executionContext) { var tracingService = executionContext.GetExtension <ITracingService>(); var context = executionContext.GetExtension <IWorkflowContext>(); var serviceFactory = executionContext.GetExtension <IOrganizationServiceFactory>(); var service = serviceFactory.CreateOrganizationService(context.UserId); var adminService = serviceFactory.CreateOrganizationService(null); var azureInterface = new AzureInterface(adminService, service, tracingService); // Using an action because we don't know how many attachments we'll have. Could take more // than process limit of 2 minutes so using action trigger async plugin. // Additionally, files larger than approx 20MB cause problems with custom workflow code // activity if passing the whole file in the context. azureInterface.SendFileToSharePointActionRequest(context.PrimaryEntityName, context.PrimaryEntityId); }