Sunday, October 3, 2010

Getting around the Firefox XMLHTTPRequest Cross Site Limitation

In one of our recent project, we had a module where we need to access a web service hosted on a third party domain into our SharePoint application. Well this appears as one of those mundane tasks of adding a reference to the web service and using the web service proxy in the C# code behind unless your client asks you to provide a postback free experience and he does not have his production SharePoint servers configured with AJAX configurations.

In this situation the only way you are left with is JavaScript hence we did the same. Now for accessing the third party web service we leveraged the XMLHttpRequest object to issue an HTTPGET request to the desired web method and accordingly use the response as returned back from the service.

Everything was working like a charm until we tested our app in Firefox. Bang here goes app!!

Below is the JavaScript script that issues an XMLHttpRequest request directly to the to the web service

Script_WebServiceCall

In Internet Explorer the above script successfully calls the HelloWorld web method and displays the result.

IE_WithoutProxy

However in Firefox you will receive an error with status code 0.

FF_WithoutProxy

Debugging this issue I found that I was always getting the xmlhttprequest.status code as 0 instead of 200. Now that was weird since the same code works fine in IE 7 & IE 8 but fails in Firefox. Moreover I couldn’t find any documentation for the 0 status code.

Googling around this issue I found some explanation here

The XMLHttpRequest object is subjected to the browser’s security “sandbox.” Any resources
requested by the XMLHttpRequest object must reside within the same domain from which the
calling script originated. This security restriction prevents the XMLHttpRequest object from
requesting resources outside the domain from which the script was originally served.
The strength of this security restriction varies by browser. Internet
Explorer shows an alert stating that a potential security risk exists but gives the user a choice
of whether to continue with the request. Firefox simply stops the request and shows an error
message ..."

Cutting the long story short it is no possible to access a web service on another domain/port via XMLHttpRequest object in Firefox.

So finally we decided to adopt an alternative of creating a server side proxy (managed code) which would take up the task of communicating with the web service. Further our JavaScript code would remain as is but one change i.e. instead of requesting the web service, the script will issue an XMLHttpRequest to server side proxy who is apparently on the same domain and this approach worked flawlessly.

Here is how the code behind for the proxy page would look like:

ProxyPage_CodeBehind

The above code is initiating the web service object (hellowrldsvc) and calling the required web method (HelloWorld). Further we are writing the result as returned by the web method back to the page response.

Here is the updated JavaScript:

Script_ProxyPageCall

Notice the url (as highlighted) is now pointing to the proxy page and the rest of the code is as is. Further upon executing the same, we get the result in IE and Firefox as shown below.

In IE:

IE_WithProxy

In Firefox:

FF_WithProxy

If your web method requires some parameter to execute, then you can pass them in page query string (as shown below) and further in the proxy page code behind read them using Page.Request.QueryString.

Script_ProxyPageCall_withQueryString

In case you are dealing with SharePoint, I would recommend you to deploy the proxy page as a Layout page and update the url accordingly.

Hope you will find this post helpful.

The associated code behind and the Visual Studio 2010 project can be downloaded from here:

Sunday, September 12, 2010

SharePoint 2010 Pluggable Workflow Services – Part 2

This is the second post in the series SharePoint 2010 Pluggable Workflow Services. In the first post I demonstrated creating a very basic sequential workflow and exposing a business object which we’ll be leveraging to communicate the information from the workflow. In this post we will dive into the nitty-gritties of a Pluggable Workflow Service.

Creating a Pluggable Workflow Service

Here comes the crux of this post of as how we can create pluggable workflow service.

1. We will add new class file to our project and name is OrderTrackingService.

2. Add the following namespace deceleration to the class.

using System.Workflow.Activities;
using Microsoft.SharePoint.Workflow;

3. Now we will declare an interface IOrdertrackingService and add the following to the body of the interface.

[ExternalDataExchange]
public interface IOrderTrackingService
{
event EventHandler<OrderTrackingEventArgs> OrderTrackingEvent;
void DispatchOrder(Order order);
}

So what we did above is we defined a method signature DispatchOrder which when implemented on a class would do the needful task of creating an order entry in the database. This method would then be further called from the workflow service CallExternalMethod Activity. Also after executing the DispatchOrder method raises the OrderTrackingEvent to notify the workflow that the service has completed its execution. The HandleExternalEvents workflow activity then takes care of the event arguments as passed by the OrderTrackingEvent.

4. Add the following OrderTrackingEventArgs class.

[Serializable()]
public class OrderTrackingEventArgs : ExternalDataEventArgs
{
public OrderTrackingEventArgs(Guid id) : base(id) { }
public string DeliveryStatus;
}

The above code indicates that we will be passing DeliveryStatus as an argument to HandleExternalEvents activity back in the workflow.

5. Next on our OrderTrackingService class we will implement SPWorkflowExternalDataExchangeService and IOrderTrackingService interface.

class OrderTrackingService : SPWorkflowExternalDataExchangeService,IOrderTrackingService
{

public event EventHandler<OrderTrackingEventArgs> OrderTrackingEvent;

public void DispatchOrder(Order order)
{
throw new NotImplementedException();
}

public override void CallEventHandler(Type eventType, string eventName, object[] eventData, SPWorkflow workflow, string identity, System.Workflow.Runtime.IPendingWork workHandler, object workItem)
{
throw new NotImplementedException();
}

public override void CreateSubscription(MessageEventSubscription subscription)
{
throw new NotImplementedException();
}

public override void DeleteSubscription(Guid subscriptionId)
{
throw new NotImplementedException();
}
}

Now let’s write the logic for DispatchOrder method. Here we will use LINQ to SQL and connect to the local ContosoOrderTracking database which you restored using the db script.

6. Add a new item to the project of the type LINQ to SQL class and name is ContosoOrders.LinqToSqlClass

7. Using the server explorer create a connection to the ContosoOrderTracking db.ServerExpplorer

8. Drag and drop the ContosoOrder db table to the design surface.ContosoOrderTable

9. Back in the OrderTrackingService class, update the DispatchOrder method to like this.

public void DispatchOrder(Order order)
{
const string connection = @"Data Source=SHAREPOINT2010;Initial Catalog=ContosoOrderTracking;Integrated Security=True";

using (ContosoOrdersDataContext contosoDataCntxt = new ContosoOrdersDataContext(connection))
{
try
{
ContosoOrder corder = new ContosoOrder();
corder.Title = order.Title;
corder.Quantity = order.Quantity;
corder.Amount = order.Amount;
corder.CutomerName = order.CustomerName;
corder.ID = new Guid(order.ID);

contosoDataCntxt.ContosoOrders.InsertOnSubmit(corder);
contosoDataCntxt.SubmitChanges();

order.DeliveryStatus = "Delivered";
}
catch
{
order.DeliveryStatus = "Returned";
}
}

RaiseEvent(this.CurrentWorkflow.ParentWeb, this.CurrentWorkflow.InstanceId,
typeof(IOrderTrackingService), "OrderTrackingEvent", new object[] { order.DeliveryStatus });
}

In the above code, we leveraged the LINQ to SQL to create a new entry in the ContosoOrder database. The order object as used in the above code would be supplied by the calling workflow. Also we are setting the DeliveryStatus property of the order object to Delivered if the database entry is created successfully else we set it to Returned indicating a failure.

At the end we call the RaiseEvent method to notify the calling workflow of the completion of the service activity.

10. The final piece to complete this puzzle is to implement the CallEventHandler method as follows.

public override void CallEventHandler(Type eventType, string eventName, object[] eventData, SPWorkflow workflow, string identity, System.Workflow.Runtime.IPendingWork workHandler, object workItem)
{
if (string.Equals(eventName, "OrderTrackingEvent", StringComparison.OrdinalIgnoreCase))
{
var args = new OrderTrackingEventArgs(workflow.InstanceId);
args.DeliveryStatus = eventData[0].ToString();
this.OrderTrackingEvent(null, args);
}
}

The CallEventHandler method gets called each time when the workflow service requests an event. Here we create the OrderTrackingEventArgs instance and pass in the workflow's instance ID to so the event knows which workflow it's invoking the event with. We next pass in the status message from the event receiver and finally invoke the event.

This completes the workflow service here. Now we need to make our Order Tracking workflow be able to call this service.

Updating the Workflow to call Pluggable Workflow Service

1. Back in our Order Tracking workflow design surface; add the following activities as shown after logTOHistoryActivity1.

WorkflowDesign


2. After adding the above activities, select callExternalMethodActivity1 and set the following properties in the property pane as shown below.callExternalMethodActivity_1

3. Now right click handleExternalEventActivity1 and Generate Handlers. Also set the properties as shown below.handleExternalEventActivity1

4. For the property with the name e, we will bind it to a new activity field.bind_e

Back in the OrderTracking.cs file we will remove the highlighted code.

removecode

5. Update the handleExternalEventActivity1_Invoked as shown below.

public OrderTrackingEventArgs handleExternalEventActivity1_e1;
private void handleExternalEventActivity1_Invoked(object sender, ExternalDataEventArgs e)
{
logToHistoryListActivity2.HistoryDescription = string.Format("Order delivered to the customer sucessfully.");
}

6. Back in our Order Tracking workflow design surface, right click codeActivity2 and click Generate Handlers.

7. Update the codeActivity2_ExecuteCode method as follows.

private void codeActivity2_ExecuteCode(object sender, EventArgs e)
{
SPListItem item = workflowProperties.Item;
item["DeliveryStatus"] = handleExternalEventActivity1_e1.DeliveryStatus;
if (String.Equals(handleExternalEventActivity1_e1.DeliveryStatus,
"Delivered", StringComparison.OrdinalIgnoreCase))
{
item["InvoiceStatus"] = "Invoiced";
}
item.Update();
}

In the above code, we have used the value of the event arguments DeliveryStatus property to set list item’s delivery status field. Also we are checking if the order was delivered then raise the invoice to the customer.

8. The final step in this entire flow is to add some configurations to the target web applications web.config file to make the web application aware of our pluggable workflow service.

Add the entries below to the WorkflowServices tag under SharePoint section in the target web application.

<WorkflowService Assembly="OrderTrackingSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=YOUR_ASSEMLBLY_PKT" Class="OrderTrackingSystem.OrderTrackingService">
</WorkflowService>
webconfigchanges
9. Hit F5 and deploy the solution.

10. Running the workflow on the item we created previously.

ItemStatus_final

The history list shows the following updates.

workflowhistoryupdate The Database receives a new entry via the Pluggable Workflow Service


DatabaseEntry

Hope this series helped you to understand some basic concepts of creating a Pluggable Workflow Services.


The associated code and other resources can be downloaded from here:

SharePoint 2010 Pluggable Workflow Services – Part 1

Along with the many advancements and new features, SharePoint 2010 introduces a yet another important feature of Pluggable Workflow Services. While Pluggable Workflow Services have been around since Windows Workflow Foundation in .Net 3.5, its support was missing in SharePoint 2007. But now the SharePoint 2010 workflow engine supports it.

So what’s a Pluggable Workflow Service all about?

Here is what MSDN says:

Pluggable workflow services provide a mechanism that allows external applications or components to programmatically communicate with workflow instances currently running on the server.

This means that workflows in SharePoint 2010 now can interact with a wide variety of external events and allows a developer to control up to which point the workflow gets executed and waits for information from an external process.

Now when you say that the workflow instance waits for information from an external process, it doesn’t mean that the workflow instance needs to wait in an active state and consume server resources (like CPU, RAM etc.) till the time it gets the response back. The workflow instance would be dehydrated (aka the state of the workflow instance would be written to the database) and rehydrated back (aka workflow instance state read back from the database) once the external activity gets completed.

In this post I will attempt to explain a simple pluggable workflow service taking an order tracking system as an example. The order tracking system implements a sequential workflow which gets started as soon as a new order request is created. This workflow tracks the delivery status and the invoice status for a particular order.

When a new order request is created (via SharePoint list), the workflow calls a pluggable workflow service which tracks whether the order was delivered to the customer or not (creating a new database table entry) and accordingly updates the workflow about this information.

For running this example, you would need to

  • Restore ContosoOrderTracking.sql script for creating the ContosoOrderTracking database.
  • Create an Orders list using the Orders.stp list definition.

Create a Sequential Workflow

  1. Open visual Studio 2010, Select New->Project.
  2. Under the installed templates, select the SharePoint -> 2010.
  3. Select the Empty SharePoint Project Template and enter the project name as OrderTrackingSystem and click OK.
  4. Enter the target site collection name for debugging purpose. Now, since we are going to create a Visual Studio workflow, we need to deploy this solution as a farm solution. DeploymentType

5. Click Finish

At this point we have a bare metal SharePoint solution ready. Now we will add a new Sequential Workflow SPI (SharePoint Items) to this solution.

6. Add a new item and select Sequential Workflow and name it OrderTracking.AddSequentialWF

7. Click Add.
8. Name the workflow as Order Tracking and leave the workflow type as List Workflow.WorkFlowType

9. Click Next.
10. From the library or list dropdown, select the Orders list (as shown below) which you created using the attached stp file and leave the other selections as is.SelectList

11. Click Next.
12. We want this workflow to get started on new item creation as well as manually. Leave the current selections default and click Finish.ConditionToStart

At this point our solution should look like as shown below. Before we move ahead, we would need to make some changes to this solution for consistency.SolutionStructure

13. Rename the Feature1 to a sensible name as OrderTrackingWorkflow.

At this point we are done creating a very basic SharePoint sequential workflow solution. You can optionally hit F5 to ensure that everything is fine which I am sure it would be J.

Creating a Business Object

Now we will need a custom business object “Order” which can encapsulate the order information and makes it easy for us to communicate with our workflow and the Pluggable Workflow Service.

  1. Add a new class Order to our workflow solution.
  2. We will add 6 properties to our order class representing the attributes of an order namely ID, Title, Quantity, Amount, Customer, DeliveryStatus.
  3. Since we are dealing with a workflow where persisting the object state is a must, we would need to make Order class Serializable by implementing ISerializable interface and decorate it with Serializable attribute.
  4. Also we would need to implement the GetObjectData method for serializing the object and the default constructer to deserialize it.
    At this point the Order class should look like this.
  5. using System;
    using System.Runtime.Serialization;

    [Serializable()]
    public class Order : ISerializable
    {
    public string ID { get; set; }
    public string Title { get; set; }
    public string Quantity { get; set; }
    public string CustomerName { get; set; }
    public string Amount { get; set; }
    public string DeliveryStatus { get; set; }

    public Order()
    {}

    public Order(SerializationInfo info, StreamingContext context)
    {
    ID = (string)info.GetValue("ID", typeof(string));
    Title = (string)info.GetValue("Title", typeof(string));
    Quantity = (string)info.GetValue("Quantity", typeof(string));
    CustomerName = (string)info.GetValue("CustomerName", typeof(string));
    Amount = (string)info.GetValue("Amount", typeof(string));
    DeliveryStatus = (string)info.GetValue("DeliveryStatus", typeof(string));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
    info.AddValue("ID", ID);
    info.AddValue("Title", Title);
    info.AddValue("Quantity", Quantity);
    info.AddValue("CustomerName", CustomerName);
    info.AddValue("Amount", Amount);
    info.AddValue("DeliveryStatus", DeliveryStatus);
    }
    }

Adding Life to thee Workflow

Now we will add some activities to the sequential workflow we created above.

  1. Switch to the workflow design view and drag and drop a Code and LogToHistoryList activity on the design surface.WorkflowDesign_part1

2. Right click in codeActivity1 and click Generate Handlers from the menu. This will add a code behind method for this activity.

3. Back in the code create in instance of the Order class.

public Order order = new OrderTrackingSystem.Order();

4. Also the following code to the codeActivity1_ExecuteCode method.

In the code below we are taking the current list item on which the workflow is running and initializing the order object with the required properties. Also we are updating the list item DeliveryStaus choice field to Dispatched indicating that the order has been dispatched to the customer.

private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
SPListItem item = workflowProperties.Item;
order.Title = item.Title;
order.ID = item.UniqueId.ToString();
order.Quantity = item["Quantity"].ToString();
order.Amount = item["Amount"].ToString();
order.CustomerName = item["CustomerName"].ToString();

item["DeliveryStatus"] = "Dispatched";
item.Update();
}

5. At this point it would be a good idea to update the workflow history list with a status message. Repeat #2 to generate handlers for logToHistoryListActivity1 and add the following code.

private void logToHistoryListActivity1_MethodInvoking(object sender, EventArgs e)
{
logToHistoryListActivity1.HistoryDescription = "Order dispatched to the customer.";
}


6. Put a break point in codeActivity1_ExecuteCode hit F5 to deploy and debug the solution.


Now let’s add a new item to the Orders list and see if the workflow is functioning properly.

NewItem

As soon as you save the above item, the break point in our workflow gets hit where you can further play around and see the runtime properties of the objects. Further hit F5 to come out of debugging mode.

DebugCode

This will complete you workflow on the item you created above and now the DeliveryStatus field shows Dispatched. Also the workflow status field show Completed.

ItemStatus

Also clicking on this Completed link will navigate you to page below where you can see the status page of the workflow where we can see the comments in workflow history.

WorkflowStatus

In the next post we will dive into the details of creating a Pluggable Workflow Service.

The associated code and other resources can be downloaded from here:

Sunday, August 1, 2010

Duplicate name error while creating SharePoint publishing page instance

Most of the time you would always find some or the other issues while deploying your solution components from dev environment to any other environment like authoring or staging.

A couple of days before, we encountered one such issue while creating page instances using our custom content types on authoring environment. The error we encountered was

A duplicate name “YOUR CONTENT TYPE NAME” was found. at Microsoft.SharePoint.Publishing.Internal.Codebehind.CreatePagePage.HandleUnexpectedException(PublishingPage newPage, Exception exception)….

Also this error also wouldn’t even let the content deployment job to succeed.

pageinstanceerror

After scratching my head for a couple of hours I finally found the issue/resolution and thought to share the same with the community.

The issue circles around the Content Type Association feature which we leveraged to binds our custom content type instance with the MOSS Pages library.

Background:

The content types we created for sprint 1 inherited from MOSS Page content type and accordingly they we associated them with the designated page layouts, packaged and deployed on authoring environment.

Everything worked fine here!!

Later in Sprint 2, due to some change in the customer requirement we had to update our custom content types to inherit from a different content type – ABC content type (provided by the customer). So accordingly we updated the IDs for all the content type but rest of the properties (like Name) remained same. This update was again packaged and redeployed on authoring environment.

The above error occurred!! 

Root Cause:

Now once you redeployed a branding WSP, it would first delete the existing site content types and columns and other stuff but!! it won’t update the content type associations which are already there with the Pages library (at least for the content types having the same names). So our content types instances (apparently stale) in Pages library continued to inherit from Page content type instead of ABC content type. And here we ended up with two versions of content types with duplicate names.  

Solution:

Just delete the stale content type instance from the Pages library before you redeploy the new package and everything should work fine. Simple isn’t it J

Friday, July 23, 2010

Duplicate web parts shown in SharePoint publishing page layouts and page instances


Recently I came across another interesting issue with SharePoint page layouts. For a project requirement, we created some page layouts with almost the same structure having couple of predefined web part zones. Further each web part zone had a predefined Content Editor Web Part (CEWP). After packaging the same, I deployed the WSP on our test environment.

As pictures speak more than words, the screen grab below (left most) depicts the issue I encountered. When creating a page instance using any of our custom page layout, every web part zone showed duplicate CEWP web parts instead of just one CEWP.

Page instance in edit mode

  Page layout in SPD

Inspecting the page layouts in SharePoint Designer (SPD) resulted in the screen grab above (right most). The same duplicate web part appeared on the design mode.

At first I tried to repackage and redeploy the page layouts a couple of times thinking this would solve my issue, but was disappointed. Again, everything worked fine on the development environment where the page layouts were designed and created. It’s only when I packaged and deployed the page layouts via WSP and features this issue would show up.

I finally started inspecting the markup of the page layouts and found something interesting. I did a search for the web part zone GUIDs in SPD and below is the result of the query.

The result showed 82 occurrences of the same web part zone GUID in our custom page layouts (highlighted in yellow)!!.

 SPD GUID search result

 

 

 

 

 

 

 

 

Apparently what happened was the designer had taken the advantage of the fact that all the page layouts had almost the same structure and used the magic keys (CTRL+C & CTRL+V) to create them J

Issue:
Using the same web part zone GUID multiple times whether in same page layout or a different  page layout would result into the web part being shown up multiple times.

Resolution:
Ensure that every web part zone and web part in your page layouts have a unique GUID across your site collection.

Wednesday, January 27, 2010

SharePoint 2010 Social Networking Part 1: Setting the user My Site status message programmatically

SharePoint 2010 comes along with a wide range of the social feature like note boards, rating, bookmarking, tagging etc. I’ll be doing a series of blog posts to share some code snippets for managing these cool features programmatically.

One of the interesting social feature is setting the My Site status message which depicts the mood of the user. In the part 1 of this series I’ll demonstrate a small code snippet to set the My Site status message programmatically.

So we’ll start by adding the required assembly references to our console application:

Microsoft.SharePoint.dll
Microsoft.Office.Server.dll
Microsoft.Office.Server.UserProfiles.dll
System.Web

Followed by the following namespace decelerations:

using Microsoft.SharePoint;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;

Now one wearied issue that the users with Visual Studio 2010 beta would notice here is as soon as you compile the solution, you’ll probably notice this error followed by a warning:

image

I wasted a whole day fighting this issue until I found this post by Chris where he points out it as a development issue in VS2010 beta build.

So essentially we would need to add the reference to System.Web.DataVisualization.dll into our project and we are good to go.

Now we’ll add the method as shown below to our application:

  SetStatusMessage

Essentially here we are stating by instantiating the SPSite object for a SharePoint site URL (http://intranet.contoso.com). Then we are creating an object of SPServiceContext class which would enable us make a call to the user profile service application.

Next is to instantiate the UserProfileManager class object for accessing the user profiles and their data stored in the user profile database. The GetUserProfile method of the UserProfileManager class accepts several overloads and returns the user profile for the specified user (in our case the administrator).

Now among the several OOB user profile properties configured on the server, the property SPS-StatusNotes is the one which we are looking for. Setting the value of this property with a string value would set the the status message for the user. The final step is to commit the changes by calling the Commit method.

Now call this method and pass a string message “Status set from code.”. Finally executing our console app would result in setting the status message for administrator as shown in the image below.

 My Site status.