Muhammad Ali Khan

MS CRM 3.0, MS CRM 4.0, Sharepoint 2007 & Sharepoint 2010

Archive for the ‘Sharepoint 2007’ Category

U2U Article: A Microsoft SharePoint 2007 custom field type for Microsoft CRM Dynamics 4.0

Posted by Ali Khan on August 9, 2009

I found this great post on U2U articles for integeration between ms crm and sharepoint , and decided to share with you.

Source : U2U
For details go to the article URL.
Custom Field Type For MS CRM 4.0


Advertisements

Posted in MS CRM 4.0, Sharepoint 2007 | Leave a Comment »

Creating Custom WebService In SharePoint 2007

Posted by Ali Khan on August 7, 2009

In this post i am going to show you how to create a custom webservice in sharepoint 2007. There is already an article (Hello World Webservice) on msdn about this.

http://msdn.microsoft.com/en-us/library/ms464040.aspx

Except the fact, the article on MSDN wants you to create the WSDL and DISCO file for yourself, which I found out to be very hectic and time consuming. Instead we can just use any tool that will generate the WSDL and DISCO file for us.

1.    As First Step, Create a class library in Visual Studio 

1

2.    Add the references to the “Microsoft.Sharepoint.dll” and “System.Web.Services” dll

  2

 

3.    Add a new class and inherit it from “Webservice” class

3

4.    Sign the assembly. As it will be deployed in GAC

  

4

 

5.    Write your code for the custom webserivce. Here are just two methods for renaming the folder in a document library

 

0

 

6.    Build your project and install it in GAC.

 

5

 

7.    Create a custom SPFolderWS.asmx file which will point to the SPFolderWS.cs (which you defined in the class library, and is installed in GAC). Note this file “SPFolderWS.asmx” doesn’t need to be in the project.

 

16

 

8.    Use the SPDev Tool to generate the DISCO and WSDL file for you. ( You can download the SPDev Tool from the following website)

http://www.crsw.com/spdev/Wiki%20Pages/GenWS.aspx

 

6

 

9.    Here are your generated WSDL and DISCO file.

 7

 

10. Copy these files to the “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI” directory

 

11

 

11. Browse the URL to make sure the webservice is properly deployed

 9

 

12. That’s it.

Now to test the above webservice, we will create a console application.

1.    Create a Console Application, and add the reference to the webservice as shown below

 

12

 

2.    Write the following code snippet to call the methods of the custom webservice.

 

15

 

3.    If everything works fine, the folder should be re-named.

 

14

 4.    That’s All

You can also download this code from the following location.

Custom WebService Code
 

Posted in Sharepoint 2007 | 9 Comments »

Run SharePoint 2007 On Vista

Posted by Ali Khan on August 3, 2009

If you are a developer for SharePoint your best friend has been Virtual PC or VMWare. It’s time to introduce a new friend, Bamboo Nation’s SharePointOnVista.

If you have limited RAM and don’t want the VM, here is how you can install SharePoint on windows Vista.

 Install SharePoint on Vista

Posted in Sharepoint 2007 | Tagged: | Leave a Comment »

Create, Rename SharePoint Document Library and Integerate With MS CRM 4.0

Posted by Ali Khan on July 31, 2009

In this post, I will show you how to create and then rename document library in Sharepoint.  While creating a document library is a very common task, but there are times when you want to rename the document library as well. Suppose you want integration between MS CRM 4.0 Account Entity and the SharePoint Document Library, so whenever the account entity is created you create a document library on the name of an account and when the account is re-named, you rename the document library again. Off course, it’s understood that you will create & rename document library from account entity Plugin.

Creating a document library is a straight forward task, you can either use the SPWeb.Lists.Add() Method or the List.asmx webservice to create a new document library.

Here is how you can create a document library from the lists.asmx webservice

Create a New Document Library

You can put the following code in the create event of the account entity plugin.

Lists objList = new Lists();

objList.Url = http://moss:32901/sites/testsite/_vti_bin/Lists.asmx”;

objList.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;

XmlNode objNode = objList.AddList(“My New List”, “Using Default credit”, 101);

Console.WriteLine(objNode.OuterXml);

Well, there is no API available for re-name document library neither in the lists.asmx or any other webserivce and nor in the Micorosoft.Sharepoint.dll assembly.

The following code will only change the title of the Document Library and it will not rename the document library itself.

Lists listService = new Lists();

listService.Url = http://moss:32901/sites/testsite/_vti_bin/Lists.asmx”;

listService.Credentials = new System.Net.NetworkCredential(“administrator”, “pass@word1”, “litwareinc”);

  

XmlNode ndList = listService.GetList(“My New List”);

XmlNode ndVersion = ndList.Attributes[“Version”];

  

XmlDocument doc = new XmlDocument();

doc.LoadXml(ndList.OuterXml);

string listID = ndList.Attributes[“ID”].Value;

  

XmlDocument xmlDoc = new System.Xml.XmlDocument();

  

XmlNode ndProperties = xmlDoc.CreateNode(XmlNodeType.Element, “List”,“”);

  

XmlAttribute ndTitleAttrib =  (XmlAttribute)xmlDoc.CreateNode(XmlNodeType.Attribute,“Title”, “”);

  

XmlAttribute ndDescriptionAttrib =

    (XmlAttribute)xmlDoc.CreateNode(XmlNodeType.Attribute,“Description”, “”);

 

ndTitleAttrib.Value = “My New List Updated”;

ndDescriptionAttrib.Value = “New Description Here”;

 

ndProperties.Attributes.Append(ndTitleAttrib);

ndProperties.Attributes.Append(ndDescriptionAttrib);

 

try

{

      XmlNode ndReturn = listService.UpdateList(listID,

              ndProperties, null, null, null, ndVersion.Value);

 

      MessageBox.Show(ndReturn.OuterXml);

}

 

catch (Exception ex)

{

      MessageBox.Show(“Message:\n” + ex.Message + “\nStackTrace:\n” +

               ex.StackTrace);

}

As Obvious from the above code, the title of the document library will be updated but not the URL. So if the URL of the list was http://moss:32901/sites/testsite/My New List/ before the above code was executed it will remain the same after the above code is executed (http://moss:32901/sites/testsite/My New List/), as shown in the figure below.

NewList1 

Before the update title code

 

NewList2b 

After the Update Title code

As you can see only the title is updated and not the actual List name, the URL of the list remains un-changed as see in the address bar. 

NewList3 

Rename Document Library:-

First question you may ask, why would we need to rename a document library, well it’s a very common requirement if you are integerating SharePoint with other products like MS CRM. Now suppose you create an account “Adventure Wroks” (Note the dilberate spelling mistake) and the document library gets created. Now the URL will be something like this http://moss:32901/sites/testsite/Adventure Wroks/ . Later you realized that there is a spelling mistake and you want to rename the account entity to (Adventure Works), but at the same point you want the url to be updated as well to something like this http://moss:32901/sites/testsite/Adventure Works/  without effecting all the documents and the folder that you already have in your document library.

So what should be our solution, one approach is to use account id (guid) as the document library name which off-course will not changed but it will not look anything meanfull, e.g. http://moss:32901/sites/testsites/9C39AE6D-E96C-488D-8BA3-2624F2AAE4BE/ . But it doesn’t make any sense to the end users.

Well, now I will show you how to rename the document library from the .net code. But First

Warning: – Please note the rename document library code (below) is not a supported customization of sharepoint. Although I have tested the below code in development senarios to be working with 100% success, but I will not be liable for any data lost  or damages to sharepoint that may be caused by the rename document library code (below).

If you have the list Id and run a simple query to the “alldocs” table, you may found out something like below which could be the reason of not providing the rename functionality to the document library.

Run this query against the “WSS_Content” database.

 (select * from alldocs where listid=‘4D62A2C4-DDEA-438E-86D2-64DCB67166E8’)

 NewList4

As you can see the complete URL’s to all the folders and the documents that are created inside the list is maintained.

As clearly seen from the above diagram, there is an UPDATE Analomy and it violates the 2nd Normal Form of normalization. Off-course there could be reason to maitain the data in above format, like performance, easing indexing for crawlers or may be lesser joins to the table, but that is another topic. Just to surprise you more, “alldocs” is not the only table that is containing the list nameJ. Unfornatley it is not the best of the database desgin.

Any way, so here is the code to update the document library name, I have used the SqlTransaction object just to make sure we commit if all the updates are successful or rollback completely in case of any errors.

You can put the below code in the update event of the account entity plugin.

private void RenameDocumentLibrary()

{

string oldListName = “My New List”;

      string newListName = “My New List Updated”;

 

      // first thing first, check if the new list name is valid

      if (!ValidListName(newListName))

            throw new InvalidOperationException(“List name is not valid”);

 

      Lists listService = new Lists();

listService.Url = http://moss:32901/sites/testsite/_vti_bin/Lists.asmx”;

 

listService.Credentials = new System.Net.NetworkCredential(“administrator”, “pass@word1”, “litwareinc”);

 

      XmlNode ndList = listService.GetList(oldListName);

 

      XmlDocument doc = new XmlDocument();

      doc.LoadXml(ndList.OuterXml);

      string listID = ndList.Attributes[“ID”].Value;

 

      SqlConnection objCon = null;

      SqlTransaction objTrans = null;

 

      try

      {

string connectionStr = “Data Source=moss;Initial Catalog=WSS_Content;user id=alitest;password=alitest;”;

            objCon = new SqlConnection(connectionStr);

            objCon.Open();

 

            objTrans = objCon.BeginTransaction();

 

// step 0: first reterview the site in which list is contained.

// These ids will be used later in the update process

string sql = “select top 1 siteid from alldocs where listid='” + listID + “‘”;

           

            SqlCommand cmd = new SqlCommand(sql, objCon, objTrans);

            string siteID = cmd.ExecuteScalar().ToString();

 

            // step 1: first update the title of the list

            sql = “update alllists set tp_title = @p1 where tp_ID=@p2”;

 

            cmd = new SqlCommand(sql, objCon, objTrans);

            cmd.Parameters.AddWithValue(“@p1”, newListName);

            cmd.Parameters.AddWithValue(“@p2”, listID);

            cmd.ExecuteNonQuery();

 

            // step 2: now update the leaf name of the list

            sql = “update alldocs set leafname = ‘” + newListName + “‘” +

” where listid = ‘” + listID + “‘ and leafname='” + oldListName + “‘”;

 

            cmd = new SqlCommand(sql, objCon, objTrans);

            cmd.ExecuteNonQuery();

 

            // step 3: now update all the files, folders for the list

sql = “update alldocs set dirname = replace(dirname,'” + oldListName + “‘,'” + newListName + “‘)” + ” where listid = ‘” + listID + “‘”;

 

            cmd = new SqlCommand(sql, objCon, objTrans);

            cmd.ExecuteNonQuery();

 

// step 4: now update all links to the documents in “alluserdata” // in the table

sql = “update alluserdata set tp_dirname=replace(tp_dirname,'” + oldListName + “‘,'” + newListName + “‘) “ + ” where tp_listid = ‘” + listID + “‘”;

 

            cmd = new SqlCommand(sql, objCon, objTrans);

            cmd.ExecuteNonQuery();

 

            // step 5: now update the build dependencies

sql = “update builddependencies set dirname = replace(dirname,'” + oldListName + “‘,'” + newListName + “‘) “ + ” where dirname like ‘%/” + oldListName + “/%’ and siteid='” + siteID + “‘”;

 

            cmd = new SqlCommand(sql, objCon, objTrans);

            cmd.ExecuteNonQuery();

 

            // step 6: finally, now update the eventcache table

sql = “update eventcache set itemfullurl = replace(itemfullurl,'” + oldListName + “‘,'” + newListName + “‘) “ + ” where itemfullurl like ‘%/” + oldListName + “/%’ and siteid='” + siteID + “‘”;

 

            cmd = new SqlCommand(sql, objCon, objTrans);

            cmd.ExecuteNonQuery();

 

            // if everything goes fine, commit transaction

            objTrans.Commit();

 

            MessageBox.Show(“Document Library re-named”);

      }

catch (Exception ex)

{

      // roll back gracefully, in case of any errors

if (objTrans != null)

                  objTrans.Rollback();

 

            throw;

}

finally

{

if (objTrans != null)

                  objTrans.Dispose();

 

            if (objCon != null)

                  objCon.Close();

 

            objTrans = null;

            objCon = null;

}

}

 

bool ValidListName(string newListName)

{

      //  You can used regular expression for this purpose

if (newListName.Contains(“~”) || newListName.Contains(“`”) || newListName.Contains(“!”) || newListName.Contains(“@”)

|| newListName.Contains(“#”) || newListName.Contains(“%”) || newListName.Contains(“^”) || newListName.Contains(“*”)

|| newListName.Contains(“(“) || newListName.Contains(“)”) || newListName.Contains(“\””) || newListName.Contains(“\'”)

      || newListName.Contains(“:”) || newListName.Contains(“;”))

            return false;

 

      return true;

}

 

As you can see in the pictures below, the above code will not only update the URL to the document library but it will update the URL’s of all the documents and the folders that are contained inside that document library, so if the URL to a document was http://moss:32901/sites/testsite/My New List/ Ali test document.docx (before rename), then after the above code is executed, it will be like this http://moss:32901/sites/testsite/My New List Updated/Ali test document.docx

NewList5

 NewList6 

 Note:  If you are using the moss search service; you may have to run the crawler again on this document library since the document library is renamed.

Posted in MS CRM 4.0, Sharepoint 2007 | Tagged: | 8 Comments »

MS CRM 4.0 Plugin Integeration With Sharepoint using Sharepoint.dll

Posted by Ali Khan on July 19, 2009

 
Using Microsoft.Sharpoint.dll inside the MS CRM 4.0 Plugin

Well there may be points in your MS CRM 4.0 development, where you need integration with SharePoint. I came across one such scenario where I have to create a SharePoint Folder in a document library on the Create Event of an Entity “Account”. Also once the account is renamed, I have to rename the folder as well.

Now SharePoint gives you two options to customize its document library either using the webservices of lists.asmx or Dws.asmx or using the SPList and SPSite Object from Microsoft.SharePoint.Dll. Since in my case I wanted to create a folder on the create event of an account so I used this code for my application.

For creating Folder in Sharepoint

Add the reference to the Dws.asmx webservices. This webservice has a create folder method and use this code in the plugin where you want to create a folder in Sharepoint

       Dws objDws = new Dws();

       objDws.Url = http://moss:32901/sites/testsite/_vti_bin/Lists.asmx”;

      if(MossSiteUser.Length == 0)

                 objDws.Credentials =System.Net.CredentialCache.DefaultNetworkCredentials;

     else

                objDws.Credentials = new System.Net.NetworkCredential(MossSiteUser, MossSitePwd, MossSiteDomain);

     string returnResult = objDWS.CreateFolder(newFolderName);

For Renaming the folder in Sharepoint

So far so good, but to my surprise L, Dws.asmx doesn’t provide any method for RenameFolder() nor does List.asmx. However, the SPFolder Class in Microsoft.SharePoint.dll does have one such
method (Actually it’s still not RenameFolder(), but it has one method MoveFolder() which can serves the purpose of the RenameFolder). The problem how-ever is if you try to use this code to RenameFolder() inside the plugin. It will Fail with 401 Access Denied Error.

            SPSite spSite = new SPSite(siteURL);

           SPWeb site =spSite.OpenWeb();

            site.AllowUnsafeUpdates = true;

            SPFolder folder =site.GetFolder(sourceFolderName);

            folder.MoveTo(destinationFolderName);

The above code will never work inside the plugin, because the plugin normally runs under the security context of the “Network Service”. Even though it should impersonate but you are never mentioning in your code (above which user to use, nor there is a way to mentioned it). I check on some sites which recommends to use the put the code in SPSecurity.RunWithElevatedPrivileges but I didn’t have any success with this method either, because the SPUserToken object was always null L.

So what is the solution? The solution is to create a custom webservice and deploy this webservice in SharePoint as a custom webservice and then it will behave just like the normal MOSS webservice.

So here we go:-

Step 1, Create a windows Library which will contain the code of the Custom Webservice:-

Create a Windows Library project e.g. “MyCustomFolder.dll”. Sign the assembly (Add the sign.key from the properties window). Add the Reference to the Microsoft.Sharepoint.dll and System.Web.Services.dll as show in the picture below. 

References 

Create a class, name it “SPFolderWS” add the following method to it, and add the following methods as it is:-

using System;

using System.Web;

using System.Web.Services;

using System.Web.Services.Protocols;

using Microsoft.SharePoint;

[WebService(Namespace= http://tempuri.org/”)] 

[WebServiceBinding(ConformsTo= WsiProfiles.BasicProfile1_1)]

public class SPFolderWS : System.Web.Services.WebService

{

    public SPFolderWS ()

    {

    }

 

       [WebMethod]

      public bool IsFolderExits(string siteURL, string sourceFolderName)

      {

            SPSite spSite = new SPSite(siteURL);

            SPWeb site = spSite.OpenWeb();

            site.AllowUnsafeUpdates = true;

            SPFolder folder = site.GetFolder(sourceFolderName);

            return folder.Exists;

      }

 

       [WebMethod]

      public bool RenameFolder(string siteURL, string sourceFolderName,    string destinationFolderName)

      {

            SPSite spSite = new SPSite(siteURL);

            SPWeb site = spSite.OpenWeb();

             site.AllowUnsafeUpdates = true;

            SPFolder folder =site.GetFolder(sourceFolderName);

            folder.MoveTo(destinationFolderName);

             return true; 

      }  

}

 As you may have guessed from the above code, we created a class which inherited from Webservice in order to make our component as
webservice. Build this class library and install this library in GAC. (You can simply drag and drop the file from the folder to c:\windows\assembly folder or use the GacUtil command line tool).

Step 2, Create the Webservice Project:-

 For the 2nd step, we will create a Webservice project (which only has the asmx file, no .cs file). Add the reference to the above class library “MyCustomFolder.dll”.  After adding the asmx file modify the asmx file to point to the correct webservice class (SPFolderWS) from “MyCustomFolder.dll”

<%@ WebService Language=”C#” Class=”SPFolderWS, MyCustomFolder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6a7dfbe963f8254e” %>

Please note that the public key token will vary for your dll. Now Build the Project.

Step 3, Create WSDL & Disco File for Webservice and Deploy in MOSS:-

Now the 3rd Step, Now you have to deploy your custom webservice in sharepoint. You can go through the hectic way of  generating the WSDL and DISCO file yourself. But I would perfer you use the great SPDev tool which you can download form this site, which can geneate the disco and wsdl file for you.

http://www.crsw.com/spdev/Wiki%20Pages/GenWS.aspx

Just type this in the command line.

SPDev.exe -o GenWS -url http://moss:32901 -asmx SPFolderWS.asmx –deploy

The above command line will generate the disco and wsdl file in the directory and two .aspx files. Simply copy these files to the following directory “C:\Program Files\Common
Files\Microsoft Shared\Web Server Extensions\12\ISAPI”
. Now you have successfully registered a custom webservice inside Microsoft Sharepoint. Browse the following URL to confirm your custom webservice is properly generated.

http://moss:80/SPFolder/_vti_bin/SPFolderWS.asmx

Now go to the plugin project and add the reference to the above webservice and write the following code.

SPFolderWS objService = new SPFolderWS();

objService.Url = “http://moss:32901/sites/test_ali_site/_vti_bin/SPFolder.asmx;

if(MossSiteUser.Length == 0)

objService.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;

else

      objService.Credentials  = new System.Net.NetworkCredential(MossSiteUser,MossSitePwd, MossSiteDomain);

if  (objService.IsFolderExits(siteURL, folderName))

      objService.RenameFolder(siteURL, folderName, newFolderName);

It should work greatJ.

 
For step by step details of creating a custom webservice in sharepoint, see my following post Custom WebService In SharePoint

Posted in MS CRM 4.0, MS CRM Plugin, Sharepoint 2007 | Tagged: | 2 Comments »

Posted by Ali Khan on September 14, 2007

Coming Soon…

Posted in Biztalk 2006, C# 2.0 & C# 3.0, Sharepoint 2007 | 1 Comment »