Saturday, February 19, 2011

Create SharePoint Document Locations in CRM 2011 - Part 3

This is the last of 3 posts describing how to add SharePoint document locations into CRM.
Part 1
Part 2

This code should be added to that in the previous blog post. I had a devil of a job with a 401 error, but this finally cracked it.

Add a web reference to
http://server01/_vti_bin/Lists.asmx and name the reference listservice
http://server01/_vti_bin/Views.asmx and name the reference views

Add a using statement
using system.Xml;

Add this method into the code in previous blog post.


private static void CreateSharePointFolder(string docfolderUrl)
{
if (docfolderUrl == String.Empty || docfolderUrl.IndexOf("/") == -1)
{
return;
}
try
{
// last part is the folder name
string folderName = docfolderUrl.Substring(docfolderUrl.LastIndexOf("/") + 1);
// remove the folder name
docfolderUrl = docfolderUrl.Replace("/" + folderName, "");
// get the document libray name
string docLib = docfolderUrl.Substring(docfolderUrl.LastIndexOf("/") + 1);
// now remove the doc lib to leave the sharepoint site url
string sharePointSiteUrl = docfolderUrl.Replace("/" + docLib, "");

listservice.Lists myLists = new listservice.Lists();
views.Views myViews = new views.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 query
XmlDocument 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 errors
NameTable 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 name
XmlNode errNode = resultNode.SelectSingleNode("tns:Result/tns:ErrorText", nsmgr);
if (errNode != null)
{
// Write error to log;
}
}

}
catch (Exception ex)
{
throw ex ;
}
}

10 comments:

Unknown said...

Thank you, just passed a link to your post along to a developer who needs to create Sharepoint folders using Web Service calls. I think he'll find the information helpful. Have a good day!

.NetCodeSnippets said...

Hello,

I am receiving this error when i try to debug the code "System.Web.Services.Protocols.SoapException: Exception of type Microsoft.SharePoint.SoapServer.SoapServerException was thrown." can you help me on this?

DeHaynes said...

I am trying to run your code. I am having an issue with the web service references.


listservice.Lists myLists = new listservice.Lists();
views.Views myViews = new views.Views();

My listservice doesn't have a Lists class. My views doesn't have a Views class.

I am using the following URL for views.

http://apr-tst-crm2/sites/CRM//_vti_bin/Views.asmx

When I look at that code, I see ViewSoap, ViewSoapChannel, ViewSoapClient.

Am I missing something?

DeHaynes said...
This comment has been removed by the author.
DeHaynes said...

I tried

http://apr-tst-crm2/_vti_bin/Views.asmx

as well, but still now Views class.

DeHaynes said...

Nevermind. I figured it out. I was adding a Service Reference instead of a Web Reference. All fixed now.

Unknown said...

If anyone is trying to do this with the SAML Provider, here is a little help. I bashed my head against the desk for days trying to figure this one out. Finally had to involve MS.

Evidently, when accessing SharePoint with both SAML Provider and Windows Authentication enabled, the connection will seek the highest level of authentication possible. In this case, that is SAML (ADFS).

The list and view web services will not allow authentication with SAML because they cannot code every possible customer configuration in to the web services. Only Windows Authentication is allowed. Therefore, the code needs to be modified from Charles' original to force Windows authentication.

Two things need to be done:

1. Modify the list and view web service References.cs file for your project with (each web reference has its own reference file, so make sure you get both):

protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
System.Net.WebRequest wr = null;
try
{

wr = base.GetWebRequest(uri);
wr.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");

}
catch (Exception exp)
{
Console.WriteLine("Error!!" + exp.Message);
}
return wr;
}

2. Modify your main code to include the following:

System.Net.NetworkCredential cred = new System.Net.NetworkCredential();
cred.UserName = "Username";
cred.Domain = "Domain";
cred.Password = "Password";

myLists.Credentials = cred;
myViews.Credentials = cred;

Hope this saves a few people some grief. :)

Zarour said...

Thanks
but I got a sql timeout error when executing the CreateSharePointDocLocation method ?
What it could be the problem ?
Thanks

Charles Emes said...

Hi Dave Malsen,
Thanks for your comment and sharing your code (and pain!!).
Charles

The Hermit said...

Thanks for all the code samples.

Just as a matter of interest have you successfully managed to get the connector to work in an Account centric fashion.

All of the documentation implies that when you configure that option then once you have created an account document library, then any libraries for related entities (Case, Contact) should be created under the parent - this does not appear to work.

We have tried this in several environments, with and without rollups and we get the same result. We just get a root library created for each of the ticked entities, no nesting takes place.

Your code should help us to create the structure in the manner Microsoft describe in their documentation.

Just trying to work out if its just us or if anyone managed to make it work before we log a support call with MS...