Saturday, December 19, 2009

WorkflowInvoker in WF 4.0

Just noticed this new and handy class in .NET 4.0 Beta 2. Following is its description on MSDN document:

"Windows Workflow Foundation (WF) provides several methods of hosting workflows. WorkflowInvoker provides a simple way for invoking a workflow as if it were a method call and can be used only for workflows that do not use persistence."

Simple enough, if we just want to invoke a workflow synchronously with current thread (WorkflowInvoker also provides asynchronous versions of the invoke method with InvokeAsync and BeginInvoke), WorkflowInvoker is your best friend, and you don't need to set up the environment for workflow runtime:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Activities;
using System.Activities.Statements;

class Program
{
static void Main(string[] args)
{
Activity activity = new WriteLine() { Text = "Workflow running at " + DateTime.Now.ToString() };
WorkflowInvoker.Invoke(activity);
Console.ReadLine();
}
}
For long running workflows or persistence scenarios, .NET 4.0 also added a new WorkflowApplication class, which provides a richer model for executing workflows that includes notification of lifecycle events, execution control, bookmark resumption, and persistence. Details refer to http://msdn.microsoft.com/en-us/library/system.activities.workflowapplication.aspx.

Friday, December 11, 2009

New DynamicObject In .NET 4.0

Microsoft has released SharePoint 2010 Beta2 and .NET 4.0 Beta2 recently (Ironically SharePoint 2010 is still based on .NET 3.5).

The new Dynamic type in .NET 4.0 looks quite interesting. Not like .NET 3.5 dynamic variable (var keyword) which is static type inference by compiler, Dynamic objects are run-time behavior. Following code example is copied from MSDN documentation, and comments are removed for brevity reason:
using System;
using System.Collections.Generic;
using System.Dynamic;

public class DynamicDictionary : DynamicObject
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public int Count { get { return dictionary.Count; }}

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string name = binder.Name.ToLower();
return dictionary.TryGetValue(name, out result);
}

public override bool TrySetMember(SetMemberBinder binder, object value)
{
dictionary[binder.Name.ToLower()] = value;
return true;
}
}

class Program
{
static void Main(string[] args)
{
dynamic person = new DynamicDictionary();
person.FirstName = "Ellen";
person.LastName = "Adams";

Console.WriteLine(person.firstname + " " + person.lastname);
Console.WriteLine( "Number of dynamic properties:" + person.Count);
Console.Read();
}
}
The result is:
Ellen Adams
Number of dynamic properties:2

Thursday, December 03, 2009

SharePoint Impersonation by SPUser

The SPUser class has a UserToken property that can be passing into the SPSite constructor to impersonate that particular user:
        SPSite contextSite = SPContext.Current.Site;
        SPUser user = contextSite.SystemAccount;
        using (SPSite site = new SPSite(contextSite.ID, user.UserToken))
        {
            using (SPWeb web = site.OpenWeb())
            {
                // Do stuff
            }
        }
Above code snippet impersonates the system account to open a SPSite which is equivalent to:
        SPSecurity.RunWithElevatedPrivileges(delegate()
        {
            using (SPSite site = new SPSite(SPContext.Current.Site.ID))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    // Do stuff
                }
            }
        });

Tracing IIS 500 Error Using Failed Request Tracing Rules

After extended a SharePoint Web Application I got a 500 server error. There's not related event log and the IIS log shows:
2009-12-02 19:37:21 IP GET / - 10.10.1.11 Jakarta+Commons-HttpClient/3.1 500 19 183 0
The HTTP status code 500.19 for IIS 7.0 is "Configuration data is Invalid.". That's not very helpful and I couldn't find obvious issue in web.config. To see more detailed error message I enabled IIS Failed Request Tracing, where I was able to find out the exact error in configuration file:



So the error is caused by "cannot add duplicate collection entry of type 'add' with unique key attribute 'name' set to 'session'". It looks like the "Session" module has already been registered somewhere by SharePoint when the configuration entries are merged. Change the the web.config from original:
    <add name="Session" type="System.Web.SessionState.SessionStateModule" />
    <remove name="Session" />
to:
    <remove name="Session" />
    <add name="Session" type="System.Web.SessionState.SessionStateModule" />
Then the extended web application works normally.