Guy Burstein's Blog

All about the newest tools and technologies from Microsoft

News

Guy Burstein
Work:
Microsoft Israel, 2 Hapnina st', Raanana
Israel
Email:
Or, use this form.
Guy Burstein The Bu

Disclaimer
Postings are provided 'As Is' with no warranties and confer no rights.

Guy Burstein LinkedIn Profile

TwitterCounter for @bursteg

The Bu

Links

Articles

Blogs I Read

ASP.Net MVC on Windows Azure | ASP.Net MVC Web Role

ASP.Net MVC on Windows Azure | ASP.Net MVC Web Role

ASP.Net MVC Web Role Windows AzureWhen you install Windows Azure Tools for Visual Studio, you only get a project template for an ASP.Net Web Role. In this post I’ll talk about how to create a new ASP.Net MVC Web Role or move an existing ASP.Net MVC Application to Windows Azure.

There are 2 ways to do this:

  • ASP.Net MVC Web Role Windows AzureManually adding an ASP.Net MVC application as a Web Role (suitable both for a new ASP.Net MVC application and for an existing one).
  • Use a Project Template to simply create a new ASP.Net MVC Web Role (new ASP.Net MVC application only).

Creating a New ASP.Net MVC Web Role

The following steps apply both for creating a new ASP.Net MVC application and to moving an existing ASP.Net MVC application to Windows Azure.

1. Create an empty ASP.Net MVC Application (with or without a test project), or make sure you have an existing ASP.Net MVC application that you want to move to the Windows Azure.

ASP.Net MVC Web Role Windows Azure

2. Close this solution and create a new Blank Cloud Service. Make sure you start Visual Studio as an administrator because working with the Development Fabric requires that.

ASP.Net MVC Web Role Windows Azure

3. Add an existing project to the cloud service and select the ASP.Net MVC Application you have created earlier.

ASP.Net MVC Web Role Windows Azure

4. Right click the ASP.Net MVC project and select Unload Project.

ASP.Net MVC Web Role Windows Azure

5. When the project is unloaded, right click it and edit the project file.

ASP.Net MVC Web Role Windows Azure

6. The project file opens in the XML Editor.

<Project ToolsVersion="3.5" DefaultTargets="Build" ...>

  <PropertyGroup>

    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

    ...

  </PropertyGroup>

  ...
</Project>

Inside the PropertyGroup Element, add the RoleType element and mark this ASP.Net MVC project as a Web Role.

<Project ToolsVersion="3.5" DefaultTargets="Build" ...>

  <PropertyGroup>

    <RoleType>Web</RoleType>

    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

    ...
  </PropertyGroup>

  ...

</Project>

7. Close this project file, and reload the project.

ASP.Net MVC Web Role Windows Azure

8. Since the ASP.Net MVC now runs on the Windows Azure Service Hosting environment and will probably use its services – add a reference to Microsoft.ServiceHosting.ServiceRuntime.dll.

ASP.Net MVC Web Role Windows Azure

9. Right click the Roles node in the project tree, and add a Web Role Project in the solution. Select the ASP.Net MVC project from the project list.

ASP.Net MVC Web Role Windows Azure

Now the ASP.Net MVC project is shown as a Web Role.

ASP.Net MVC Web Role Windows Azure

10. Since the Windows Azure provides us only with the default .Net Framework 3.5 SP1 assemblies, we must make sure we also copy the ASP.Net MVC Assemblies to the cloud. To do this, right click on each of the following references of the ASP.Net MVC application, and set the Copy Local property to True:

  • System.Web.Abstractions
  • System.Web.Mvc
  • System.Web.Routing

ASP.Net MVC Web Role Windows Azure 

That’s it. You can run the application to make sure that it is running on the Development Fabric.

ASP.Net MVC Web Role Windows Azure

Creating an ASP.Net MVC Web Role using a Project Template

Thanks to a great word done by the community, we can use a project template to do all the above steps for us. Here’s how to do this:

1. Download the project template from Codeplex at http://c4mvc.codeplex.com/.

ASP.Net MVC Web Role Windows Azure

2. Create a new project and select the Azure ASP.Net MVC template in the Community for MVC category.

ASP.Net MVC Web Role Windows Azure

This creates a new Cloud Service for Windows Azure with ASP.Net MVC Application as a Web Role.

ASP.Net MVC Web Role Windows Azure

Enjoy!

Visual Studio 2010 and .Net Framework 4.0 Beta 1 Is Publically Available

Visual Studio 2010 and .Net Framework 4.0 Beta 1 Is Publically Available

Visual Studio 2010 .Net Framework 4.0 Beta 1Downloads

Training and Resources

Enjoy!

WF/WCF using Visual Studio 2010 and .NET Framework 4 Training Kit

WF/WCF using Visual Studio 2010 and .NET Framework 4 Training Kit

WF/WCF using Visual Studio 2010 and .NET Framework 4 Training Kit   WF/WCF using Visual Studio 2010 and .NET Framework 4 Training Kit

The Microsoft WF/WCF using Visual Studio 2010 and .NET Framework 4 Training Kit includes presentations, hands-on labs, and demos. This content is designed to help you learn how to utilize the Visual Studio 2010 features and a variety of WF and WCF new features.

  • Learn basic workflow creation, hosting and running , and test-drive workflow development.
  • Get an introduction to workflow services, communication between workflows and content based correlation of workflow instances.
  • Use the flexibility of Flowchart workflow activities to implement non-sequential workflows.
  • Learn how to rehost the workflow designer in a WPF desktop application and customize it in several ways.
  • Learn how you can leverage some of the main WF and WCF monitoring features to track application execution and troubleshoot problems with services when necessary.
  • Learn how Service discovery allows you to locate services on the same subnet using ad hoc discovery, or using a proxy to establish connections with servers regardless of where they are.

This version of the training kit is compatible with Visual Studio 2010 Beta 1.

Download here.

WF 4.0: Long Running Custom Activities with Bookmarks and NativeActivity

WF 4.0: Long Running Custom Activities with Bookmarks and NativeActivity

WF 4.0: Long Running Custom Activities Bookmarks NativeActivity

This is another post in my WF 4.0: Custom Activities series. In a previous post I have talked about creating a code only custom activity that performs a simple task. In this post I’ll talk about creating a more complex activities that takes inputs from the calling program during their execution.

In the previous post WF 4.0: Code Only Custom Activities for Atomic Actions | CodeActivity, CodeActivity<T> I implemented the following activity for reading a string from the console.

public class ReadString2 : CodeActivity<string>

{

  protected override void Execute(CodeActivityContext context)

  {

    string value = Console.ReadLine();

    context.SetValue(Result, value);

  }

}

While this activity will perform the task it is meant to do, it is blocking the calling thread and bad for scalability. In addition to that It is bound to getting the value from the console only, and it is not generic enough to support another input methods.

Enter Bookmarks.

Using NativeActivity for Complex Activities

To create a long running activity, add a new item of type Workflow Element item to the project. Notice that the default activity inherits from CodeActivity.

public class ReadString3 : CodeActivity

{

  protected override void Execute(CodeActivityContext context)

  {

  }

}

To create complex activities such as long running activities, me need to change the base class and inherit from NativeActivity or NativeActivity<T>. In addition to that, there is a difference between the type of the parameter that the CodeActivity takes for the Execute method and the type that NativeActivity takes. Change the input parameter type from CodeActivityContext to ActivityExecutionContext.

public class ReadString3 : NativeActivity

{

  protected override void Execute(ActivityExecutionContext context)

  {

    throw new NotImplementedException();

  }

}

Enter Bookmarks

In previous versions of Windows Workflow Foundation we had the ExternalDataExchangeService and WorkflowQueue when we wanted to build a simple long running activity. In WF 4.0 this is much more simple to do using Bookmarks.

To use bookmarks we need to:

  • Create a named bookmark and Implement a callback method
  • Signal from the caller program

Register a Named Bookmak

The following activity registers a bookmark called “input” with a callback method called OnBookmarkCallback.

public class ReadString3 : NativeActivity

{

  OutArgument<string> name;

  public OutArgument<string> Name

  {

    get { return this.name; }

    set

    {

      ThrowIfOpen();

      this.name = value;

    }

  }

  protected override void Execute(ActivityExecutionContext context)

  {

    context.CreateNamedBookmark("input", new BookmarkCallback(this.OnBookmarkCallback));

  }

  void OnBookmarkCallback(ActivityExecutionContext context, Bookmark bookmark, object obj)

  {

    this.Name.Set(context, (string)obj);

  }

}

Signal the workflow from the caller program

In a previous post I have talked about the code that is needed to execute a workflow. Since we are now talking about long running workflows we will start with the default code that is generated for us when we create a new sequential workflow console application that uses the WorkflowInstance that lets know when the workflow instance is idle, and to resume a bookmark:

...

myInstance.Run();

//Get a string from the console and resume the bookmark called “input”

string input = Console.ReadLine();

myInstance.ResumeBookmark("input", input);

syncEvent.WaitOne();
...

The main program performs the input and delivers the value to the workflow. Using this approach:

  • The main program is flexible in how it wants to get values from the user and any other input source
  • The workflow becomes idle when it is waiting for the input and during that time not consuming any resources from the machine.

To query the available bookmarks in a workflow instance, we can use the following code:

IList bookmarks = myInstance.GetAllBookmarks();

foreach (BookmarkInfo info in bookmarks)

{

  Console.Write(info.BookmarkName);

}

Enjoy!

WF 4.0: Code Only Custom Activities for Atomic Actions | CodeActivity, CodeActivity<T>

WF 4.0: Code Only Custom Activities for Atomic Actions | CodeActivity, CodeActivity<T>

WF 4.0  Code Custom Activities CodeActivity CodeActivity<T>

This is another post in my WF 4.0: Custom Activities series. In this post I’ll talk about creating a code only custom activity that performs a simple task. I’ll also use input and output parameters and talk about activities that returns a single value.

A Simple Code Activity

Lets start by building a simple activity that outputs a certain string to the console. To to that, lets add a new item of type Workflow Element (under the Workflow node in the item templates).

WF 4.0  Code Custom Activities CodeActivity CodeActivity<T>

Visual Studio adds a new code file (remember – this is a code-only activity) with a class that inherits from the abstract class System.Activities.CodeActivity.

public class OutputString : CodeActivity

{

  protected override void Execute(CodeActivityContext context)

  {

 

  }

}

To implement the logic of the atomic action, we just have to code it here. Notice that we don’t have to tell the runtime that the status of this activity is closed or something like this like we had to in WF 3.5.

public class OutputString : CodeActivity

{

  protected override void Execute(CodeActivityContext context)

  {

    Console.WriteLine("Hello world");

  }

}

After building the project, the new custom activity will appear in the Toolbox, and can be used in the workflow.

WF 4.0  Code Custom Activities CodeActivity CodeActivity<T>

Adding Input Parameters to the Custom Activity

To add a new input parameter to the activity, we declare a InArgument<T> field and property where T is the type of the parameter.

public class OutputString : CodeActivity

{

  InArgument<string> name;

 

  public InArgument<string> Name

  {

    get { return name; }

    set {

      ThrowIfOpen();

      name = value;

    }

  }

 

  protected override void Execute(CodeActivityContext context)

  {

    Console.WriteLine("Hello,  " + this.Name.Get(context));

  }

}

Note that in the property setter implementation I am calling the base class’ ThrowIfOpen() method. This method throws an InvalidOperationException if the activity has already been prepared for execution and the value cannot be set.

Also note that in order to get the property value, we do not store the value in a private member in the class, but instead – we use the InArgument class and using the Get method passing it the activity context.

Output Parameters to Custom Activities

Lets create a simple activity that reads the name from the console.

public class ReadString : CodeActivity

{

  OutArgument<string> outputString;

 

  public OutArgument<string> Output

  {

    get { return outputString; }

    set {

      ThrowIfOpen();

      outputString = value;

    }

  }

 

  protected override void Execute(CodeActivityContext context)

  {

    string value = Console.ReadLine();

    context.SetValue(Output, value);

  }

}

Notice how the code required for an output argument is similar to the one required for an input argument. Also notice how we set the value back to the output value using the ActivityContext instance.

Activities with a Single Output Parameter - CodeActivity<T>

The above sample read a string from the console and placed the value in the output parameter. If this is the case we can also inherit from CodeActivity<T>:

public class ReadString2 : CodeActivity<string>

{

  protected override void Execute(CodeActivityContext context)

  {

    string value = Console.ReadLine();

    context.SetValue(Result, value);

  }

}

Inheriting from CodeActivity<T> makes it more simple to write a custom activity that has a single output parameter. It has additional benefits which I’ll talk about in a subsequent post.

Summary

In this post I talked about creating a code only custom activities that performs a simple task. I have also talked about input and output parameters.

WF 4.0: Custom Activities

WF 4.0: Custom Activities

WF 4.0 Custom Activities

There are several ways to build custom activities in WF 4.0:

In the following posts I’ll talks about each of those approaches and update the above links.

Enjoy!

WF 4.0: How to Execute a Worklflow (WorkflowInvoker vs WorkflowInstance)

WF 4.0: How to Execute a Worklflow (WorkflowInvoker vs WorkflowInstance)

Note: This post is based on Visual Studio 2010 Beta 1 which is the latest version available in the time of writing this post, so by the time this technology ships, there are probably things that will be slight different.

Execute Worklflow (WorkflowInvoker WorkflowInstanceThere are two ways to execute a workflow:

  • Using the WorkflowInstance class
  • Using the WorkflowInvoker class

Execute Workflows using WorkflowInstace

When you create a new Sequential Workflow Console Application, Visual Studio creates the basic code needed to execute the workflow inside the Main method:

static void Main(string[] args)

{

  AutoResetEvent syncEvent = new AutoResetEvent(false);

 

  WorkflowInstance myInstance = new WorkflowInstance(new Sequence1());

 

  myInstance.OnCompleted = delegate(WorkflowCompletedEventArgs e)

  {

    syncEvent.Set();

  };

 

  myInstance.OnUnhandledException = delegate(WorkflowUnhandledExceptionEventArgs e)

  {

    Console.WriteLine(e.UnhandledException.ToString());

    return UnhandledExceptionAction.Terminate;

  };

 

  myInstance.OnAborted = delegate(WorkflowAbortedEventArgs e)

  {

    Console.WriteLine(e.Reason);

    syncEvent.Set();

  };

 

  myInstance.Run();

 

  syncEvent.WaitOne();

 

}

1. A workflow instance is created and gets a reference to the root activity of the workflow. The WorkflowInstance class lets us control the running instance of the workflow and exposes several methods for this such as Run(), Abort(), Cancel(), Load(), Unload etc.

2. Since the workflow execution is scheduled to another thread, we need to block the main thread until the workflow is completed or terminated. To do this, we:

  • Create an AutoResetEvent initialized to false,
  • Set the event to true when the workflow is completed, and
  • In the main thread - wait for the workflow to complete before exiting the method.

3. In order to handle errors in the workflow such as exceptions or termination, in addition to handling the OnCompleted event, we are also handling the OnHandledException and OnAborted events. Note that when the workflow has an unhandled exception, the program can still decide how it wants to end the workflow execution, whether it is by aborting, cancelling or terminating the workflow. If the workflow is terminated, the OnCompleted event will also be raised.

Execute Workflows using WorkflowInvoker

WorkflowInvoker lets you invoke a workflow much more easily than the previous approach. It takes the instance of the workflow or activity to run and executes it synchronously.

WorkflowInvoker.Invoke(new Sequence1());

There are additional overloads of this method that takes parameters and a TimeSpan in which the workflow should complete within. I’ll talk in more details about passing parameters to workflow in a subsequent post, but in general this is all we have to know about WorkflowInvoker.

Choosing between WorkflowInstance and WorkflowInvoker

If you have a simple workflow that should run synchronously – use WorkflowInvoker. This is useful also in when unit testing workflows (more on this in a later post).

If you have a long running workflow that you want to control – persist, abort, cancel etc – use WorkflowInstance.

Enjoy!

WF 4.0: Building a Hello World Sequential Workflow

WF 4.0: Building a Hello World Sequential Workflow

WF 4.0 Hello World Sequential Workflow

Note: This post is based on Visual Studio 2010 Beta 1 which is the latest version available in the time of writing this post, so by the time this technology ships, there are probably things that will be slight different.

Start Visual Studio 2010 Beta 1 and create a new Sequential Workflow Console Application.

WF 4.0 Hello World Sequential Workflow

After you click OK, visual studio creates the new projects and creates a new WF project, in which there are some things you should know about:

WF 4.0 Hello World Sequential WorkflowReferences:

  • System.Xaml – Now that there are several technologies based on Xaml, this is a new Assembly in .Net Framework 4.0 that contains Xaml services such as serialization.
  • System.Activities is the assembly that contains the implementation of WF 4.0, and as you can guess, the corresponding namespace is System.Activities and anything beneath it.
  • System.Activities.Design contains the designers for the activities and the designer re-hosting implementation. Since the new designer is based on WPF, you can also note references to WindowsBase, PresentationCode and PresentationFramework.
  • System.ServiceModel contains WCF implementation (as of .Net Framework 3.0) and now System.ServiceModel.Activities contains the activities used for Workflow Services (the integration between WF and WCF).

Sequence.xaml:

By default, workflows are created declaratively in WF 4.0 and represented in .xaml files with no code behind. If you open this file with an Xml editor, you will see it clearly.

<?xml version="1.0" encoding="utf-8" ?>

<p:Activity x:Class="HelloWorld.Sequence1"

          xmlns:p="http://schemas.microsoft.com/netfx/2009/xaml/activities"

          xmlns:s="clr-namespace:System;assembly=mscorlib"

          xmlns:sad="clr-namespace:System.Activities.Debugger;assembly=System.Activities"

          xmlns:sadx="clr-namespace:System.Activities.Design.Xaml;assembly=System.Activities.Design"

          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <p:Sequence sad:XamlDebuggerXmlReader.FileName="C:\...\HelloWorld\Sequence1.xaml">

 

    </p:Sequence>

</p:Activity>

The new WF Designer shows an empty sequence, representing an empty block of execution. Note the warning sign that says that the sequence has no child activities.

WF 4.0 Hello World Sequential Workflow

From the Procedural section in the Toolbox, drag the WriteLine Activity to the design surface.

WF 4.0 Hello World Sequential Workflow

Now, you get a warning that the Text property is not set. To set it, go the properties window, and open the Expression Editor. In WF 4.0 you use the Expression to set values to variables and parameters, and you can use either static values (like in this case) or VB. Yes! Expression are written in VB.

Type the text you want to display to the console and click OK.

WF 4.0 Hello World Sequential Workflow

Now, that the simple workflow is completed, you can use Ctrl + F5 to run it like you normally do.

WF 4.0 Hello World Sequential Workflow

Debugging a Workflow

The debugging experience when debugging a workflow in WF 4.0 is very similar to the debugging experience when using code. You can right click an activity the in designer and select Insert Breakpoint, or use F9 to do this.

WF 4.0 Hello World Sequential Workflow

Once you do this and run the workflow, the debugger highlights the current activity using a yellow border (similar to the yellow background for the current statement when debugging code).

WF 4.0 Hello World Sequential Workflow

Enjoy!

XAML in .Net 4.0: Attached Properties, IAttachedPropertyStore and AttachablePropertyServices

XAML in .Net 4.0: Attached Properties, IAttachedPropertyStore and AttachablePropertyServices 

new dot net logo

Note: This post is based on Visual Studio 2010 Beta 1 which is the latest version available in the time of writing this post, so by the time this technology ships, there are probably things that will be slight different.

In a previous post I’ve talked about XAML Serialization and Deserialization using XamlServices in .Net Framework 4.0. In this post I’ll add to my data classes support for Attached Properties, so that they will be extensible during serialization.

Implement System.Xaml.IAttachedPropertyStore interface

This interface should be implemented by classes that can store attached properties.

public interface IAttachedPropertyStore

{

  int PropertyCount { get; }

  void CopyPropertiesTo(KeyValuePair<AttachableMemberIdentifier, object>[] array,
                        int index);

  bool RemoveProperty(AttachableMemberIdentifier mi);

  void SetProperty(AttachableMemberIdentifier mi, object value);

  bool TryGetProperty(AttachableMemberIdentifier mi, out object value);

}

The simplest way of implementing it, is using a Dictionary<AttachableMemberIdentifier, object> that holds the attached properties. For example, the Book class from the previous post that now implements IAttachedPropertyStore:

[RuntimeNameProperty("Name")]

[ContentProperty("Related")]

public class Book : IAttachedPropertyStore

{

  public int ISBN { get; set; }

  public string Name { get; set; }

 

  private IList<Book> related = new List<Book>();

  public IList<Book> Related { get { return this.related; } }

 

  #region IAttachedPropertyStore Members

  IDictionary<AttachableMemberIdentifier, object> attachedProperties =
      new Dictionary<AttachableMemberIdentifier, object>();

 

  public void CopyPropertiesTo(KeyValuePair<AttachableMemberIdentifier, object>[] array,

                               int index)

  {

    attachedProperties.CopyTo(array, index);

  }

 

  public int PropertyCount

  {

    get { return attachedProperties.Count; }

  }

 

  public bool RemoveProperty(AttachableMemberIdentifier member)

  {

    return attachedProperties.Remove(member);

  }

 

  public void SetProperty(AttachableMemberIdentifier member, object value)

  {

    attachedProperties[member] = value;

  }

 

  public bool TryGetProperty(AttachableMemberIdentifier member, out object value)

  {

    return attachedProperties.TryGetValue(member, out value);

  }

  #endregion

}

Use AttachablePropertyServices  to Attach Properties to Stores

After adding support for Attached Properties to our object we can attach additional properties to it. This can be done directly with System.Xaml.AttachablePropertyServices class, but usually, we would prefer creating a class that provides strongly typed methods for those kinds of operations. For example, if we want to add more metadata to the book, such as an indication whether it is in stock or not we can create a class like this:

public class StockInfo

{

  public bool InStock { get; set; }

  public int Quantity { get; set; }

}

In order to store and retrieve the data from a class that implements IAttachedPropertyStore we can add the following static methods to the StockInfo class:

public class StockInfo

{

  public bool InStock { get; set; }

  public int Quantity { get; set; }

 

  public static StockInfo GetStockInfo(Book book)

  {

    StockInfo stockInfo = null;

    AttachablePropertyServices.TryGetProperty<StockInfo>(

      book,

      new AttachableMemberIdentifier(typeof(StockInfo), "StockInfo"),

      out stockInfo);

    return stockInfo;

  }

 

  public static void SetStockInfo(Book book, StockInfo stockInfo)

  {

    AttachablePropertyServices.SetProperty(

      book,

      new AttachableMemberIdentifier(typeof(StockInfo), "StockInfo"),

      stockInfo);

  }

}

Now, we can attach and retrieve the additional data from the instance:

Book book1 = new Book { Name = "First", ISBN = 123 };

StockInfo.SetStockInfo(book1, new StockInfo { InStock = true, Quantity = 27 });

StockInfo info = StockInfo.GetStockInfo(book1);

If we decided to serialize the instance with the attached properties assigned to it, we would get a serialized content like this:

<Book ISBN="123" Name="First" xmlns="clr-namespace:XamlSamples;assembly=XamlSamples">

  <StockInfo.StockInfo>

    <StockInfo InStock="True" Quantity="27" />

  </StockInfo.StockInfo>

</Book>

Summary

In this post I extended my data class (Book) with additional properties using the Attached Properties support in Xaml: Implementing the IAttachedPropertyStore interface by the data class and setting and getting the values using AttachablePropertyServices.

XAML in .Net 4.0: Serialization and Deserialization using XamlServices

XAML in .Net 4.0: Serialization and Deserialization using XamlServices

Serialization and Deserialization using XamlServices

Note: This post is based on Visual Studio 2010 Beta 1 which is the latest version available in the time of writing this post, so by the time this technology ships, there are probably things that will be slight different.

In order to serialize and deserialize using XAML in .Net Framework 4.0 we have to reference a new assembly called System.Xaml.dll. Since XAML was originally used only in WPF, some features are dependent on classes that are inside WindowsBase.dll.

Serialize to Xaml with XamlServices

Assuming we have a class called Book, that is defined like this:

public class Book

{

  public string Name { get; set; }

  public int ISBN { get; set; }

}

In order to serialize it, we use System.Xaml.XamlServices class:

Book book1 = new Book { Name = "First", ISBN = 123 };

string bookFileName = "book.xaml";

using (TextWriter writer = File.CreateText(bookFileName))

{

  XamlServices.Save(writer, book1);

}

The output file should contain the following content:

<Book ISBN="123"

    Name="My first book"

    xmlns="clr-namespace:XamlSamples;assembly=XamlSamples" />

If we have a more complex object graph, for example if each book had a list of related books:

public class Book

{

  ...

 

  private IList<Book> related = new List<Book>();

  public IList<Book> Related { get { return this.related; } }

}

Then for the following books with relations:

Book book1 = new Book { Name = "First", ISBN = 123 };

Book book2 = new Book { Name = "Second", ISBN = 456 };

Book book3 = new Book { Name = "Third", ISBN = 789 };

book1.Related.Add(book2);

book1.Related.Add(book3);

book2.Related.Add(book1);

book3.Related.Add(book1);

The result will be:

<Book x:Name="__ReferenceID0" ISBN="123" Name="First"

    xmlns="clr-namespace:XamlSamples;assembly=XamlSamples"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Book.Related>

        <Book ISBN="456" Name="Second">

            <Book.Related>

                <x:Reference>__ReferenceID0</x:Reference>

            </Book.Related>

        </Book>

        <Book ISBN="789" Name="Third">

            <Book.Related>

                <x:Reference>__ReferenceID0</x:Reference>

            </Book.Related>

        </Book>

    </Book.Related>

</Book>

Notice that the first book is now being identified using the x:Name property and its unique id is __ReferenceID0. This ID is also used to list the related books of the second book. Also note that there is no need to create a unique id to the second book because it is represented as a child element of the first one.

If we wanted to use the Name property of the books as the unique identifier, we could use the System.Windows.Markup.RuntimeNamePropertyAttribute in WindowsBase.dll:

[RuntimeNameProperty("Name")]

public class Book

{

  ...

}

Now, the output will be:

<Book ISBN="123" Name="First"

    xmlns="clr-namespace:XamlSamples;assembly=XamlSamples"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Book.Related>

        <Book ISBN="456" Name="Second">

            <Book.Related>

                <x:Reference>First</x:Reference>

            </Book.Related>

        </Book>

        <Book ISBN="789" Name="Third">

            <Book.Related>

                <x:Reference>First</x:Reference>

            </Book.Related>

        </Book>

    </Book.Related>

</Book>

Note that there is no x:Name attribute.

If we also want to take out the <Book.Related> nodes, and set its content to be the content node of the Book type, we can use the System.Windows.Markup.ContentPropertyAttribute in WindowsBase.dll.

[RuntimeNameProperty("Name")]

[ContentProperty("Related")]

public class Book

{

  ...

}

Now, the result is much simpler:

<Book ISBN="123" Name="First"

    xmlns="clr-namespace:XamlSamples;assembly=XamlSamples"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Book ISBN="456" Name="Second">

        <x:Reference>First</x:Reference>

    </Book>

    <Book ISBN="789" Name="Third">

        <x:Reference>First</x:Reference>

    </Book>

</Book>

Deserialize from Xaml with XamlServices

In order to deserialize an object graph from .xaml file, we can use XamlServices.Load method:

using (TextReader reader = File.OpenText(bookFileName))

{

  Book book = (Book)XamlServices.Load(reader);

  Console.WriteLine("Book {0} (ISBN:{1})", book.Name, book.ISBN);

  Console.WriteLine("Related Books:");

  foreach (Book relatedBook in book.Related)

  {

    Console.WriteLine("\t{0} (ISBN:{1})", relatedBook.Name, relatedBook.ISBN);

  }

}

After deserialization, the object graph is just as it was before serialization, and the output is:

Serialization and Deserialization using XamlServices

Summary

In this post I showed basic samples of serialization and deserialization of object graphs uisng XamlServices in System.Xaml as part of the .Net Framework 4.0. In later post I'll talk about some more advanced features such as Attached Properties and more.

Visual Studio 2010 Beta 1 is Available for MSDN Subscribers

Visual Studio 2010 Beta 1 is Available for MSDN Subscribers

Visual Studio 2010 Beta 1

Go get it, I already did!

.Net RIA Services: Custom Validation

.Net RIA Services: Custom Validation

This is another post in a series of posts about building applications with Microsoft .Net RIA Services and Silverlight 3 and ASP.Net.

In my previous post .Net RIA Services Part 3: DataForm and Validation I explained how to add validation metadata to entities and showed how the DataForm control enforces them. I used simple validation metadata attributes such as RegularExpressionAttribute, RequiredAttribute and StringLengthAttribute that help us in basic scenarios.

If you want to write custom validation, you can inherit from System.ComponentModel.DataAnnotations.ValidationAttribute, but a more simple way would be to write a validation method, and share it between the server side and the client side, as I explained in my previous post .Net RIA Services: Sharing Code between the Client and Server.

In CustomerValidation.shared.cs file (in the server side) I wrote the following method, that takes the value of a property and returns an indication whether it is valid or not.

[Shared]

public class CustomerValidation

{

  [Shared]

  public static bool IsEmailEndsWithDotCom(string email)

  {

    if (email.EndsWith(".com"))

      return true;

    return false;

  }

 

}

To apply this validation logic on an entity property, use the CustomValidationAttribute with the about type and method name, and the error message to display.

internal sealed class CustomerMetadata

{

  ... 

 

  [CustomValidation(typeof(CustomerValidation),
   "IsEmailEndsWithDotCom",

    ErrorMessage = "Customer\'s email address must end with .com")]

  public string Email;

 

  ...

}

At runtime, the framework will invoke this method passing it the property value, and if it returns False, the error message will be shown.

.Net RIA Services: Custom Validation

The above sample is also nice for scenarios is which the logic is independent of any other property about the entity that’s being validated. In cases where you need additional information about the entity to perform the validation logic, you can use a more complex signature of the validation method.

[Shared]

public class CustomerValidation

{

  [Shared]

  public static bool EnsureBusinessEmailAddress(string email,
    ValidationContext ctx,
    out ValidationResult result)

  {

    result = null;

 

    Customer cust = (Customer)ctx.ObjectInstance;

 

    if (cust.IsBusiness)

    {

      if (!cust.Email.EndsWith(".com"))

      {

        result = new ValidationResult("Business Customer's email address must end with .com");

      }

    }

 

    return false;

  }

}

In this approach I receive not only the property value, but also an instance of ValidationContext that provides me with some information about the entity and property being validated and also a reference to the entity instance itself.

Using it is the same, except that here I pass the error message in the out parameter ValidationResult, instead of providing it in the validation attribute.

internal sealed class CustomerMetadata

{

  ...

 

  [CustomValidation(typeof(CustomerValidation), "EnsureBusinessEmailAddress")]

  public string Email;

 

  ...

}

.Net RIA Services: Custom Validation

Enjoy!

.Net RIA Services: Sharing Code between the Client and Server

.Net RIA Services: Sharing Code between the Client and Server

This is another post in a series of posts about building applications with Microsoft .Net RIA Services and Silverlight 3 and ASP.Net.

In this I’ll talk about how to share code between the server side and the Silverlight client application.

One of the great things in .Net RIA Services is that code that we wrote in the server side can be resued in the client side. To do that, create a new class in the server side called with .shared.cs or .shared.vb suffix (CustomerValidation.shared.cs in this sample).

.Net RIA Services Sharing Code between Client and Server

In this class, code what you’d live to share with the client side, under the rational limitations. To make the code sections shared between the server and the client, decorate them with System.Web.Ria.Data.SharedAttribute. For example:

[Shared]

public class CustomerValidation

{

  [Shared]

  public static bool IsEmailEndsWithDotCom(string email)

  {

    if (email.EndsWith(".com"))

      return true;

    return false;

  }

}

After you build the solution, Visual Studio will copy this file to the Silverlight client application:

.Net RIA Services Sharing Code between Client and Server

and now, you can use this code in the client application, as you did in the server side. Here is an example of me using the shared code in the HomePage class in the Silverlight client application.

.Net RIA Services Sharing Code between Client and Server

Enjoy!

.Net RIA Services Part 3: DataForm and Validation

.Net RIA Services Part 3: DataForm and Validation

.Net RIA Services DataForm ValidationThis is the forth part in a series of posts about building applications with Microsoft .Net RIA Services and Silverlight 3. In part 1 of this series I created a new application, created a simple data model and used the Domain Service and Domain Context to retrieve data and bind it to a DataGrid. In part 2 we replaced the manual work needed to get the data from the server with the DomainDataSource that provided some more advanced scenarios such as filtering and sorting. In this post we’ll introduce the DataForm control and talk more about data validation.

Using the DataForm control

Add A DataForm Control and bind it to the current item of the DataGrid. Open Views\HomePage.xaml, and add a DataForm Control right after the DataPager.

<Grid x:Name="LayoutRoot" Background="White">

    ... 

    <dataControls:DataPager PageSize="3"

         Source="{Binding Data, ElementName=customersDataSource}" />

 

    <dataControls:DataForm x:Name="customerDataForm"

        Header="Customer Data"

        CurrentItem="{Binding ElementName=dataGrid, Path=SelectedItem}">

    </dataControls:DataForm>

    ...

</
Grid>

If you run the application, you should see the DataForm below the DataGrid. Move between the items, and see how the displayed customer’s data is changing as you do that.

.Net RIA Services DataForm Validation

To edit an item, click the pencil icon on the DataForm.

 .Net RIA Services DataForm Validation

When you do that, the controls will be replaced with input controls, and Save and Cancel buttons will show up.

.Net RIA Services DataForm Validation

If you change a value of a property in a customer’s data, you’ll get a notification that this data was changed and the customer is not “dirty”.

.Net RIA Services DataForm Validation

Notice that changes that are made here are tracked only in memory. This means, that by pressing the Save button, you’ll switch over to Display more, but the data is not saved to the server. To enable submitting changes back to the server, we need to add a submit button below the DataForm.

<Button x:Name="btnSubmit"

      Width="120"

      Click="btnSubmit_Click"

      Content="Submit" />

As the implementation of the submit button, you’ll need to commit the changes of the current item that is being edited (similar to EndCurrentEdit() in Windows Forms), and only then pushing the changes back the server.

private void btnSubmit_Click(object sender, RoutedEventArgs e)

{

  this.customerDataForm.CommitItemEdit();

  this.customersDataSource.SubmitChanges();     

}

Adding Validation Logic using Data Annotations

One of the great things in .Net RIA Services is that code that we wrote in the server side can be resued in the client side. This means that we can reuse the validation annotations that we have for our domain entities.

To annotate entities with validation semantics, open the metadata file for the domain service (BankDomainService.metadata.cs in the sample). In this file, you’ll find partial classes that match your domain classes (class Customer in this sample), decorated with MetadataTypeAttribute pointing to a metadata type the is also generated here as an inner class. The metadata class has fields / properties that match the properties that the original class has, that you can annotate with validation requirements.

[MetadataTypeAttribute(typeof(Customer.CustomerMetadata))]

public partial class Customer

{

  internal sealed class CustomerMetadata

  {

    public int CustomerID;

 

    public bool IsBusiness;

 

    public string Name;

 

    public string City;

 

    public string Email;

 

    public EntitySet<Account> Accounts;

  }

}

In this examples we’ll use the Regular Expression attribute, the String Length Attribute and the Required Attribute to validate the customer entity, but I encourage you to explore the System.ComponentModel.DataAnnotations namespace more deeply.

internal sealed class CustomerMetadata

{

  public int CustomerID;

 

  public bool IsBusiness;

 

  [Required(ErrorMessage="Please provide a name for the customer")]

  [StringLength(30,

    ErrorMessage="Customer's name cannot be more than 30 characters")]

  public string Name;

 

  [StringLength(30,

    ErrorMessage = "Customer's city cannot be more than 15 characters")]

  public string City;

 

  [RegularExpression(@"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$",

    ErrorMessage="Please provide a valid email address")]

  public string Email;

 

  public EntitySet<Account> Accounts;

}

Build the project and Visual Studio will regenerate the client side code for the domain context, that will now also contain the metadata.

If you now run the application, and try to update a customer’s entity with values that do not match the validations, you will get a visual notification and the data will not be updated to the server.

 .Net RIA Services DataForm Validation

In this post I talked about the new DataForm control in .Net RIA Services, showed how to add it to our application and how it works. Then we talked a little bit about annotating the entities with validation requirements and saw how the DataForm enforces them.

Enjoy!

ASP.Net QueryExtender Control and DomainDataSource

ASP.Net QueryExtender Control and DomainDataSource

ASP.Net QueryExtender DomainDataSourceJust another post about .Net RIA Services with Silverlight and ASP.Net. Previously, I wrote about Using DomainDataSource in ASP.Net and ASP.Net DomainDataSource with Select Parameters. In this post I am talking about the new ASP.Net QueryExtender Control, that applies additional filtering to the DomainDataSource. It does that by an additional expression to the expression tree that the DomainDataSource generates before hitting the DomainService with the query.

You can download the full source code for this sample: QueryExtender Sample.zip

To use the ASP.Net QueryExtender control, you first need to add a reference to Microsoft.Web.Extensions.dll (can be found at: c:\Program Files\Microsoft SDKs\RIA Services\v1.0\Libraries\Server\ folder).

Then, register the its namespace with a tag prefix at the top of the page:

<%@ Register TagPrefix="asp"

  Namespace="Microsoft.Web.Data.UI.WebControls"

  Assembly="Microsoft.Web.Extensions" %>

And now we can add the QueryExtender control to target the customersDataSource.

<asp:DomainDataSource ID="customersDataSource" ...>

</asp:DomainDataSource>

<asp:QueryExtender runat="server" TargetControlID="customersDataSource">

</asp:QueryExtender>

The QueryExtender control takes a collection of DataSourceExpressions. There are several of those in the same assenbly:

  • OrderByExpression
  • MethodExpression
  • PropertyExpression
  • RangeExpression
  • SearchExpression
  • and also CustomExpression.

To use any of those expressions, we’ll have to register another tag prefix with their namespace:

<%@ Register TagPrefix="asp"

  Namespace="Microsoft.Web.Data.UI.WebControls.Expressions"

  Assembly="Microsoft.Web.Extensions" %>

Lets filter a list by customers name. We’ll add a TextBox that will contain the search term:

<asp:TextBox runat="server" ID="txtSearch" />

and then add the expression, and bind it to a the control’s value.

<asp:QueryExtender runat="server" TargetControlID="customersDataSource">

  <asp:SearchExpression SearchType="Contains" DataFields="Name">

    <asp:ControlParameter ControlID="txtSearch" />

  </asp:SearchExpression>

</asp:QueryExtender>

If we now run the application, we can filter by the customer name.

ASP.Net QueryExtender DomainDataSource

Enjoy!

More Posts « Previous page - Next page »