Showing posts with label SharePoint Programming. Show all posts
Showing posts with label SharePoint Programming. Show all posts

Access WCF Service with jQuery in SharePoint2010


 I described how to develop a custom WCF service. Today I’ll cover how you can invoke the SharePoint WCF Service from jQuery. In my last post I described to develop a SOAP web service but for using WCF service from jQuery I’m going to use REST web service. For the list of service types and factories supported in SharePoint you can visit the link in MSDN. You can download source code from the link given at the end of the post.

Prepare the service to call from jQuery

Consider developing a service as described in Create Custom WCF Service in SharePoint2010 with the following changes:
  • For  using json I’ve used REST service factory ‘Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory’ as shown below. You can use SOAP factory but you then need to parse data in different way.
    <%@ ServiceHost Language="C#" Debug="true"
        Service="AccessSPServiceFromJQuery.MyService, $SharePoint.Project.AssemblyFullName$"  
        CodeBehind="MyService.svc.cs"
        Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory, 
    Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0,     Culture=neutral, 
    PublicKeyToken=71e9bce111e9429c" %>
    
  • Next you need to specify the return type to json in the service interface as shown below. I’ve specified both request and response type to json in WebInvoke attribute:

    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json, 
    ResponseFormat = WebMessageFormat.Json)]
        List<Product> SearchProduct(string productName);
     
     
        [OperationContract]
        [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json, 
    ResponseFormat = WebMessageFormat.Json)]    bool Save(Product product);
    }
One thing to notice here is that you can’t access the service in browser with mex endpoint. For example if you service is http://myserver/myservice.svc, then the url http://myserver/myservice.svc/mex will not work for service created with MultipleBaseAddressWebServiceHostFactory.

Call Service with jQuery

The next step is to call the service with jQuery. The url of the service to be used in jQuery will be service url and method name. For example if you service url is‘/_vti_bin/AccessSPServiceFromJQuery/MyService.svc’ and the method name you want to invoke is ‘Search’ then the full url will be ‘/_vti_bin/AccessSPServiceFromJQuery/MyService.svc/Search’. As shown in the code below, you can invoke the service Search by passing the parameter in data field of ajax call of jquery
function getProductFromService(searchText) {
    try {
        $.ajax({
            type: "GET",
            url: '/_vti_bin/AccessSPServiceFromJQuery/MyService.svc/SearchProduct',
            contentType: "application/json; charset=utf-8",
            data: { "productName": searchText },
            dataType: 'json',
            success: function (msg) {
                WCFServiceGetSucceeded(msg);
            },
            error: WCFServiceGetFailed
        });
    }
    catch (e) {

        alert('error invoking service.get()' + e);
    }
}
function WCFServiceGetSucceeded(result) {
    alert('success');
}
function WCFServiceGetFailed(error) {
    alert('Service Failed.');
}

Download and use code

I’ve uploaded the code for this post in my skydrive. You can download the code from the link below. To use the code please ensure you have internet connection as I’ve used jqery from Microsoft CDN. The search functionality get all products matching name. You can try to search just by typing a single character. You can debug and test the code. In save I’ve just shown you can pass value from browser to service using POST method.

Create Custom WCF Service in SharePoint2010


In SharePoint 2007, creating a custom Web Service was not so easy. However, asp.net web services are obsolete in SharePoint 2010. Rather new and recommended approach is to develop WCF Service. So the question comes up, “How much difficult it is to create a custom WCF service in SharePoint 2010?”. I’m going to answer the question just right in this blog.

Install CKS development tools edition

For showing how easily you can develop your own Custom WCF Service in SharePoint 2010, I’m going to use a open source Visual Studio 2010 extension know asCommunity Kit for SharePoint: Development Tools Edition. This tool will make the WCF service development much easier. It’ll automate tasks that you would have to do manually. There are two version of the extensions: One for SharePoint Foundation and another one is for SharePoint Server. Download the appropriate version and install.

Create WCF Service

Once you installed the CKSDev Visual Studio extension, you can open a SharePoint Project. In the SharePoint Project, right click on the project and try to add a new item. In the “Add New Item” dialog, you will find some new items added by CKSDev Visual Studio extension. Please select the option “WCF Service (CKSDev)” for new item as shown below:
image
Figure 1: ‘Add New WCF Service’ option ‘add new item’ dialog

Once you add the WCF Service, two files will be added by the dialog. One is the service interface and another is the Service itself.

Modify Service Types

As defined in MSDN, there are three different service types. Most of the time you need SOAP service. But if you need REST or ADO.NET Data service you can modify the service types by modifying the service factory as sown in the figure 2. The following table shows the three service types and their service factory name.
Service TypeService FactoryDescription
SOAP serviceMultipleBaseAddressBasicHttpBindingServiceHostFactoryBasic HTTP binding must be used, which creates endpoints for a service based on the basic HTTP binding.
REST ServiceMultipleBaseAddressWebServiceHostFactoryThe service factory creates endpoints with Web bindings.
ADO.NET Data ServiceMultipleBaseAddressDataServiceHostFactoryA data service host factory can be used.
When you create service with CKSDev tool, the default service generated is SOAP service. If you want to change the service type, please modify the factory in .svc file as shown below:
image
Figure 2: Service Factory defined in SVC file.

Deploy the Service

Once you are done with the service development, you are ready to deploy. But where you want to deploy the service? By default SharePoint service are kept in ISAPIdirectory. However, CKSDev deploy the service in ISAPI\ProjectNameSpace path as shown below:
image
Figure 3: Service deployment location
Once you define the service deployment location as shown in the figure 3, you can deploy the solution.

Access the Custom WCF Service

After Service deploy, you need to use the service in another projects. First try to access the service in browser. But remember you need to access the MEX endpoint either you will not get the service accessible in browser. To access the MEX endpoint, you should add “/MEX” at the end of the service name as shown below:
image
Figure 4: Access WCF Service MEX endpoint.

Finally try to add the service reference in a project using Visual Studio’s ‘Add Service Reference’ dialog as shown below:
image
Figure 5: Add Service Reference


Conclusion

So the steps described in this post are pretty simple:
  • Make sure you have downloaded and installed CKSDev Visual Studio extension.
  • Create a WCF Service (CKSDev) in the project. And if necessary, modify the service type
  • Deploy the solution and if necessary, change the deployment path.
  • Access the service MEX endpoint.

How to Iterate through All the webs in the site of SharePoint


Sometimes we need to process all webs in a site collection, as you want to do some quick fixes in the web. Few weeks back my manager asked me to do some fixes in the list items exists in all the webs in the site collection. There were about 30,000 webs in the site collection and I was looking for some kind of script that will be efficient. The usual way of looping through all webs might be using some recursive way, as shown below.
//Starting point
public void ProcessAllWeb(SPSite site)
{
    using (var web = site.RootWeb)
    {
        ProcessWebRecursive(web);
    }

}

//Recursive method
private static void ProcessWebRecursive(SPWeb web)
{
    //do some processing
    //web.Lists["listName"].ItemCount

    foreach (SPWeb subWeb in web.Webs)
    {
        using (subWeb)
        {
            ProcessWebRecursive(subWeb);            
        }
    }

}
Code Snippet 1: Recursive way of processing all webs in the site collection (Not optimized)
In the recursive way of processing all webs, there will be more than one SPWeb instance alive in memory. In the above code snippet, when the method ProcessAllWeb is invoked it’ll call the recursive method ProcessWebRecursive. The recursive method will keep calling the subwebs while keeping the parent web alive.

While I was writing the code, I was wonder if there’s any way of processing only one web non-recursively. So my intention was to open only one web in memory at once. And then I found it. You can get all web Url(including all subwebs at all level) using SPSite.AllWebs.Names. The following code snippet shows the efficient way of processing all webs in the site collection:
public void ProcessAllWeb(SPSite site)
{
    string[] allWebUrls = site.AllWebs.Names;
    foreach (string webUrl in allWebUrls)
    {
        using (SPWeb web = site.OpenWeb(webUrl))
        {
            //process web
        }
    }
}
Code Snippet 2: Process all webs one by one (Optimized for large number of webs)
Using the code snippet shown in figure 2, you just open one web at a time in memory for processing. The trick here is ‘SPSite.AllWebs.Names’ which will return all the (I mean it!) subwebs (including children and their children and so on) as a result. If you have thousands of webs under a site collection (and if it’s production), you should care about performance issue.

Supressing JavaScript errors in SharePoint sites when all else fails

In SharePoint sites that have custom templates if you do not want to re-write the whole page you end up substituing certain elements for your nice looking design. In some cases elements that you remove or do not use may be referenced by JavaScript and removing these can cause errors on the page in the browser that you cannot resolve. I had the issue on a project I was running and I found a solution that supresses the errors by turning off JavaScript error reporting on the page. I wouldn't recommend doing this site wide but on certain pages where nothing else works insert the following at the top of  the page.
1
2
3
<SCRIPT language="JavaScript">
<!--function silentErrorHandler() {return true;}window.onerror=silentErrorHandler;//-->
</SCRIPT>
 





Restricting the SharePoint 2010 site templates a user can select to create a new site

One of the biggest challenges that you will face when launching and rolling out an Intranet is stopping the intranet from sprawling. Ensuring the structure is maintained is a big job especially when users can create sites for collaboration or projects or customers. If you have customers and projects the engagements usually stick to a certain pattern and so does the files and information that is needed for that engagement. So for each new project creating a site for that project should theoretically be in a similar format to every other project. Documents usually take the same format such as quotes, change requests, bug reports etc and these are usually based on a standard company template. So wouldn't it be great if you could create a new site with all this structure setup and the documents templates available already when creating new documents.

Save the Site Template

The first step of this process is to create a site template and only allow users to create sites based on this template. Supposing we have a site that we want  create a template from. In that site select "Site Settings" from the "Site Actions" menu.  Under the "Site Actions" heading there is already an option to "Save site as template" You then get some options to save the site template. In this case don't include the content.

Site Template

Restrict the site templates that can be used

In the site that you want to use the template select "Site Settings" from the "Site Actions" menu. Select "Page layouts and site templates" from the "Look and Feel" section.

Subsite Templates

From the next screen you can select the templates that you want to restrict the user too by clicking "Add" .

That is it, for a further step if you have multiple projects per customer you could get this working for a customer and projects under that customer.






Lookup column relinker – cross site – for SharePoint 2007 and SharePoint 2010 – using JavaScript

Convert a standard SharePoint lookup column to a full blown cross site lookup using javascript only.

This article introduces a new tool that does lookup column relinking only.

SharePoint 2007
IMG

SharePoint 2010
IMG

Get the code here, and ensure you use the correct version.

The difference between the 2007 and the 2010 version is that in 2007, you must place the code in a web part in the site where the lookup column resides.

You can target another site, but must run the code in the site where the column you want to alter is located.

In the 2010 version, you can change the source web as long as you target a web within the site collection.






jQuery and Sharepoint Web Services: GetListItems with queries

The business case for this, was to add a context menu item based on an item property, in my case, document status.


Essentially this method was called just before the item is added to the context menu item, it is intercepted at the Custom_AddListMenuItems method which allows you to add list menu items. In the method below, i use the local ID of the conext menu item clicked, together with the list guid (ctx.listname) and i query the list for the document status of that item.
I only add the menu item when docstatus is not equal to published. Another interesting note is the ajax call is done synchronously which forces the program halt execution until the ajax call has received a response from the web service.

01

02
function ShowModerationHistory(currentItemID, r, t, m, v, y) {
03
 
04
    var returnValue = false;
05
    var soapEnv =
06
            "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'> \
07
                <soapenv:Body> \
08
                     <GetListItems xmlns='http://schemas.microsoft.com/sharepoint/soap/'> \
09
                        <listName>" + ctx.listName + "</listName>" +
10
			            "<viewFields>" +
11
			            "<ViewFields>" +
12
		                    "<FieldRef Name='DocumentStatus' />" +
13
			            "</ViewFields>" +
14
     			        "</viewFields>" +
15
                            "<query>" +
16
			                    "<Query>" +
17
                                    "<Where>" +
18
                                    "<Eq>" +
19
                                    "<FieldRef Name='ID' />" +
20
                                    "<Value Type='Integer'>" + currentItemID + "</Value>" +
21
                                    "</Eq>" +
22
                                    "</Where>" +
23
                                "</Query>" +
24
                            "</query> " +
25
                        "</GetListItems> " +
26
                    "</soapenv:Body> " +
27
                "</soapenv:Envelope>";
28
    $.ajax({
29
        url: SP.PageContextInfo.get_webServerRelativeUrl() + "/_vti_bin/lists.asmx",
30
        type: "POST",
31
        dataType: "xml",
32
        data: soapEnv,
33
        async: false,
34
        complete: function (xData, status) {
35
            var docStatus = $(xData.responseXML).find("z\\:row:eq(0)").attr("ows_DocumentStatus");
36
            if (docStatus != null && docStatus != undefined) {
37
                if (docStatus.toUpperCase() != "PUBLISHED") {
38
                    x = CIMOpt(r, t, m, v, null, y);
39
                }
40
            }
41
        },
42
        beforeSend: function (xhr) {
43
            xhr.setRequestHeader('SOAPAction', 'http://schemas.microsoft.com/sharepoint/soap/GetListItems');
44
        },
45
        contentType: "text/xml; charset=\"utf-8\""
46
    });
47
 
48
}

How to Creat List Items with jQuery and the SharePoint Web Services


In How to Call the SharePoint Web Services with jQuery I showed how to make a call to SharePoint’s Lists.asmx web service with the jQuery library to retrieve information about the Lists and Document Libraries that are available on a specific SharePoint Site. In the comments of that post, one of the readers asked if it would be possible to create a new item in a List using the same technique. Of course this is possible, you just need to make use of the UpdateListItems web method (yeah, the name of that method is not very intuitive). Here is a quick example!
First let’s create the UI (in this example I'll use a basic Site Page) to allow the user to enter a Title for the new task, and a button to do the action.
<asp:Content runat="server" ContentPlaceHolderID="PlaceHolderMain">
<p>
Task Title:
<input id="newTaskTitle" type="text" />
<input id="newTaskButton" type="button" value="Create Task" />
</p>
</asp:Content>
Next let’s create a Javascript function that will create a new item in a Task list. In the Javascript function I’m declaring two variables that will contain the XML which will be sent to the SharePoint Lists.asmx web service. The first variable (I called it batch) contains the CAML to create a new item. For simplicity the CAML only provides a value for the Title field, add more fields if you’d like. The second variable (called soapEnv) is the SOAP Envelope XML which wraps the batch XML. Notice that in the SOAP Envelope the name of the list is mentioned in which we’re going to create a new item (in this case the Task list). Finally the jQuery ajax function is used to POST the data to the Lists.asmx web service. (If you test this code make sure you update the url option with the URL of your site).
function CreateNewItem(title) {
var batch =
"<Batch OnError=\"Continue\"> \
<Method ID=\"1\" Cmd=\"New\"> \
<Field Name=\"Title\">" + title + "</Field> \
</Method> \
</Batch>";
var soapEnv =
"<?xml version=\"1.0\" encoding=\"utf-8\"?> \
<soap:Envelope xmlns:xsi=\"
http://www.w3.org/2001/XMLSchema-instance\" \
xmlns:xsd=\"
http://www.w3.org/2001/XMLSchema\" \
xmlns:soap=\"
http://schemas.xmlsoap.org/soap/envelope/\"> \
<soap:Body> \
<UpdateListItems xmlns=\"
http://schemas.microsoft.com/sharepoint/soap/\"> \
<listName>Tasks</listName> \
<updates> \
" + batch + "</updates> \
</UpdateListItems> \
</soap:Body> \
</soap:Envelope>";
$.ajax({
url: "
http://yoursite/_vti_bin/lists.asmx",
beforeSend: function(xhr) {
xhr.setRequestHeader("SOAPAction",
"
http://schemas.microsoft.com/sharepoint/soap/UpdateListItems");
},
type: "POST",
dataType: "xml",
data: soapEnv,
complete: processResult,
contentType: "text/xml; charset=utf-8"
});
}
The jQuery ajax function call has a complete option which points to a function, in this function you can process the result as follows:
function processResult(xData, status) {
alert(status);
}
The status parameter is a string which can be for example success or error. Finally in the ready event of the document, we'll hook up the click event of the button so the CreateNewItem function is called, with the value of the textbox as the parameter.
$(document).ready(function() {
$("#newTaskButton").click(function() {
CreateNewItem($("#newTaskTitle").val());
});
});
That’s it! If you put all the code in a simple Site Page, upload the page to a Document Library in a SharePoint site, and now you can create Task list items by only using Javascript! The sample code can be downloaded in the following zip file. The zip file also contains the jQuery library which you can upload to the same Document Library if it isn't already loaded with the help of the SmartTools.jQuery component for example.

Sharepoint2013/SharePoint2010/SharePoint2007 and JQuery Web Services: DeleteList


I had a requirement today to be able to perform a delete of a list without having to perform a postback. After a little bit of How to Call the SharePoint Web Services with jQuery and a little bit of fine-tuning i came up with a delete list method (deletelist()). Below is just an example of what can be done with the Lists.asmx webservice provided by Sharepoint. Obviously any Web Service can be used or called as required.

01
 
02
function delete_list(listid) {
03
            if (confirm("Are you sure you want to delete this container?") == true) {
04
                var message = listid;
05
                var soapEnv =
06
                "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'> \
07
                    <soapenv:Body> \
08
                        <DeleteList xmlns='http://schemas.microsoft.com/sharepoint/soap/'> \
09
                        <listName>" + listid + "</listName>\
10
                        </DeleteList> \
11
                    </soapenv:Body> \
12
                </soapenv:Envelope>";
13
 
14
                $.ajax({
15
                    url: "_vti_bin/lists.asmx",
16
                    beforeSend: function (xhr) {
17
                        xhr.setRequestHeader("SOAPAction",
18
        "http://schemas.microsoft.com/sharepoint/soap/DeleteList");
19
                    },
20
                    type: "POST",
21
                    dataType: "xml",
22
                    data: soapEnv,
23
                    contentType: "text/xml; charset=\"utf-8\"",
24
                    complete: processResult,
25
                    success: function (j) {
26
                        document.location.reload();
27
                    }
28
                });
29
 
30
            } else {
31
                return false;
32
            }
33
        }
34
        function processResult(xData, status) { 
35
            var resultXml = $(xData.responseXML).find("errorstring").text();
36
            resultXml = $.trim(resultXml);
37
            if (resultXml != "") {
38
                alert(resultXml);
39
            }           
40
        }
41

How to Creat List Items with jQuery and the SharePoint Web Services


In How to Call the SharePoint Web Services with jQuery I showed how to make a call to SharePoint’s Lists.asmx web service with the jQuery library to retrieve information about the Lists and Document Libraries that are available on a specific SharePoint Site. In the comments of that post, one of the readers asked if it would be possible to create a new item in a List using the same technique. Of course this is possible, you just need to make use of the UpdateListItems web method (yeah, the name of that method is not very intuitive). Here is a quick example!
First let’s create the UI (in this example I'll use a basic Site Page) to allow the user to enter a Title for the new task, and a button to do the action.
<asp:Content runat="server" ContentPlaceHolderID="PlaceHolderMain">
<p>
Task Title:
<input id="newTaskTitle" type="text" />
<input id="newTaskButton" type="button" value="Create Task" />
</p>
</asp:Content>
Next let’s create a Javascript function that will create a new item in a Task list. In the Javascript function I’m declaring two variables that will contain the XML which will be sent to the SharePoint Lists.asmx web service. The first variable (I called it batch) contains the CAML to create a new item. For simplicity the CAML only provides a value for the Title field, add more fields if you’d like. The second variable (called soapEnv) is the SOAP Envelope XML which wraps the batch XML. Notice that in the SOAP Envelope the name of the list is mentioned in which we’re going to create a new item (in this case the Task list). Finally the jQuery ajax function is used to POST the data to the Lists.asmx web service. (If you test this code make sure you update the url option with the URL of your site).
function CreateNewItem(title) {
var batch =
"<Batch OnError=\"Continue\"> \
<Method ID=\"1\" Cmd=\"New\"> \
<Field Name=\"Title\">" + title + "</Field> \
</Method> \
</Batch>";
var soapEnv =
"<?xml version=\"1.0\" encoding=\"utf-8\"?> \
<soap:Envelope xmlns:xsi=\"
http://www.w3.org/2001/XMLSchema-instance\" \
xmlns:xsd=\"
http://www.w3.org/2001/XMLSchema\" \
xmlns:soap=\"
http://schemas.xmlsoap.org/soap/envelope/\"> \
<soap:Body> \
<UpdateListItems xmlns=\"
http://schemas.microsoft.com/sharepoint/soap/\"> \
<listName>Tasks</listName> \
<updates> \
" + batch + "</updates> \
</UpdateListItems> \
</soap:Body> \
</soap:Envelope>";
$.ajax({
url: "
http://yoursite/_vti_bin/lists.asmx",
beforeSend: function(xhr) {
xhr.setRequestHeader("SOAPAction",
"
http://schemas.microsoft.com/sharepoint/soap/UpdateListItems");
},
type: "POST",
dataType: "xml",
data: soapEnv,
complete: processResult,
contentType: "text/xml; charset=utf-8"
});
}
The jQuery ajax function call has a complete option which points to a function, in this function you can process the result as follows:
function processResult(xData, status) {
alert(status);
}
The status parameter is a string which can be for example success or error. Finally in the ready event of the document, we'll hook up the click event of the button so the CreateNewItem function is called, with the value of the textbox as the parameter.
$(document).ready(function() {
$("#newTaskButton").click(function() {
CreateNewItem($("#newTaskTitle").val());
});
});
That’s it! If you put all the code in a simple Site Page, upload the page to a Document Library in a SharePoint site, and now you can create Task list items by only using Javascript! The sample code can be downloaded in the following zip file. The zip file also contains the jQuery library which you can upload to the same Document Library if it isn't already loaded with the help of the SmartTools.jQuery component for example.