Categories

Archives

Struct-ured programming

In a previous blarticle, I showed how to send complex data types between client and server using WebORB for .NET. Building on that foundation, this blarticle will introduce a couple of new mysteries and their solutions, including

  • the communication of struct instances,
  • debugging from the management console, and
  • activation states.

Today’s problem is this: we need to write a Flex client that enables the user to edit a color stored on a .NET server-side “color database.”

Fortunately, both Flex and .NET agree that color data should be stored using the RGB (Red, Green, Blue) color model (as opposed to HSL or HSV or HSB or CMYK or CIE XYZ…and no, I’m not making this up; there really are a slew of possible color models).

Unfortunately, Flex and .NET disagree colorfully on just about everything else.

The .NET Framework defines Color as a struct, with a gazillion static read-only properties that correspond to pre-defined colors. Flex, on the other hand, defines no Color entity at all; by convention, packs the three least-significant bytes of a 32-bit unsigned integer (uint) to store color information.

Furthermore, .NET considers alpha channel (transparency) to be an inherent aspect of color, so it’s included in .NET’s ColorĀ struct. Flex, on the other hand, treats alpha as an independent entity…even though it could be packed into the most-significant byte of the 32-bit uint, which is otherwise sitting there empty and meaningless (he says, sniffing sadly at the thought of wasting an entire byte).

To communicate color data between client and server, we’ll first have to agree on a standard data format. Let’s try using .NET’s ColorĀ struct and see what happens.

On the server side, we’ll use C# to define SimpleColorService in a .NET class library project, as follows:

using System;
using System.Drawing;

namespace SimpleColorServer
{
    public class SimpleColorService
    {
        public Color MyColor { get; set; }

        public SimpleColorService()
        {
            MyColor = Color.FromKnownColor(KnownColor.Blue);
        }

        public Color GetSimpleColor()
        {
            return MyColor;
        }

        public void SetSimpleColor(Color toColor)
        {
            MyColor = toColor;
        }
    }
}

That’s pretty simple, alright. The service exposes its Color property, MyColor, through two services, GetSimpleColor() and SetSimpleColor().

To deploy these SimpleColorServer services, we’ll drag the SimpleColorServer.DLL out of its Visual Studio project’s Debug folder and drop it into WebORB for .NET’s \bin folder, as described in previous blarticles.

To check its deployment, we’ll fire up WebORB’s management console, click on its SERVICES tab, and click down the tree-structured menu on the left to find the SimpleColorServer and its services, as shown below:
As you can see, it’s got the services on the left, and the result of invoking GetSimpleColor() on the right. You can see that I wasn’t kidding when I said that .NET’s Color struct had a gazillion static properties.

Clearly, we can’t use .NET’s humungous Color struct as a data exchange format.

We *could* use WebORB’s custom serializers, but that would only help in the server-to-client direction. Or, we could flatten the Color to a uint, including the alpha channel in the high byte, and send that back and forth — but that has its own problems.

What we’re going to do is wrap .NET’s Color struct in a class, ARGB_Color. This class is really only client-server communication, so it won’t be terribly functional. Here’s the first cut at ARGB_Color:

using System;
using System.Drawing;

using System.Diagnostics;

namespace ColorServer
{
    public class ARGB_Color
    {
        Color color { get; set; }

        public ARGB_Color()
        {
            A = 255;        // opaque
            R = G = B = 0;  // black
        }

        public int A { get { return color.A; }
                       set { color = Color.FromArgb(value, R, G, B); } }
        public int R { get { return color.R; }
                       set { color = Color.FromArgb(A, value, G, B); } }
        public int G { get { return color.G; }
                       set { color = Color.FromArgb(A, R, value, B); } }
        public int B { get { return color.B; }
                       set { color = Color.FromArgb(A, R, G, value); } }
    }
}

Pretty bare-bones — just a private ‘color’ property of type Color to act as backing store (simulating our “color database”), and some pseudo-properties (A, R, G, & B) that access color’s properties. Note that color’s properties are read-ony, so if we want to set one of them, we have to create a whole new color with the new property, and assign that to the backing store.

Now, we can write a new service that exposes this ARGB_Color; because it’s not so simple anymore, we won’t call it SimpleColorServer, but will instead call it ColorServer, as follows:

using System;
using System.Drawing;

namespace ColorServer
{
    public class ColorService
    {
        public ARGB_Color ServedColor { get; set; }

        public ColorService()
        {
            ServedColor = new ARGB_Color();
        }

        // GetServedColor()
        public ARGB_Color GetServedColor()
        {
            return ServedColor;
        }

        // SetServedColor()
        public void SetServedColor(ARGB_Color toColor)
        {
            ServedColor = toColor;
        }
    }
}

This has the same general structure as SimpleColorServer, but now it gets/sets an ARGB_Color instead of a .NET Color struct.

As always, we’ll deploy it by dragging its DLL into WebORB’s \bin folder. (Remember to drag the ColorServer project’s DLL, not the SimpleColorServer project’s DLL.) Then, we’ll fire up WebORB’s management console, refresh it’s deployed assemblies, and walk the assembly tree on the left until we get to the service GetServedColor(), which we will invoke, at which point the console should look much like this:
Much more betterish! (slang for “much better!”) None of .NET color’s screwy static properties for pre-defined colors.

Now, let’s select SetServedColor(), change the R value to (say) 255, and press the invoke button, as shown below:
OK, that worked. Now, let’s re-invoke GetServedColor(), to get that new color value back. The result of the invocation is shown below:
Wait a minute! That’s not right! The A value should be 0, and the R value should be 255, but they’re not. Instead, they are…right back where they were before we invoked SetServedColor(). It’s as if the ColorServer object were unaffected by the SetServedColor() call.

Doh!

Of course, the ColorServer object *is* unaffected by the SetServedColor() call, because it’s a stateless server object, in which a new instance is created for each service invocation. Whatever changes I make to the service’s properties in one invocation are forgotten in the next. That’s the proper RESTful way to code, but in this case I’m using the ColorService’s ServedColor property act as if it were a server-side database record…so I need to have ColorService retain state across service calls.

Fortunately, WebORB makes this easy. I can simply decorate the ColorService class with a custom attribute, SessionActivation, and all will be well. SessionActivation is defined in Weborb.Activation, which I’ll add to my “using” list. The altered ColorServer.cs class file looks like this:

using System;
using System.Drawing;
using Weborb.Activation;

namespace ColorServer
{
    [SessionActivation] // client uses the same instance for session's lifespan
    public class ColorService
    {
        public ARGB_Color ServedColor { get; set; }

        public ColorService()
        {
            ServedColor = new ARGB_Color();
        }

        // GetServedColor()
        public ARGB_Color GetServedColor()
        {
            return ServedColor;
        }

        // SetServedColor()
        public void SetServedColor(ARGB_Color toColor)
        {
            ServedColor = toColor;
        }
    }
}

Notice that line 03 now reads “using Weborb.Activation;”, while line 07 declares the attribute [SessionActivation].

Build that, deploy it’s DLL to WebORB’s \bin directory, refresh the management console’s deployed assemblies list, enter some new values into SetServedColor()’s parameters, invoke it, then invoke GetServedColor()’s result — and they should now match. (Note SetServedColor()’s argument list and GetServedColor()’s results list do not list their contents in the same order — so be sure that you are comparing apples with apples, not apples with oranges.)

So far, we’ve seen two service activation options: the default “invocation” activation, and the “session” activation set by using the {SessionActivation] attribute. There’s a third option, “application,” set by decorating the service class with the [ApplicationActivation] attribute. Its effect is left as an exercise (or you can cheat by looking it up in the WebORB for .NET Developer Guide, either in HTML or PDF (p. 56-57)).

Notice that everything we’ve done so far, in testing our server-side component, we’ve done from WebORB’s management console — no client-side code needed.

Now, however, we’ll use the management console to generate some client-side code, including the client project itself. I won’t include that code here, as you can generate it for yourself. But it comes with no UI, or any methods for interacting with the server-side objects, After adding those to the project’s main.mxml file, the result looks something like this:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="onLoad()" height="361" width="362">
	<mx:Script>
		<![CDATA[
			import ColorServer.ColorService;
			import ColorServer.ColorServiceModel;
			import ColorServer.DataTypeInitializer;
			import ColorServer.vo.ARGB_Color;

			import mx.events.ColorPickerEvent;
			import mx.events.SliderEvent;

			[Bindable]
			private var model:ColorServiceModel = new ColorServiceModel();
			private var serviceProxy:ColorService = new ColorService( model );

			public function onLoad():void
			{
				new DataTypeInitializer();

				serviceProxy.GetServedColor();
			}

			private function channels2Int(a:int, r:int, g:int, b:int):int
			{
				return a << 24 | r << 16 | g << 8 | b << 0;
			}

			private function ARGB2int (c:ARGB_Color):int
			{
				return channels2Int(c.A, c.R, c.G, c.B);
			}

			private function int2ARGB (value:int):ARGB_Color
			{
				var a:ARGB_Color = new ARGB_Color();

				a.A = value >> 24 & 0xFF;
				a.R = value >> 16 & 0xFF;
				a.G = value >>  8 & 0xFF;
				a.B = value >>  0 & 0xFF;

				return a;
			}

			protected function UI_changeHandler(event:Event):void
			{
				// update the server-side data to reflect the user's UI action
				var i:uint = picker.selectedColor;
				var c:ARGB_Color = int2ARGB(i);
				c.A = aSlider.value;
				serviceProxy.SetServedColor(c);

				// update the client-side model to reflect current server-side data
				serviceProxy.GetServedColor();
			}
		]]>
	</mx:Script>

	<mx:Panel x="12" y="9" width="340" height="214" layout="absolute"
						title="ColorService color:">
		<mx:ColorPicker id="picker" x="10" y="15" width="82" height="24"
						alpha="{aSlider.value/255}"
						selectedColor="{ARGB2int(model.GetServedColorResult)}"
						change="UI_changeHandler(event)"/>

		<mx:Label x="10" y="53" text="Alpha" fontWeight="bold"/>
		<mx:Label x="10" y="101" text="Red" fontWeight="bold"/>
		<mx:Label x="10" y="127" text="Green" fontWeight="bold"/>
		<mx:Label x="10" y="153" text="Blue" fontWeight="bold"/>

		<mx:Label x="54" y="53" text="{model.GetServedColorResult.A}"/>
		<mx:Label x="54" y="101" text="{model.GetServedColorResult.R}"/>
		<mx:Label x="54" y="127" text="{model.GetServedColorResult.G}"/>
		<mx:Label x="54" y="153" text="{model.GetServedColorResult.B}"/>

		<mx:HSlider id="aSlider" x="99" y="53" width="211" maximum="255"
					snapInterval="1"
					labels="['0','255']" dataTipPrecision="0"
					liveDragging="true"
					value="{model.GetServedColorResult.A}"
					change="UI_changeHandler(event)" />
	</mx:Panel>
</mx:Application>

This UI looks like the (non-interactive) image shown at right. The color-picker at the top-left enables the selection of an RGB color; the slider enables the selection of an alpha (transparency) value (with 0 being transparent and 255 being opaque).

The UI elements are bound to the service’s model. Whenever the model changes, they are updated to reflect the state of the model.

Likewise, whenever the UI elements receive a change event, UI_changeHandler() is called. It derives the intended color state from the current UI, and sets the server’s state to match. It then gets the server’s state, which sets the model, which sends out change notifications, which update the UI’s elements to reflect the model’s new state.

Easy-peasy.

Things to watch out for:
WebORB’s management console display a handy-dandy message (like the one at left) if you attempt to access a service after its DLL has been deleted. Always remember to hit the “refresh assemblies” button before invoking a service that you’ve just modified.

The error message provided in the client, at run-time, is considerably less informative, as shown below.

So, now you know:

  • Wrap server-side structs in wrapper classes
  • Test all services in WebORB’s management console before engaging the client-side code
  • Decorate the service class with activation attribute if you want it to be stateful.

Whee! ;-)

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Spam protection by WP Captcha-Free