Blog - Microsoft .NET, ASP.NET, AJAX and more

ObjectDataSource, SOA Style

by Dave Marini 8/18/2008 11:43:59 PM

It's been entirely too long since my last post, and with the olympics in full swing, we'll go with a volleyball theme for this post.


BUMP

So here's the scenario. After really digging your teeth into ASP.NET 2.0 and playing around wiih all the cool data access features, you decide to apply a liberal use of the ObjectDataSource for its ability to take care of the paging and sorting calls for you. Now, you begin to convert your site to a service oriented back end and you wonder how you're going to make calls against your web service. You have a few options in front of you. You can create a thin facade layer that will act as a liaison between your presentation code and your service layer calls, and hook your ObjectDataSource to that. This works especially well when you have a complex object model that makes use of the web service calls behind the scenes. It's also beneficial when you are generating your proxy classes from metadata or contacting a foreign web service. In the scenario I'm going to demonstrate here, I'm referencing a shared contract and service library, so I'll be using using the ObjectDataSource to make direct calls to ChannelFactory<T> for this example.

SET

The main ingredients for this technique include a dash of class inheritance, a heaping spoonful of refluxion (as one of my friends says it), and some method overriding, to taste.  The main issue here is that since WCF contracts are interfaces, how can we declare them in the ObjectDataSource being that you can't instantiate an interface. Well, let's show some code, starting off with a very basic service contract and implementation:

[ServiceContract]
public interface IContract
{
    [OperationContract]
    string SayHello(string name);
}

public class ContractService : IContract
{
    public string SayHello(string name)
    {
        return "Hello " + name + "!";
    }
}

So I need some way of creating an instance of ChannelFactory<IContract> in my ObjectDataSource in order to call the SayHello method. To do this, we use extend the ObjectDataSource and register our extended class to handle the ObjectCreating event of the ObjectDataSource. This event gives us the ability to set the instance of the object that we want to call our method on. The following code shows how we will set the stage for our reflection extravaganza:

public class WebServiceObjectDataSource : ObjectDataSource
{
    public WebServiceObjectDataSource()
        : base()
    {
        ObjectCreating += new 
ObjectDataSourceObjectEventHandler(WebServiceObjectDataSource_ObjectCreating); } protected virtual void WebServiceObjectDataSource_ObjectCreating
(object sender, ObjectDataSourceEventArgs e) { } }

For our example, we're going to assume that the user is going to specify the name of the service contract in the existing "TypeName" property of the control. Using this, we're going to generate our proxy. Here's the code that creates the actual object:

protected virtual void WebServiceObjectDataSource_ObjectCreating
(object sender, ObjectDataSourceEventArgs e) { string contractTypeName = String.IsNullOrEmpty(EndpointContractTypeName) ? TypeName : EndpointContractTypeName; Type serviceContractType = BuildManager.GetType(contractTypeName, true); Type channelFactoryType = typeof(ChannelFactory<>)
.MakeGenericType(new[] { serviceContractType }); var factory = Activator.CreateInstance(
channelFactoryType, new[] { EndpointConfigurationName }); e.ObjectInstance = factory.GetType().GetMethod("CreateChannel", Type.EmptyTypes)
.Invoke(factory, null); }

SPIKE

Analyzing the code above, you can see that we use a heavy dose of reflection and some generics to create an instance of ChannelFactory<T> and then call the "CreateChannel" method to get the instance of the proxy to call the SelectMethod.  You'll notice the first line chooses between the typename property and a custom made property on the control called EndpointContactTypeName. I'll explain this in the next section. Needless to say, the heart of the work is done by the CreateInstance and Invoke methods that are called to create the ChannelFactory and Contract proxy instance.  My example here is pretty basic and doesn't talk about things like connecting to a service proxy using client credentials or one of the other overloads of the ChannelFactory constructor. Just know that these scenarios are all possible by adding additional properties and creative use of reflection to determine the proper constructors and/or methods to call on the classes to get just the proxy type you need.

WATCH OUT FOR THE NET!

One little gotcha in this whole thing. There are cases when you have a master contract, which is an interface that inherits from another interface. Sometimes I do this to consolidate the number of services I expose so that I don't have a configuration that's a mile long with 100+ service contracts that each contain one method. consider this contract scenario:

[ServiceContract]
 public interface IMainContract : IContract
 {
 }

 [ServiceContract]
 public interface IContract
 {
     [OperationContract]
     string SayHello(string name);
 }

This is pretty simplistic but you can get the idea. So, in this case, I may expose IMainContract as a service. If I use IMainContract as the "TypeName" property in my extended ObjectDataSource class, it will throw an exception that it could not find the "SayHello" method that I specified as the SelectMethod in the interface. This has to do with how C# deals with interface inheritance. Needless to say that there are workarounds, but because of the way ObjectDataSource was coded, you cannot change the way that it checks for these methods. Also, because the configuration file exposes the service as the IMainContract class, if you specify a TypeName of IContract, then the select method will be found, but you'll get an error saying that the ChannelFactory could not find a service contract with the type IContract. Quite the Catch 22! The solution for this is to set the TypeName to IContract since our method is defined here. Also, I added a property called EndpointContractTypeName which can be set to IMainContract so that when the object is being created it will generate that type, and since IMainContract implements IContract it follows that once the instance is created, we can call any method that existed on IContract with no problems.

The full source for the version I'm using looks something like this:

    public class WebServiceObjectDataSource : ObjectDataSource
    {
        public string EndpointConfigurationName { get; set; }

        public string EndpointContractTypeName { get; set; }

        public WebServiceObjectDataSource()
            : base()
        {
            ObjectCreating += new ObjectDataSourceObjectEventHandler(
WebServiceObjectDataSource_ObjectCreating); } protected virtual void WebServiceObjectDataSource_ObjectCreating
(object sender, ObjectDataSourceEventArgs e) { string contractTypeName = String.IsNullOrEmpty(EndpointContractTypeName) ? TypeName : EndpointContractTypeName; Type serviceContractType = BuildManager.GetType(contractTypeName, true); Type channelFactoryType = typeof(ChannelFactory<>)
.MakeGenericType(new[] { serviceContractType }); var factory = Activator.CreateInstance(
channelFactoryType, new[] { EndpointConfigurationName }); e.ObjectInstance = factory.GetType().GetMethod("CreateChannel", Type.EmptyTypes)
.Invoke(factory, null); } }
 
Technorati Tags: ,,,

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: .NET | ASP.NET | C# | Reflection | WCF | Web Services | Website
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Dynamic AJAX Control Toolkit - ValidatorCallout Extender

by Damien White 7/24/2008 8:51:38 AM
Technorati Tags: ,

I added one of these a while ago and figured I would include another.  Dynamic AJAX Toolkit Controls seem to really be an issue for some, so I hope this helps.  This time, we will create a dynamic ValidatorCallout for a TextBox with a RequiredFieldValidator (although you can use any validation method).  One other thing to note on the ValidatorCallout is that  it only works with client-side validation.

TextBox nameTextbox = new TextBox();
nameTextbox.ID = "name";
nameTextbox.MaxLength = 100;

RequiredFieldValidator nameRequired = new RequiredFieldValidator();
nameRequired.ID = "nameRequired";
nameRequired.ControlToValidate = nameTextbox.ID;
nameRequired.ErrorMessage = "Name is required.";
nameRequired.Text = "*";

ValidatorCalloutExtender nameRequiredCallout = new ValidatorCalloutExtender();
nameRequiredCallout.ID = "nameRequiredCallout";
nameRequiredCallout.TargetControlID = nameRequired.ID;
 

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Dynamic Control ViewState Problems

by Damien White 7/23/2008 8:08:19 PM

Technorati Tags: ,

The ID Property is Important

I've encountered quite a few developers having ViewState problems with dynamic controls.  Ever have a control get recreated, but the value isn't there on PostBack and you are creating your controls at the correct time?  Frustrating to say the least.  Anyway, even if you follow the correct pattern for creating / recreating dynamic controls, you may either forget (D'oh) or don't set (Double D'oh) an ID for the control.  By not setting an ID, you are relying on ASP.NET to create the control with the same ID.  Sometimes it will, other times it won't... not a gamble you should take. 

Recently, I ran into a problem with this.  For some reason, I simply forgot to set the ID for one of my controls.  I had sporadic results and couldn't figure out why.  Sometimes one of the controls would have the value, and other times I came up completely empty.  It's amazing how blind one can be when reviewing their own code :).  Anyway, setting an ID made all my issues go away, and I felt pretty stupid.

Enabled and ReadOnly Fun

One other thing to note on this topic that I encountered.  I was creating a standard ASP.NET TextBox dynamically, pretty easy.  My requirement was to restrict the user from changing the value.  Just to get the full picture of the problem, I was also using a Wizard control to allow previous and next actions.  I needed to maintain the ViewState for these dynamic controls since the user could go back and in the Finish Step I needed to read this value in order to save everything.  Anyway, back to the requirement.  Ok, the user shouldn't be able to edit the value, let's set it to Enabled = false.  Great, run it, no ViewState.  After a bit of research, you'll find that this isn't a .NET problem, it has to do with the client-side disabled property.  When a control is marked as "disabled", it isn't persisted when the form is posted, therefore, ASP.NET is not aware of it when the ViewState gets loaded.  So the next logical step was ReadOnly with a bit of style to make it "look" disabled.  However, if you look at the spec for ReadOnly, you will find an important note roughly half way down the page that states the server does no processing on a ReadOnly TextBox.  Since I'm creating the controls dynamically, this equates to no ViewState for me again.  What a pain.  In the end, the solution was to just add the client-side attribute readonly to the TextBox, like so...

TextBox1.Attributes.Add("readonly", "readonly");

And again, I added a simple CSS style to make it look disabled:

.disabled { background-color:#ddd; color:#666; }

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: .NET | ASP.NET | C# | CSS
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

AJAX Control Toolkit - DropDownExtender Always Visible

by Damien White 6/12/2008 3:44:22 PM

imageToday I came across a problem of making the DropDownExtender appear as if it is a standard drop down like it is when you hover over it (as shown in the image to the right).  Initially I was thinking you could do something with the Animation framework, but after a bit of research I found the way to do it.  This forum post (look for the accept answer by KristoferA), has the solution.  The source code below the full working solution.

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%
@ register assembly="AjaxControlToolkit" namespace="AjaxControlToolkit" tagprefix="cc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<
html xmlns="http://www.w3.org/1999/xhtml">
<
head runat="server">
    <
title>Always Visible Drop Down</title>
</
head>
<
body>
    <
form id="form1" runat="server">
    <
script language="javascript" type="text/javascript">
    function
DropDownExtender1_pageLoad()
    {
      $find('DropDownExtender1').unhover = doNothing;
      $find('DropDownExtender1')._dropWrapperHoverBehavior_onhover();
    }
    function doNothing() {}

    Sys.Application.add_load(DropDownExtender1_pageLoad);
   
    </script>
    <
div>
        <
asp:scriptmanager id="sm" runat="server" />
        <
asp:label id="Label1" text="Select a value" runat="server" width="200" />
        <
asp:panel id="DropPanel1" runat="server">
            <
asp:linkbutton id="Link1" runat="server" text="Item 1" /><br />
            <
asp:linkbutton id="Link2" runat="server" text="Item 2" /><br />
            <
asp:linkbutton id="Link3" runat="server" text="Item 3" /><br />
            <
asp:linkbutton id="Link4" runat="server" text="Item 4" />
        </
asp:panel>
       
        <
cc1:dropdownextender id="DropDownExtender1" TargetControlID="Label1"
           
DropDownControlID="DropPanel1" runat="server">
        </
cc1:dropdownextender>
    </
div>
    </
form>
</
body>
</
html>

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

AJAX Control Toolkit - Layout Problems

by Damien White 6/11/2008 9:55:07 PM

A real common problem with using the AJAX Control Toolkit revolves around the rendering of the controls.  Taking an example from the ASP.NET Forums, let's say you have a Tab Control on your page.  Everything looks ok, and then you run it.  You notice that there is a weird space towards the bottom of one of your tabs.  D'oh!  What could be wrong?  Well, in general, usually the cause of these types of problems are related to one of two issues, Quirks Mode or CSS conflicts.  In the ASP.NET Forum example above, it was a Quirks Mode issue.

  1. Quirks Mode - A complete definition as well as what causes Quirks Mode to occur can be found on Wikipedia.  A quick definition is that Quirks Mode is a type of rendering that the browser adheres to.  Typically, a browser supports Quirks Mode and Standards Mode rendering.  The main difference between the two have to do with the box model and how things are calculated.  For example, if you have a DIV with a width of 100px, and that DIV has a padding of 5px, is the DIV's width 100px or 110px?  Well that's the confusion.  In Standards Mode, it's 100px, in Quirks Mode, it's a narrower 90px because the padding takes up part of the width.  The thing you need to know is that the AJAX Control Toolkit assumes Standards Mode rendering, otherwise, things will be out of whack. 

    The Fix - Quirks Mode
    To fix this issue, it's as simple as verifying you are using a proper DOCTYPE (these can be found in the Wikipedia entry).  The other thing to note is whether you should include or exclude anything (such as an XML declaration) before the DOCTYPE, which is also described in the Wikipedia article.  For example, to designate a page as conforming to XHTML 1.1, you would have something along these lines (note I am using a Master page):

    <%@ Master enabletheming="true" Language="C#" AutoEventWireup="true" CodeBehind="MyMaster.master.cs" Inherits="MyMaster" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

  2. CSS - Another common problem occurs with CSS.  There are many times when a developer has a style that may conflict with that being set by the Toolkit Control.  An example of this could be something like having a style defined for all SPAN elements, and then realizing that the Tab Control doesn't look correctly.  It could really be just about any one of styles you can apply to elements.  Because of this,  this is a harder problem to catch and requires troubleshooting on your part.

    The Fix - CSS Issues
    The fix for this is just finding that pesky style that is causing you the issue.  Easier said than done.  However, there are some tools to make your job easier.  First, my favorite is an add-in called Firebug, but it only works in Firefox (although there is a "lite" version for IE).  You can inspect any element on the page, and get the CSS being applied, plus you can edit the style in real time!  It is a invaluable tool for debugging not just CSS, but also JavaScript, and it does so much more.  I would recommend it highly for every web developer. 

    On the Internet Explorer side, you can use the IE Developer Toolbar.  Like Firebug, you can inspect the styles for an element, but you can't manipulate or toggle them like you can with Firebug.

In my experience one of these have been the issue in just about every case I've come across.  I hope this helps in solving those ASP.NET AJAX Toolkit issues that you may come across in your applications.

Currently rated 3.0 by 2 people

  • Currently 3/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: AJAX | AJAX Control Toolkit | ASP.NET | CSS
Actions: E-mail | Permalink | Comments (1) | Comment RSSRSS comment feed

Wrox Blox - ASP.NET AJAX Control Development with Visual Studio 2008 and .NET 3.5 Framework

by Damien White 4/28/2008 11:28:17 PM
Technorati Tags: ,,

ASP.NET AJAX Control Development with Visual Studio 2008 and .NET 3.5 Framework Wrox BloxI'm happy to announce that my second Wrox Blox is done and available for purchase as of today!  As you may remember, back in January, my first Wrox Blox on the ASP.NET AJAX Control Toolkit was released.  Now, continuing with the ASP.NET AJAX theme, the new Wrox Blox deals with creating your own ASP.NET AJAX controls, from scratch.  As you may or may not know, control development is one of my favorite topics.  There are always times when you create something that you and others will useful in multiple applications, and these cases usually are good candidates for a server control.  This book takes the "Server Control" to the next level by enabling a rich client interface with ASP.NET AJAX.  If you are still working in VS 2005, don't let the title scare you away.  Even though the book focuses on VS 2008 and .NET 3.5, you'll still find the code and concepts apply within VS 2005 with .NET 2.0 and ASP.NET AJAX Extensions 1.0.  As for a quick overview, the book starts out with outlining the important changes specifically for AJAX developers in VS 2008 and .NET 3.5.  You will then venture in and create an ASP.NET Control from scratch, step-by-step.  You'll understand each step in the process explicitly as well as understand how everything in an ASP.NET AJAX Control fits together.  Once you complete the Wrox Blox, you will have a solid understanding of ASP.NET AJAX Controls and I'm sure you will come up with some great ideas for new controls.

The direct link to the book is: http://www.wrox.com/WileyCDA/WroxTitle/productCd-0470286652.html. If you link out to it, you can get a synopsis as well as the complete table of contents for the book on the Wrox site.

I'd like to thank the whole team at Wrox for doing such a great job.  I'd especially like to thank Jim Minatel for his understanding and patience.  Also, special thanks to the Wrox editors: Sara Shlaer, Doug Holland, and Debra Banninger.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Building A Better FindControl

by Dave Marini 4/3/2008 6:32:00 AM
Technorati Tags: ,


I've come across a lot of times when I wish I could just use the standard FindControl method on a Page or on a container control and have it be found without having to make sure that the control was a direct child of my current container.  Also, I wish I could find all controls of a particular type on a page.  Why couldn't the Control class be given these gems out of the box?  Well, thanks to extension methods, custom iterators and a dash of linq, I've built my own Control Finding mechanism that gives a broader search and adds some type safety to the mix.

FindControl 101

Let's look at our basic implementation. Finding controls is a recursive process by nature, but any recursive algorithm can be turned into an iterative (and thus more performant) one, so for our first pass, let's just implement the FindControl method as it is now but with a deeper searching algorithm:

    public static ControlAdvancedFindControl(Control container, string controlId)
    {
        Queue<Control> controlQueue = new Queue<Control>(new[] { container });
        Control currentControl;

        while(controlQueue.Count > 0)
        {
            currentControl = controlQueue.Dequeue();

            foreach (Control child incurrentControl.Controls) { controlQueue.Enqueue(child); }

            if(currentControl.ID == controlId)
                return currentControl;
        }

        return null;
    }

In the most basic sense, that's all we have to do. We can now add this to a helpers class and call it statically.  But there's so much more that can be done...

Pour Some Syntactic Sugar On Me

wouldn't it be nice if I could call my new method from ANY control as if Microsoft had actually thought I might want this much better working version of its FindControl method when they were building the Control class?  well, extension methods allow me to fake it. This will require that I make a static container class for my new method and change the method signature a bit.. let's take a look at our improved version:

public static class Extensions
{
    public static Control AdvancedFindControl(this Control container, string controlId)
    {
        Queue<Control> controlQueue = new Queue<Control>(new[] { container });
        Control currentControl;

        while (controlQueue.Count > 0)
        {
            currentControl = controlQueue.Dequeue();

            foreach (Control child in currentControl.Controls) { controlQueue.Enqueue(child); }

            if (currentControl.ID == controlId)

                return currentControl;
        }

        return null;
    }
}

Not much of a difference in code, but a huge difference in how I can use it. Now, instead of having to invoke our find this way:

Control found = UtilityFunctions.AdvancedFindControl(Page, "TextBox1");

We can now invoke it like this:

Control found = Page.AdvancedFindControl("TextBox1");

The key is the word this in the signature of our method. It tells the compiler that any object that inherits from Control will be able to invoke this method as if it was a part of the class. Of course it isn't really adding the new method to the class, but it makes it MUCH easier to get to our methods.  I'm still not satisfied, because I'm looking for a textbox and I'm getting back a control that might be a textbox (or might not). I'd like not to have to cast the control when it comes back.

Generically Speaking...

We can now change our AdvancedFindControl to return any control we want by using generics... the new version is below:

public static class Extensions
{
    public static TControl AdvancedFindControl<TControl>(this Control container, string controlId) where TControl : Control
   
{
        Queue<Control> controlQueue = new Queue<Control>(new[] { container });
        Control currentControl;

        while (controlQueue.Count > 0)
        {
            currentControl = controlQueue.Dequeue();

            foreach (Control child in currentControl.Controls) { controlQueue.Enqueue(child); }

            if (currentControl is TControl && currentControl.ID == controlId)

                return (TControl)currentControl;
        }

        return null;
    }
}

Now, let's say I want that textbox named "TextBox1". I can call it this way:

var result = Page.AdvancedFindControl<TextBox>("TextBox1");

Response.Write(result.Text);

Have It Your Way

Ok, now for the grand finale. It's nice to be able to find a typed control by ID, but sometimes you want to find a control by more than one criteria. And, for that matter, what if I want to find all the controls that match a particular set of criteria.  We can easily modify our function to do this with custom iterators and a bit of linq to make it fancy.  Our final set of functions is below:

public static class Extensions
{
     public static TControl AdvancedFindControl<TControl>(this Control container, Predicate<TControl> criteria) where TControl : Control
    
{
           return DoTheWork<TControl>(container, criteria).FirstOrDefault();
     }

     public static IEnumerable<TControl> AdvancedFindControls<TControl>(this Control container, Predicate<TControl> criteria) where TControl : Control
    
{
           return DoTheWork<TControl>(container, criteria);
     }

     private static IEnumerable<TControl> DoTheWork<TControl>(Control container, Predicate<TControl> criteria) where TControl : Control
    
{
          Queue<Control> controlQueue = new Queue<Control>(new[] { container });
          Control currentControl;

          while (controlQueue.Count > 0)
          {
               currentControl = controlQueue.Dequeue();

               foreach(Control child in currentControl.Controls) { controlQueue.Enqueue(child); }

               if(currentControl is TControl && criteria((TControl)currentControl))
                    yield return (TControl)currentControl;
          }
     }
}

This final set of functions moves all the heavy lifting into a private method called DoTheWork, which now returns an IEnumerable of our searched control type. This is enabled by replacing our old return with yield return, a .NET 2.0 feature.  Our original static extension method calls this private method and I renamed it AdvancedFindControls so that it's clear it returns more than one. I also created another extension method called AdvancedFindControl which also makes use of the private method and then uses some linq filtering (in this case the FirstOrDefault() extension method) to give us only the first. You could easily write additional methods to give you the last, middle or even every other result of your search with similar functions available on the IEnumerable<T> type. So, using these new functions, how can I search for all of the textboxes on my page?  Simple!

//get all textboxes on my Page
var allTextBoxes = Page.AdvancedFindControls<TextBox>(control => true);

//get all my textboxes for which the user entered some text and the mode is MultiLine
var filledTextAreas = Page.AdvancedFindControls<TextBox>(control =>
             !String.IsNullOrEmpty(control.Text) &&
             control.TextMode ==  TextBoxMode.MultiLine);

So as you can plainly see the features of extension methods, custom iterators and linq can be combined to give us a significantly better way to search through controls. 

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags: , , ,
Categories: .NET | ASP.NET | C# | LINQ
Actions: E-mail | Permalink | Comments (2) | Comment RSSRSS comment feed

Great TV - Download: The True Story of the Internet

by Damien White 4/2/2008 11:32:22 AM

Technorati Tags: ,

I just wanted to drop a quick note to let everybody know about a great show I caught two episodes of on the Science Channel.  It is called "Download: The True Story of the Internet".  I watched the episode "Bubble", which discusses the .COM bubble, it also focuses on Amazon.com and EBay.com, as they are two companies that made it through the .COM bust and changed the way we do business.  I also caught the episode titled "People Power".  This episode talks about how there is a new breed of sites out there that empower the user.  This ranges from Napster to MySpace, YouTube, Facebook, etc.  There are two other episodes listed in the Science Channel's schedule for the show that I'm looking forward to, "Browser Wars" and "Search".  Last I checked, you can catch all four episodes on April 5th and 6th.  I highly recommend checking them out. 

It should be noted that sadly, as of this writing, Discovery/Science Channel doesn't have "Download" available for download on the Internet.

Currently rated 4.3 by 3 people

  • Currently 4.333333/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: Television
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

ASP.NET AJAX Control Development and the Chatty onMouseOut Event

by Damien White 3/24/2008 8:40:00 AM
Technorati Tags: ,,,

If you have been working on developing ASP.NET AJAX web controls, there is a good chance that you may have encountered some issues with the onMouseOut event.  The issue comes about when you are developing a container-type control (e.g. a Panel or DIV) and you wish to capture the mouse out event on the parent container.  A container control contains children, and what ends up happening is when you move your mouse around the control, you'll find that onMouseOut fires for the parent even though the mouse hasn't left the container.  The problem is due to event bubbling.  This probably isn't anything too new for you if you have done a lot of JavaScript and there are solutions on the Internet that discuss this issue.  However, in an ASP.NET AJAX Control, the process is similar to the straight JavaScript equivalent, but there are some changes to be aware of.

The solution involves performing a test on the element that the mouse is now on.  The element can be retrieved using the relatedTarget in FireFox or toElement in Internet Explorer.  Once we have the element, we will make sure that it isn't the element itself or a child of the element.  Remember, we only want to fire the onMouseOut event when the mouse has fully left the parent.  The setup here is that you have an ASP.NET AJAX Control that has a method named _onMouseOut where you have already created the handler and such for it.  If you aren't familiar with this, I would recommend checking out the ASP.NET AJAX Documentation under the ASP.NET AJAX Extensibility section, specifically, a good example is this one, which illustrates using the IScriptControl.

The Solution

_onMouseOut : function(e) {
    /// <summary>
    /// Handler for the Control's mouseout event
    /// </summary>
    /// <param name="e" type="Sys.UI.DomEvent">
    /// Event info
    /// </param>    
    
    // Access the raw event since we need the relatedTarget/toElement
    var ev = e.rawEvent;    
    
    // Access the DomElement; this is the parent we will be testing
    var parent = this.get_element();
    
    // Access the element the mouse is now over
    // relatedTarget = FireFox; toElement = IE
    var rel = (ev.relatedTarget) ? ev.relatedTarget : ev.toElement;
    
    // Ensure the mouse isn't still over the control
    // And make sure the mouse isn't over a child of the control
    if (parent != rel && !this._isChild(parent, rel)) {
        // TODO: Handle OnMouseOut        
    }
},
// Helper Methods 
_isChild : function(parent, child) {
    /// <summary>
    /// Helper method to determine if an element is a child of a parent DomElement
    /// </summary>
    /// <param name="parent" type="Sys.UI.DomElement">
    /// The parent element
    /// </param>          
    /// <param name="child" type="Sys.UI.DomElement">
    /// The element to check if it is a child of the parent
    /// </param>  
    
    // Make sure that the child node isn't null
    if (child != null) {
        
        // While the child still has a parent node
        while(child.parentNode) {
            // Move up the chain of parents
            child = child.parentNode;
            
            // Test if the test parent element is in the chain
            if(child == parent)
                return true;
        }
    }
    // Element isn't a child of the parent
    return false;
} 

I have added inline comments to make the code self-explanatory, I feel it is pretty straightforward to understand.  In addition to the _onMouseOut method, you can see I also added a helper method to test if an element is a child of a parent element.  You can trim these down into a single function if you'd like.  The one thing that you may find confusing is accessing the rawEvent.  Note that the event argument passed in an ASP.NET AJAX Control is of the type  Sys.UI.DomEvent, not the native DOM event, so hence the rawEvent property, which exposes this.  The DomEvent contains this property even though it isn't listed in the ASP.NET AJAX Documentation as of this writing.

I came up with this technique after doing some research on the Internet and came across this post on the CodeHead forums as well as this one on QuirksMode.org.  Using these ideas, I tweaked them to get them to work within the context of an ASP.NET AJAX Control.  

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Metadata Exchange Using SvcUtil: A Cautionary Tale

by Dave Marini 3/21/2008 7:42:00 AM


One of the projects that I've been working on the past week is a conversion project that involves a web site that has a tightly coupled business logic layer. The goal of the project is to re-engineer the site so that the business logic and corresponding data access tiers are decoupled and distributed as services. For us the obvious choice for this is using the new Windows Communication Foundation framework to accomplish the task. After some heavy reading and a lot of trial and error, we're very close to having this done and I'm proud of the outcome given the short span of the project (~ 5 weeks). We probably could have finished in 4 weeks if it weren't for a seemingly innocuous problem with proxy generation that ended up costing me 3 day's time to solve.  If you're using a tcp based Metadata Exchange binding and having trouble generating a service proxy with SvcUtil, read on!

The Error Rears It's Ugly Head

This is the error that I was getting when trying to have SvcUtil generate my proxy class for a particular service of mine:

WS-Metadata Exchange Error   URI: net.tcp://localhost:8888/MyServices/MyBigFatGreekService

Metadata contains a reference that cannot be resolved: 'net.tcp://localhost:8888/MyServices/MyBigFatGreekService'.

The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:04:59.9843748'.

An existing connection was forcibly closed by the remote host

Oh how silly of me! As you can see, SvcUtil was built to tell you exactly what's going on, NOT!! this error is terribly vague because it leads you to believe that you have a network issue going on, which hey, you might. But in my case, I had 15 services hosted on the SAME address and I was able to generate 14/15 with no problem. Now, let's take a look at what kind of problems cause this error to appear:

Common Beginner Mistakes

I'm going to take a small digression here to talk about some common mistakes that take 30 seconds to fix that could cause this error to occur.  Most people who get errors from SvcUtil are missing something in the configuration of their services that is causing the problem.  The biggest two culprits I've seen:

1.) Make sure you enable Metadata Exchange. you need to do this explicitly for each service and it's commonly missed. This is done with a Service Behavior Configuration Section, like below. The key piece here is the serviceMetadata element:

<behaviors>
     <serviceBehaviors>
          <behavior name="MetaDataBehavior">
            <serviceMetadata />
          </behavior>
     </serviceBehaviors>
</behaviors>

If you're using a Tcp based binding, just making sure it's there as above enables the exchange. For using an Http based binding, specify either HttpGetEnabled or HttpsGetEnabled, as in the below example:

<serviceMetadata httpGetEnabled="true" />

2.) Make sure that the security settings on your binding match what you want to achieve.  If the discovery of your metadata is to be public, explicitly set your security to "None" so that you are sure not to encounter authentication issues. If not, make sure you configure the security correctly. In my example, we're not securing the metadata endpoint.

<services>
   <service name="Service.MyService" behaviorConfiguration="MyServiceBehavior">
      <host>
        <baseAddresses>
           <add baseAddress = "net.tcp://localhost:8888/MyService" />
        </baseAddresses>
      </host>
      <endpoint address="" binding="netTcpBinding" contract="Service.IMyService" 
           bindingConfiguration="myNetTcp" />
      <endpoint address="mex" binding="netTcpBinding" contract="IMetadataExchange" 
           bindingConfiguration="mexTcp" />
   </service>
</services>
<bindings>
  <netTcpBinding>
     <binding name="myNetTcp" portSharingEnabled="true">
     </binding>
     <binding name="mexTcp" portSharingEnabled="true">
         <security mode="None" />
     </binding>
     </netTcpBinding>
</bindings>

In this case I'm using port sharing because we want all of our services to share the same Tcp port regardless of how many we have in the future. If you have port sharing enabled for one service, do yourself a favor and keep it consistent. For more detailed information about port sharing, read this blog post by Nicholas Allen to get a true understanding of why you need this.

Sleuthing About

None of my other services were having proxy generation problems, so I knew that I had the services set up correctly. I even double checked to make sure I didn't have any syntax errors on that one service that could cause me problems. After this, I began seeing some strange things. Turns out, switching to an Http based binding like mexHttpBinding fixed the problem. But I didn't want http, I wanted Tcp, so I pressed on. What could be the difference between the two bindings that could cause such a problem?

It turns out that the service I had trouble with was the largest of all the services I was trying to generate (~ 30 methods). I found that by commenting out a few of the methods in the service contract, the Tcp Metadata exchange WORKED! It also didn't matter which methods were commented, which ruled out problems like an incorrectly serialized type or a duplicate operation name.  Now, in Juval Lowy's book on WCF, he states that service contracts should have no more than 5 - 7 methods if they are properly factored and this makes sense,  but I didn't have time to factor this class straight away due to time constraints.  For now, the class has to stay big. There was no documentation stating that service contracts had a maximum size restriction, so again, WHY THIS ERROR?

I thought that maybe I needed to up the default throttling controls on the metadata exchange binding for the services, so I increased the maxReceivedMessageSize and all of the limits in the readerQuotas element, but received the same error. It should be noted here that the mexTcpBinding is a very specific type of netTcpBinding that doesn't allow you to tweak these settings. So, just use netTcpBinding, there's no rule against it.

Send In The Marines!

Hey everyone, SvcUtil has a limit on how much metadata it can receive! Did you know that?  If you did, congratulations, because this is not well documented at all! Especially disconcerting is the apparent inconsistency with which this limit is imposed, which was the reason that my mexHttpBinding worked without a hitch. How do we tell SvcUtil to eat more fiber?  It turns out I was on the right track with increasing the throttling controls on the binding, but not in the right place. It turns out that I needed to create an app.config for SvcUtil itself, place it in the directory with SvcUtil.exe and THEN run it. Here's the config that finally made it work:

<configuration>
  <system.serviceModel>
     <client>
        <endpoint name="net.tcp" binding="netTcpBinding" bindingConfiguration="myTcp"
          contract="IMetadataExchange" />
     </client>
     <bindings>
        <netTcpBinding>
            <binding name="myTcp" maxBufferPoolSize="60000000" maxBufferSize="60000000" 
                 maxReceivedMessageSize="60000000" >
              <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
                 maxArrayLength="2147483647" maxBytesPerRead="2147483647" 
                 maxNameTableCharCount="2147483647" />
            </binding>
        </netTcpBinding>
     </bindings>
  </system.serviceModel>
</configuration>

So there it is. Make sure that the binding configuration that you use in the svcutil app.config matches the one you're using in the configuration file for your service host. If you don't, you will be getting a different error when you run SvcUtil, explaining that you have mismatched service settings and therefore the action is invalid.

Roll Credits

I can't say I figured this problem out on my own. In fact, when I was so frustrated that I ripped all my hair out, I finally posted the MSDN Forums to see if ANYONE had the same problem as me. Thanks to the moderators there, I was pointed in the right direction which solved my problem. You can see my post here.

In my next post, I'll be discussing why Visual Studio's Service Reference Proxy Generation Tool isn't adequate for those who are producing and consuming their own services and want to share multiple collection data types between the service and client, and how to use SvcUtil to overcome that inadequacy.

Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5