With the new built in integration of sharepoint list mode, crm offers the capability to integrate with sharepoint. However we are are often stuck with the builtin tool to create teh sharepoint folders which are not effective. So I am presenting a solution to automate the integration. In my previous post we have created a plugin to generate autonumber. We will use this to create the sharepoint folder.
Remember
1. Update the sharepoint site URL
2. If you want to use the defaults, update the GUID from your database
3. Remember to use the entity names as display names in sharepoint site
Assumption
1. Sharepoint site already created
2. Document libraries are created for each entity in CRM that integrated with sharepoint
(Created by default when you enable storing documents in shrepoint)
The below code will generate the sharepoint structure as below
spsite/entity/unique-identifier
If the folder already exists in sharepoint, it just links the folder in CRM else it creates the folder in Sharepoint and then created the document locations in CRM. You can customize in the code on which fileld to be used for the document location "GetSharepointAttribute(string EntityName)". Update this function to reflect your needs
Remember
1. Update the sharepoint site URL
2. If you want to use the defaults, update the GUID from your database
3. Remember to use the entity names as display names in sharepoint site
Assumption
1. Sharepoint site already created
2. Document libraries are created for each entity in CRM that integrated with sharepoint
(Created by default when you enable storing documents in shrepoint)
The below code will generate the sharepoint structure as below
spsite/entity/unique-identifier
If the folder already exists in sharepoint, it just links the folder in CRM else it creates the folder in Sharepoint and then created the document locations in CRM. You can customize in the code on which fileld to be used for the document location "GetSharepointAttribute(string EntityName)". Update this function to reflect your needs
using System;using System.Collections.Generic;using System.Linq;using System.Text;using Microsoft.Xrm.Sdk;using System.Xml;using Microsoft.Xrm.Sdk.Query;using Microsoft.Xrm.Sdk.Client;using System.Net;namespace SharepointIntegration{public class SharepointIntegration : IPlugin{string debugText = "";public void Execute(IServiceProvider serviceProvider){debugText = "Inside Execute \n";System.Threading.Mutex mtx = null;try{Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));if (context.InputParameters.Contains("Target") &&context.InputParameters["Target"] is Entity){Entity entity = (Entity)context.InputParameters["Target"];debugText += "Inside if loop - target \n";IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);Entity spSite = new Entity("sharepointsite");Entity spEntDocLoc = new Entity("sharepointdocumentlocation");Entity spDocLoc = new Entity("sharepointdocumentlocation");EntityCollection result = null;string defaultSharepointSite = "http://spserver:8054/crm/documents";string spSiteId = "8CAD9F38-0C4C-E111-9138-00155D01750A";string defaultSite = "Default Site";string defaultDocumentLocation = "";string defaultEntityLocation = entity.LogicalName;string fetchXmlTemplate = "", docLocAttr = "";string absoluteURL = "";bool useDefaults = false;Guid _spSiteId, _spDocEntId, _spDocId;defaultDocumentLocation = GetSharepointAttribute(entity.LogicalName);docLocAttr = entity.GetAttributeValue<string>(defaultDocumentLocation);if (docLocAttr == "" || docLocAttr == null || docLocAttr == "null"){throw new InvalidPluginExecutionException("Document location attribute is null");}absoluteURL = defaultSharepointSite + "/" + defaultEntityLocation + "/" + docLocAttr;debugText += absoluteURL;CreateSharePointFolder(absoluteURL);fetchXmlTemplate = @"<fetch mapping='logical'><entity name='[ENTITY_NAME]'><all-attributes/><filter type=""and""><condition attribute=""[ATTR_NAME]"" operator=""eq"" value='[ATTR_VALUE]'/></filter></entity></fetch>";if (useDefaults){_spSiteId = new Guid(spSiteId);_spDocEntId = new Guid(GetDocEntId(entity.LogicalName));}else{debugText = debugText + "Before executing fetch \n";result = GetResults(fetchXmlTemplate, "sharepointsite", "name", defaultSite, service);debugText = debugText + "After executing fetch \n";if (result.Entities.Count == 0){debugText = debugText + "inside the if loop - sharepointsite create \n";spSite.Attributes.Add("name", defaultSite);spSite.Attributes.Add("description", "Default Sharepoint Location");spSite.Attributes.Add("absoluteurl", defaultSharepointSite);// Create a SharePoint site record named Sample SharePoint Site._spSiteId = service.Create(spSite);}else if (result.Entities.Count == 1){debugText = debugText + "inside the if loop - sharepointsite found \n";spSite = result.Entities.First();_spSiteId = result.Entities.First().Id;}else{throw new InvalidPluginExecutionException("Multiple sharepoint locations are found");}debugText = debugText + "GUID for sharepoint site " + spSite.LogicalName + " is " + _spSiteId.ToString();result = GetResults(fetchXmlTemplate, "sharepointdocumentlocation", "name", entity.LogicalName, service);debugText = debugText + "After executing fetch for sharepoint document location\n";if (result.Entities.Count == 0){debugText += "inside the if loop - sharepoint document site create \n";spEntDocLoc.Attributes.Add("name", entity.LogicalName);spEntDocLoc.Attributes.Add("description", "Default SharePoint Document Location record for " + entity.LogicalName);// Set the Sample SharePoint Site created earlier as the parent site.spEntDocLoc.Attributes.Add("parentsiteorlocation", new EntityReference("sharepointsite", _spSiteId));spEntDocLoc.Attributes.Add("relativeurl", entity.LogicalName);debugText += "before sharepoint document site create \n";_spDocEntId = service.Create(spEntDocLoc);debugText += "after sharepoint document site create \n";}else{spEntDocLoc = result.Entities.First();_spDocEntId = spEntDocLoc.Id;}}debugText = debugText + "outside the if loop - sharepoint document site create \n";result = GetResults(fetchXmlTemplate, "sharepointdocumentlocation", "name", docLocAttr, service);debugText = debugText + "After executing fetch \n";if (result.Entities.Count == 0){debugText = debugText + "inside the if loop - sharepointsite create \n";spDocLoc.Attributes.Add("name", docLocAttr);spDocLoc.Attributes.Add("description", "Default SharePoint Document Location record for " + docLocAttr);// Set the Sample SharePoint Site created earlier as the parent site.spDocLoc.Attributes.Add("parentsiteorlocation", new EntityReference("sharepointdocumentlocation", _spDocEntId));spDocLoc.Attributes.Add("relativeurl", docLocAttr);// Associate this document location instance with the entity recordspDocLoc.Attributes.Add("regardingobjectid", new EntityReference(entity.LogicalName, entity.Id));_spDocId = service.Create(spDocLoc);}}}catch (Exception ex){if (mtx != null){mtx.ReleaseMutex();mtx = null;}throw new InvalidPluginExecutionException("An error occured in SharepointIntegration plugin" + ex + "\n" + debugText);}finally{if (mtx != null){mtx.ReleaseMutex();mtx = null;}debugText = null;}}private string GetDocEntId(string EntityName){switch (EntityName){case "account":return "F379A2D4-8A9A-E111-8459-00155D01750A";case "opportunity":return "642D28B5-479B-E111-8459-00155D01750A";default:return "";}}private EntityCollection GetResults(string FetchXML, string EntityName, string AttrName, string AttrValue, IOrganizationService service){FetchXML = FetchXML.Replace("[ENTITY_NAME]", EntityName);FetchXML = FetchXML.Replace("[ATTR_NAME]", AttrName);FetchXML = FetchXML.Replace("[ATTR_VALUE]", AttrValue);debugText = debugText + FetchXML;return service.RetrieveMultiple(new FetchExpression(FetchXML));}private static string GetSharepointAttribute(string EntityName){switch (EntityName){case "account":return "accountid";case "opportunity":return "name";default:return "";}}private static void CreateSharePointFolder(string docfolderUrl){if (docfolderUrl == String.Empty || docfolderUrl.IndexOf("/") == -1){return;}try{// last part is the folder namestring folderName = docfolderUrl.Substring(docfolderUrl.LastIndexOf("/") + 1);// remove the folder namedocfolderUrl = docfolderUrl.Replace("/" + folderName, "");// get the document libray namestring docLib = docfolderUrl.Substring(docfolderUrl.LastIndexOf("/") + 1);// now remove the doc lib to leave the sharepoint site urlstring sharePointSiteUrl = docfolderUrl.Replace("/" + docLib, "");SharepointList.Lists myLists = new SharepointList.Lists();SharepointView.Views myViews = new SharepointView.Views();myLists.Url = sharePointSiteUrl + "/_vti_bin/lists.asmx";myViews.Url = sharePointSiteUrl + "/_vti_bin/views.asmx";myLists.UseDefaultCredentials = true;myViews.UseDefaultCredentials = true;XmlNode viewCol = myViews.GetViewCollection(docLib);XmlNode viewNode = viewCol.SelectSingleNode("*[@DisplayName='All Documents']");string viewName = viewNode.Attributes["Name"].Value.ToString();/*Get Name attribute values (GUIDs) for list and view. */System.Xml.XmlNode ndListView = myLists.GetListAndView(docLib, viewName);/*Get Name attribute values (GUIDs) for list and view. */string strListID = ndListView.ChildNodes[0].Attributes["Name"].Value;string strViewID = ndListView.ChildNodes[1].Attributes["Name"].Value;// load the CAML queryXmlDocument doc = new XmlDocument();string xmlCommand;xmlCommand = "<Method ID='1' Cmd='New'><Field Name='FSObjType'>1</Field><Field Name='BaseName'>" + folderName + "</Field> <Field Name='ID'>New</Field></Method>";XmlElement ele = doc.CreateElement("Batch");ele.SetAttribute("OnError", "Continue");ele.SetAttribute("ListVersion", "1");ele.SetAttribute("ViewName", strViewID);ele.InnerXml = xmlCommand;XmlNode resultNode = myLists.UpdateListItems(strListID, ele);// check for errorsNameTable nt = new NameTable();XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);nsmgr.AddNamespace("tns", "http://schemas.microsoft.com/sharepoint/soap/");if (resultNode != null){ // look for error text in case of duplicate folder or invalid folder nameXmlNode errNode = resultNode.SelectSingleNode("tns:Result/tns:ErrorText", nsmgr);if (errNode != null){// Write error to log;}}}catch (Exception ex){throw ex;}}}}
6 comments:
Thank you
but I have a null value when callin
XmlNode viewNode = viewCol.SelectSingleNode("*[@DisplayName='All Documents']");
string viewName = viewNode.Attributes["Name"].Value.ToString();
can you please help me ?
HI,
use this below tool to track the request sent and received. See if you are receiving a proper xml back from sharepoint
http://webservicestudio.codeplex.com/
Will this work with CRM and Sharepoint via Office 365? When trying to develop this solution on my local machine I get error related to 'SharepointLists'. Thanks!
Please check the language and the list name. It's different in different languages. Use the webservice studio to track the request and response and you can see the list name from the response and then use that list name in the code.
Great article. Using this plugin approach, I'm trying to find a way to create new a document (say a Word or Excel file), and subsequenntly store/save the file in the SharePoint location assosiated with the active Entity (say Account or Opportunity). I'm struggling with finding a suitable angle on how to save the document to SharePoint from inside the Dynamics CRM plugin. Our environment is Office365 and Dynamics CRM 2015 (Online) with server to server integration enabled.
Post a Comment