Welcome to MSDN Blogs Sign in | Join | Help

Guy Burstein

Experiences of a Developer Evangelist in Israel
Getting Started with jQuery in Visual Studio 2008

Getting Started with jQuery in Visual Studio 2008

jQuery IntellSense in Visual Studio 2008

In this post I’ll talk about adding jQuery IntellSense in Visual Studio 2008, and how to add jQuery to a simple Web Application inside Visual Studio 2008.

jQuery IntelliSense in Visual Studio 2008 - KB946581

In order to use jQuery in Visual Studio 2008 with IntelliSence a hotfix for Visual Studio 2008 must be installed:

  1. Download the hotfix from Connect
  2. Run the executable and extract its contents to a folder in your hard drive.
  3. Make sure all instances of Visual Studio 2008 are closed, and run VS90-KB946581.exe from the above folder.

Download the Latest jQuery Library + Documentation

To use jQuery in Visual Studio 2008, and enjoy its IntelliSense, you should download 2 javascript files. One contains the actual jQuery library, and the second contains the library with documentation for Visual Studio 2008 to display its IntelliSense.

  1. Go to jQuery Official Download Page
  2. Scroll down and find the Current Release section.
  3. Download the Uncompressed version (jquery-1.2.6.js) and the documentation for Visual Studio (jquery-1.2.6-vsdoc.js).

Using jQuery in a Visual Studio 2008 Web Application

jQuery IntelliSense in Visual Studio 2008 - KB946581In a new Web Application or inside an existing one, add the jQuery scripts into a certain folder.

In a web page (or a master page), add a reference to the jQuery library:

<head runat="server">

  <title>jQuery Sample</title>

 

  <script src="scripts/jquery-1.2.6.js"
          type="text/javascript" ></script>

 

</head>

Then, in any javascript function you can start using jQuery functions and enjoy the IntelliSense in Visual Studio 2008.

jQuery IntelliSense in Visual Studio 2008 - KB946581

A Simple Example of Using jQuery Functions

For example, Assuming that you have a page with the following content in it:

<form id="form1" runat="server">

<div>

  <input type="text" class="inputs" id="txtName"
         value="Enter Text Here" />

  <input type="button" class="inputs" id="btnSubmit"
         value="Click Me" onclick="handleButtonClick();" />

</div>

</form>

This form contains a single textbox followed by a button.

jQuery IntelliSense in Visual Studio 2008 - KB946581

The handleButtonClick() function handles the button onclick event.

<script type="text/javascript">

  function handleButtonClick() {

  }

</script>

The way jQuery works is by selecting DOM elements and then doing something with them, such as executing a function or applying some properties. For example:

<script type="text/javascript">

  function handleButtonClick() {

    $("#txtName").css("border", "solid 2px red");

  }

</script>

The above method uses the selector function $ to select DOM elements (in this case – a single element with id = txtName) and to apply a style property of a red border. Running this page and clicking the button results in this output:

jQuery IntelliSense in Visual Studio 2008 - KB946581

Summary

In this post I talked about the steps you should follow in order to use jQuery in Visual Studio 2008 with InstelliSense support. Then, we used jQuery in a simple web application.

Twitter API From C#: Getting a User’s Time Line

Twitter API From C#: Getting a User’s Time Line

Twitter API C#: Getting Time Line From Twitter API Documentation page:

User Timeline:

Returns the 20 most recent statuses posted from the authenticating user:

http://twitter.com/statuses/user_timeline.xml

It's also possible to request another user's timeline. For example:

http://twitter.com/statuses/user_timeline/bursteg.xml

Making an HTTP Request

Since all the API is expressed in REST, I figured out that I need a simple reusable method to perform HTTP requests. This method takes the URL and the method (GET or POST), gets the credentials from the configuration file and makes the request.

private string PerformRequest(string method, string url)

{

    string user = ConfigurationManager.AppSettings["user"];

    string password = ConfigurationManager.AppSettings["password"];

 

    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);

    request.Method = method;

    request.Credentials = new NetworkCredential(user, password);

    WebResponse response = request.GetResponse();

    StreamReader reader = new StreamReader(response.GetResponseStream());

    string responseString = reader.ReadToEnd();

    reader.Close();

    return responseString;

}

Just for the simplicity, I also added the following methods:

private string Post(string url)

{

    return PerformRequest("POST", url);

}

 

private string Get(string url)

{

    return PerformRequest("GET", url);

}

Getting a User’s Time Line from Twitter

Using the following code, you can get a user’s timeline from twitter in xml  format:

string url = string.Format("http://twitter.com/statuses/friends/{0}.xml", user);

string response = Get(url);

This call returns the following piece of xml:

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

<statuses type="array">

  <status>

    <created_at>Sat Nov 15 10:08:15 +0000 2008</created_at>

    <id>1006846483</id>

    <text>Testing &quot;posts&quot; #devacademy3</text>

    <source>web</source>

    <truncated>false</truncated>

    <in_reply_to_status_id></in_reply_to_status_id>

    <in_reply_to_user_id></in_reply_to_user_id>

    <favorited>false</favorited>

    <user>

      <id>6849932</id>

      <name>Guy Burstein</name>

      <screen_name>bursteg</screen_name>

      <location></location>

      <description></description>

      <profile_image_url>http://.../Guy_Burstein_Small_normal.jpg</profile_image_url>

      <url>http://blogs.microsoft.co.il/blogs/bursteg</url>

      <protected>false</protected>

      <followers_count>42</followers_count>

    </user>

  </status>

 

  <status>

    ...

  </status>

</statuses>

As we can see, this response is an array of statuses, each contains the details about the user who posted it.

Extracting the Data

With my favor to LINQ to XML, I used it to extract the data that I was interested in, and construct CLR objects that I can easily work with.

XDocument document = XDocument.Parse(response, LoadOptions.None);

 

var query = from e in document.Root.Descendants("status")

            select new UserStatus

            {

                UserName = e.Element("user").Element("name").Value,

                ProfileImage = e.Element("user").Element("profile_image_url").Value,

                Status = HttpUtility.HtmlDecode(e.Element("text").Value),

                StatusDate = (e.Element("created_at").Value.ParseDateTime())

            };

First, I parsed an xml document from the response string. Then, I created a list of UserStatus objects from the contents of the response xml.

public class UserStatus

{

    public string UserName { get; set; }

    public string ProfileImage { get; set; }

    public string Status { get; set; }

    public DateTime StatusDate { get; set; }

}

Few things to note about the above code:

1. HttpUtility.HtmlDecode is being used in order to get a readable text. The response contained text like “Testing &quot;posts&quot; #devacademy3” and this method (in System.Web) converts it to “Testing posts #devacademy3”.

2. The ParseDateTime() method on the element’s value is an extension method I created in order to parse a DateTime from the special string representation of the time the status was posted:

Sat Nov 15 10:08:15 +0000 2008

This method looks like:

public static class StringExtensions

{

    public static DateTime ParseDateTime(this string date)

    {

        string dayOfWeek = date.Substring(0, 3).Trim();

        string month = date.Substring(4, 3).Trim();

        string dayInMonth = date.Substring(8, 2).Trim();

        string time = date.Substring(11, 9).Trim();

        string offset = date.Substring(20, 5).Trim();

        string year = date.Substring(25, 5).Trim();

        string dateTime = string.Format("{0}-{1}-{2} {3}", dayInMonth, month, year, time);

        DateTime ret = DateTime.Parse(dateTime);

        return ret;

    }

}

 

If you come up with another idea of how to parse this string into a DateTime object, please let me know.

Wrapping it up...

The final version of the GetUserTimeLine method looks like this:

public List<UserStatus> GetUserTimeLine(string user)

{

    string url = string.Format("http://twitter.com/statuses/user_timeline/{0}.xml", user);

    string response = Get(url);

 

    XDocument document = XDocument.Parse(response, LoadOptions.None);

 

    var query = from e in document.Root.Descendants("status")

                select new UserStatus

                {

                    UserName = e.Element("user").Element("name").Value,

                    ProfileImage = e.Element("user").Element("profile_image_url").Value,

                    Status = HttpUtility.HtmlDecode(e.Element("text").Value),

                    StatusDate = (e.Element("created_at").Value.ParseDateTime())

                };

 

    List<UserStatus> users = (from u in query

                              where u.Status != ""

                              orderby u.StatusDate descending

                              select u).ToList();

 

    return users;

}

The techniques I’ve used here can be used in almost all the “get” methods of the REST API of Twitter.

Enjoy!

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!

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: 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.

.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 DomainDataSource with Select Parameters

ASP.Net DomainDataSource with Select Parameters

ASP.Net DomainDataSource with Select Parameters

Continuing with .Net RIA Services with Silverlight and ASP.Net. In the last port I wrote about Using DomainDataSource in ASP.Net, and showed its basic usage. In this post I’ll show a more advanced scenario in which you want to use a domain service select method that takes parameters, and get the parameter value from a control on the form.

In the previous post, we had a GridView bound to a DomainDataSource that called a Select Method on the DomainService.

<asp:GridView runat="server" ID="GridView"

  AutoGenerateColumns="true"

  DataSourceID="customersDataSource">

</asp:GridView>

 

<asp:DomainDataSource runat="server" ID="customersDataSource"

  DomainServiceTypeName="Samples.Bank.Domain.BankDomainService"

  SelectMethod="GetCustomers">

</asp:DomainDataSource>

The output was:

ASP.Net DomainDataSource with Select Parameters

Now we want to filter the output list by the City property. To do that, we first have to add a method in our Domain Service that returns the data filtered by a city parameter.

public class BankDomainService : LinqToSqlDomainService<BankDataContext>

{

  public IQueryable<Customer> GetCustomers()

  {

    return this.Context.Customers;

  }

 

  public IQueryable<Customer> GetCustomersByCity(string city)

  {

    if (city == null)

      return GetCustomers();

 

    return GetCustomers().Where(c => c.City == city);

  }

 

  ...

}

Notice that GetCustomersByCity method uses the GetCustomers method that returns an IQueryable<Customer> and filters the result by city.

To select which city we want to filter by, lets add a ListBox with some items:

<asp:ListBox ID="lstCities" AutoPostBack="true" runat="server">

  <asp:ListItem>Tel Aviv</asp:ListItem>

  <asp:ListItem>Raanana</asp:ListItem>

  <asp:ListItem>Ramat Gan</asp:ListItem>

</asp:ListBox>

Note that I had to specify AutoPostBack=”true” in make any change to the filter, since this is a server control.

Now, in order to filter the data source according to the domain method with the select parameter I have to specify a SelectParameter that takes its value from the ListBox, and change the select method to execute.

<asp:DomainDataSource runat="server" ID="customersDataSource"
  DomainServiceTypeName="Samples.Bank.Domain.BankDomainService"

  SelectMethod="GetCustomersByCity">

  <SelectParameters>

    <asp:ControlParameter Name="city" ControlID="lstCities"
         PropertyName="SelectedValue"  Type="String" />

  </SelectParameters>

</asp:DomainDataSource>

Now, If we run the application, we can select items in the ListBox, and the items in the GridView will be filtered by the city value.

ASP.Net DomainDataSource with Select Parameters

Enjoy!

Using DomainDataSource in ASP.Net

Using DomainDataSource in ASP.Net

DomainDataSource ASP.Net

In ASP.Net 2.0 we were introduced to this concept of Data Source controls. We got the ObjectDataSource, XmlDataSource and SqlDataSource that let us bind a GridView or a ListBox to some data without having to write any additional code. In .Net Framework 3.5 we got LinqDataSource and with .Net Framework 3.5 – the EntityDataSource. In the future of ASP.Net, among other significant improvements around data access, we get a new way of accessing our data – DomainDataSource.

The benefits of using the DomainDataSource is that is give us nice separation from the way our Data Model is represented (LINQ to SQL vs EF, POCO and Cloud) and gives us more control over how the data is being retrieved and manipulated.

In this post I’ll introduce the DomainDataSource that is already available as part of .Net RIA Service, and give a quick walkthrough on how to use it in an ASP.Net Web Forms application.

Creating a Data Model and a Domain Service

DomainDataSource ASP.NetCreate a new ASP.Net Web Application in Visual Studio 2008.

Add a Data Model to your application, whether it is a LINQ to SQL data model, an Entity Framework Data Model, or any other data model. In this sample I am using the Bank Schema with LINQ to SQL.

Make sure to build the project so that Visual Studio will generate the data classes and data context before the next step.

Add a new Domain Service. Add a new Item to the server project, and select the Domain Service template in the Web category.

DomainDataSource ASP.Net

After you add this item, the New Domain Service Class Dialog is shown. Select the Data Context (BankDataContext in this sample), select the entities you want to expose and whether you want to allow editing and click OK.

DomainDataSource ASP.Net

This adds the BankDomainService.cs that contains the code that exposes the data to the client, and BankDomainService.metadata.cs that contains additional metadata, mostly for presentation and validation.

This is how the DomainService looks like when working with LINQ to SQL. If you were working with the Entity Framework, the base class would be different. It simply contains CRUD methods for working with the data context.

public class BankDomainService : LinqToSqlDomainService<BankDataContext>

{

  public IQueryable<Customer> GetCustomers()

  {

    return this.Context.Customers;

  }

 

  public void InsertCustomer(Customer customer)

  {

    this.Context.Customers.InsertOnSubmit(customer);

  }

 

  public void UpdateCustomer(Customer currentCustomer, Customer originalCustomer)

  {

    this.Context.Customers.Attach(currentCustomer, originalCustomer);

  }

 

  public void DeleteCustomer(Customer customer)

  {

    this.Context.Customers.Attach(customer, customer);

    this.Context.Customers.DeleteOnSubmit(customer);

  }

}

It also adds some new references to System.ComponentModel.DataAnnotations, System.Web.DomainServices, System.Web.DomainServices.Providers and System.Web.Ria.

In addition to that, a new Http Handler was added to the web.config file.

<httpHandlers>

  ...

  <add path="DataService.axd"

      verb="GET,POST"

      type="System.Web.Ria.DataServiceFactory, System.Web.Ria,
            Version=2.0.0.0, Culture=neutral,PublicKeyToken=31BF3856AD364E35
"

      validate="false" />

</httpHandlers>

Use the DomainDataSource with ASP.Net

In a page of your choice, add a GridView control or any control that can bind to a DataSourceControl.

<asp:GridView runat="server" ID="GridView">

</asp:GridView>

Add a reference to System.Web.DomainServices.WebControls.dll, and in your page, register the prefix for this namespace:

<%@ Register TagPrefix="asp" Namespace="System.Web.DomainServices.WebControls" Assembly="System.Web.DomainServices.WebControls" %>

Add a DomainDataSource and bind it to the Grid. Notice the in the DomainDataSource declaration I referenced the type of the DomainService with its full namespace, and added which method in it should be used to retrieve data.

<asp:GridView runat="server" ID="GridView"

  AutoGenerateColumns="true"

  DataSourceID="customersDataSource">

</asp:GridView>

 

<asp:DomainDataSource runat="server" ID="customersDataSource"

  DomainServiceTypeName="Samples.Bank.Domain.BankDomainService"

  SelectMethod="GetCustomers">

</asp:DomainDataSource>

If you now run the application, you’ll see the grid populated with the results.

ASP. Net DomainDataSource

With DomainDataSource you get more control on how your data is retrieved and manipulated. You can add your logic to the select method, for example – providing a filter by the authenticated user, and add logic in the update methods, such as adding default values before updating the database.

Enjoy!

More Posts Next page »
Page view tracker