PGCodeWorks"/
This Month
November 2008
Sun Mon Tue Wed Thu Fri Sat
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
Search
View Article  Moved my blog

So...I have bought my own domain and have decided to move my blog and email.

My new blog is at http://blog.petegoo.com

Thanks to Matt

View Article  T4 Editor update from Clarius coming soon

Just after I'd gone and mentioned that the T4 editor from Clarius Consulting doesn't give you intellisense, Victor Garcia Aprea announces that they're working on an update which does exactly that. Looks really nice too.

Pete

View Article  T4 Templating in C#3.0 / .Net 3.5 and its uses in DSL development

Cut to the chase

OK. So you just want to know how to do it? Modify your template directives to the following.

<#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" language="C#v3.5" #>

What?..Why?

Recently I have been doing a lot of work in Microsoft's Domain Specific Language Tools for Visual Studio. In fact for the past 8 months this has pretty much been my main focus. I've learned a lot of things on the way and it occurred to me that the development of T4 templates used in DSL tools would be made a lot easier with the use of extension methods. To understand why, you need to understand the concepts behind DSL tools and the development process involved in creating a model to define your problem domain and templating to create the desired output.

One of the problems that becomes apparent in the latter stages of developing a DSL tools implementation is that templating can become quite messy. In DSL tools you create a model of the API which will allow you to interact with the visual elements and this generates code containing the classes you defined in the pattern necessary for these visual elements to be able to use them. After you are happy with the model you move on to generating your output. Typically this takes the form of T4 templates which will generate C# classes.

T4 templating, despite the fact that the engine is now built into Visual Studio 2008, does not get any designer support. It is an ASP-like syntax which compiles at template-transform-time into C# class files used to generate the output into files in your solution. Even using editors like Clarius Consulting's T4 Editor does not give you the intellisense you are used to in ordinary C# (well not yet anyway....see here). What tends to happen is that developers make extensions to the model API classes generated by the DSL tools using partial classes to support common scenarios in templating (don't even go down the path of static helper classes.....eek). This seems a good idea at first but after some time your API classes tend to suffer from explosion of methods and properties. These methods and properties are not helpful in defining your domain and do not make sense in Domain Driven Design concepts, they have no place in the ubiquitous language of the domain, they only make sense to the text transformation process employed in your T4 templates.

The solution can be to add common base templates which are included in your task specific templates using an ASP-like include directive. An issue with this is you typically create new class structures to encapsulate the functionality you want to perform. This has an obvious overhead in setup and maintenance, also the code in the include template is compiled into the same class as the task specific template which simply adds to the issues.

No wonder then that I was interested in the possibility of using Extension Methods to extend the DSL generated API with templating specific methods. After asking the question in the VSX forum I submitted a Microsoft Connect issue and got the answer of the above undocumented feature in a reply email. Basically this undocumented (AFAIK) feature allows you to add "v3.5" to the language definition in a template directive and it can be used, it seems like a bit of an after-thought but it does work.

One thing to note is that you can't specify extension method classes inside nested classes so it won't work in template include file, but you could externalise them to another assembly if required. So now you can add a class like the following to your code.

    1 namespace PGCodeWorks.Dsl.Test.TestDsl.TemplatingExtensions {

    2     public static class ExampleElementExtensions {

    3         public static string LowerCaseName(this ExampleElement element) {

    4             return element.Name.ToLower();

    5         }

    6     }

    7 }

And from your template code you can do the following.

   14     <#= element.LowerCaseName() #>

How nice is that? Should make templating a lot easier in VS2008.

Pete

View Article  WCF Exceptions and Fault Contracts

I ran across an issue recently trying to get a custom exception across a WCF boundary. The trouble is, WCF does not like to tell you what the problem was, and for good reason. I was thinking about exceptions the wrong way. In reality we do not want to pass exceptions across a WCF service boundary, instead we want to pass a Fault back to the caller.

An exception is a CLR concept, it does not make sense to expose this outside of the CLR, despite the fact that an exception contains potentially dangerous information (like the stack trace) which we do not want to expose. If your service does not handle an exception, it will fault. Hence a lot of the time we implement a try-catch handler and raise a FaultException which gets sent across the boundary.

 

 

[OperationContract]

[FaultContract(typeof(DivideByZeroException))]

public void MyServiceMethod() {

    try {

 

        // Do some actual stuff

    }

    catch(DivideByZeroException ex) {

        throw new FaultException<DivideByZeroException>(ex, new FaultReason("DivisionByZero"));

    }

}

Then on your proxy side you will typically recreate this exception and throw it.

This approach sometimes has problems when your exception has some extra data in it. Consider the following custom exception type:

 

public class MyDivideByZeroException : DivideByZeroException, ISerializable {

 

    protected MyDivideByZeroException(SerializationInfo info, StreamingContext context)

        : base(info, context) {

        numerator = (int)info.GetValue("numerator", typeof(int));

        denominator = (int)info.GetValue("denominator", typeof(int));

    }

 

    private int numerator;

    public int Numerator {

        get { return numerator; }

        set{ numerator = value;}

    }

 

    public int denominator;

    public int Denominator {

        get { return denominator; }

        set { denominator = value; }

    }

 

    public MyDivideByZeroException(int numerator, int denominator) : base() {

        this.numerator = numerator;

        this.denominator = denominator;

    }

 

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {

        info.AddValue("numerator", numerator, typeof(int));

        info.AddValue("denominator", denominator, typeof(int));

        base.GetObjectData(info, context);

    }

}

When you try this with the FaultException you may get an exception like the following:
The underlying secure session has faulted before the reliable session fully completed. The reliable session was faulted. The reliable messaging channel threw an exception because the reliable session was broken.

In this case you can create a Fault class. Your fault class is simply a Data Contract serializable type containing the information you require to create your exception on the other side. e.g.

 

[DataContract]

public class DivideByZeroFault {

 

    public DivideByZeroFault(MyDivideByZeroException exception) {

        this.numerator = exception.Numerator;

        this.denominator = exception.Denominator;

    }

 

    public MyDivideByZeroException GetException() {

        return new MyDivideByZeroException(numerator, denominator);

    }

 

    [DataMember]

    private int numerator;

    public int Numerator {

        get { return numerator; }

        set { numerator = value; }

    }

 

    [DataMember]

    public int denominator;

    public int Denominator {

        get { return denominator; }

        set { denominator = value; }

    }

}

 

Therefore your service code in the first example will change to be:

[OperationContract]

[FaultContract(typeof(DivideByZeroFault))]

public void MyServiceMethod() {

    try {

 

        // Do some actual stuff

    }

    catch(MyDivideByZeroException ex) {

        throw new FaultException<DivideByZeroFault>(new DivideByZeroFault(ex), new FaultReason("DivisionByZero"));

    }

}

 

This will allow WCF to send across the relevant information without compromising the applications security by sending a stack trace etc.

Pete

View Article  What is a comfortable office temperature?

Its 27 degrees Celsius today in our office and it feels like an oven. One of the guys has hooked up a digital multi-meter as a thermometer, you have to love geeks.

View Article  NHibernate - Custom User Types and Collections

NHibernate is an extremely powerful ORM but sometimes its quite difficult to find information on how to do certain things and why other things are the way they are. Recently I've been working on generating NHibernate mapping files and a domain model with its classes using Visual Studio DSL tools. Below are some of the difficulties I came across and their solutions.

Mapping Enums to string database representations

Sometimes you have a database schema which requires you to provide things like "M" for male and "F" for female. It does not make sense to force your users to use a string for the gender. We simply want an enum. On the other hand we cannot simply put an integer in the database as it then requires the domain to have any context and is not self-describing. What we really want is enums in our domain and single char fields in our db.

Obviously we need some custom mapping. This is where the IUserType interface from NHibernate comes into play. You can implement this type on a converter class and specify the converter type in the type attribute in your NHibernate mapping instead of the actual enum type.

More Info at the following links:
NHibernate Documentation - Custom value types
Jeremy D. Miller's blog - Mapping Enumerations with NHibernate - and hooray for open source unit tests

Generic Identifiers and Generators

Sometimes you have a mix of identifier types in your database schema, we may have guids, ints and even strings (eh? strings? what were you thinking?). You could implement a generic identifier type which hides these three types as you never really care about the content of the identifier, only that the ORM can use it to query etc. The problem is how do we tell NHibernate to convert this type and how do we allow a generator to build the e.g. guid before sending to the database?

First, your identifier type needs to implement a Identifier.Empty as default and allow it to always return default(T) as a non-instantiated version when you new-up an object in your domain. NHibernate will detect this equality and differentiate between new instances and instances which need to be updated instead of inserted.

Secondly, you need to implement an IUserType as above for each schema type. This will be the type specified in your HBM file and will convert between db type and your all-encompassing Identifier type.

Now we have a problem, the standard id generators in NHibernate no longer work as they want to generate the new id in the domain class before persisting, this will cause a type cast failure between the expected db type output from the generator and your custom identifier type. This time you need to create a custom identifier using a new class which implements NHibernate.Id.IPersistentIdentifierGenerator and NHibernate.Id.IConfigurable. This can detect the type of the real db schema and generate the correct type. You can also pass params to allow this to be configurable.

ISet<T> and IList<T> - sets, bags etc

NHibernate requires the usage of a set to allow the tracking of items added and removed on a collection. Unfortunately there is no concept of a set in the .Net Framework. The implementation of a set is provided in the Iesi.Collections dll which is shipped with NHibernate.

At runtime NHibernate tries to wrap the collection on a property which is defined in the HBM as a set with a collection which derives from Iesi.Collections.Generic.ISet<T> it can use to track changes in the collection. This allows NHibernate to only issue updates to changed members rather than deleting and recreating the entire collection. Normally the collection Iesi.Collections.Generic.HashedSet<T> is used in the domain class and this is then wrapped by NHibernate at runtime in a NHibernate.Collection.Generic.PersistentGenericSet<T> which allows the tracking of changes. This wrapping happens when a transient collection is saved or when a persisted collection is returned from the database.

This means that we cannot have purely CLR types in our domain model because we need to have an implementation of the ISet for transient and persisted collections. To protect the domain model in the possible future event of replacing NHibernate as a persistence strategy (and cos we don't want persistence creeping into our domain), new collection types have to be created. Create your own interface e.g. ISet<T>. This ISet<T> implements IList<T> and Iesi.Collections.Generic.ISet<T> allowing us to use standard IList<T> and ICollection<T> methods while keeping compatibility with NHibernate. The transient version of the set is called e.g. Set<T>, this also implements IUserCollectionType which defines the contract for NHibernate specific wrapping to persistent collection etc. The persisted version is called e.g. PersistentSet<T> and this inherits from NHibernate.Collection.Generic.PersistentGenericSet<T> to give NHibernate the change tracking it requires.

To use the new Sets in a domain, the following implementation is necessary.

  • The private fields and public properties for collections are defined as IList<T>. This allows standard interaction with the collection for domain consumption.
  • The actual implementation when the domain needs to instantiate a collection is of type MyNamespace.Set<T> to allow NHibernate to cast properly at runtime.
  • In the case of readonly collections, one of the two readonly collections is created from the constructor passing in the IList<T> as part of the get accessor of the property
  • In the HBM mapping file the collection-type attribute is added to the set declaration with the generic type name of the transient collection e.g. collection-type="MyNamespace.Set`1[[MyNamespace.MyDomain.MyDomainClass]]"

Once this is done you should be able to save and retrieve your collections without issues. Notice that when you save a transient collection, it is automatically cast to your persistent collection using the Wrap method of IUserCollectionType and this type is also used when retrieving from the db. Nice!

View Article  Concatenating Delimited Strings with Generic Delegates

I knew this must be possible through generic delegates and eventually found this really useful post by Phil Haack which describes using a generic delegate Join method to concatenate strings. Saves a lot of ugly code if you are using T4 or A-N-Other templating language to produce code from a  Dsl or schema.

View Article  Windows Live Writer

Finally the latest version of windows live writer seems to work with my blogging engine. Seems they have made some updates to allow blogware engine support for categories etc. Or maybe I just missed these on previous releases. Anyhoo, looks good.

View Article  Visual Studio 2008 RTM'd

....and commence downloading.

http://weblogs.asp.net/scottgu/archive/2007/11/19/visual-studio-2008-and-net-3-5-released.aspx

http://blogs.msdn.com/somasegar/archive/2007/11/19/visual-studio-2008-and-net-framework-3-5-shipped.aspx

 

View Article  TFS: Work Item Search

I've been using this plugin now for the past few months. You would not believe the difference it makes.

This plugin puts a little search box right into Visual Studio to make it easy to find work items.  It is an addin for Team Foundation Client (Team Explorer) and is accessible from the Team menu when you're connected to a Team Foundation Server and is also avalible from a VS Toolbar.  You just type in some search text and it runs a work item query for you showing you results across the work item store.



Source: Codeplex project "Search Work Items"

View Article  HeadMelter of the week - Self-Constrained Generic Base Classes

Melted my own brain for a few hours with this one today. Essentially a self-constrained generic base class looks like the following.

    public class MyEntity : EntityBase<MyEntity> {

    }

 

This allows me to put some generic implementations in a base class for code that I would simply duplicate otherwise. For example:

 

    public class EntityBase<T> : IEquatable<T>, IComparable<T>

    {

        public int CompareTo(T other) {

            // Insert compare code here

 

        }

 

        public bool Equals(T other) {

            // Insert Equality Code Here

        }

    }

 

Enjoy!

View Article  WCF: Custom Collections with Extra Payload

I came across a pretty annoying problem to solve in WCF today. Suppose you have a custom collection of items you wish to use in a WCF contract but it also has extra properties that you have added, for example change tracking.

    [Serializable]

    public class DtoCollection<T> : List<T>

    {

        private List<T> addedItems;

        private List<T> removedItems;

    }

 

It will serialize the collection fine but your added properties and fields will not appear. The [CollectionDataContract] attribute will not help you. If you look at this really great post from Sowmy Srinivasan's blog you can see the order of preference for WCF serialization markup. So in the case above you can implement IXmlSerializable to customize the serialization and deserialization of your custom collection. I originally found this solution on David Foderick's blog - OnMaterialize(), but the link seems to be down at the moment. I'll not repost the code here but google cache should still have it at this link.

View Article  Useful macro for creating Visual Studio 2005 dependent (nested) items
Check out this useful macro for visual studio 2005 dependent (nested) items. Useful for breaking up large classes into partials when refactoring doesn't make sense. I found it useful when you want, for example one integration test class per implementation class and the test class is getting a bit large.



Source: http://www.delarou.net/weblog/PermaLink,guid,a81a2d9d-02de-4fe1-ad8d-ee2fee97cf20.aspx

Visual Studio .NET Macro for nesting project items

This macro enables you to nest project items inside Visual Studio .NET. Until now, there is no easy way to nest project items through the Visual Studio IDE, you can only do it by manipulating the project (.csproj or .vbproj) file and adding the DependentUpon element.

Inside the IStaySharp.vsmacros file there is a macro called 'Create Dependency' which allows you to nest two selected items. I have even created a video (672,18 KB) to illustrate how to configure and use the macro.

View Article  Visual Studio Unit Test and the evil vsmdi

During a recent project we found a recurring problem where the test view of the unit (& integration) test projects would not load and we could not run tests. This was typically seen by the Test View load progress bar sitting at around 99%. This just adds to the list of "features" of VSTS Unit Test that make life oh so irritating

It is due to the corruption of the *.vsmdi files in the visual studio solution which is caused by auto-merging the content of the file or having the test view property window open when getting the latest version.

The problem is outlined in this blog post (also note the comments for possible workarounds)

Source: http://kjellsj.blogspot.com/2006/04/vsmdi-file-weak-spot-of-vsts-test.html

View Article  I am 70% Optimus Prime....oh yes

I AM
70%
OPTIMUS PRIME
Take the Transformers Quiz

Optimus Prime is the heroic leader of the Autobots. He is the personification of courage, strength, and integrity. His personal motto is that “Freedom is the right of all sentient beings.”

Like Optimus Prime, you are good by nature. But beware because mischievous thoughts sometimes tempt you. You are inspiring, confident, and a natural leader. The Autobots have chosen well. In addition, you enjoy being one step ahead of your friends as far as trends and technology.

Hmmmm.....Not sure I filled that one out right.

View Article  Visual Studio 2008 Beta 2 Released

First impressions are really good. The install went fine on a dual core laptop in parallel with VS 2005 already installed. The first thing I notice is that the performance is good (no worse than 2005) and the XAML designer is much improved over the cider CTPs.

Had a quick play with LINQ on a generic list and the intellisense support seems spot on.

Must sleep now.

View Article  WPF Routed Commands

Working in WPF, it's not very long before you come across Routed Commands. The idea of allowing events to bubble and tunnel up and down the UI tree has always been around but the ICommand, RoutedCommand and RoutedUICommand features of WPF have made it a lot easier.

Here are some useful resources for finding out more if you are stuck.

Jelle Druyts Article "The Command Pattern in Windows Presentation Foundation"
Adam Nathan's sample chapter on "Important New Concepts in WPF>Commands"

View Article  Re-Throwing Exceptions

I was going over some old code recently to try to resolve a production issue. The log of the stack trace was not providing enough information on the thrown exception and it reminded me of a good tip for throwing and specifically re-throwing exceptions.

Consider the following code:

 

try
{
  int x = 0;
  int y = 5 / x;
}
catch (Exception ex)
{
 
throw ex;
}

The stack trace at the time that the DivisionByZero is thrown will be different from the rethrow in the catch block. This is because the "throw ex" will create a new exception and throw it. Instead, you should try to use the code below.

try
{
 
int x = 0;
 
int y = x / 5;
}
catch (Exception ex)
{
 
throw;
}

In this case the original exception will be thrown with the correct stack trace. Of course wrapping the exception before it is thrown will also preserve the stack trace.

View Article  Creating a custom AJAX control - DateTimePicker

Lately I decided to see how easy was to create AJAX custom controls specifically using the included javascript libraries. I thought it might be useful to try to use the included javascript libraries to enable client side access to the selected value from a custom control.

The example I will use is a date time picker which uses the calendar extender from the ajax control toolkit for the date and a simple drop down for the time. Much like outlook, the date is pickable from a textbox and the time in a list of 15 minute intervals. The goal is to allow the client and server side code to have access to the same DateTime type without having to do any work parsing the strings in the HTML elements on the page.

Usage Pattern

The control on the client page looks like the following.

<pgc:DateTimePicker ID="dtpMyDate" runat="server" TimeInterval="15" Format="dd/MM/yyyy"/>

The client script needed to get the value from the control is as follows

function displayClientDate()
{
    alert( $find( "dtpMyDate" ).get_selectedDateTime().format("dddd dd MMMM yyyy HH:mm") );
}

....and that's it! The screenshot below shows the output.

The Implementation

To implement the custom control described above we have to implement the IScriptControl interface from the AJAX Extensions as well as the standard CompositeControl. This requires that we implement a few methods on our control above and beyond the standard control methods, these are the GetScriptReferences and the GetScriptDescriptors methods.

GetScriptReferences allows us to add in the client script files to the output sent to the user. This tells the ScriptManager on the page to send down our client script file.

protected virtual IEnumerable<ScriptReference> GetScriptReferences()
{
    ScriptReference ProtoReference = newScriptReference();
    ProtoReference.Path = Page.ClientScript.GetWebResourceUrl(this.GetType(), "PGCodeWorks.AjaxControls.DateTimePicker.DateTimePicker.js");
    return newScriptReference[] { ProtoReference };
}

GetScriptDescriptors allows us to tell the control which variables to pass through to the client script. These variables are set on the client when the page is sent down and allow us to use the same javascript object to represent multiple controls on one page with different instances and properties.

protectedvirtualIEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
    ScriptBehaviorDescriptor descriptor = newScriptBehaviorDescriptor("PGCodeWorks.DateTimePicker", this.ClientID);

    descriptor.AddProperty("textBoxClientID", this.txtDate.ClientID);
    descriptor.AddProperty("dropDownClientID", this.ddlTime.ClientID);
    descriptor.AddProperty("selectedDateTime", this._selectedDateTime);
    descriptor.AddProperty("dateFormat", this.ceCalExtender.Format);
    descriptor.AddProperty("timeFormat", this._timeFormat);
    descriptor.AddProperty("timeInterval", this._timeInterval);

    return newScriptDescriptor[] { descriptor };

}

Then, after implementing the rest of our control we need to add the client script .js file to the solution and mark it as an embedded resource. To make the file embed itself within the DLL select the file in solution explorer and change the "Build Action" in the properties window. Also you must add a reference to it in the AssemblyInfo.cs file.

The actual file follows the object-oriented javascript approach to allow properties etc on the prototype model. Below is the structure of the .js file (some code has been cut-out to save space).

// Register the namespace for the control

Type.registerNamespace('PGCodeWorks');

//

// Define the control properties

//

PGCodeWorks.DateTimePicker = function(element) {

    PGCodeWorks.DateTimePicker.initializeBase(this, [element]);

   

    // Set properties to null

    this._textBoxClientID = null;

    this._dropDownClientID = null;

    // *** Code Truncated ***

}

//

//

PGCodeWorks.DateTimePicker.prototype = {

    initialize : function() {

        PGCodeWorks.DateTimePicker.callBaseMethod(this, 'initialize');

        this._onDateTimeChangeHandler = Function.createDelegate(this, this._onDateTimeChange);

        this._onDateChangeHandler = Function.createDelegate(this, this._onDateChange);

        this._onTimeChangeHandler = Function.createDelegate(this, this._onTimeChange);

        $addHandler($get(this._textBoxClientID), 'change' , this._onDateChangeHandler );

                    

        $addHandler($get(this._dropDownClientID), 'change', this._onTimeChangeHandler);

       

   

    },

   

    dispose : function() {

        $removeHandler($get(this._textBoxClientID), 'change' , this._onDateChangeHandler );

        $removeHandler($get(this._dropDownClientID), 'change', this._onTimeChangeHandler);

        

        PGCodeWorks.DateTimePicker.callBaseMethod(this, 'dispose');

    },

   

    //

    // Custom Methods

    //

    setDateTimeValues : function() {

        // Get Values

        var strDate = $get(this._textBoxClientID).value;

        var strTime = $get(this._dropDownClientID).value;

        var strTimeFormat = this._timeFormat;

        if( strDate != null && strDate != "" )

        {

            if( strTime == null || strTime == "" )

            {

                strTime = "00:00";

                strTimeFormat = "HH:mm";

            }

            var totalDateTimeFormat = this._dateFormat + ' ' + strTimeFormat;

            var newDate = Date.parseInvariant(  strDate + ' ' + strTime, totalDateTimeFormat  );

            this.set_selectedDateTime( newDate );

            //alert( this._selectedDateTime );

        }

    },

   

    //

    // Event delegates

    //

    _onDateTimeChange : function(e) {

        this.setDateTimeValues();

    },

   

    _onDateChange : function(e) {

        this.setDateTimeValues();

    },

    _onTimeChange : function(e) {

        this.setDateTimeValues();

    },

    //

    // Control properties

    //

    get_textBoxClientID : function() {

        return this._textBoxClientID;

    },

    set_textBoxClientID : function(value) {

        if (this._textBoxClientID !== value) {

            this._textBoxClientID = value;

            this.raisePropertyChanged('textBoxClientID');

        }

    },


    // *** Code Truncated ***

   

    get_timeInterval : function() {

        return this._timeInterval;

    },

   

    set_timeInterval : function(value) {

        if(this._timeInterval != value) {

            this._timeInterval = value;

            this.raisePropertyChanged('timeInterval');

        }

    }

   

} // end of prototype declaration

// Optional descriptor for JSON serialization.

PGCodeWorks.DateTimePicker.descriptor = {

    properties: [   {name: 'textBoxClientID', type: String},

                    {name: 'dropDownClientID', type: String},

                    {name: 'selectedDateTime', type: Date},

                    {name: 'dateFormat', type: String},

                    {name: 'timeFormat', type: String},

                    {name: 'timeInterval', type: Number} ]

}

// Register the class as a type that inherits from Sys.UI.Control.

PGCodeWorks.DateTimePicker.registerClass('PGCodeWorks.DateTimePicker', Sys.UI.Control);

if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

The above code has allowed the client to be able to call the javascript object representing the overall control and retrieve it's selectedDateTime property.

How Does it Work?

The libraries provided with the ASP.Net AJAX Extensions allow us to create composite controls which we can deal with as a single object on the client using object-oriented javascript. Using the patterns and examples given on the AJAX web site we can recreate the types of functionality in the AjaxControlToolkit and start building rich client side experiences.

In this example we have simply provided a public method on our object which grabs the values from the controls on the page and uses the type extensions in AJAX to provide a similar experience in client side development as we experience on the server side. To extend this example I have created a RequiredFieldValidator and a CompareValidator which will work with the above control and I hope to post this when it has been cleaned up.

The full code and solution for this example is available here

View Article  Microsoft announces Silverlight

Microsoft have just announced Silverlight, the new branding for what was previously known as WPF/E. They've also provided a lot more details about the specifications and their future plans. 

Silverlight is the new Adobe (Macromedia) Flash competitor from Microsoft, it is based on the new Windows Presentation Foundation graphics engine found in Vista. It turns out that it will be very tightly integrated with .Net even to the point of shipping with its own cut down runtime.

The download should be around 2MB though initially it will not contain 3D capabilities. IE, Firefox and Safari will be supported at launch.

Silverlight website: http://www.microsoft.com/silverlight/