Jun
2
2008

Microsoft.SharePoint.WebControls.SoapDataSource - An easy way to create web service data source in SharePoint

SoapDataSource from Microsoft.SharePoint assembly is a concreted class of BaseXmlDataSource and also implemented with IDataSource interface.

It can be used for making web service call and served as data source to your SharePoint custom controls / web parts.

For example, We have created a web service which returns stock quote and it has been depolyed as SharePoint web serivce in ~SiteUrl/_layouts/.

This web service has following properties

- Web service name : EnhancedSharePriceWebService.asmx

- Web service namespace URI: http://jamestsai.net

- Web serivce action name : GetMultiQuotes

- Input parameter: symbols (stock symobls in comma-saparator format. e.g. MSFT;AAPL;GOOG)

SOAP 1.1 request

soap1-1

SOAP 1.1 response

SoapResponse

SoapDataSource contains some properties that you must set values to it. They are:

SoapDataSource.SelectServiceName - Web service name

SoapDataSource.SelectUrl - Web service full URL

SoapDataSource.WsdlPath - Web service WSDL path

SoapDataSource.SelectPort - Web service SOAP portocal

SoapDataSource.SelectAction - Web service action name

SoapDataSource.SelectCommand - SOAP request command

SoapDataSource.SelectParameters - Parameters

 

Following code sample shows how to set up SoapDataSource with parameter to retrive data from our share price quote web service.

private SoapDataSource CreateDataSource(SPSite site)
{
     string serverUrl = site.Url; //Get SharePoint root site URL
     SoapDataSource datasource = new SoapDataSource(); //Initiate new SoapDataSource obj
     string symbols = "MSFT;AAPL;GOOG";
     datasource.SelectServiceName = "EnhancedSharePriceWebService";
     datasource.SelectUrl = serverUrl + "/_layouts/EnhancedSharePriceWebService.asmx";
     datasource.WsdlPath = serverUrl + "/_layouts/EnhancedSharePriceWebService.asmx?WSDL";
     datasource.SelectAction = http://jamestsai.net/GetMultiQuotes; //SOAP Action name
     datasource.SelectPort = "EnhancedSharePriceWebServiceSoap"; //SOAP Protocal name
     datasource.SelectParameters.Add("symbols", symbols);
     datasource.SelectCommand = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"> <soap:Body><GetMultiQuotes xmlns=\"http://jamestsai.net/\"> <symbols>{symbols}</symbols></GetMultiQuotes></soap:Body></soap:Envelope>";

}


//Create SoapDataSource by calling CreateDataSource method above
SoapDataSource bindedDS = CreateDataSource(SPContext.Current.Site);
//Get return data as XmlDocument
XmlDocument xdoc = bindedDS.GetXmlDocument();

If you have setup everything correctly, You should be able to see the web serivce result in XmlDocument xdoc. You can also bind SoapDataSource to your data-bound controls.

 

James

May
20
2008

Using JavaScript to check SharePoint list item workflow status - Via Web Service call.

Microsoft Office SharePoint Server comes with many built-in Web services. And the one we are going to use here is the Workflow web service "/_vti_bin/workflow.asmx"

- GetWorkflowDataForItem operation in particular

The following JavaScript code example is fairly easy to understand.

It takes two parameters.

siteUrl - URL to your site, currentItemFileFullUrl - absolute URL to the item

And it will return you the message about item workflow status.

function CheckRunningWorkflow(siteUrl,currentItemFileFullUrl)
{
    var xh=new ActiveXObject("Microsoft.XMLHTTP");

    if (xh==null)
        return "Error: Cannot create XMLHTTP object";

    xh.Open("POST", siteUrl+"/_vti_bin/workflow.asmx", false);
    xh.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    xh.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/workflow/GetWorkflowDataForItem");

    var soapData='<?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>'+
    '<GetWorkflowDataForItem xmlns="http://schemas.microsoft.com/sharepoint/soap/workflow/"><item>'+
    currentItemFileFullUrl+
    '</item></GetWorkflowDataForItem></soap:Body></soap:Envelope>'

    xh.Send(soapData);   

    if (xh.status==200)
    {
        xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
        if (xmlDoc==null)
            return false;
        xmlDoc.async = "false";                   
        if(!xmlDoc.loadXML(xh.ResponseText))
            return false;
    var xpath = "/soap:Envelope"+
    "/soap:Body"+
    "/GetWorkflowDataForItemResponse"+
    "/GetWorkflowDataForItemResult"+
    "/WorkflowData"+
    "/ActiveWorkflowsData"+
    "/Workflows"+
    "/Workflow"

        var activeWF=xmlDoc.selectSingleNode(xpath)

    //Check if there is an active workflow for current item       
        if(activeWF != null)
        {
        //Check Workflow status code
            if(activeWF.getAttribute("InternalState") == '2')
            {
                return "Running";
            }
        else if(activeWF.getAttribute("InternalState") == '4')
            {
                return "Completed";
            }
        }
    else
    {
        reutrn "No active workflow for this item";
    }

    return "Workflow status for this item is not Running or Completed"
    }
    return "Failed to call web service";
}

 

Note: In above we only checked InternalState  is 2 or 4. Which are SPWorkflowState enumeration values of "Running" and "Completed"

The complete set of status are:

None

0

Locked

1

Running

2

Completed

4

Cancelled

8

Expiring

16

Expired

32

Faulting

64

Terminated

128

Suspended

256

Orphaned

512

HasNewEvents

1024

NotStarted

2048

All

4095

I always found this code useful when client wants custom Context menu, or when managed code is not an option.
May
8
2008

How to add Microsoft Office Communicator user presence icon to custom page/web part in SharePoint

James Tsai .Net Blog SharePoint c# VSTO ASP.Net - Microsoft Office Communicator user presence onlin icon

 

In Microsoft.SharePoint.Publishing.WebControls.ConsoleUtilities class you can see this line of code

internal static string GetUserPawnMarkup(string sipAddress, string suffix)

{

    return("<span><img border=\"0\" height=\"12\" src=\"/_layouts/images/imnhdr.gif\" onload=\"IMNRC('" + SPHttpUtility.EcmaScriptStringLiteralEncode(sipAddress) + "')\" ShowOfflinePawn=\"1\" alt=\"\" id=\"MWP_pawn_" + suffix +"\"/></span>");

}

And this is the code used for showing user presence icon in SharePoint site/library/list/item

If you want to have this on your custom .aspx page or web part, you can do it simply by change "sipAdress" with user email address.


<!-- custom .aspx page -->


<%


string userEmail = "james.tsai@local.com";


this.Response.Write("<span><img border=\"0\" height=\"12\" src=\"/_layouts/images/imnhdr.gif\" onload=\"IMNRC('" + userEmail+ "')\" ShowOfflinePawn=\"1\" alt=\"\" id=\"user_presence_icon\"/></span>");


%>

James Tsai .Net Blog SharePoint c# VSTO ASP.Net - Microsoft Office Communicator user presence icon clicked

 

And of course, To get this icon actually working (turn green when user is on) you must have Microsoft Office Communicator installed on client machine.

May
6
2008

Using ASP.NET Web User Control with Code Behind in SharePoint

What are we trying to do?

Let's say you want to create an ASP.NET page in SharePoint site. HelloWorld.aspx and put it in ~site/_layouts/HelloWorld.aspx.

In this HelloWorld.aspx page, you have some Web User Controls (.ascx) that provide different functions to user when they view this page. And each Web User Control has its code behind file (.ascx.cs)

How can you do this in SharePoint?

First of all, you have to understand where those files should live in file system hierarchy.

HelloWorld.aspx - 12\TEMPLATE\LAYOUTS\

WebUserControl1.ascx - 12\TEMPLATE\CONTROLTEMPLATES

WebUserControl2.ascx - 12\TEMPLATE\CONTROLTEMPLATES

WebUserControl1.ascx.cs - compiled as .dll and put in GAC

WebUserControl2.ascx.cs - GAC

As you can see unlike normal ASP.NET web site where .ascx and .ascx.cs store under same folder and will get complied at runtime. In SharePoint there is no concept of code behind but assembly references.

How to do it?

Step 1. Register Web User Controls In HelloWorld.aspx. Just like how normal ASP.NET page would do for Web User Controls.


<!--HelloWorld.aspx - register web user control and use it -->

<%@ Register src="~/_controltemplates/WebUserControl1.ascx" TagName="WebUserControl1" TagPrefix="ucWebUserControl1" %>

<ucWebUserControl1:WebUserControl1 ID="myWebUserControl11" runat="server" />

 

 

Step 2. Create a new class project with all your code behind class files (.ascx.cs)

//WebUserControl1.ascx.cs

namespace JamesTsai.Net.UserControls

{

    public partial class WebUserControl1 : System.Web.UI.UserControl

    {

        protected TextBox txtBox1;

        protected void Page_Load(object sender, EventArgs e)

        {

             txtBox1.Text = "hello world";

        }

    }

}

Compile this project with strong name (signing with key). MAKE sure this .dll is copied to GAC

In this example JamesTsai.Net.UserControls.dll will contains infomation like

"JamesTsai.Net.UserControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=30dc9c27cebc6002"

 

Step 3. Create Web User Control (.ascx)

The Web User Control will look like


<%@ Assembly Name ="JamesTsai.Net.UserControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=30dc9c27cebc6002"%>


<%@ Control Language="C#" AutoEventWireup="false" Inherits="JamesTsai.Net.UserControls.WebUserControl1" %>


<!-- you can use textbox we declared in code behind like this -->


<asp:TextBox id="txtBox1" runat="server" Text="" />

 

Step 4. View your page

After you deployed above files you can view your page in

http://yoursite/_layouts/HelloWorld.aspx

And hopefully you can also see a textbox with text "hello world" inside. If you have more than one Web User Controls, just repeat steps 1 to 3 above.

 

May
1
2008

Quick and dirty way to access Shared Resource Provider (Shared Service Provider) properties

I have came across a very interesting code today when I tried to access the properties of Shared Services (SSPs) on my farm.

//Use reflection to get SharedResourceProviderCollection on farm

ServerContext sc = ServerContext.Default;

object serverFarm = sc.GetType().GetField("m_ServerFarm", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(sc);

object sharedReourceProviders = serverFarm.GetType().GetProperty("SharedResourceProviders").GetValue(serverFarm, null);


//Loop through each SSP on farm and get its name, user name and password (!)

foreach (object sharedResourceProvider in sharedReourceProviders as IEnumerable)

{

    string sspName = sharedResourceProvider.GetType().GetProperty("Name").GetValue(sharedResourceProvider, null).ToString();

    string sspUserName = sharedResourceProvider.GetType().GetProperty("UserName").GetValue(sharedResourceProvider, null).ToString();

    string sspPassword = sharedResourceProvider.GetType().GetProperty("Password").GetValue(sharedResourceProvider, null).ToString();

}

Although this is not a ideal way to code it, but it does allows you to get what you want (or do what you wanted to do) out from Shared Service Provider.

More properties can be found in

sharedResourceProvider.GetType().GetProperties();

I believe it will come handy in future