Saturday, February 19, 2011

Create SharePoint Document Locations in CRM 2011 - Part 2

This is part 2 of three posts
Part 1
Part 3


This code expects the Guid for the Contact and then returns the SharePointDocumentLocation AbsoluteUrl. For example it should return <a href="http://server01/contact/Charles Emes">http://server01/contact/Charles Emes</a>. That folder should exist in the SharePoint document library 'Contact'. Note that the code for creating the SharePoint folder is in the following blog post.

Add references to Microsoft.Crm.Sdk.Proxy.dll and Microsoft.Xrm.Sdk.dll to your project. Add the file crmsdktypes.cs into your project (note the SharePointDocumentLocation object is defined within this class and the code won't work without it). All of these files you will find in the CRM SDK directory.

Add the following using statements
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Crm.Sdk.Messages;

public class IntegrationService
{

// private static string ContactId = "3E339B88-C632-E011-BCDE-00155D110735";

public static string GetSharePointLocation(string ContactId)
{

try
{
// Connect to the Organization service.
System.ServiceModel.Description.ClientCredentials cred = new System.ServiceModel.Description.ClientCredentials();
cred.Windows.ClientCredential = new System.Net.NetworkCredential("Username", "Password", "Domain");

Uri organizationUri = new Uri("http://server01:5555/orgName/XRMServices/2011/Organization.svc");

Uri homeRealmUri = null;

OrganizationServiceProxy orgService = new OrganizationServiceProxy(organizationUri, homeRealmUri, cred, null);

// This statement is required to enable early-bound type support.
// IMPORTANT ADD THIS LINE
orgService.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());

Guid guidSPDocLoc = RetrieveSharePointLocation(orgService, ContactId);

string absouteUrl = GetAbslouteUrl(orgService, guidSPDocLoc);

orgService.Dispose();

return absouteUrl;


}

// Catch any service fault exceptions that Microsoft Dynamics CRM throws.
catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex)
{
// You can handle an exception here or pass it back to the calling method.
return ex.Message;
}

}
private static Guid RetrieveSharePointLocation(OrganizationServiceProxy orgService, string ContactId)
{
Guid _spDocLocId = Guid.Empty;
// get the fullname from the contactid - that will be foolder name
string FolderName = GetEntityNamefromGuid(orgService, ContactId);
// replace any illegal chars with '-'
// TO DO
string fetch2 = @"
<fetch mapping='logical'>
<entity name='sharepointdocumentlocation'>
<attribute name='sharepointdocumentlocationid'/>

<filter type='and'>
<condition attribute='regardingobjectid' operator='eq' value='[GUID]' />
</filter>

</entity>
</fetch> ";
fetch2 = fetch2.Replace("[GUID]", ContactId);

EntityCollection result = orgService.RetrieveMultiple(new FetchExpression(fetch2));
foreach (var c in result.Entities)
{
// TO DO there can be more than one so add condition
_spDocLocId = (Guid) c.Attributes["sharepointdocumentlocationid"];
}
if (_spDocLocId == Guid.Empty)
{
// there is no location so create one
_spDocLocId = CreateSharePointDocLocation(orgService, FolderName, ContactId);

// get the abslouteURL from the doc location just created
string absouteUrl = GetAbslouteUrl(orgService, _spDocLocId);
// We still need to create a SharePoint folder
// THIS METHOD IN FOLLOWING POST **********
CreateSharePointFolder(absouteUrl);

}
return _spDocLocId;
}

private static string GetEntityNamefromGuid(OrganizationServiceProxy orgService, string ContactId)
{
string fetch1 = @"
<fetch mapping='logical'>
<entity name='contact'>
<attribute name='fullname'/>

<filter type='and'>
<condition attribute='contactid' operator='eq' value='[GUID]' />
</filter>

</entity>
</fetch> ";
fetch1 = fetch1.Replace("[GUID]", ContactId);
string fullname = string.Empty;
EntityCollection result = orgService.RetrieveMultiple(new FetchExpression(fetch1));
foreach (var c in result.Entities)
{ // there can be more than one so add condition
fullname = c.Attributes["fullname"].ToString();
}
return fullname;


}

private static Guid CreateSharePointDocLocation(OrganizationServiceProxy _serviceProxy, string FolderName, string ContactId)
{

// use the Parent Location Id NOT the SharePointSiteId
// Parent Location will create url http://sharepoint/contact/CharlesEmes
// SharePointSiteID will create url http://sharepoint/CharlesEmes
Guid _spParentLocId = new Guid("415FF5BA-CA39-E011-92D1-00155D110735");
// Instantiate a SharePoint document location object.

SharePointDocumentLocation spDocLoc = new SharePointDocumentLocation
{
Name = "Documents on Default Site 1",
Description = null,
// Set the Regarding Object id - in this case its a contact
RegardingObjectId = new EntityReference(Contact.EntityLogicalName , new Guid(ContactId)),

// Set the Parent Location ID
ParentSiteOrLocation = new EntityReference(SharePointDocumentLocation.EntityLogicalName, _spParentLocId),
RelativeUrl = FolderName
};

// Create a SharePoint document location record named Documents on Default Site 1.
Guid _spDocLocId = _serviceProxy.Create(spDocLoc);
// Console.WriteLine("{0} created.", spDocLoc.Name);
return _spDocLocId;

}

private static string GetAbslouteUrl(OrganizationServiceProxy orgService, Guid _spDocLocId)
{
IOrganizationService _service = (IOrganizationService)orgService;

RetrieveAbsoluteAndSiteCollectionUrlRequest retrieveRequest = new RetrieveAbsoluteAndSiteCollectionUrlRequest
{
Target = new EntityReference(SharePointDocumentLocation.EntityLogicalName, _spDocLocId)
};
RetrieveAbsoluteAndSiteCollectionUrlResponse retrieveResponse = (RetrieveAbsoluteAndSiteCollectionUrlResponse)_service.Execute(retrieveRequest);

return retrieveResponse.AbsoluteUrl.ToString();
}

}

8 comments:

Sultan Morozov said...

Can you change you theme? The reason is that content get a bit messy.


Thanks

Akin Gursel said...

Hello Charles, great post!

One question, do I need an assembly reference for SharePointDocumentLocation?

Thanks,
Akin

James Peel said...

This post is really useful, i just get one error when i try to use SharePointDocumentLocation. Like Akin, It says the name does not exist and also has asked if i need a reference for it. How would i fix this?

Thanks

Charles Emes said...

James, let me check my code tomorrow and get back to you.

Charles Emes said...

The SharePointDocumentLocation is defined in the CRMSDKTypes class so you need to add CRMSDKTypes.cs to your project.
I've updated my post to reflect that.

James Peel said...

Thats great, i've got it all working now. Thanks for your help.

Ariel Plon said...

Charles, thank you SO MUCH for "assembling" all the parts together. You post has helped us a great deal to further integrate CRM, SharePoint and a .Net portal.

We still have a problem we have not been able to figure out. In the "CreateSharePointDocLocation" routine, you hard code the ParentLocId (Dim _spParentLocId As New Guid("415FF5BA-CA39-E011-92D1-00155D110735")), and we have not been able to figure out where to get this Guid from. We have tried to retrieve it from several fields, including SharePointSite.Id, SharePointSite.SitecollectionId, etc., but we always get the same error: "sharepointdocumentlocation With Id = 35e1830a-17f0-e211-8885-78e3b5089bdb Does Not Exist".

Can you please share some light as to where that GUID comes from? Any ideas will be greatly appreciated.

Regards, Ariel

Jones said...

Hi - Thanks for your code example. I'm trying to use this but I've adapted it in order to use it for a Case object rather than a Contact object. I've got the code recognising when a Case Object already has a Document Location OK, but when I use a Case Object that does not have a document location, I get an error in the CreateSharePointDocLocation function - "sharepointdocumentlocation With Id = Does Not Exist"

Can you advise what this means, because the point is the document location doesn't exist, and that's why this function is trying to create it?

- Mark