Wednesday, November 20, 2013

C# Update a document using the DocumentId in Sharepoint when you do not know the site collection

A problem arises when you want to update a SharePoint document's attributes using the document ID, when the document might have moved to a different site collection. Because, whereas the search service spans site collections, the data service does not. Therefore, you have to use the search service to locate the document's full path, then using the full path, you can determine where the data service for that document is.
 
Scenario:
 
If you have a permalink to a document, for example:

http://portal-test.sharepoint.nterprise.net:1700/hub/loaniq/_layouts/DocIdRedir.aspx?ID=6K3XF6XK5YEP-1-4724

You can get the document ID out of it by parsing it. In this case, it is 6K3XF6XK5YEP-1-4724

Its as simple as:

string docId = sharepointPermalink.Substring(sharepointPermalink.IndexOf("ID=") + 3);
Great. So go look for that document, and get the full path back.

Define a web reference (not a service reference) to search.asmx. In this case, it is

http://portal-test.sharepoint.nterprise.net:1700/hub/loaniq/_vti_bin/search.asmx

I'm calling it QuerySharepointLoanIq.It should add the following to your app.config file:

    <applicationSettings>
        <UpdateSharepointUsingDocId.Properties.Settings>
            <setting name="UpdateSharepointUsingDocId_QuerySharepointLoanIq_QueryService"
                serializeAs="String">
                <value>
http://portal-test.sharepoint.nterprise.net:1700/_vti_bin/search.asmx
                </value>
            </setting>
        </UpdateSharepointUsingDocId.Properties.Settings>
    </applicationSettings>



Now define a service reference (not a web reference) to the DataService. In this case it is
http://portal-test.sharepoint.nterprise.net:1700/hub/loaniq/_vti_bin/ListData.svc
I'm calling it DataServiceSharepointLoanIq.

Now code against it, (assuming there is a text control called textBoxPermalinkUrl on the form containing the permalink url)

 
string sharepointPermalink; //the document we start out with
string docId; //we pull the docId from the sharepointPermalink
string pathName; //QueryService uses the docId to locate the document, to give us the pull path
string dataServiceUrl;//We will parse the pathName to determine the location of the data service

QuerySharepointLoanIq.QueryService queryService; //the service that looks for the document
TheHubLoanIQFCBTDevDataContext dataService; //the service that updayes the document
System.Data.DataSet queryResults;//the dataset that receives the query results
 
queryService = new QuerySharepointLoanIq.QueryService();
queryService.Credentials = System.Net.CredentialCache.DefaultCredentials;
           
 
//this is the name of the document we are looking for
sharepointPermalink = textBoxPermalinkUrl.Text;
           
//extract the document id from the permalink
docId = sharepointPermalink.Substring(sharepointPermalink.IndexOf("ID=") + 3);
 
//Give the docId to the query service to get back the full name of the document
queryResults = queryService.QueryEx(GetXMLString(docId));
pathName = (string)queryResults.Tables[0].Rows[0]["path"];
 
//identify what part of the pathname is the site collection
//and from that, build the url of the DataService
dataServiceUrl = pathName.Substring(0, pathName.IndexOf("LoanIQDocumentsNV")) + "_vti_bin/listdata.svc";
 
//instantiate the dataService with the dataServiceUrl
dataService = new TheHubLoanIQFCBTDevDataContext(new Uri(dataServiceUrl));
dataService.Credentials = new System.Net.NetworkCredential(@"sharepointTester", "test my sharepoint", "nterprise");
 
//use the dataservice to grab the document, once again based on the document ID
LoanIQDocumentsNVItem document = dataService.LoanIQDocumentsNV.Where(i => i.DocumentIDValue == docId).FirstOrDefault();

//now change the attributes of the document, and commit the changes back to sharepoint.
document.ApprovalStatus = comboBoxApproval.SelectedItem.ToString();
dataService.UpdateObject(document);
dataService.SaveChanges();


 
// Note that this is done this way to provide clarity to the reader.
// The tabs have to be stripped out otherwise it breaks the query.

private string GetXMLString( string docId)
{
    string xml = string.Empty;

    xml+="<QueryPacket xmlns='urn:Microsoft.Search.Query'>";
    xml+="    <Query>";
    xml+="           <SupportedFormats>";
    xml+="                 <Format revision='1'>";
    xml+="                        urn:Microsoft.Search.Response.Document:Document";
    xml+="                 </Format>";
    xml+="           </SupportedFormats>";
    xml+="           <Context>";
    xml+="                 <QueryText language='en-US' type='STRING'>";
    xml+=  docId;
    xml+="                 </QueryText>";
    xml+="           </Context>";
    xml+="    </Query>";
    xml += "</QueryPacket>";

    xml=xml.Replace("\t",string.Empty);

    return xml;

}