Today I will show you how we can put the Flow we created in the previous part into action.
You should complete the workflow to Generate a Word document from a template in this post before we can proceed. Our goal is to convert the Word document to a PDF document and attach it to a Note.
First, in your custom workflow activity project, create a new custom workflow with following code snippet. I’m not going to explain it as you can understand easily when you have a closer look. You just need to pay attention to the “ConvertWordToPdf” method where we send request to our Flow. I put some comments there also.
public class MyCustomWorkflowActivity : CodeActivity { protected override void Execute(CodeActivityContext executionContext) { ITracingService tracer = executionContext.GetExtension(); IWorkflowContext context = executionContext.GetExtension(); IOrganizationServiceFactory serviceFactory = executionContext.GetExtension(); IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId); try { Entity entity = (Entity)context.InputParameters["Target"]; // Get the last note with word attachment generated from the previous step var wordNote = GetLastWordNote(service, context.PrimaryEntityId); // send it to our Flow, convert it to pdf and attach to a note if (wordNote != null) { ConverToPdfNote(service, wordNote, context.PrimaryEntityId); } } catch (Exception e) { throw new InvalidPluginExecutionException(e.Message); } } private Entity GetLastWordNote(IOrganizationService service, Guid targetId) { QueryExpression query= new QueryExpression("annotation") { ColumnSet = new ColumnSet(true), Criteria = new FilterExpression() { Conditions = { new ConditionExpression() { AttributeName="isdocument", Operator = ConditionOperator.Equal, Values = { true } }, new ConditionExpression() { AttributeName = "objectid", Operator = ConditionOperator.Equal, Values = { targetId } } } }, Orders = { new OrderExpression() { AttributeName = "createdon", OrderType = OrderType.Descending } } }; // optional: filter for mimetype to make sure it is a word attachment var docFilter = query.Criteria.AddFilter(LogicalOperator.Or); docFilter.AddCondition("mimetype", ConditionOperator.Equal, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); docFilter.AddCondition("mimetype", ConditionOperator.Equal, "application/octet-stream"); var response = service.RetrieveMultiple(query); if (response.Entities.Count > 0) { return response.Entities.First(); } return null; } private void ConverToPdfNote(IOrganizationService service, Entity note, EntityReference targetRef) { var mime = note.Contains("mimetype") ? (string)note["mimetype"] : string.Empty; if (mime != "application/vnd.openxmlformats-officedocument.wordprocessingml.document" && mime != "application/octet-stream") { throw new InvalidPluginExecutionException("Source file is an invalid Word format"); } var fileName = note.Contains("filename") ? (string)note["filename"] : string.Empty; var noteData = note.Contains("documentbody") ? (string)note["documentbody"] : string.Empty; if (string.IsNullOrWhiteSpace(fileName) || string.IsNullOrWhiteSpace(noteData)) { throw new InvalidPluginExecutionException("Source file is invalid"); } try { // Send request to Flow var pdfData = ConvertWordToPdf(fileName, noteData); Entity pdfnote = new Entity("annotation"); pdfnote["filename"] = fileName + ".pdf"; pdfnote["documentbody"] = pdfData; pdfnote["mimetype"] = "application/pdf"; pdfnote["objectid"] = targetRef; service.Create(pdfnote); } catch (Exception ex) { throw; } } private static string ConvertWordToPdf(string filename, string base64word) { var result = string.Empty; var json = string.Format("{{'filename': '{0}', 'base64data': '{1}'}}", filename, base64word); // TODO: store api url somewhere else var apiurl = "https://prod-02.southeastasia.logic.azure.com:443/workflows/"; try { using (WebClientEx client = new WebClientEx()) { client.Timeout = 60000; client.Headers.Add(HttpRequestHeader.ContentType, "application/json"); client.Encoding = System.Text.Encoding.UTF8; result = client.UploadString(apiurl, json); } } catch (WebException exception) { string str = string.Empty; if (exception.Response != null) { using (StreamReader reader = new StreamReader(exception.Response.GetResponseStream())) { str = reader.ReadToEnd(); } exception.Response.Close(); } if (exception.Status == WebExceptionStatus.Timeout) { throw new InvalidPluginExecutionException("The timeout elapsed while attempting to issue the the PDF conversion request.", exception); } throw new InvalidPluginExecutionException(string.Format("A Web exception occurred while attempting to issue the PDF conversion request. {0}: {1}", exception.Message, str), exception); } catch { throw new InvalidPluginExecutionException("Failed to convert to PDF"); } return result; } } public class WebClientEx : WebClient { public int Timeout { get; set; } protected override WebRequest GetWebRequest(Uri address) { var request = (HttpWebRequest)base.GetWebRequest(address); request.Timeout = Timeout; // Keep-Alive set to true in the HTTP request header can cause delays upwards of 20+ seconds request.KeepAlive = false; return request; } }
Next, build and deploy the workflow to CRM.
Then, open CRM workflow to generate word document, and add a step to our custom workflow. I marked my workflow to be on-demand so I can test it easily with existing record.
And check out the result. A new PDF note is created.
That’s it. hope it helps!
P/S: if you have any suggestion regarding converting Word to PDF online or on-premise, please let me know. Cheers!
Thank you for this series. They helped me better understand the flows and how to interact with them.
LikeLike
Hi, Thanks for providing this very useful feature. I really apricate you. We tried to use this custom workflow and got an error. ConverToPdfNote(service, wordNote, context.PrimaryEntityId); and private void ConverToPdfNote(IOrganizationService service, Entity note, EntityReference targetRef) , Here 3rd parameter passing guid and receiving as entity reference. It gives error please let me know the detail.
LikeLike