﻿<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
  <channel>
    <title>Eddie@Blog</title>
    <description>The little potato working towards a hash brown</description>
    <link>http://fszlin.dymetis.com/</link>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>BlogEngine.NET 2.0.0.47</generator>
    <language>en-US</language>
    <blogChannel:blogRoll>http://fszlin.dymetis.com/opml.axd</blogChannel:blogRoll>
    <blogChannel:blink>http://www.dotnetblogengine.net/syndication.axd</blogChannel:blink>
    <dc:creator>Eddie Z. Lin</dc:creator>
    <dc:title>Eddie@Blog</dc:title>
    <geo:lat>0.000000</geo:lat>
    <geo:long>0.000000</geo:long>
    <item>
      <title>Protecting WCF Data Services using OAuth</title>
      <description>&lt;p&gt;Regarding this topic, there is a nice post &lt;a href="http://blogs.msdn.com/b/astoriateam/archive/2011/01/20/oauth-2-0-and-odata-protecting-an-odata-service-using-oauth-2-0.aspx"&gt;here&lt;/a&gt;by Alex James. One thing that I am wondering after reading the article, is that the demo rely on &lt;em&gt;HttpModule&lt;/em&gt; and &lt;em&gt;HttpContext.Current&lt;/em&gt; directly. For the purpose of test automation, I would like to avoid this if at all possible. And Andrew Arnott ships an example of securing WCF service using &lt;a href="http://oauth.net/"&gt;OAuth&lt;/a&gt;, in his &lt;a href="http://www.dotnetopenauth.net/"&gt;DotNetOpenAuth&lt;/a&gt; library, which use &lt;a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.serviceauthorizationmanager.aspx"&gt;ServiceAuthorizationManager&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/system.identitymodel.policy.iauthorizationpolicy.aspx"&gt;IAuthorizationPolicy&lt;/a&gt; to inject identities. This approach is more flexible in my case, and I don’t have to worry about combining this with Form authentication, which is used by the existing part of the application.&lt;/p&gt;

&lt;p&gt;In this post, I am going to build a demo WCF Data Service which is protected by &lt;em&gt;OAuth&lt;/em&gt; using &lt;em&gt;ServiceAuthorizationManager&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Since this post is focus on gaining access to protected resources, I will start from the point that the client already has the access token. First, let’s take a look at what’s needed before coding. &lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;DotNetOpenAuth&lt;/em&gt;, used to validate &lt;em&gt;OAuth&lt;/em&gt; tokens; &lt;/li&gt;

  &lt;li&gt;A pair of valid &lt;em&gt;OAuth&lt;/em&gt; access token and secret; &lt;/li&gt;

  &lt;li&gt;Simple WCF Data Service to be protected; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before setting up the authorization, we need a simple entity model to backup the Data Service. The EDM is created using Code-First, as shown in the following diagram.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Database Models" src="http://fszlin.dymetis.com/image.axd?picture=2011%2f5%2fProtectingWCF.Db.png" /&gt;&lt;/p&gt;

&lt;p&gt;And the WCF Data Service.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;public class SimpleDbService : DataService&amp;lt;SimpleDbContext&amp;gt;
{
    public static void InitializeService(DataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule(&amp;quot;Contacts&amp;quot;, EntitySetRights.AllRead);
        config.SetEntitySetAccessRule(&amp;quot;Employees&amp;quot;, EntitySetRights.AllRead);
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
        config.UseVerboseErrors = true;
    }
}&lt;/pre&gt;

&lt;p&gt;The next is to implement a custom &lt;em&gt;OAuthAuthorizationManager&lt;/em&gt;. In the &lt;a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.serviceauthorizationmanager.checkaccesscore.aspx"&gt;CheckAccessCore&lt;/a&gt; method, it will try to extract the access token from the authorization header, which is available from the request message. And then issue the corresponding identity if the request containing a valid access token.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;protected override bool CheckAccessCore(OperationContext operationContext)
{
    if (!base.CheckAccessCore(operationContext))
    {
        return false;
    }

    // Resolve OAuth service provider.
    var oAuthProvider = SessionContext.Container.Resolve&amp;lt;ServiceProvider&amp;gt;();

    // Extract authorization data.
    var requestMessage = operationContext.RequestContext.RequestMessage;
    var httpDetails = requestMessage.Properties[HttpRequestMessageProperty.Name] 
        as HttpRequestMessageProperty;
    var requestUri = requestMessage.Properties.Via;

    // Validate the access token.
    var authorizedRequest = oAuthProvider.ReadRequest(
        new HttpRequestInfo(httpDetails, requestUri)) as AccessProtectedResourceRequest;

    IIdentity identity;
    ServiceSecurityContext securityContext;

    if (authorizedRequest != null)
    {
        // Create OAuth principal and identity from the access token.
        var principal = oAuthProvider.CreatePrincipal(authorizedRequest);

        // Initialize the security context, which will then issued the name claim in the policy.
        securityContext = new ServiceSecurityContext(
            new List&amp;lt;IAuthorizationPolicy&amp;gt;()
            {
                new OAuthPrincipalAuthorizationPolicy(principal) 
            }.AsReadOnly());

        identity = principal.Identity;
    }
    else
    {
        // Issue anonymous principal and identity.
        securityContext = ServiceSecurityContext.Anonymous;
        var principal = new GenericPrincipal(new GenericIdentity(String.Empty), new string[0]);
        securityContext.AuthorizationContext.Properties[&amp;quot;Principal&amp;quot;] = principal;

        identity = principal.Identity;
    }

    // Setup the security context and identity.
    operationContext.IncomingMessageProperties.Security.ServiceSecurityContext = securityContext;
    securityContext.AuthorizationContext.Properties[&amp;quot;Identities&amp;quot;] = new List&amp;lt;IIdentity&amp;gt; { identity };
            
    // The service will handle security, so allow the process continue here regardless.
    return true;
}&lt;/pre&gt;

&lt;p&gt;The &lt;em&gt;OAuthPrincipalAuthorizationPolicy&lt;/em&gt; used above is the same as the one in Andrew’s example, which sets the name claim and principal.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
    evaluationContext.AddClaimSet(
        this, new DefaultClaimSet(Claim.CreateNameClaim(this.principal.Identity.Name)));
    evaluationContext.Properties[&amp;quot;Principal&amp;quot;] = this.principal;
    return true;
}&lt;/pre&gt;

&lt;p&gt;The implementation here will allow anonymous access, so that our WCF Data Service can response selectively. For instance, I want to allow anonymous to query Contact entries, but only authorized request are allowed to query Employee entries. To grad operations, we can use &lt;a href="http://msdn.microsoft.com/en-us/library/system.data.services.queryinterceptorattribute.aspx"&gt;QueryIntercepter&lt;/a&gt; and &lt;a href="http://technet.microsoft.com/en-us/library/system.data.services.changeinterceptorattribute.aspx"&gt;ChangeIntercepter&lt;/a&gt; to monitor the requests, and response with 401 if the contextual identity is not authenticated.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;[QueryInterceptor(&amp;quot;Employees&amp;quot;)]
public Expression&amp;lt;Func&amp;lt;Employee, bool&amp;gt;&amp;gt; OnQueryEmployees()
{
    if (ServiceSecurityContext.Current == null || 
        !ServiceSecurityContext.Current.PrimaryIdentity.IsAuthenticated)
    {
        throw new DataServiceException(401, &amp;quot;Access is denied.&amp;quot;);
    }

    return e =&amp;gt; true;
}&lt;/pre&gt;

&lt;p&gt;Finally, to tie all of these things together, we need to configure the custom authorization manger via service behaviour. The following will set the custom authorization manager as default.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;&amp;lt;behavior name=&amp;quot;&amp;quot;&amp;gt;
  &amp;lt;serviceDebug includeExceptionDetailInFaults=&amp;quot;true&amp;quot;/&amp;gt;
  &amp;lt;serviceAuthorization serviceAuthorizationManagerType=&amp;quot;Dymetis.Security.Authorization.OAuthAuthorizationManager, Dymetis.Security&amp;quot; principalPermissionMode=&amp;quot;Custom&amp;quot; /&amp;gt;
&amp;lt;/behavior&amp;gt;&lt;/pre&gt;

&lt;p&gt;Now, if querying Contact entries using browser, you should see the data feed, as shown in the following screen shot.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Querying Contacts" src="http://fszlin.dymetis.com/image.axd?picture=2011%2f5%2fProtectingWCF.QueryingContacts.png" /&gt;&lt;/p&gt;

&lt;p&gt;While accessing the Employee entries will receive &lt;em&gt;401 Unauthorized&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Querying Employees" src="http://fszlin.dymetis.com/image.axd?picture=2011%2f5%2fProtectingWCF.QueryingEmployees.png" /&gt;&lt;/p&gt;

&lt;p&gt;So how can we attach the authorization header when sending requests using Data Service Client? First, we need to turn the access token into authorization header. The following sample simply get the header from a request prepared using &lt;em&gt;DotNetOpenAuth&lt;/em&gt;.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;var consumerClient = new WebConsumer(description, consumerTokenManager);
var serviceEndpoint = new MessageReceivingEndpoint(
    new Uri(baseAddress, &amp;quot;Contacts&amp;quot;),
    HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest);
var httpRequest = consumerClient.PrepareAuthorizedRequest(serviceEndpoint, accessToken.Token);
var authHeader = httpRequest.Headers[HttpRequestHeader.Authorization];&lt;/pre&gt;

&lt;p&gt;Not like regular WCF service client, which use OperationContextScope to modify the headers, when using data service client, we can inject our header by listening SendingRequest event.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;var dataContext = new SimpleDbContext(baseAddress);
dataContext.SendingRequest += (sender, e) =&amp;gt; e.RequestHeaders[HttpRequestHeader.Authorization] = authHeader;&lt;/pre&gt;

&lt;p&gt;Now we’re good for publishing and accessing WCF Data Service using &lt;em&gt;OAuth&lt;/em&gt;. Even though the above example is using &lt;em&gt;OAuth&lt;/em&gt; 1.0, the same principals should work for any authorization flow that using HTTP header to send security tokens. In the next post, I am going to automated the tests for this demo, which is one of my major concern.&lt;/p&gt;
</description>
      <link>http://fszlin.dymetis.com/post/2011/05/20/Protecting-WCF-Data-Services-using-OAuth.aspx</link>
      <comments>http://fszlin.dymetis.com/post/2011/05/20/Protecting-WCF-Data-Services-using-OAuth.aspx#comment</comments>
      <guid>http://fszlin.dymetis.com/post.aspx?id=492c6cf1-e3b2-4573-b203-81aca6032347</guid>
      <pubDate>Fri, 20 May 2011 02:00:00 -0400</pubDate>
      <category>Web Development</category>
      <dc:publisher>fszlin</dc:publisher>
      <pingback:server>http://fszlin.dymetis.com/pingback.axd</pingback:server>
      <pingback:target>http://fszlin.dymetis.com/post.aspx?id=492c6cf1-e3b2-4573-b203-81aca6032347</pingback:target>
      <slash:comments>317</slash:comments>
      <trackback:ping>http://fszlin.dymetis.com/trackback.axd?id=492c6cf1-e3b2-4573-b203-81aca6032347</trackback:ping>
      <wfw:comment>http://fszlin.dymetis.com/post/2011/05/20/Protecting-WCF-Data-Services-using-OAuth.aspx#comment</wfw:comment>
      <wfw:commentRss>http://fszlin.dymetis.com/syndication.axd?post=492c6cf1-e3b2-4573-b203-81aca6032347</wfw:commentRss>
    </item>
    <item>
      <title>Screen Capturing with Silverlight Applications</title>
      <description>&lt;p&gt;The user of a Silverlight application is keep complaining about he couldn't capture pictures of the application. I navigate to the web site, press print screen, paste into Paint.NET, and everything works as expected. After sitting with the user, it turns out that he is using a Firefox extension &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/screengrab/"&gt;Screengrab&lt;/a&gt; to capture the web page.&lt;/p&gt;

&lt;p&gt;Then I browsing around the internet, and using couples of screen capturing extensions to shoot Silverlight apps. Apparently, most of Silverlight apps don&amp;rsquo;t like these extensions. The following screen shot shows what happen when using &lt;a href="https://chrome.google.com/extensions/detail/cpngackimfmofbokmjmljamhdncknpmg"&gt;Google Capture&lt;/a&gt; with the Silverlight template.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://fszlin.dymetis.com/image.axd?picture=2011%2f5%2fGoogle-Capture-Windowless-False.png" alt="Capturing with Windowless Off" /&gt;&lt;/p&gt;

&lt;p&gt;This sounds like overlapping issue, and the solution is simple &amp;ndash; setting &lt;em&gt;windowless&lt;/em&gt; parameter to true in the Silverlight object tag. It will look like this, which is getting from &lt;a href="http://silverlight.net"&gt;silverlight.net&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://fszlin.dymetis.com/image.axd?picture=2011%2f5%2fGoogle-Capture-Windowless-On.png" alt="Capturing with Windowless On" /&gt;&lt;/p&gt;
&lt;p&gt;But the parameter &lt;em&gt;windowless&lt;/em&gt; comes with costs, it should be turn on only if necessary. See &lt;a href="http://msdn.microsoft.com/en-us/library/cc838156.aspx"&gt;here&lt;/a&gt;for more details.&lt;/p&gt;</description>
      <link>http://fszlin.dymetis.com/post/2011/05/05/Screen-Capturing-with-Silverlight-Applications.aspx</link>
      <comments>http://fszlin.dymetis.com/post/2011/05/05/Screen-Capturing-with-Silverlight-Applications.aspx#comment</comments>
      <guid>http://fszlin.dymetis.com/post.aspx?id=ec7cd8b7-43eb-4a2c-be73-bf5d7dbc7b7f</guid>
      <pubDate>Thu, 05 May 2011 00:29:00 -0400</pubDate>
      <category>Web Development</category>
      <dc:publisher>fszlin</dc:publisher>
      <pingback:server>http://fszlin.dymetis.com/pingback.axd</pingback:server>
      <pingback:target>http://fszlin.dymetis.com/post.aspx?id=ec7cd8b7-43eb-4a2c-be73-bf5d7dbc7b7f</pingback:target>
      <slash:comments>452</slash:comments>
      <trackback:ping>http://fszlin.dymetis.com/trackback.axd?id=ec7cd8b7-43eb-4a2c-be73-bf5d7dbc7b7f</trackback:ping>
      <wfw:comment>http://fszlin.dymetis.com/post/2011/05/05/Screen-Capturing-with-Silverlight-Applications.aspx#comment</wfw:comment>
      <wfw:commentRss>http://fszlin.dymetis.com/syndication.axd?post=ec7cd8b7-43eb-4a2c-be73-bf5d7dbc7b7f</wfw:commentRss>
    </item>
    <item>
      <title>TFS Event Filtering, Logical Expressions and Expression Tree</title>
      <description>    &lt;p&gt;
        In TFS, we can filter the server events by using &lt;a href="http://msdn.microsoft.com/en-us/library/bb130302.aspx"&gt;
            Visual Studio Event Filter Language&lt;/a&gt; (VSEFL). Obviously, VSEFL is a variation
        of logical expression. On the other hand, since C# 3.0 introduces Expression Tree,
        I am always seeking for a lightweight library can translate logical expressions
        to Expression tree, and vice versa. So that the program can manipulate the expression
        easily, and then evaluate it as Lambda expression. However, the VSEFL parser is
        hidden inside TFS’ assemblies. This post will present a way to implement a parser
        for translating logical expressions, which is used to support VSEFL in the &lt;a href="http://teamalert.codeplex.com"&gt;
            this project&lt;/a&gt;.&lt;/p&gt;
    &lt;p&gt;
        First of all, let’s compare the VSEFL with C# expressions, and how we do it in C#.
        Note that I assume there’s no side effect when retrieving field values, hence logical
        AND/OR are considered the same as short-circuiting conditional AND/OR.&lt;/p&gt;
    &lt;table&gt;
        &lt;thead&gt;
            &lt;tr&gt;
                &lt;th&gt;
                    VSEFL
                &lt;/th&gt;
                &lt;th&gt;
                    Expression Type
                &lt;/th&gt;
                &lt;th&gt;
                    C#
                &lt;/th&gt;
            &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    AND
                &lt;/td&gt;
                &lt;td&gt;
                    And
                &lt;/td&gt;
                &lt;td&gt;
                    &amp;amp;&amp;amp;
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    OR
                &lt;/td&gt;
                &lt;td&gt;
                    Or
                &lt;/td&gt;
                &lt;td&gt;
                    ||
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    NOT
                &lt;/td&gt;
                &lt;td&gt;
                    Not
                &lt;/td&gt;
                &lt;td&gt;
                    !
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    =
                &lt;/td&gt;
                &lt;td&gt;
                    Equal
                &lt;/td&gt;
                &lt;td&gt;
                    ==
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    &amp;lt;&amp;gt;
                &lt;/td&gt;
                &lt;td&gt;
                    NotEqual
                &lt;/td&gt;
                &lt;td&gt;
                    !=
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    &amp;lt;
                &lt;/td&gt;
                &lt;td&gt;
                    LessThan
                &lt;/td&gt;
                &lt;td&gt;
                    &amp;lt;
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    &amp;lt;=
                &lt;/td&gt;
                &lt;td&gt;
                    LessThanOrEqual
                &lt;/td&gt;
                &lt;td&gt;
                    &amp;lt;=
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    &amp;gt;
                &lt;/td&gt;
                &lt;td&gt;
                    GreaterThan
                &lt;/td&gt;
                &lt;td&gt;
                    &amp;gt;
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    &amp;gt;=
                &lt;/td&gt;
                &lt;td&gt;
                    GreaterThanOrEqual
                &lt;/td&gt;
                &lt;td&gt;
                    &amp;gt;=
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    UNDER
                &lt;/td&gt;
                &lt;td&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    String.StartsWith
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    MATCH, LIKE
                &lt;/td&gt;
                &lt;td&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    Regex.IsMatch
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    Integer Literal
                &lt;/td&gt;
                &lt;td&gt;
                    Constant
                &lt;/td&gt;
                &lt;td&gt;
                    Int32.ToString
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    String Literal
                &lt;/td&gt;
                &lt;td&gt;
                    Constant
                &lt;/td&gt;
                &lt;td&gt;
                    String
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    NULL
                &lt;/td&gt;
                &lt;td&gt;
                    Constant
                &lt;/td&gt;
                &lt;td&gt;
                    null
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    Date Expression
                &lt;/td&gt;
                &lt;td&gt;
                &lt;/td&gt;
                &lt;td&gt;
                    DateTime.Now, DateTime.Parse and DateTime.AddDays
                &lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
                &lt;td&gt;
                    Value by Field Name
                &lt;/td&gt;
                &lt;td&gt;
                    Parameter
                &lt;/td&gt;
                &lt;td&gt;
                    variables
                &lt;/td&gt;
            &lt;/tr&gt;
        &lt;/tbody&gt;
    &lt;/table&gt;

    &lt;p&gt;
        As shown in the above table, some of the VSEVL operators have no corresponding expression,
        but they can be easily simulated as one or more method calls.
    &lt;/p&gt;
    &lt;p&gt;
        In the following event filter for a BuildCompletionEvent2 event, the expression
        will yield all non-succeed builds that belong to DemoProject.
    &lt;/p&gt;
    &lt;pre class="brush: text"&gt;DefinitionPath Under '\DemoProject\'
AND (
	StatusCode LIKE 'Stopped|Failed|PartiallySucceeded'
	OR (
		StatusCode = Succeeded
		AND TestStatus &amp;lt;&amp;gt; Succeeded
	)
)&lt;/pre&gt;
    &lt;p&gt;
        As you saw, field names are presented as string literals in VSEVL. In my case, I
        want to have a more generic expression parser, which will need to know exactly a
        token is field or literal. Anyway, let’s see how the expression tree can be built
        in C# manually.&lt;/p&gt;
    &lt;pre class="brush: csharp"&gt;var paramDefinitionPath = Expression.Parameter(typeof(string), &amp;quot;DefinitionPath&amp;quot;);
var paramStatusCode = Expression.Parameter(typeof(string), &amp;quot;StatusCode&amp;quot;);
var paramTestStatus = Expression.Parameter(typeof(string), &amp;quot;TestStatus&amp;quot;);

var expression =
    Expression.And(
        Expression.Call(
            paramDefinitionPath,
            typeof(string).GetMethod(&amp;quot;StartsWith&amp;quot;, new[] { typeof(string), typeof(StringComparison) }),
            Expression.Constant(@&amp;quot;\DemoProject\&amp;quot;, typeof(string)),
            Expression.Constant(StringComparison.OrdinalIgnoreCase, typeof(StringComparison))
        ),
        Expression.Or(
            Expression.Call(
                typeof(Regex).GetMethod(&amp;quot;IsMatch&amp;quot;,
                    new[] { typeof(string), typeof(string), typeof(RegexOptions) }),
                paramStatusCode,
                Expression.Constant(&amp;quot;Stopped|Failed|PartiallySucceeded&amp;quot;, typeof(string)),
                Expression.Constant(RegexOptions.IgnoreCase, typeof(RegexOptions))
            ),
            Expression.And(
                Expression.Equal(
                    paramStatusCode,
                    Expression.Constant(&amp;quot;Succeeded&amp;quot;, typeof(string))
                ),
                Expression.NotEqual(
                    paramTestStatus,
                    Expression.Constant(&amp;quot;Succeeded&amp;quot;, typeof(string))
                )
            )
        )
    );

var lambda = Expression.Lambda&amp;lt;Func&amp;lt;string, string, string, bool&amp;gt;&amp;gt;(
    expression, paramDefinitionPath, paramStatusCode, paramTestStatus);

var result = lambda.Compile().Invoke(@&amp;quot;\DemoProject\MyApp&amp;quot;, &amp;quot;Succeeded&amp;quot;, &amp;quot;Failed&amp;quot;);
Assert.IsTrue(result);&lt;/pre&gt;
    &lt;p&gt;
        Essentially, it a tree with various types of expression nodes. Here’s how it looks
        like graphically.&lt;/p&gt;
    &lt;p&gt;&lt;img src="http://fszlin.dymetis.com/image.axd?picture=2011%2f4%2fExpressionTree.png" alt="Expression Tree" /&gt;&lt;/p&gt;
    &lt;p&gt;
        So far, we have everything in VSEFL mapped out to expressions, or if needed, we
        can always map special operations to method calls. The rest of the task is simply
        string parsing. For the expressions discussed here, a forward only algorithm is
        enough and given a time complexity of O(n), where n is the length of the input expression.
        If you want to handle more complicate scenario, you may want to check out &lt;a href="http://dlr.codeplex.com/"&gt;
            DLR&lt;/a&gt; or &lt;a href="http://www.antlr.org/"&gt;ANTLR&lt;/a&gt; before working on your
        lexer.&lt;/p&gt;
    &lt;p&gt;
        As previously mentioned, I want to represent fields(or parameters) in a way that
        different from string literals. I have chosen to prefix parameters with dollar sign
        ($), which is the simplest I found, in terms of converting existing VSEFL expressions.&lt;/p&gt;
    &lt;p&gt;
        Another tricky thing is the comparisons. Due to lack of data type information, the
        parameters values are always supplied as objects, and this may cause confusion if
        a value can be implicitly converted to the other data type. See the following example
        which comparing Int32 and Int64 values.&lt;/p&gt;
    &lt;pre class="brush: csharp"&gt;int intVal = 123;
long longVal = 123;
 
// True
Console.WriteLine(intVal == longVal);
 
// False
Console.WriteLine((object)intVal == (object)longVal);

// False
Console.WriteLine(((object)intVal).Equals(longVal));&lt;/pre&gt;
    &lt;p&gt;
        To solve this, the trick is converting the values as dynamic first, even though
        this way requires warping the comparisons as a method call.&lt;/p&gt;
    &lt;p&gt;
        Lastly, this how to evaluate the sample expression using the parser. Have a look
        a the source &lt;a href="http://teamalert.codeplex.com"&gt;here&lt;/a&gt; if you are interested.&lt;/p&gt;
    &lt;pre class="brush: csharp"&gt;var input =
    &amp;quot;$DefinitionPath Under '\\DemoProject\\' &amp;quot; +
    &amp;quot;AND (&amp;quot; +
    &amp;quot;    $StatusCode LIKE 'Stopped|Failed|PartiallySucceeded' &amp;quot; +
    &amp;quot;    OR ( &amp;quot; +
    &amp;quot;        $StatusCode = Succeeded &amp;quot; +
    &amp;quot;        AND $TestStatus &amp;lt;&amp;gt; Succeeded &amp;quot; +     
    &amp;quot;    ) &amp;quot; +     
    &amp;quot;)&amp;quot;;
 
var parameters = CreateLookup(
    Tuple.Create(&amp;quot;DefinitionPath&amp;quot;, @&amp;quot;\DemoProject\MyApp&amp;quot;),
    Tuple.Create(&amp;quot;StatusCode&amp;quot;, @&amp;quot;Succeeded&amp;quot;),
    Tuple.Create(&amp;quot;TestStatus&amp;quot;, @&amp;quot;Failed&amp;quot;)
);
 
var expression = LogicalExpression.Parse(input, LogicalExpressionSyntax.ExtendedEventFilter);
 
var result = expression.Evaluate(parameters);
 
Assert.IsTrue(result);&lt;/pre&gt;
</description>
      <link>http://fszlin.dymetis.com/post/2011/04/19/TFS-Event-Filtering-Logical-Expressions-And-Expression-Tree.aspx</link>
      <comments>http://fszlin.dymetis.com/post/2011/04/19/TFS-Event-Filtering-Logical-Expressions-And-Expression-Tree.aspx#comment</comments>
      <guid>http://fszlin.dymetis.com/post.aspx?id=04ed1507-c119-4113-982f-e4e3db0b8297</guid>
      <pubDate>Tue, 19 Apr 2011 09:37:00 -0400</pubDate>
      <category>Development Environment</category>
      <dc:publisher>fszlin</dc:publisher>
      <pingback:server>http://fszlin.dymetis.com/pingback.axd</pingback:server>
      <pingback:target>http://fszlin.dymetis.com/post.aspx?id=04ed1507-c119-4113-982f-e4e3db0b8297</pingback:target>
      <slash:comments>310</slash:comments>
      <trackback:ping>http://fszlin.dymetis.com/trackback.axd?id=04ed1507-c119-4113-982f-e4e3db0b8297</trackback:ping>
      <wfw:comment>http://fszlin.dymetis.com/post/2011/04/19/TFS-Event-Filtering-Logical-Expressions-And-Expression-Tree.aspx#comment</wfw:comment>
      <wfw:commentRss>http://fszlin.dymetis.com/syndication.axd?post=04ed1507-c119-4113-982f-e4e3db0b8297</wfw:commentRss>
    </item>
    <item>
      <title>Event Notification Plugin for TFS 2010</title>
      <description>&lt;p&gt;Couple days ago, I published the &lt;a href="http://teamalert.codeplex.com"&gt;Team Alert&lt;/a&gt; project on CodePlex.
It is a server side extension for TFS 2010, which allows you sending E-Mail notifications to any person field in 
the event, regardless the field contain a SID, account name or display name. Of course, you may configure it to
send notification to fixed E-Mail addresses too.&lt;/p&gt;

&lt;p&gt;I have described some situations that you may want to notify contextual users in my previous 
&lt;a href="http://fszlin.dymetis.com/post/2011/03/09/Email-Alerts-In-Team-Foundation-Server.aspx"&gt;post&lt;/a&gt;. Here is a quick comparison between
&lt;em&gt;Project Alerts&lt;/em&gt;, &lt;em&gt;Alert Editor&lt;/em&gt; and &lt;em&gt;Team Alert&lt;/em&gt;.&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;&lt;th&gt;Project Alerts&lt;/th&gt;&lt;th&gt;Alert Editor&lt;/th&gt;&lt;th&gt;Team Alert&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;

&lt;tr&gt;
&lt;th&gt;Supported Events&lt;/th&gt;&lt;td&gt;WIC, C, BC, BSC&lt;/td&gt;&lt;td&gt;BC, BRSC, C, WIC, BSC&lt;/td&gt;&lt;td&gt;BC, WIC&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;th&gt;Filter Expression&lt;/th&gt;&lt;td&gt;Predefined&lt;/td&gt;&lt;td&gt;VSEFL&lt;/td&gt;&lt;td&gt;VSEFL(modified)&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;th&gt;Delivery Type&lt;/th&gt;&lt;td&gt;Html, Plain Text, SOAP&lt;/td&gt;&lt;td&gt;Html, Plain Text, SOAP&lt;/td&gt;&lt;td&gt;Html, Plain Text&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;th&gt;Work Item Custom Fields&lt;/th&gt;&lt;td&gt;Not Supported&lt;/td&gt;&lt;td&gt;Not Supported&lt;/td&gt;&lt;td&gt;Supported&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;th&gt;Person Fields as Recipients&lt;/th&gt;&lt;td&gt;Not Supported&lt;/td&gt;&lt;td&gt;Not Supported&lt;/td&gt;&lt;td&gt;Supported&lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;&lt;td&gt;Team Explorer, TFS Web Access&lt;/td&gt;&lt;td&gt;Team Explorer with Power Tool&lt;/td&gt;&lt;td&gt;Configuration File&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class="table-foot"&gt;* WIC – WorkItemChangedEvent, BC – BuildCompletionEvent, BSC – BuildStatusChangeEvent, BRSC – BuildResourceStatusChanges, C – CheckinEvent&lt;/p&gt;


&lt;p&gt;Apparently, Team Alert is not a replacement of any of these tools. At least, it does not provide any client 
side subscription tool yet, but it does have additional features that I need.&lt;/p&gt;
&lt;p&gt;
Now, let's see how to configure it. Download the binary from &lt;a href="http://teamalert.codeplex.com/releases"&gt;CodePlex&lt;/a&gt;,
and then replace the configuration file with the following. Note that we specified that we want to attach the event XML.
&lt;/p&gt;

&lt;pre class="brush: xml"&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;
&amp;lt;configuration&amp;gt;
  &amp;lt;configSections&amp;gt;
    &amp;lt;section name="teamAlert" type="Dymetis.TeamAlert.Configuration.TeamAlertConfigurationSection, Dymetis.TeamAlert"/&amp;gt;
  &amp;lt;/configSections&amp;gt;

  &amp;lt;teamAlert&amp;gt;
    &amp;lt;alerts&amp;gt;
      &amp;lt;alert
        name="Debug WorkItemChangedEvent"
        event="WorkItemChangedEvent"&amp;gt;
 
        &amp;lt;recipients&amp;gt;
          &amp;lt;recipient
            name="Dev"
            address="YourEmail@YourDomain.com"
            type="EmailAddress"
            allowHtml="true"
            attachRawEvent="true"/&amp;gt;
        &amp;lt;/recipients&amp;gt;
      &amp;lt;/alert&amp;gt;
    &amp;lt;/alerts&amp;gt;
  &amp;lt;/teamAlert&amp;gt;
 
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;

&lt;p&gt;Copy the assembly and configuration to the TFS Plugins folder, such as &lt;em&gt;X:\Program Files\Microsoft Team Foundation Server 2010\Application
Tier\Web Services\bin\Plugins&lt;/em&gt;. TFS will restart automatically.&lt;/p&gt;

&lt;p&gt;Once any work item changed, you should receive an E-Mail like this:
&lt;br /&gt;&lt;img src="http://fszlin.dymetis.com/image.axd?picture=2011%2f3%2fTeamAlertEmail.png" alt="Team Alert E-Mail" /&gt;&lt;/p&gt;

&lt;p&gt;If you open the attached XML, it should contain all core fields, changed fields, text fields, and custom fields, if there is any. Now we
 got the sample XML, writing the XPath for filter expression is a piece of cake. Alternately, you can check out the schema in &lt;em&gt;tbl_EventType&lt;/em&gt;
  table, just keep in mind that the CustomField element is appended by Team Alert as a work around.&lt;/p&gt;

&lt;p&gt;If you start wonder how it helps, let's say we use TFS as Bug tracking system. And in the case of a bug get updated by developers, 
the reporter of the bug should be notified. Normally, you may need to subscribe each reporter to the &lt;em&gt;WorkItemChangedEvent&lt;/em&gt;,
or write a custom SOAP web service for this.&lt;/p&gt;
&lt;p&gt;Here is how you to achieve this with Team Alert. First, an expression is defined to filter events. The first half will limit the
work item to bugs only, and the second half will prevent the reporter get notify for his/her own changes. The only different between 
this and VSEFL is a dollar sign is added in front of each field. (This may not be the only different, because it seems VSEFL doesn't
allow you specify a field on the right side of Boolean operators based on its &lt;a href="http://msdn.microsoft.com/en-us/library/bb130302.aspx"&gt;definition&lt;/a&gt;,
but the March release of TFS power tool do put fields on both sides.)&lt;/p&gt;

&lt;pre class="brush: text"&gt;$"CoreFields/StringFields/Field[ReferenceName='System.WorkItemType']/NewValue" 
	= Bug 
AND $"CoreFields/StringFields/Field[ReferenceName='System.AuthorizedAs']/NewValue" 
	&amp;lt;&amp;gt; $"CoreFields/StringFields/Field[ReferenceName='System.CreatedBy']/NewValue"&lt;/pre&gt;


&lt;p&gt;Then we specify the recipient to be the user of this field:&lt;/p&gt;

&lt;pre class="brush: text"&gt;CoreFields/StringFields/Field[ReferenceName='System.CreatedBy']/NewValue&lt;/pre&gt;

&lt;p&gt;The whole alert configuration element will look like this:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;alert
  name="Bug Changes"
  event="WorkItemChangedEvent"
  filterExpression="$&amp;amp;quot;CoreFields/StringFields/Field[ReferenceName='System.WorkItemType']/NewValue&amp;amp;quot; = Bug AND $&amp;amp;quot;CoreFields/StringFields/Field[ReferenceName='System.AuthorizedAs']/NewValue&amp;amp;quot; &amp;amp;lt;&amp;amp;gt; $&amp;amp;quot;CoreFields/StringFields/Field[ReferenceName='System.CreatedBy']/NewValue&amp;amp;quot;"&amp;gt;
  &amp;lt;recipients&amp;gt;
    &amp;lt;recipient
      name="Owner"
      address="CoreFields/StringFields/Field[ReferenceName='System.CreatedBy']/NewValue"
      type="DisplayNameField"
      allowHtml="true"/&amp;gt;
  &amp;lt;/recipients&amp;gt;
&amp;lt;/alert&amp;gt;&lt;/pre&gt;

&lt;p&gt;And now, all you have to do it wait for something happen, and confirm that the guys are getting notifications. 
If you didn't receive E-Mails, check the event log on the server of TFS, or use the first configuration to 
get the XML and test your XPath.&lt;/p&gt;
&lt;p&gt;Thank you for reading. Feedbacks and suggestions are welcome.&lt;/p&gt;
</description>
      <link>http://fszlin.dymetis.com/post/2011/03/22/Event-Notification-Plugin-for-TFS-2010.aspx</link>
      <comments>http://fszlin.dymetis.com/post/2011/03/22/Event-Notification-Plugin-for-TFS-2010.aspx#comment</comments>
      <guid>http://fszlin.dymetis.com/post.aspx?id=9a8e8802-ec3f-4890-adad-d86e1839a6f2</guid>
      <pubDate>Tue, 22 Mar 2011 23:50:00 -0400</pubDate>
      <category>Development Environment</category>
      <dc:publisher>fszlin</dc:publisher>
      <pingback:server>http://fszlin.dymetis.com/pingback.axd</pingback:server>
      <pingback:target>http://fszlin.dymetis.com/post.aspx?id=9a8e8802-ec3f-4890-adad-d86e1839a6f2</pingback:target>
      <slash:comments>447</slash:comments>
      <trackback:ping>http://fszlin.dymetis.com/trackback.axd?id=9a8e8802-ec3f-4890-adad-d86e1839a6f2</trackback:ping>
      <wfw:comment>http://fszlin.dymetis.com/post/2011/03/22/Event-Notification-Plugin-for-TFS-2010.aspx#comment</wfw:comment>
      <wfw:commentRss>http://fszlin.dymetis.com/syndication.axd?post=9a8e8802-ec3f-4890-adad-d86e1839a6f2</wfw:commentRss>
    </item>
    <item>
      <title>Masking Links in Comment (BlogEngine.NET)</title>
      <description>&lt;p&gt;Recently, I start getting spam comments, and some of them are smart enough to pass the filters. As these comments have been validated, they are likely suitable to be displayed.  But if they contain links in the content, I don’t want to the show the links before I checked them. In the other word, I want to mask the links before I add the corresponding domain into whitelist.&lt;/p&gt;

&lt;p&gt;For unverified sites, they should be displayed like these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;www.affiliate.com =&gt; www.***.com&lt;/li&gt;
&lt;li&gt;http://www.affiliate.com =&gt; http://www.***.com&lt;/li&gt;
&lt;li&gt;https://www.affiliate.net/abc.html =&gt; https://www.***.net/abc.html&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The domains in whitelist should be converted.&lt;/p&gt;

&lt;p&gt;I created a simple extension for &lt;em&gt;BlogEngine.NET&lt;/em&gt; to achieve this. This is the outcome:&lt;br /&gt;
 &lt;img src="http://fszlin.dymetis.com/image.axd?picture=2011%2f3%2fCommentMaskingExample.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;And you may specify the masking pattern and allowed domains in the extension settings.&lt;br /&gt;
 &lt;img src="http://fszlin.dymetis.com/image.axd?picture=2011%2f3%2fCommentMaskingSettings.png" alt="" /&gt;&lt;/p&gt;
 
&lt;p&gt;To create such an extension in &lt;em&gt;BlogEngine.NET&lt;/em&gt; couldn't be easier. All it needs is register an event hander FilterLinks to &lt;em&gt;BlogEngine.Core.Comment.Serving&lt;/em&gt; event. In the &lt;em&gt;FilterLinks&lt;/em&gt; method, simply replace &lt;em&gt;ServingEventArgs.Body&lt;/em&gt;, which will be displayed, with the masked content.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;[Extension("Masking links in comments", "1.0", 
		"&amp;lt;a href=\"http://fszlin.dymetis.com\"&amp;gt;Eddie Z. Lin&amp;lt;/a&amp;gt;", 10)]
public class CommentLinkMasking
{
    static CommentLinkMasking()
    {
        Comment.Serving += FilterLinks;
 
        InitSettings();
    }
 
    private static void FilterLinks(object sender, ServingEventArgs e)
    {
        if (String.IsNullOrEmpty(e.Body))
        {
            return;
        }
 
        e.Body = linkRegex.Replace(e.Body, ReplaceLink);
    }
 
    // Other methods.
}&lt;/pre&gt;

&lt;p&gt;To install this extension in &lt;em&gt;BlogEngine.NET&lt;/em&gt;, simply put the source file into the Extensions folder. The full source is available &lt;a href="http://fszlin.dymetis.com/page/Masking-Links-in-Comment-BlogEngine-NET-Source.aspx"&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
      <link>http://fszlin.dymetis.com/post/2011/03/20/Masking-Links-in-Comment-BlogEngine-NET.aspx</link>
      <comments>http://fszlin.dymetis.com/post/2011/03/20/Masking-Links-in-Comment-BlogEngine-NET.aspx#comment</comments>
      <guid>http://fszlin.dymetis.com/post.aspx?id=a0f9b9b7-5aa3-40ed-a0a2-b6fff265367c</guid>
      <pubDate>Sun, 20 Mar 2011 02:05:00 -0400</pubDate>
      <category>Web Development</category>
      <dc:publisher>fszlin</dc:publisher>
      <pingback:server>http://fszlin.dymetis.com/pingback.axd</pingback:server>
      <pingback:target>http://fszlin.dymetis.com/post.aspx?id=a0f9b9b7-5aa3-40ed-a0a2-b6fff265367c</pingback:target>
      <slash:comments>543</slash:comments>
      <trackback:ping>http://fszlin.dymetis.com/trackback.axd?id=a0f9b9b7-5aa3-40ed-a0a2-b6fff265367c</trackback:ping>
      <wfw:comment>http://fszlin.dymetis.com/post/2011/03/20/Masking-Links-in-Comment-BlogEngine-NET.aspx#comment</wfw:comment>
      <wfw:commentRss>http://fszlin.dymetis.com/syndication.axd?post=a0f9b9b7-5aa3-40ed-a0a2-b6fff265367c</wfw:commentRss>
    </item>
    <item>
      <title>Using WCF Data Service Operations in Silverlight</title>
      <description>&lt;p&gt;WCF Data Services use OData protocol to expose data over the Internet, which makes integrating other systems much easier. Everything looks fine,  until me trying to use WCF Data Services instead of WCF RIA Services in Silverlight application - The client won&amp;rsquo;t generate and service operation.   The good news is, we still able to consume service operations without writing raw HTTP requests.&lt;/p&gt;
&lt;p&gt;This post will describes how to supply parameters to operations exposure by WCF Data Service.&lt;/p&gt;
&lt;p&gt;Let's say we exposing the following operation via Data Service:&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;[WebGet]
public IQueryable&amp;lt;ItemCategory&amp;gt; Foo()
{
   return CurrentDataSource.ItemCategories;
}&lt;/pre&gt;
&lt;p&gt;This is how we can invoke it in Silverlight:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;var context = new SomeContext(serviceUri);
 
var dataQuery = (DataServiceQuery&amp;lt;ItemCategory&amp;gt;)context
    .CreateQuery&amp;lt;ItemCategory&amp;gt;("Foo").Take(10);
 
dataQuery.BeginExecute(result =&amp;gt;
{
    var collection = new DataServiceCollection&amp;lt;ItemCategory&amp;gt;(
        dataQuery.EndExecute(result));
 
    // consume data here

}, null);&lt;/pre&gt;
&lt;p&gt;An operation doesn't do much if we cannot supply parameters. According to &lt;a href="http://msdn.microsoft.com/en-us/library/cc668788.aspx"&gt;this&lt;/a&gt;, parameter  can only be &lt;a href="http://msdn.microsoft.com/en-us/library/system.type.isprimitive.aspx"&gt;primitive types&lt;/a&gt;. Note that this doesn&amp;rsquo;t mean all primitive   types are supported. Apparently, Char, IntPtr, UIntPtr, and all unsigned numeric types (except Byte) are not supported, according to the protocol.&lt;/p&gt;
&lt;p&gt;So, let&amp;rsquo;s try the other types:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;[WebGet]
public IQueryable&amp;lt;ItemCategory&amp;gt; Foo(
    bool paramBool, 
    byte paramByte,
    sbyte paramSByte,
    short paramInt16,
    int paramInt,
    long paramInt64, 
    float paramFloat,
    double paramDouble,
    string paramString
    )
{
    return CurrentDataSource.ItemCategories;
}&lt;/pre&gt;
&lt;p&gt;And this is the metadata exposed:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;FunctionImport Name="Foo" 
                EntitySet="ItemCategories" 
                ReturnType="Collection(ProductTraceModel.ItemCategory)" 
                m:HttpMethod="GET"&amp;gt;
  &amp;lt;Parameter Name="paramBool" Type="Edm.Boolean" Mode="In" /&amp;gt;
  &amp;lt;Parameter Name="paramByte" Type="Edm.Byte" Mode="In" /&amp;gt;
  &amp;lt;Parameter Name="paramSByte" Type="Edm.SByte" Mode="In" /&amp;gt;
  &amp;lt;Parameter Name="paramInt16" Type="Edm.Int16" Mode="In" /&amp;gt;
  &amp;lt;Parameter Name="paramInt" Type="Edm.Int32" Mode="In" /&amp;gt;
  &amp;lt;Parameter Name="paramInt64" Type="Edm.Int64" Mode="In" /&amp;gt;
  &amp;lt;Parameter Name="paramFloat" Type="Edm.Single" Mode="In" /&amp;gt;
  &amp;lt;Parameter Name="paramDouble" Type="Edm.Double" Mode="In" /&amp;gt;
  &amp;lt;Parameter Name="paramString" Type="Edm.String" Mode="In" /&amp;gt;
&amp;lt;/FunctionImport&amp;gt;&lt;/pre&gt;
&lt;p&gt;To append parameters to the request URL, we may use DataServiceQuery.AddQueryOption method. This method will simply convert the given value to  string, and the call will failed since the value is not proper converted.&lt;/p&gt;
&lt;p&gt;The query should look like this:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;var dataQuery = (DataServiceQuery&amp;lt;ItemCategory&amp;gt;)context
    .CreateQuery&amp;lt;ItemCategory&amp;gt;("Foo")
    .AddQueryOption("paramBool", "false")
    .AddQueryOption("paramByte", "120")
    .AddQueryOption("paramSByte", "99")
    .AddQueryOption("paramInt16", Int16.MaxValue)
    .AddQueryOption("paramInt", Int32.MaxValue)
    .AddQueryOption("paramInt64", Int64.MaxValue + "L")
    .AddQueryOption("paramFloat", 123.56 + "F")
    .AddQueryOption("paramDouble", 123.56)
    .AddQueryOption("paramString", "'" + "Eddie's Blog".Replace("'", "''") + "'")
    .Take(10);&lt;/pre&gt;
&lt;p&gt;Interestingly, even though Byte should be Hex as per the specification, but WCF Data Service only accepts Dec.&lt;/p&gt;
&lt;p&gt;Despite Time and DateTimeOffset are described in the protocol, WCF Data Service does not support mapping TimeSpan and DateTimeOffset.  For the Binary and DateTime, the metadata will looks like this:&lt;/p&gt;
&lt;pre class="brush: xml"&gt;&amp;lt;FunctionImport Name="Foo" EntitySet="ItemCategories" 
    ReturnType="Collection(ProductTraceModel.ItemCategory)" m:HttpMethod="GET"&amp;gt;
  &amp;lt;Parameter Name="byteArray" Type="Edm.Binary" Mode="In" /&amp;gt;
  &amp;lt;Parameter Name="dateTime" Type="Edm.DateTime" Mode="In" /&amp;gt;
&amp;lt;/FunctionImport&amp;gt;&lt;/pre&gt;
&lt;p&gt;Here is how to convert these two types:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;var dataQuery = (DataServiceQuery&amp;lt;ItemCategory&amp;gt;)context
    .CreateQuery&amp;lt;ItemCategory&amp;gt;("Foo")
    .AddQueryOption("byteArray", "X'" + 
        BitConverter.ToString(new byte[] { 24, 65, 73 }).Replace("-", String.Empty) + "'")
    .AddQueryOption("dateTime", "datetime'" + DateTime.Now.ToString("yyyy-MM-ddThh:mm:ss.fffffff") + "'")
    .Take(10);&lt;/pre&gt;
&lt;p&gt;For nullable parameters, instead of issuing a null as per specification, you should ignore the parameter,  otherwise you will receive a syntax error.&lt;/p&gt;
&lt;p&gt;Here is a helper class to simplify the conversions.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;// Copyright (c) 2011 Eddie Z. Lin.
//
// This source is subject to the Microsoft Public License.
// See http://www.opensource.org/licenses/ms-pl.
// All other rights reserved.
    
/// &amp;lt;summary&amp;gt;
/// Helper methods used to append parameters to WCF Data Service querys.
/// &amp;lt;/summary&amp;gt;
public static class DataServiceQueryExtensions
{
    public static DataServiceQuery&amp;lt;TElement&amp;gt; AddParameter&amp;lt;TElement&amp;gt;(
        this DataServiceQuery&amp;lt;TElement&amp;gt; query, string name, bool? value)
    {
        return value.HasValue ?
            query.AddQueryOption(name, value.Value ? "true" : "false") : 
            query;
    }
 
    public static DataServiceQuery&amp;lt;TElement&amp;gt; AddParameter&amp;lt;TElement&amp;gt;(
        this DataServiceQuery&amp;lt;TElement&amp;gt; query, string name, long? value)
    {
        return value.HasValue ? 
            query.AddQueryOption(name, String.Format("{0}L", value)) :
            query;
    }
 
    public static DataServiceQuery&amp;lt;TElement&amp;gt; AddParameter&amp;lt;TElement&amp;gt;(
        this DataServiceQuery&amp;lt;TElement&amp;gt; query, string name, float? value)
    {
        return value.HasValue ?
            query.AddQueryOption(name, String.Format("{0}F", value)) :
            query;
    }
 
    public static DataServiceQuery&amp;lt;TElement&amp;gt; AddQueryParameter&amp;lt;TElement&amp;gt;(
        this DataServiceQuery&amp;lt;TElement&amp;gt; query, string name, string value)
    {
        return value != null ?
            query.AddQueryOption(name, String.Format("'{0}'", value.Replace("'", "''"))) :
            query;
    }
 
    public static DataServiceQuery&amp;lt;TElement&amp;gt; AddQueryParameter&amp;lt;TElement&amp;gt;(
        this DataServiceQuery&amp;lt;TElement&amp;gt; query, string name, byte[] value)
    {
        return value != null ?
            query.AddQueryOption(name, 
                String.Format("X'{0}'",  BitConverter.ToString(value).Replace("-", String.Empty))) :
            query;
    }
 
    public static DataServiceQuery&amp;lt;TElement&amp;gt; AddQueryParameter&amp;lt;TElement&amp;gt;(
        this DataServiceQuery&amp;lt;TElement&amp;gt; query, string name, DateTime? value)
    {
        return value != null ?
            query.AddQueryOption(name, 
                String.Format("X'{0}'", value.Value.ToString("yyyy-MM-ddThh:mm:ss.fffffff"))) :
            query;
    }
 
    public static DataServiceQuery&amp;lt;TElement&amp;gt; AddParameter&amp;lt;TElement&amp;gt;(
        this DataServiceQuery&amp;lt;TElement&amp;gt; query, string name, int? value)
    {
        return value != null ?
            query.AddQueryOption(name, value.ToString()) :
            query;
    }
 
    public static DataServiceQuery&amp;lt;TElement&amp;gt; AddParameter&amp;lt;TElement&amp;gt;(
        this DataServiceQuery&amp;lt;TElement&amp;gt; query, string name, object value)
    {
        return value != null ?
            query.AddQueryOption(name, value.ToString()) : 
            query;
    }
}&lt;/pre&gt;
&lt;p&gt;Hope this helps.&lt;/p&gt;</description>
      <link>http://fszlin.dymetis.com/post/2011/03/15/Using-WCF-Data-Service-Operations-in-Silverlight.aspx</link>
      <comments>http://fszlin.dymetis.com/post/2011/03/15/Using-WCF-Data-Service-Operations-in-Silverlight.aspx#comment</comments>
      <guid>http://fszlin.dymetis.com/post.aspx?id=a1436006-9eee-4702-9b22-21b40bd9c94a</guid>
      <pubDate>Tue, 15 Mar 2011 00:52:00 -0400</pubDate>
      <category>Web Development</category>
      <dc:publisher>fszlin</dc:publisher>
      <pingback:server>http://fszlin.dymetis.com/pingback.axd</pingback:server>
      <pingback:target>http://fszlin.dymetis.com/post.aspx?id=a1436006-9eee-4702-9b22-21b40bd9c94a</pingback:target>
      <slash:comments>492</slash:comments>
      <trackback:ping>http://fszlin.dymetis.com/trackback.axd?id=a1436006-9eee-4702-9b22-21b40bd9c94a</trackback:ping>
      <wfw:comment>http://fszlin.dymetis.com/post/2011/03/15/Using-WCF-Data-Service-Operations-in-Silverlight.aspx#comment</wfw:comment>
      <wfw:commentRss>http://fszlin.dymetis.com/syndication.axd?post=a1436006-9eee-4702-9b22-21b40bd9c94a</wfw:commentRss>
    </item>
    <item>
      <title>Email Alerts in Team Foundation Server</title>
      <description>&lt;p&gt;If you ever wonder how to send an E-Mail notification to a user participating in the event in TFS, the solution would be a little bit tricky for &lt;a href="http://msdn.microsoft.com/en-us/library/bb130154.aspx"&gt;a flexible, extensible mechanism for subscription and notification.&lt;/a&gt; One of the &lt;em&gt;easiest&lt;/em&gt; ways to achieve this is using the &lt;em&gt;Event Service&lt;/em&gt; to listen to the event, and then send the notification.&lt;/p&gt;
&lt;p&gt;These are some of the situations you may want to have this feature out of box:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Notify the developer checked in when the build is failed;&lt;/li&gt;
&lt;li&gt;Notify the reporters when a bug work item is changed by others.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Obviously, programing a web service or event handler for each of these cases requires a lot of work. It would be nice to utilize the subscription service in TFS, so that we don't have to worry about filtering and formatting events. Here are the steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Listen the target event;&lt;/li&gt;
&lt;li&gt;Find out the E-Mail address of the user;&lt;/li&gt;
&lt;li&gt;Subscribe the user to the same event with proper filter.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the following example, I am going to handle the &lt;em&gt;WorkItemChangedEvent&lt;/em&gt; to notify the reporters when a bug work item is changed by others, with the helps of &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.framework.server.teamfoundationidentityservice.aspx"&gt;TeamFoundationIdentityService&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.framework.server.teamfoundationnotificationservice.aspx"&gt;TeamFoundationNotificationService&lt;/a&gt;. (Sadly, the documentation on MSDN doesn't actually tell you anything more than &lt;em&gt;Object Browser&lt;/em&gt; regarding the TFS server API.)&lt;/p&gt;
&lt;p&gt;Before performing any task, we need to get notify when the a work item has been updated. This is done by implementing the &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.framework.server.isubscriber.aspx"&gt;ISubscriber&lt;/a&gt; interface.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;public sealed class EmailAlertSubscriber : ISubscriber
{

    public string Name
    {
        get { return "EmailAlertSubscriber" }
    }

    public SubscriberPriority Priority
    {
        get { return SubscriberPriority.Normal }
    }

    public EventNotificationStatus ProcessEvent(
        TeamFoundationRequestContext requestContext, 
        NotificationType notificationType, 
        object notificationEventArgs, 
        out int statusCode, 
        out string statusMessage,
        out ExceptionPropertyCollection properties) 
    {
        statusCode = 0;
        statusMessage = null;
        properties = null;

        if (notificationType == NotificationType.Notification)
        {
            var eventArgs = notificationEventArgs as WorkItemChangedEvent;
            if (eventArgs != null)
            {
                // Process event...
            }
        }

        return EventNotificationStatus.ActionPermitted;
    }

    public Type[] SubscribedTypes()
    {
        return new Type[] { typeof(WorkItemChangedEvent) };
    }
}
&lt;/pre&gt;
&lt;p&gt;Next, we can retrieve the value of person field form &lt;em&gt;notificationEventArgs&lt;/em&gt;. As per our example, I need the user who created the bug work item.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;var createdByDisplayName = 
    eventArgs
    .CoreFields
    .StringFields
    .Single(
        f =&amp;gt; f.ReferenceName.Equals(
            "System.CreatedBy", StringComparison.OrdinalIgnoreCase))
    .NewValue;
&lt;/pre&gt;
&lt;p&gt;The field value may be a display name, domain account or Sid (Security Identifier), but the base steps to retrieve E-Mail address are the same - read the &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.framework.server.teamfoundationidentity.aspx"&gt;TeamFoundationIdentity&lt;/a&gt;; and then load the E-Mail address from &lt;em&gt;Active Directory&lt;/em&gt;. Just make sure you reading the E-Mail address from the correct domain.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;var identityService = requestContext.GetService&amp;lt;TeamFoundationIdentityService&amp;gt;();

// Read TFS identity by display name.
var tfsId = identityService.ReadIdentity(
    requestContext, 
    IdentitySearchFactor.DisplayName, 
    displayName, 
    MembershipQuery.None, ReadIdentityOptions.None);

// Read TFS identity by account name.
var tfsId = identityService.ReadIdentity(
    requestContext, 
    IdentitySearchFactor.AccountName, 
    accountName, 
    MembershipQuery.None, ReadIdentityOptions.None);

// Read TFS identity by Sid.
var idDescriptor = IdentityHelper.CreateDescriptorFromSid(sid);
var tfsId = identityService.ReadIdentity(
    requestContext, 
    idDescriptor, 
    MembershipQuery.None, ReadIdentityOptions.None);

var domainName = IdentityHelper.GetDomainName(identity);

using (var context = new PrincipalContext(ContextType.Domain, domainName))
{
    var userPrincipal = UserPrincipal.FindByIdentity(
        context, IdentityType.Sid, identity.Descriptor.Identifier);

    // Now we got the E-Mail address as userPrincipal.EmailAddress;
}
&lt;/pre&gt;
&lt;p&gt;Now, we have all the information we need to subscribe the user to event. In the following code snippet, the &lt;em&gt;classification&lt;/em&gt; is used to identify the subscription. It likely contains the event type and user identifier, so that the handler won't subscribe the user every time the event fired. On the other hand, we may supply a filter expression limiting the E-Mail going out.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;var classification = // Identifer for the subscription.

var notificationService = requestContext.GetService&amp;lt;TeamFoundationNotificationService&amp;gt;();
var subscriptions = notificationService.GetEventSubscriptions(
    requestContext, 
    userIdentity.Descriptor,
    classification);

// Check for whether the subscription already exists.
if (subscriptions.Count == 0)
{
    var filterExpression = // Filter used to limit the E-Mail notifications.

    var perference = new DeliveryPreference()
    {
        Address = userPrincipal.EmailAddress,
        Schedule = DeliverySchedule.Immediate,
        Type = DeliveryType.EmailHtml
    };

    notificationService.SubscribeEvent(
        requestContext,
        userIdentity.Descriptor, 
        "WorkItemChangedEvent", 
        filterExpression, 
        perference, 
        classification);
}
&lt;/pre&gt;
&lt;p&gt;After all these, the handler is ready to be deployed. To use it, simply compile the code to an assembly, and copy it to &lt;em&gt;%Program Files%\Microsoft Team Foundation Server 2010\Application Tier\Web Services\bin\Plugins&lt;/em&gt; of the TFS server. The E-Mail will start filling up your mail box now.&lt;/p&gt;
&lt;p&gt;You may want to unsubscribe the user, such as when the work item is closed. This can be done by:&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;if (subscriptions.Count &amp;gt; 0)
{
    foreach (var subscription in subscriptions)
    {
        requestContext.GetService&amp;lt;TeamFoundationNotificationService&amp;gt;()
            .UnsubscribeEvent(requestContext, subscription.ID);
    }
}
&lt;/pre&gt;
&lt;p&gt;The problem here is that the E-Mail is send by the delayed job. By the time the job being executed, the subscription is removed, and the user won't get notify when the work item is closed. Interestingly, this delay is exactly what ensuring the user get notify the first time when we subscribing the user.&lt;/p&gt;
&lt;p&gt;If you don't mind the event subscriptions table get fill up, or you willing to clean the table once a while. This approach will work quite well.&lt;/p&gt;
&lt;p&gt;So, in order to find a better solution, I will show you how to filter events using &lt;a href="http://msdn.microsoft.com/en-us/library/bb130302.aspx"&gt;VSEFL&lt;/a&gt; , and then wire up everything in other posts.&lt;/p&gt;</description>
      <link>http://fszlin.dymetis.com/post/2011/03/09/Email-Alerts-In-Team-Foundation-Server.aspx</link>
      <comments>http://fszlin.dymetis.com/post/2011/03/09/Email-Alerts-In-Team-Foundation-Server.aspx#comment</comments>
      <guid>http://fszlin.dymetis.com/post.aspx?id=b517cf41-e705-455f-b5ab-468546c2d387</guid>
      <pubDate>Wed, 09 Mar 2011 03:54:00 -0400</pubDate>
      <category>Development Environment</category>
      <dc:publisher>fszlin</dc:publisher>
      <pingback:server>http://fszlin.dymetis.com/pingback.axd</pingback:server>
      <pingback:target>http://fszlin.dymetis.com/post.aspx?id=b517cf41-e705-455f-b5ab-468546c2d387</pingback:target>
      <slash:comments>521</slash:comments>
      <trackback:ping>http://fszlin.dymetis.com/trackback.axd?id=b517cf41-e705-455f-b5ab-468546c2d387</trackback:ping>
      <wfw:comment>http://fszlin.dymetis.com/post/2011/03/09/Email-Alerts-In-Team-Foundation-Server.aspx#comment</wfw:comment>
      <wfw:commentRss>http://fszlin.dymetis.com/syndication.axd?post=b517cf41-e705-455f-b5ab-468546c2d387</wfw:commentRss>
    </item>
    <item>
      <title>Comsuming WCF Services With Android</title>
      <description>&lt;p&gt;It seems processing XML is too heavy for mobile devices. Android
did not provide any tool to help consuming SOAP web service. But as
Android bundled with org.apache.http and org.json packages, it is
relative simple to consume RESTful WCF services.&lt;/p&gt;&lt;p&gt;The following sections describe the steps to create RESTfule WCF
services and the Android client to consume the services.&lt;/p&gt;&lt;p&gt;First, I created a service contract with two GET and one POST
operations. Since the Android client will transfer data in JSON
objects, I specify JSON as request and response format. In order to
support more than one parameter, I set &lt;em&gt;BodyStyle&lt;/em&gt; to
&lt;em&gt;WrappedRequest&lt;/em&gt;.&lt;/p&gt;&lt;pre class="brush: csharp"&gt;
namespace HttpWcfWeb
{
    [ServiceContract(Namespace = "http://services.example.com")]
    public interface IVehicleService
    {
        [OperationContract]
        [WebGet(
            UriTemplate = "GetPlates",
            BodyStyle = WebMessageBodyStyle.WrappedRequest,
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json)]
        IList&amp;lt;string&amp;gt; GetPlates();

        [OperationContract]
        [WebGet(UriTemplate = "GetVehicle/{plate}",
            BodyStyle = WebMessageBodyStyle.WrappedRequest,
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json)]
        Vehicle GetVehicle(string plate);

        [OperationContract]
        [WebInvoke(
            Method = "POST",
            UriTemplate = "SaveVehicle",
            BodyStyle = WebMessageBodyStyle.WrappedRequest,
            ResponseFormat = WebMessageFormat.Json,
            RequestFormat = WebMessageFormat.Json)]
        void SaveVehicle(Vehicle vehicle);
    }
}
&lt;/pre&gt;&lt;p&gt;Next, I defined the composite object will be transferred between
server and Android client. It is simple but enough to prove we will
be able to transfer complex objects.&lt;/p&gt;&lt;pre class="brush: csharp"&gt;
namespace HttpWcfWeb
{
    [DataContract]
    public class Vehicle
    {
        [DataMember(Name = "year")]
        public int Year
        {
            get;
            set;
        }

        [DataMember(Name = "plate")]
        public string Plate
        {
            get;
            set;
        }

        [DataMember(Name = "make")]
        public string Make
        {
            get;
            set;
        }

        [DataMember(Name = "model")]
        public string Model
        {
            get;
            set;
        }
    }
}
&lt;/pre&gt;&lt;p&gt;Now, expose the WCF service via &lt;em&gt;webHttp&lt;/em&gt; behavior in
&lt;em&gt;web.config&lt;/em&gt;.&lt;/p&gt;&lt;pre class="brush: xml"&gt;
&amp;lt;system.serviceModel&amp;gt;
  &amp;lt;behaviors&amp;gt;
    &amp;lt;endpointBehaviors&amp;gt;
      &amp;lt;behavior name="httpBehavior"&amp;gt;
        &amp;lt;webHttp /&amp;gt;
      &amp;lt;/behavior&amp;gt;
    &amp;lt;/endpointBehaviors&amp;gt;
    &amp;lt;serviceBehaviors&amp;gt;
      &amp;lt;behavior name=""&amp;gt;
        &amp;lt;serviceMetadata httpGetEnabled="true" /&amp;gt;
        &amp;lt;serviceDebug includeExceptionDetailInFaults="false" /&amp;gt;
      &amp;lt;/behavior&amp;gt;
    &amp;lt;/serviceBehaviors&amp;gt;
  &amp;lt;/behaviors&amp;gt;
  &amp;lt;serviceHostingEnvironment multipleSiteBindingsEnabled="true" /&amp;gt;
    &amp;lt;services&amp;gt;
      &amp;lt;service name="HttpWcfWeb.VehicleService"&amp;gt;
        &amp;lt;endpoint address=""
                     behaviorConfiguration="httpBehavior"
                     binding="webHttpBinding"
                     contract="HttpWcfWeb.IVehicleService" /&amp;gt;
    &amp;lt;/service&amp;gt;
  &amp;lt;/services&amp;gt;
&amp;lt;/system.serviceModel&amp;gt;
&lt;/pre&gt;&lt;p&gt;It you are using Visual Studio's Development Server to test the
WCF service, you may need to deploy the service to IIS. This is due
to the Development Server only serve request from local machine,
and the Android client won't be able to access the service hosted
on it.&lt;/p&gt;&lt;p&gt;Further, if you are using host name (e.g. computer name) in the
URL of the service, you may have to setup the DNS in you device or
emulator, so that it can resolve the host name. Simply go to
Settings -&amp;gt; Wireless Control -&amp;gt; Mobile Networks -&amp;gt; Access
Point Names, click on the one that is in use, fill in
&lt;em&gt;Proxy&lt;/em&gt; and &lt;em&gt;Port&lt;/em&gt; with your DNS server.&lt;br /&gt;&lt;img alt="Setup Proxy and Port" src="http://fszlin.dymetis.com/image.axd?picture=2011%2f3%2fandroid-proxy.png" /&gt;&lt;/p&gt;&lt;p&gt;Now, I have my WCF service ready, and I am going to build the
Android client to consume the WCF service.&lt;br /&gt;&lt;img alt="Android UI" src="http://fszlin.dymetis.com/image.axd?picture=2011%2f3%2fandriod-ui.png" /&gt;&lt;/p&gt;&lt;p&gt;During initialization, the &lt;em&gt;Activity&lt;/em&gt; will invoke
&lt;em&gt;IVehicleService.GetPlates&lt;/em&gt; method to populate the
&lt;em&gt;Spinner&lt;/em&gt;. When the &lt;em&gt;Load Vehicle&lt;/em&gt; button is clicked,
the vehicle will be loaded from the
&lt;em&gt;IVehicleService.GetVehicle&lt;/em&gt; method and the
&lt;em&gt;EditText&lt;/em&gt; views will be populated. On the other hand,
&lt;em&gt;Save&lt;/em&gt; button will wrap the data entered and post to
&lt;em&gt;IVehicleService.SaveVehicle&lt;/em&gt; method.&lt;/p&gt;&lt;p&gt;The code the initialize the UI I created.&lt;/p&gt;&lt;pre class="brush: java"&gt;
public class MainActivity extends Activity {

    private final static String SERVICE_URI = "http://lt0.studio.entail.ca:8080/VehicleService.svc";

    private Spinner plateSpinner;
    private EditText makeEdit;
    private EditText plateEdit;
    private EditText yearEdit;
    private EditText modelEdit;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        plateSpinner = (Spinner)findViewById(R.id.plate_spinner);
        makeEdit = (EditText)findViewById(R.id.make_edit);
        plateEdit = (EditText)findViewById(R.id.plate_edit);
        yearEdit = (EditText)findViewById(R.id.year_edit);
        modelEdit = (EditText)findViewById(R.id.model_edit);
    }
    
    @Override
    public void onResume() {
        super.onResume();

        // Invoke IVehicleService.GetPlates and populate plateSpinner
        refreshVehicles();
    }
}
&lt;/pre&gt;&lt;p&gt;The &lt;em&gt;refreshVehicles&lt;/em&gt; method will be invoked when the
activity is resumed or a new vehicle is saved. It send a GET
request to the WCF service and retrieves a list of plates in JSON
string, and the response string is parsed by
&lt;em&gt;JSONArray&lt;/em&gt;.&lt;/p&gt;&lt;pre class="brush: java"&gt;
    private void refreshVehicles() {
        try {

            // Send GET request to &amp;lt;service&amp;gt;/GetPlates
            HttpGet request = new HttpGet(SERVICE_URI + "/GetPlates");
            request.setHeader("Accept", "application/json");
            request.setHeader("Content-type", "application/json");

            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpResponse response = httpClient.execute(request);

            HttpEntity responseEntity = response.getEntity();
            
            // Read response data into buffer
            char[] buffer = new char[(int)responseEntity.getContentLength()];
            InputStream stream = responseEntity.getContent();
            InputStreamReader reader = new InputStreamReader(stream);
            reader.read(buffer);
            stream.close();

            JSONArray plates = new JSONArray(new String(buffer));

            // Reset plate spinner
            ArrayAdapter&amp;lt;String&amp;gt; adapter = new ArrayAdapter&amp;lt;String&amp;gt;(this, android.R.layout.simple_spinner_item);
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            for (int i = 0; i &amp;lt; plates.length(); ++i) {
                adapter.add(plates.getString(i));
            }
            plateSpinner.setAdapter(adapter);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
&lt;/pre&gt;&lt;p&gt;The &lt;em&gt;onLoadVehicleClick&lt;/em&gt; method is the event handler for
&lt;em&gt;Load Vehicle&lt;/em&gt; button. Just like &lt;em&gt;refreshVehicles&lt;/em&gt;
method, It send a GET request to the WCF service and retrieve the
vehicle information by plate number. But instead of
&lt;em&gt;JSONArray&lt;/em&gt;, it used &lt;em&gt;JSONObject&lt;/em&gt; to parse the
response data, since the WCF service is returning an vehicle
object.&lt;/p&gt;&lt;pre class="brush: java"&gt;
    public void onLoadVehicleClick(View button) {
        try {
            // Send GET request to &amp;lt;service&amp;gt;/GetVehicle/&amp;lt;plate&amp;gt;
            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpGet request = new HttpGet(SERVICE_URI + "/GetVehicle/" + plateSpinner.getSelectedItem());

            request.setHeader("Accept", "application/json");
            request.setHeader("Content-type", "application/json");

            HttpResponse response = httpClient.execute(request);

            HttpEntity responseEntity = response.getEntity();

            // Read response data into buffer
            char[] buffer = new char[(int)responseEntity.getContentLength()];
            InputStream stream = responseEntity.getContent();
            InputStreamReader reader = new InputStreamReader(stream);
            reader.read(buffer);
            stream.close();

            JSONObject vehicle = new JSONObject(new String(buffer));

            // Populate text fields
            makeEdit.setText(vehicle.getString("make"));
            plateEdit.setText(vehicle.getString("plate"));
            modelEdit.setText(vehicle.getString("model"));
            yearEdit.setText(vehicle.getString("year"));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
&lt;/pre&gt;&lt;p&gt;When &lt;em&gt;Save&lt;/em&gt; button is clicked,
&lt;em&gt;onSaveVehicleClick&lt;/em&gt; method will be invoked. It simply
gather all text fields into a &lt;em&gt;JSONObject&lt;/em&gt; and post it to
the WCF service. Noticed that the all the data was wrapped into an
object named &lt;em&gt;vehicle&lt;/em&gt;, WCF will pass this object as
parameter &lt;em&gt;vehicle&lt;/em&gt;.&lt;/p&gt;&lt;pre class="brush: java"&gt;
    public void onSaveVehicleClick(View button) {

        try {

            Editable make = makeEdit.getText();
            Editable plate = plateEdit.getText();
            Editable model = modelEdit.getText();
            Editable year = yearEdit.getText();

            boolean isValid = true;

            // Data validation goes here

            if (isValid) {

                // POST request to &amp;lt;service&amp;gt;/SaveVehicle
                HttpPost request = new HttpPost(SERVICE_URI + "/SaveVehicle");
                request.setHeader("Accept", "application/json");
                request.setHeader("Content-type", "application/json");

                // Build JSON string
                JSONStringer vehicle = new JSONStringer()
                    .object()
                        .key("vehicle")
                            .object()
                                .key("plate").value(plate)
                                .key("make").value(make)
                                .key("model").value(model)
                                .key("year").value(Integer.parseInt(year.toString()))
                            .endObject()
                        .endObject();
                StringEntity entity = new StringEntity(vehicle.toString());

                request.setEntity(entity);

                // Send request to WCF service
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpResponse response = httpClient.execute(request);

                Log.d("WebInvoke", "Saving : " + response.getStatusLine().getStatusCode());
                
                // Reload plate numbers
                refreshVehicles();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
&lt;/pre&gt;&lt;p&gt;Finally, add the internet permission into
&lt;em&gt;AndroidManifest.xml&lt;/em&gt;, to allow the sample application
access WCF service.&lt;/p&gt;&lt;pre class="brush: xml"&gt;
    &amp;lt;uses-permission android:name="android.permission.INTERNET" /&amp;gt;
   
&lt;/pre&gt;&lt;p&gt;And the demo is ready to go.&lt;br /&gt;&lt;img alt="Android Application" src="http://fszlin.dymetis.com/image.axd?picture=2011%2f3%2fandroid-application.png" /&gt;&lt;/p&gt;</description>
      <link>http://fszlin.dymetis.com/post/2010/05/10/Comsuming-WCF-Services-With-Android.aspx</link>
      <comments>http://fszlin.dymetis.com/post/2010/05/10/Comsuming-WCF-Services-With-Android.aspx#comment</comments>
      <guid>http://fszlin.dymetis.com/post.aspx?id=787e4a79-814b-4828-b634-21b6809564f3</guid>
      <pubDate>Mon, 10 May 2010 04:39:00 -0400</pubDate>
      <category>Mobile Development</category>
      <dc:publisher>fszlin</dc:publisher>
      <pingback:server>http://fszlin.dymetis.com/pingback.axd</pingback:server>
      <pingback:target>http://fszlin.dymetis.com/post.aspx?id=787e4a79-814b-4828-b634-21b6809564f3</pingback:target>
      <slash:comments>456</slash:comments>
      <trackback:ping>http://fszlin.dymetis.com/trackback.axd?id=787e4a79-814b-4828-b634-21b6809564f3</trackback:ping>
      <wfw:comment>http://fszlin.dymetis.com/post/2010/05/10/Comsuming-WCF-Services-With-Android.aspx#comment</wfw:comment>
      <wfw:commentRss>http://fszlin.dymetis.com/syndication.axd?post=787e4a79-814b-4828-b634-21b6809564f3</wfw:commentRss>
    </item>
    <item>
      <title>A Silverlight Text Diff Control</title>
      <description>&lt;p&gt;Text diff tool is really useful for checking the updates of
versioning files. On the web, it is widely used in wiki systems to
see the changes of articles. It may also useful for tracing forum
posts, page updates of CMS, etc.&lt;/p&gt;&lt;p&gt;This article will describes how to create a simple text diff
control in Silverlight. Before going into the details, this is
screen shot of our text diff control.&lt;br /&gt;&lt;img alt="Text Diff Control Screen Shot" src="http://fszlin.dymetis.com/image.axd?picture=2011%2f3%2fSilverlight-Diff-Preview.png" /&gt;&lt;/p&gt;&lt;p&gt;This control contains two major parts, the core algorithm to do
the calculation job, and the user interface to display the
result.&lt;/p&gt;&lt;h4&gt;Diff Algoirithms&lt;/h4&gt;&lt;p&gt;The purpose of diff algorithm is to compute the &lt;em&gt;Shortest
Edit Script&lt;/em&gt; of two list of equalable items. Hence, all of our
algorithm will implement the following &lt;em&gt;IDiffEngine&lt;/em&gt;
interface.&lt;/p&gt;&lt;pre class="brush: csharp"&gt;
/// &amp;lt;summary&amp;gt;
/// Supports aligning two sequences.
/// &amp;lt;/summary&amp;gt;
public interface IDiffEngine
{
    IList&amp;lt;DiffResult&amp;gt; Align&amp;lt;T&amp;gt;(IList&amp;lt;T&amp;gt; from, IList&amp;lt;T&amp;gt; to, IEqualityComparer&amp;lt;T&amp;gt; comparer);
}

/// &amp;lt;summary&amp;gt;
/// Represents a particular elements alignment result.
/// &amp;lt;/summary&amp;gt;
public enum DiffResult
{
    /// &amp;lt;summary&amp;gt;
    /// Two elements are considered as the same.
    /// &amp;lt;/summary&amp;gt;
    Matched,

    /// &amp;lt;summary&amp;gt;
    /// The element in target sequence is inserted to the result alignment.
    /// &amp;lt;/summary&amp;gt;
    Inserted,

    /// &amp;lt;summary&amp;gt;
    /// The element in original sequence is inserted to the result alignment.
    /// &amp;lt;/summary&amp;gt;
    Deleted
}
   
&lt;/pre&gt;&lt;p&gt;Other than this, we need an interface accepting string list, in
other word, lines of a text. It is because we may have extensions
specified to text, i.e. spacing handling, case sensitivity,
etc.&lt;/p&gt;&lt;pre class="brush: csharp"&gt;
/// &amp;lt;summary&amp;gt;
/// Supports aligning two list of strings.
/// &amp;lt;/summary&amp;gt;
public interface ITextDiffEngine
{
    IList&amp;lt;DiffResult&amp;gt; Algin(IList&amp;lt;string&amp;gt; from, IList&amp;lt;string&amp;gt; to);
}
   
&lt;/pre&gt;&lt;p&gt;Considering implementation, a widely used diff algorithm is the
one described by Eugene W. Myers, in his paper, "An O(ND)
Difference Algorithm and Its Variations". A simple implementation
is included in the sample, which has O((N + M)D) time and space
complexity. This article won't explain the details of this
algorithm, but a good tutorial is available on &lt;a href="http://www.codeproject.com/KB/recipes/DiffTutorial_1.aspx"&gt;The
Code Project&lt;/a&gt; by Nicholas Butler.&lt;/p&gt;&lt;p&gt;Another algorithm in our control is Needleman-Wunsch algorithm
which is commonly use for sequence alignment. This algorithm has
complexity O(N + M) in both time and space. Now, we can verify both
algorithms by comparing the outputs.&lt;/p&gt;&lt;h4&gt;User Interface&lt;/h4&gt;&lt;p&gt;As the screen shot shown previously, the control UI is similar
with some text diff applications. It is using two text blocks to
display the texts comparing, two scroll bars used for scrolling
text blocks, and a bar on the left to summarize the diff result.
Further, the text blocks is wrapping in side scroll viewer so that
the scroll bar can hook on them.&lt;/p&gt;&lt;p&gt;Let's define a Silverlight templated control
&lt;em&gt;DiffViewer&lt;/em&gt;, with the sub controls addressed above. These
controls are retrieved in &lt;em&gt;OnApplyTemplate&lt;/em&gt; method.&lt;/p&gt;&lt;pre class="brush: csharp"&gt;
/// &amp;lt;summary&amp;gt;
/// Represents the text diff control.
/// &amp;lt;/summary&amp;gt;
[TemplatePart(Name = RightTextBlockElement, Type = typeof(TextBlock))]
[TemplatePart(Name = LeftTextBlockElement, Type = typeof(TextBlock))]
[TemplatePart(Name = DiffBrushElement, Type = typeof(LinearGradientBrush))]
[TemplatePart(Name = HorizontalScrollBarElement, Type = typeof(ScrollBar))]
[TemplatePart(Name = VerticalScrollBarElement, Type = typeof(ScrollBar))]
[TemplatePart(Name = RightTextScrollViewerElement, Type = typeof(ScrollViewer))]
[TemplatePart(Name = LeftTextScrollViewerElement, Type = typeof(ScrollViewer))]
public class DiffViewer : Control
{
    /// &amp;lt;summary&amp;gt; ...
    private const string RightTextBlockElement = "RightTextBlockElement";

    /// &amp;lt;summary&amp;gt; ...
    private const string LeftTextBlockElement = "LeftTextBlockElement";

    /// &amp;lt;summary&amp;gt; ...
    private const string DiffBrushElement = "DiffBrushElement";

    /// &amp;lt;summary&amp;gt; ...
    private const string HorizontalScrollBarElement = "HorizontalScrollBarElement";

    /// &amp;lt;summary&amp;gt; ...
    private const string VerticalScrollBarElement = "VerticalScrollBarElement";

    /// &amp;lt;summary&amp;gt; ...
    private const string RightTextScrollViewerElement = "RightTextScrollViewerElement";

    /// &amp;lt;summary&amp;gt; ...
    private const string LeftTextScrollViewerElement = "LeftTextScrollViewerElement";
    
    /// &amp;lt;summary&amp;gt; ...
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        // Lookup template parts
        rightTextBlock = GetTemplateChild(RightTextBlockElement) as TextBlock;
        leftTextBlock = GetTemplateChild(LeftTextBlockElement) as TextBlock;
        horizontalScrollBar = GetTemplateChild(HorizontalScrollBarElement) as ScrollBar;
        verticalScrollBar = GetTemplateChild(VerticalScrollBarElement) as ScrollBar;
        leftTextScrollViewer = GetTemplateChild(LeftTextScrollViewerElement) as ScrollViewer;
        rightTextScrollViewer = GetTemplateChild(RightTextScrollViewerElement) as ScrollViewer;
        diffBrush = GetTemplateChild(DiffBrushElement) as LinearGradientBrush;
        
        leftTextBlock.SizeChanged += TextBlockSizeChanged;
        rightTextBlock.SizeChanged += TextBlockSizeChanged;

        verticalScrollBar.Scroll += VerticalScrollBarScroll;
        horizontalScrollBar.Scroll += HorizontalScrollBarScroll;

        templatedApplied = true;

        UpdateComparison();
    }
        
    /// ...
}
   
&lt;/pre&gt;&lt;p&gt;In &lt;em&gt;OnApplyTemplate&lt;/em&gt; method, I also added event handlers
to &lt;em&gt;SizeChanged&lt;/em&gt; and &lt;em&gt;Scroll&lt;/em&gt; event of text blocks
and scroll bars. Essentially, the scroll bars will be adjusted
according to the size of text blocks, and the viewport of text
blocks will be moved according to the position of scroll bars.&lt;/p&gt;&lt;pre class="brush: csharp"&gt;
public class DiffViewer : Control
{
    /// &amp;lt;summary&amp;gt; ...
    private void HorizontalScrollBarScroll(object sender, ScrollEventArgs e)
    {
        // Scroll text blocks horiontally
        leftTextScrollViewer.ScrollToHorizontalOffset(horizontalScrollBar.Value);
        rightTextScrollViewer.ScrollToHorizontalOffset(horizontalScrollBar.Value);
    }

    /// &amp;lt;summary&amp;gt; ...
    private void VerticalScrollBarScroll(object sender, ScrollEventArgs e)
    {
        // Scroll text blocks vertically
        leftTextScrollViewer.ScrollToVerticalOffset(verticalScrollBar.Value);
        rightTextScrollViewer.ScrollToVerticalOffset(verticalScrollBar.Value);
    }

    /// &amp;lt;summary&amp;gt; ...
    private void TextBlockSizeChanged(object sender, SizeChangedEventArgs e)
    {
        UpdateScrollBars();
    }

    /// &amp;lt;summary&amp;gt; ...
    private void UpdateScrollBars()
    {
        // Horizontal scroll bar
        var viewportWidth = Math.Max(leftTextScrollViewer.ViewportWidth, rightTextScrollViewer.ViewportWidth);
        var extentWidth = Math.Max(leftTextScrollViewer.ExtentWidth, rightTextScrollViewer.ExtentWidth);
        horizontalScrollBar.ViewportSize = viewportWidth;
        horizontalScrollBar.Maximum = extentWidth - viewportWidth;

        // Vertical scroll bar
        var viewportHeight = Math.Max(leftTextScrollViewer.ViewportHeight, rightTextScrollViewer.ViewportHeight);
        var extentHeight = Math.Max(leftTextScrollViewer.ExtentHeight, rightTextScrollViewer.ExtentHeight);
        verticalScrollBar.ViewportSize = viewportHeight;
        verticalScrollBar.Maximum = extentHeight - viewportHeight;
    }
        
    /// ...
}
&lt;/pre&gt;&lt;p&gt;Then, we need the dependency properties for two text inputs and
the &lt;em&gt;ITextDiffEngine&lt;/em&gt; instance to be used. A static method
&lt;em&gt;UpdateComparison&lt;/em&gt; is tracing these properties and delegates
to namesake method of the &lt;em&gt;DiffView&lt;/em&gt; instance.&lt;/p&gt;&lt;pre class="brush: csharp"&gt;
public class DiffViewer : Control
{
    /// &amp;lt;summary&amp;gt; ...
    public static readonly DependencyProperty LeftTextProperty =
        DependencyProperty.Register("LeftText", typeof(string), typeof(DiffViewer), new PropertyMetadata(UpdateComparison));

    /// &amp;lt;summary&amp;gt; ...
    public static readonly DependencyProperty RightTextProperty =
        DependencyProperty.Register("RightText", typeof(string), typeof(DiffViewer), new PropertyMetadata(UpdateComparison));

    /// &amp;lt;summary&amp;gt; ...
    public static readonly DependencyProperty DiffEngineProperty =
        DependencyProperty.Register("DiffEngine", typeof(ITextDiffEngine), typeof(DiffViewer), new PropertyMetadata(UpdateComparison));

    /// &amp;lt;summary&amp;gt; ...
    public string LeftText
    {
        get { return (string)GetValue(LeftTextProperty); }
        set { SetValue(LeftTextProperty, value); }
    }

    /// &amp;lt;summary&amp;gt; ...
    public string RightText
    {
        get { return (string)GetValue(RightTextProperty); }
        set { SetValue(RightTextProperty, value); }
    }

    /// &amp;lt;summary&amp;gt; ...
    public ITextDiffEngine DiffEngine
    {
        get { return (ITextDiffEngine)GetValue(DiffEngineProperty); }
        set { SetValue(DiffEngineProperty, value); }
    }
    
    private static void UpdateComparison(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
    {
        var diffView = dependencyObject as DiffViewer;
        if (diffView != null)
        {
            if (diffView.templatedApplied &amp;amp;&amp;amp; diffView.AutoUpdate)
            {
                diffView.UpdateComparison();
            }
        }
    }
        
    /// ...
}
   
&lt;/pre&gt;&lt;p&gt;Finally, &lt;em&gt;UpdateComparison&lt;/em&gt; method will invokes the diff
engine and displaying result. Inside the method, each line in both
texts will be aligned and added to text blocks as &lt;em&gt;Inline&lt;/em&gt;
objects. The color brush will be draw in the same time as well.&lt;/p&gt;&lt;pre class="brush: csharp"&gt;
public class DiffViewer : Control
{
    /// &amp;lt;summary&amp;gt; ...
    public void UpdateComparison()
    {
        // ...

        // Compute alignment
        var diffSolution = engine.Algin(leftTextLines, rightTextLines);

        // ...

        for (int i = 0; i &amp;lt; solutionLength; ++i)
        {
            var lineResult = diffSolution[i];

            // Append inlines according to result
            switch (lineResult)
            {
                case DiffResult.Matched:
                    // ...
                    break;
                case DiffResult.Deleted:
                    // ...
                    break;
                case DiffResult.Inserted:
                    // ...
                    break;
            }


            // ...

            if (lastResult != lineResult)
            {
                // End previous color
                gradientStops.Add(CreateGradientStop(lastResult, i, solutionLength));

                // Start new color
                gradientStops.Add(CreateGradientStop(lineResult, i, solutionLength));

                lastResult = lineResult;
            }
        }
        
        // ...
    }
        
    /// ...
}
   
&lt;/pre&gt;&lt;p&gt;If you have Silverlight 3 installed, you should be able to see
the sample application running underneath. Feel free to have a
try!&lt;/p&gt;&lt;p&gt;
  &lt;object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="320"&gt;
    &lt;param name="source" value="http://fszlin.dymetis.com/file.axd?file=2011%2f3%2fSilverDiff.Sample.xap" /&gt;
    &lt;param name="background" value="white" /&gt;
    &lt;param name="minRuntimeVersion" value="3.0.40818.0" /&gt;
    &lt;param name="autoUpgrade" value="true" /&gt;
    &lt;a href="http://go.microsoft.com/fwlink/?LinkID=149156&amp;amp;v=3.0.40818.0" style="text-decoration: none"&gt;
      &lt;img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none" /&gt;
    &lt;/a&gt;
  &lt;/object&gt;
&lt;/p&gt;</description>
      <link>http://fszlin.dymetis.com/post/2010/01/12/A-Silverlight-Text-Diff-Control.aspx</link>
      <comments>http://fszlin.dymetis.com/post/2010/01/12/A-Silverlight-Text-Diff-Control.aspx#comment</comments>
      <guid>http://fszlin.dymetis.com/post.aspx?id=0c5dc636-ab57-4eb9-81cb-30e82203ed56</guid>
      <pubDate>Tue, 12 Jan 2010 12:53:00 -0400</pubDate>
      <category>Web Development</category>
      <dc:publisher>fszlin</dc:publisher>
      <pingback:server>http://fszlin.dymetis.com/pingback.axd</pingback:server>
      <pingback:target>http://fszlin.dymetis.com/post.aspx?id=0c5dc636-ab57-4eb9-81cb-30e82203ed56</pingback:target>
      <slash:comments>159</slash:comments>
      <trackback:ping>http://fszlin.dymetis.com/trackback.axd?id=0c5dc636-ab57-4eb9-81cb-30e82203ed56</trackback:ping>
      <wfw:comment>http://fszlin.dymetis.com/post/2010/01/12/A-Silverlight-Text-Diff-Control.aspx#comment</wfw:comment>
      <wfw:commentRss>http://fszlin.dymetis.com/syndication.axd?post=0c5dc636-ab57-4eb9-81cb-30e82203ed56</wfw:commentRss>
    </item>
    <item>
      <title>Converting XPS to PDF Programmatically</title>
      <description>&lt;p&gt;I am working on a simple utility tool which pulls data from
database and then generates reports as E-Mail attachments. An
additional requirement is to exam the reports before sending them
out. Hence, I want a document format that meets these criteria.&lt;/p&gt;&lt;ul&gt;
  &lt;li&gt;Easy to generate;&lt;/li&gt;
  &lt;li&gt;Can be review in Win Form program;&lt;/li&gt;
  &lt;li&gt;Widely support by client computers.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Using WPF, &lt;a href="http://en.wikipedia.org/wiki/XML_Paper_Specification"&gt;XPS&lt;/a&gt;
is the best choice for first two requirements. Precisely,
generating a &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.documents.flowdocument.aspx"&gt;
FlowDocument&lt;/a&gt; is as simple as writing HTML, and XSLT can
translate any XML data into XPS flow document. On the other side,
&lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.documents.fixeddocument.aspx"&gt;
FixedDocument&lt;/a&gt; provides the same feel as a print out.&lt;/p&gt;&lt;p&gt;However, XPS requires a viewer installed. Some of our recipients
may not have the privilege to install the viewer. So I would like
to send out a PDF instead of XPS.&lt;/p&gt;&lt;h4&gt;Converting FlowDocument to FixedDocument&lt;/h4&gt;&lt;p&gt;In order to review the exact same documents as the ones sending
out. We need to first convert the flow document to fixed document.
A easy way is simply save the flow document by setting it"s page
size.&lt;/p&gt;&lt;pre class="brush: csharp"&gt;
var source = (IDocumentPaginatorSource)flowDoc;
var paginator = source.DocumentPaginator;

// Letter size
paginator.PageSize = new Size(8.5 * 96, 11 * 96);

using (XpsDocument doc = new XpsDocument(tempXpsPath, FileAccess.Write))
{
    var writer = XpsDocument.CreateXpsDocumentWriter(doc);
    writer.Write(paginator);
}
&lt;/pre&gt;&lt;p&gt;Now, use a DocumentViewer to display it in WPF. Here is the
result:&lt;br /&gt;&lt;img alt="XPS Viewer" src="http://fszlin.dymetis.com/image.axd?picture=2011%2f3%2fXPS-Viewer.png" /&gt;&lt;/p&gt;&lt;p&gt;If you would like to do it in memory, &lt;a href="http://khason.net/blog/printing-more-then-one-page-creation-in-memory-xps-document-and-documentviewer-customization/"&gt;
Here&lt;/a&gt; is an article from Tamir Khason. But I will need the
temporary XPS files for next step anyway.&lt;/p&gt;&lt;h4&gt;Converting XPS to PDF&lt;/h4&gt;&lt;p&gt;This part is much more challenging. I would like to do a trick
to get my PDFs, rather than read through the XPS/PDF
specifications. I am using &lt;a href="http://www.ghostscript.com/GhostPCL.html"&gt;GhostPCL&lt;/a&gt; to
convert XPS to PDF. Download and build GhostXPS following the
instruction, then copy gxps.exe (under xps/obj folder) to our
project.&lt;/p&gt;&lt;p&gt;Now, we may call gxps to convert the temporary XPS to PDF.&lt;/p&gt;&lt;pre class="brush: csharp"&gt;
// Convert XPS to PDF using gxps
ProcessStartInfo gxpsArguments = new ProcessStartInfo("gxps.exe", String.Format("-sDEVICE=pdfwrite -sOutputFile={0} -dNOPAUSE {1}", path, tempXpsPath));
gxpsArguments.WindowStyle = ProcessWindowStyle.Hidden;
using (var gxps = Process.Start(gxpsArguments))
{
    gxps.WaitForExit();
}
&lt;/pre&gt;&lt;p&gt;The sample program can be download &lt;a href="http://fszlin.dymetis.com/file.axd?file=2011%2f3%2fXPS2Pdf.zip"&gt;here&lt;/a&gt;. Hope
this help!&lt;/p&gt;</description>
      <link>http://fszlin.dymetis.com/post/2010/01/04/Converting-XPS-To-PDF-Programmatically.aspx</link>
      <comments>http://fszlin.dymetis.com/post/2010/01/04/Converting-XPS-To-PDF-Programmatically.aspx#comment</comments>
      <guid>http://fszlin.dymetis.com/post.aspx?id=3e503e5b-6563-43e9-8f82-86ed602a5c02</guid>
      <pubDate>Mon, 04 Jan 2010 06:02:00 -0400</pubDate>
      <category>Windows Development</category>
      <dc:publisher>fszlin</dc:publisher>
      <pingback:server>http://fszlin.dymetis.com/pingback.axd</pingback:server>
      <pingback:target>http://fszlin.dymetis.com/post.aspx?id=3e503e5b-6563-43e9-8f82-86ed602a5c02</pingback:target>
      <slash:comments>167</slash:comments>
      <trackback:ping>http://fszlin.dymetis.com/trackback.axd?id=3e503e5b-6563-43e9-8f82-86ed602a5c02</trackback:ping>
      <wfw:comment>http://fszlin.dymetis.com/post/2010/01/04/Converting-XPS-To-PDF-Programmatically.aspx#comment</wfw:comment>
      <wfw:commentRss>http://fszlin.dymetis.com/syndication.axd?post=3e503e5b-6563-43e9-8f82-86ed602a5c02</wfw:commentRss>
    </item>
  </channel>
</rss>