Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Microsoft Dynamics CRM (Archived)

Moving annotation attachment of Quote to SharePoint with a custom Workflow in C#

(0) ShareShare
ReportReport
Posted on by

So I am trying to create my own logic for moving a Quote Annotation to a SharePoint location. After multiple trial-and-errors I am now at a point which I cannot seem to solve. 

The objective of the custom Workflow is simple;

  1. A user creates a Quote and activate it.
  2. When the quote is activated a word template is generated, this is being done in a Workflow with SetWordTemplate Entity (Quote), this all works fine, a word document based on the Quote is being created and is added as annotation to the quote. 
  3. The next step in this same workflow should be as following: Get the created annotation and move/copy it to the customer his (online) SharePoint location. 

For step 3 I created a Custom Workflow plugin with the following tutorials as references:

vikramxrm.blogspot.nl/.../copy-ms-crm-2011-attached-documents-in.html

https://github.com/jlattimer/CRM-Note-Workflow-Utilities

https://www.powerobjects.com/2015/01/21/retrieve-and-create-attachments-associated-to-notes-of-an-entity-in-dynamics-crm/

The code I have so far is:

public class MoveQuoteToSharepoint : CodeActivity
    {
        [Input("SourceQuote")]
        [ReferenceTarget("quote")]

        public InArgument<EntityReference> SourceQuote { get; set; }
        private String _fileName;

        protected override void Execute(CodeActivityContext executionContext)
        {


            //Create the context
            IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
            IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();

            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);


            // Get the target entity from the context
            Entity regQuote = (Entity)service.Retrieve("quote", context.PrimaryEntityId, new ColumnSet(new string[] { "name", "ownerid" }));
            string quoteName = (string)regQuote.Attributes["name"];


            //Get the notes from the Quote (context)
            QueryExpression _quoteAttachmentQuery = new QueryExpression
            {

                EntityName = "annotation",
                ColumnSet = new ColumnSet
                (
                    "subject",
                    "filename",
                    "documentbody"
                ),

                Criteria = new FilterExpression
                {
                    Conditions =
                    {
                        new ConditionExpression
                        {
                            AttributeName = "objectid",
                            Operator = ConditionOperator.Equal,
                            Values = { context.PrimaryEntityId }

                        },

                        new ConditionExpression

                        {
                            AttributeName = "isdocument",
                            Operator = ConditionOperator.Equal,
                            Values = {true}
                        }
                    }
                }

            };



            EntityCollection results = service.RetrieveMultiple(_quoteAttachmentQuery);

            //Annotation found
            if (results.Entities.Count > 0)
            {
                //Fetch first annotation
                Entity retrievedAnnotation = results.Entities.First();

                _fileName = retrievedAnnotation.GetAttributeValue<string>("filename");

                using (FileStream fileStream = new FileStream(_fileName, FileMode.OpenOrCreate))
                {
                    byte[] fileContent = Convert.FromBase64String(retrievedAnnotation.GetAttributeValue<string>("documentbody"));
                    //fileStream.Write(fileContent, 0, fileContent.Length);
                    CopyToSharePoint2013(retrievedAnnotation.Id, service, quoteName, fileContent, _fileName);                 }

            }
            else
            {
                throw new Exception("There are no annotations found for this Quote.");
            }

        }



        public static void CopyToSharePoint2013(Guid _CaseId, IOrganizationService _service, string _FolderName, byte[] fileContent, string filename)
        {
            try
            {
                string _SharePointServer = @"mydomain.sharepoint.com/.../xxx";
                using (ClientContext _clientContext = new ClientContext(_SharePointServer))
                {
     

                    SecureString passWord = new SecureString();
                    foreach (char c in "xxxx".ToCharArray()) passWord.AppendChar(c);

                    _clientContext.Credentials = new SharePointOnlineCredentials("me@loginemail.com", passWord);

                    //create web object
                    Web web = _clientContext.Web;

                    List oList = web.Lists.GetByTitle("Quote");

                    if (oList != null)
                    {
                        //Create Folder
                        var folders = oList.RootFolder.Folders;
                        _clientContext.Load(folders);
                        _clientContext.ExecuteQuery();
                        var newFolder = folders.Add(_FolderName);
                        _clientContext.ExecuteQuery();

                        //Copy file into created folder
                        FileCreationInformation oFileCreationInformation = new FileCreationInformation();
                        oFileCreationInformation.Content = fileContent;
                        oFileCreationInformation.Url = @_SharePointServer + "/quote/" + _FolderName + "/" + filename;
                        oFileCreationInformation.Overwrite = true;
                        oList.RootFolder.Files.Add(oFileCreationInformation);
                        _clientContext.Load(oList);
                        _clientContext.ExecuteQuery();

                        //Create SharePoint Location record
                        if (!AlreadyExistDocumentLocationRecord(_CaseId, _service))
                        {
                            CreateDocumentLocationRecord(_service, _FolderName, oFileCreationInformation.Url, _CaseId);
                        }

                    }
                }
            }
            catch (Exception Ex)
            {
                Console.Write(Ex.Message);
                if (Ex.InnerException != null)
                {
                    Console.WriteLine(Ex.InnerException.Message);
                    Console.ReadLine();
                }
            }
        }




        private static void CreateDocumentLocationRecord(IOrganizationService service, string _locationName, string _locationURL, Guid _regarding)
        {
            try
            {
                // Instantiate an account object.
                Entity DocumentLocation = new Entity("sharepointdocumentlocation");
                //set the fields values
                DocumentLocation["name"] = _locationName;
                DocumentLocation["regardingobjectid"] = new EntityReference("quote", _regarding);
                DocumentLocation["relativeurl"] = _locationName;
                if ((GetParentSiteUrl(service)) != Guid.Empty)
                {
                    DocumentLocation["parentsiteorlocation"] = new EntityReference("sharepointdocumentlocation", GetParentSiteUrl(service));
                }
                //create the record
                Guid DocumentLocationid = service.Create(DocumentLocation);

            }
            catch (Exception Ex)
            {
                Console.Write(Ex.Message);
                if (Ex.InnerException != null)
                {
                    Console.WriteLine(Ex.InnerException.Message);
                    Console.ReadLine();
                }
            }

        }



        private static Guid GetParentSiteUrl(IOrganizationService service)
        {
            Guid _Id = Guid.Empty;
            try
            {
                QueryExpression _Query = new QueryExpression
                {
                    EntityName = "sharepointdocumentlocation",
                    ColumnSet = new ColumnSet("relativeurl"),
                    Criteria = new FilterExpression
                    {
                        FilterOperator = LogicalOperator.And,

                        Conditions =
                        {
                            new ConditionExpression
                            {
                                AttributeName = "relativeurl",
                                Operator = ConditionOperator.Equal,
                                Values = { "quote" }
                            },
                        }

                    }
                };

                EntityCollection _EntityLocation = service.RetrieveMultiple(_Query);

                if (_EntityLocation.Entities.Count > 0)
                {
                    _Id = _EntityLocation.Entities[0].Id;
                }

            }
            catch (Exception Ex)
            {
                Console.Write(Ex.Message);
                if (Ex.InnerException != null)
                {
                    Console.WriteLine(Ex.InnerException.Message);
                    Console.ReadLine();
                }
            }
            return _Id;
        }



        private static bool AlreadyExistDocumentLocationRecord(Guid CaseId, IOrganizationService _service)
        {

            QueryExpression _Query = new QueryExpression
            {
                EntityName = "sharepointdocumentlocation",
                ColumnSet = new ColumnSet("regardingobjectid"),
                Criteria = new FilterExpression
                {
                    FilterOperator = LogicalOperator.And,

                    Conditions =
                    {
                        new ConditionExpression
                        {
                            AttributeName = "regardingobjectid",
                            Operator = ConditionOperator.Equal,
                            Values = { CaseId }
                        },
                    }

                }
            };

            EntityCollection _EntityLocation = _service.RetrieveMultiple(_Query);

            if (_EntityLocation.Entities.Count > 0)
                return true;
            else
                return false;

        }







    }


After some testing I am getting the following error:

 Unexpected exception from plug-in (Execute): MyNameSpace.MoveQuoteToSharepoint: System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.FileIOPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.

I guess it is being caused by the following bit of code, but I am not sure:

using (FileStream fileStream = new FileStream(_fileName, FileMode.OpenOrCreate))
                {
                    byte[] fileContent = Convert.FromBase64String(retrievedAnnotation.GetAttributeValue<string>("documentbody"));
                    //fileStream.Write(fileContent, 0, fileContent.Length);
                    CopyToSharePoint2013(retrievedAnnotation.Id, service, quoteName, fileContent, _fileName);                 }


Anyone have a clue how to fix this? I am also not sure if the SharePoint bits of code will work, not even got there because of the previous error. Does anyone think I should program it differently?

Thank you in advance!








*This post is locked for comments

  • David Jennaway Profile Picture
    14,065 on at
    RE: Moving annotation attachment of Quote to SharePoint with a custom Workflow in C#

    You're right in what line of code is causing the problem. It looks like your plugin is running in the sandbox, which blocks FileIO access. You've 3 main options:

    1. If you've CRM On Premise, deploy the plugin outside of the sandbox
    2. The sandbox does allow you to make web requests, so you could write the file to SharePoint using SharePoint's web services. However, the sandbox also blocks a lot of the assemblies used for authentication, so this may still not work
    3. Write the code to run outside of CRM - maybe use SSIS or a scheduled console application, or if you're in CRM Online, make the plugin Azure aware to run in a separate Azure enviroment

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

🌸 Community Spring Festival 2025 Challenge Winners! 🌸

Congratulations to all our community participants!

Adis Hodzic – Community Spotlight

We are honored to recognize Adis Hodzic as our May 2025 Community…

Kudos to the April Top 10 Community Stars!

Thanks for all your good work in the Community!

Leaderboard > Microsoft Dynamics CRM (Archived)

#1
Mohamed Amine Mahmoudi Profile Picture

Mohamed Amine Mahmoudi 83 Super User 2025 Season 1

#2
Community Member Profile Picture

Community Member 52

#3
dkrishna Profile Picture

dkrishna 6

Overall leaderboard

Featured topics

Product updates

Dynamics 365 release plans