Dot Net

Syrinx .NET Development Blog
Need help on your project? info@syrinx.com, or toll free (888) 579-7469, press 1

News



Need help with your .NET Development project?

Syrinx works with clients throughout New England to architect, design, develop, and deploy .NET Applications. Working on fully outsourced projects, as part of your team, helping to train your team, or rescuing projects in trouble, we are comfortable doing it all. Projects from a couple weeks to several months in duration, reference clients available. Contact us today - info@syrinx.com, or toll free (888) 579-7469 and press 1 to speak to someone now!

December 2008 - Posts

XAMLFest 2008

After all of the success of the first round of Boston XAMLFest (12/11 and 12/12), Microsoft decided to host a second set of days this week (12/15 and 12/16).  XAMLFest was a quick but detailed look into WPF and SilverLight; with minimal marketing slides and a lot of hands-on coding and walk-throughs.  The time was split up between Visual Studio development (John P) for the coding aspects and Expression Blend 2 (John B) for the UI. 

While I have been doing a lot WPF work for a bit, this experience was awesome.  I learned several tips and tricks that should help for my current and future projects.  I also learned about some great tools that are must-haves for working with SilverLight or WPF.

One tool that is a must for understanding the details of what is happening within a running WPF application is Snoop.  This tool allows you to see the entire inheritance tree of all visual elements, with "actual" properties, values, and indicators so you know if the values are default, set, or inherited. 

I also learned a simple tip that helped solve a minor problem I was having.  I created a fancy title bar to replace the default title bar.  The problem was, one of my visual elements was over the buttons, causing only half of the button to respond to click events.  While there were likely many other ways to fix the problem, one simple property setting took care of the problem.  By setting IsHitTestVisible to False on the UI element, it no longer blocked the mouse down event from reaching the makeshift close and minimize buttons on my title bar.

Finally, there were a couple of differences between SilverLight and WPF that made a difference to me (though the full list is much bigger!)

  • In SilverLight, you have a much more limited list of set Brushes to use when styling.  This was to keep the download package smaller.
  • The default binding mode for SilverLight elements is OneWayToSource, while in WPF it is "default" (which varies by object type). 
  • There is no native support for synchronized collection binding (IsSynchronizedWithCurrentItem or "/" notation to indicate "current item in collection".  This makes it more difficult to do "master-detail" binding, where you have a list view that automagically updates a detailed view.

I'm playing around with some list templates that should allow for some cool visual effects for both viewing and editing data.  I'll post them up when I get them done.

Joe

Enumerators Decorated with the Flag Attribute

 

An enumerator decorated with the [Flags] or [FlagAttribute] attribute (they are one in the same), is able to store a byte that represents the concatenation of all possible combinations of the enumeration.   Because of this concatenation it is required that the enumeration be numbered implementing a base 2 sequence (i.e. 0, 1, 2, 4).  As seen in the sample code this evaluates to the following base 2 numbers:

0 = 0000

1 = 0001

2 = 0010

4 = 0100

For the sake of simplicity we added another enum to represent when all of the flags have been selected All = 7

7 = 0111

The following code (a simple aspx page and its code-behind) will display a the uses of Flags as well as the differences from regular enums.  The code uses Bitwise OR to concatenate a flag (i.e. will toggle the bit on if either or both bits in the sequence are true (1)), as follows:

0010

0001

0011

The code also uses the the Bitwise Complement (~) operator as well as the Bitwise AND (&) operator to negate (remove) a specific flag (i.e. will toggle the bit off if both bits in the sequence are true (1)), as follows:

  0111

~0010

  0101

ASPX Code:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="UsingEnums.aspx.cs" Inherits="UsingEnums" %>

 

<!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>Using Enumerators Page</title>

</head>

<body>

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

    <div style="text-align: center; width: 604px;">

        <asp:Label ID="lblProjectRequirements" runat="server" Text="Project Requirements (Pick up to two)"></asp:Label>

        <asp:CheckBox ID="chkAutoCorrect" runat="server" Text="Auto-correct" />

        <asp:CheckBoxList ID="cblProjectPreference" runat="server">

        </asp:CheckBoxList>

        <asp:Button ID="btnSelectRequirements" runat="server" Text="Select Requirements"

            OnClick="btnSelectRequirements_Click" Style="height: 26px" /><br />

        <asp:Label ID="lblResults" runat="server" Height="91px" Width="552px"></asp:Label><br />

        <asp:Button ID="btnCompare" runat="server" Text="Comapre Flags to Enums" OnClick="btnCompare_Click"

            Style="height: 26px" /><br />

        <asp:Label ID="lblFlagsDisplay" runat="server" Height="40px" Width="300px"></asp:Label>

        <asp:Label ID="lblEnumDisplay" runat="server" Height="40px" Width="300px"></asp:Label>

    </div>

    </form>

</body>

</html>

Code-Behind:

using System;

using System.Web.UI;

using System.Web.UI.WebControls;

 

[Flags]

public enum ProjectPreference

{

    /// <summary>

    /// No project requirements are selected

    /// </summary>

    None = 0,                   // (0000)

    /// <summary>

    /// The project must be done as inexpensively as possible

    /// </summary>

    Cheap = 1,                  // (0001)

    /// <summary>

    /// The project must be done as quickly as possible

    /// </summary>

    Fast = 2,                   // (0010)

    /// <summary>

    /// The project must be of the highest quality

    /// </summary>

    Good = 4,                   // (0100)

    /// <summary>

    /// This is an illegal value, since only two can be slected at one time

    /// </summary>

    All = Cheap | Fast | Good   // (0111)

}

 

// Based on Microsoft http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx

// Define an Enum without FlagsAttribute.

public enum SingleHue : short

{

    Black = 0,

    Red = 1,

    Yellow = 2,

    Blue = 4

}

 

// Define an Enum with FlagsAttribute.

[FlagsAttribute]

public enum MultiHue : short

{

    Black = 0,

    Red = 1,

    Yellow = 2,

    Blue = 4

}

 

public partial class UsingEnums : Page

{

    private const int SKIP_FOR_NONE_AND_ALL = 2;

    protected void Page_Load(object sender, EventArgs e)

    {

        if (!IsPostBack)

        {

            // Get a string array of all the enum names

            string[] projectTypes = Enum.GetNames(typeof(ProjectPreference));

            // Don't display None or All enum values

            string[] displayProjectPreferences = new string[projectTypes.Length - SKIP_FOR_NONE_AND_ALL];

            int i = 0;

            foreach (string projectType in projectTypes)

            {

                if (

                        !projectType.Equals(ProjectPreference.None.ToString())

                    &&

                        !projectType.Equals(ProjectPreference.All.ToString())

                    )

                {

                    displayProjectPreferences[i++] = projectType;

                }

            }

            cblProjectPreference.DataSource = displayProjectPreferences;

            cblProjectPreference.DataBind();

        }

    }

    protected void btnSelectRequirements_Click(object sender, EventArgs e)

    {

        ProjectPreference selectedProjectPreferences = new ProjectPreference();

        try

        {

            // Gather all of the selected flags

            foreach (ListItem liProjectPreference in cblProjectPreference.Items)

            {

                if (liProjectPreference.Selected)

                {

                    // Concatenate the flag using the Enum.Parse method and the Bitwise OR (|) operator

                    selectedProjectPreferences |=

                        (ProjectPreference) Enum.Parse(typeof (ProjectPreference), liProjectPreference.Value, true);

                }

            }

            // if all have been selected then ...

            if (selectedProjectPreferences == ProjectPreference.All)

            {

                // if auto-correct is on remove the 'Cheap' flag

                if (chkAutoCorrect.Checked)

                {

                    // Use the Bitwise Complement (~) operator as well as the Bitwise AND (&)

                    // operator to negate (remove) a specific flag

                    selectedProjectPreferences &= ~ProjectPreference.Cheap;

                    foreach (ListItem liProjectPreference in cblProjectPreference.Items)

                    {

                        if (liProjectPreference.Value == ProjectPreference.Cheap.ToString())

                        {

                            liProjectPreference.Selected = false;

                        }

                    }

                }

                // otherwise throw an error

                else

                {

                    cblProjectPreference.SelectedIndex = -1;

                    throw new Exception("You can select no more than two project preferences.");

                }

            }

            lblResults.Text = selectedProjectPreferences.ToString();

        }

        catch (Exception ex)

        {

            // The flag enumeration evaluates to 'All' - no coding required

            string errMessage = string.Format("The error value of the flag enumeration is: {0}<br />",

                                              selectedProjectPreferences);

                    // Reset to 'None'

                    selectedProjectPreferences = ProjectPreference.None;

            errMessage += string.Format("{0}<br />The current value of the flag enumeration has been reset to: {1}",

                                            ex.Message, selectedProjectPreferences);

            lblResults.Text = errMessage;

        }

    }

 

    protected void btnCompare_Click(object sender, EventArgs e)

    {

        // Display all possible combinations of values.

        // Also display an invalid value.

        string flagDisplay = "<b>With</b> FlagsAttribute:<br />";

 

        for (int val = 0; val <= 8; val++)

        {

            flagDisplay += string.Format("{0,3} - {1}<br />", val, ((MultiHue)val));

        }

        lblFlagsDisplay.Text = flagDisplay;

       

        string enumDisplay = "<b>Without</b> FlagsAttribute:<br />";

        for (int val = 0; val <= 8; val++)

        {

            enumDisplay += string.Format("{0,3} - {1}<br />", val, ((SingleHue)val));

        }

        lblEnumDisplay.Text = enumDisplay;

    }

}

Using the [Flags] attribute allows you to let the code handle some of the display of the flags, as the ToString() method will return a comma seperated list of enums (e.g. "Cheap, Fast"),  it will also resolve the ToString() to an aggregated value (in this case to 'All' if all of the flags are selected) and finally in walking through code you will be able to hover and see the concatenated list of flags instead of a somewhat hard-to-decipher number.  That is, if you are walking through code after a breakpoint you can hover over a [Flags] enum and see "Cheap | Good" instead of "5", making debugging far easier.

That wraps it up for this time.  Hope it helps.

Posted: Dec 15 2008, 02:33 AM by JohnF | with no comments
Filed under: , , ,
Filtering HTTP Responses

As part of a Microsoft Dynamics CRM implementation for a call center application, we were required to put a large number of edit controls on a single form, in order to satisfy the business requirement of having the fields available to the user during a call while keeping page navigation to a minimum.  While we were able to spread the controls across different tabs on the form, in order to improve navigation and user-friendliness, we ran into a browser performance issue in production whereby the page rendering slowed significantly due to the large number of controls on the form.  The problem was especially noticeable on machines with minimal RAM and slower CPUs.

We investigated several workarounds to this problem, but due to the requirement of CRM to only show one object per page, we were limited in the possible solutions we could implement.  One solution included breaking up the entity to several smaller entities, which would require changes to data structures and introduce extra navigation that would ultimately raise the average handling time (AHT) for a user processing a call.  Another solution involved using an IFrame in the form to host the data in our own page, which would give us the flexibility and performance we need, but at the price of a considerable development effort to implement the new page.

As a short term solution, we came up with a third alternative, which consisted of buffering the contents of the individual tabs into a javascript array on the server-side, so that the browser would not have to render the contents of each tab until a user clicked on that tab.  This reduced the initial rendering of the page down to an acceptable time, and the rendering of each tab would only occur if the user accessed that tab.  In order to buffer the contents of the tabs into a javascript array on the server-side, we implemented a custom HTTP filter for the form in question, which parsed and modified the HTTP output just before it is sent back to the client.  The filter processes the outbound HTML by first removing the content within each of the tabs, writing out the modified HTML, and then writing out to a block of javascript which defines the array containing the contents of the tabs.  On the client side, a tab click triggers javascript code which re-inserts the contents of the tab from the array, thereby delaying the rendering of the content until the user clicks into the tab. Of course, there are some concerns with this solution in general, most of which come down to the fact that this is not a supported solution from Microsoft, and that it will most likely not survive an upgrade path, but as a short-term solution it appears to work well, and did not require lengthy development time to implement.  The following articles, along with Microsoft documentation, provided excellent resources for implementing an HTTP filter: http://www.dotnet6.com/blogs/erik_lenaerts/archive/2007/07/19/translate-content-using-a-httpresponse-filter.aspx

http://www.ondotnet.com/pub/a/dotnet/2003/10/20/httpfilter.html

JohnH

Four easy steps to implementing an ASP.NET AJAX Web Service

 

In this blog post I'm going to show you the four easy steps to implementing an ASP.NET AJAX Web Service:

  • 1) Set-up a web service, this sample call invalidates any name beginning with the letter ‘a' (it is already taken), throws an exception for any name beginning with the letter ‘b' and validates all other names.

using System;

using System.Globalization;

using System.Web.Services;

 

namespace BlogDemo.Utility

{

    /// <summary>

    /// The BlogDemoService provides a sample web service to demonstrate AJAX client-side web service calls

    /// </summary>

    [WebService(Namespace = "http://syrinx.net/")]

    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.

    Make sure to remove the following comment marks è // [System.Web.Script.Services.ScriptService]

    [System.Web.Script.Services.ScriptService]

    public class BlogDemoService : WebService

    {

        [WebMethod]

        public bool IsNameTaken(string checkName)

        {

            bool retVal = false;

            if (checkName.StartsWith("a", true, CultureInfo.CurrentCulture))

            {

                retVal = true;

            }

            else if (checkName.StartsWith("b", true, CultureInfo.CurrentCulture))

            {

                throw new Exception("Names cannot start with either the letter 'B' or 'b'");

            }

            return retVal;

        }

    }

}

N.B.: The asmx file must have the fully qualified name (including namespace) :

<%@ WebService Language="C#" CodeBehind="~/App_Code/BlogDemoService.cs" Class="BlogDemo.Utility.BlogDemoService" %>

  • 2) Add the ScriptManager control to the page like so:

    <asp:ScriptManager ID="ScriptManager1" runat="server">

        <Services>

            <asp:ServiceReference Path="~/Services/BlogDemoService.asmx" />

        </Services>

    </asp:ScriptManager>

 

  • 3) Add javascript to call the webservice - note that it requires a call to the fully qualified name

    <script type="text/javascript">

        function CheckNameAvailability(info)

        {

            var checkName = $get("txtUserName").value;

            BlogDemo.Utility.BlogDemoService.IsNameTaken(checkName, OnCheckNameSuccess, OnCheckNameFailure, info);

        }

        function OnCheckNameSuccess(results, userContext, methodName)

        {

            alert("Success using method: " + methodName);

            alert("This data was passed with the call: " + userContext);

            if(results)

            {

                alert("Name is taken");

            }

            else

            {

                alert("Name is available");

            }

        }

        function OnCheckNameFailure(exception, userContext, methodName)

        {

            alert("Failure using method: " + methodName);

            alert("This data was passed with the call: " + userContext);

            alert(exception._message);

        }

    </script>

The calls to and from the web service use the complete signature to the Web Service call.  The signature for the call into the Web Service is:
FullyQualifiedWebService. WebMethod(parameters, successfulCallback, failedCallback, userContext);

The successful callback signature is: function successfulCallback(result, userContext, methodName) {}

The failed callback signature is: function failedCallback(exception,userContext,methodName) {}.  The exception variable passed to the failedCallback is a JSON serialized Exception object, providing the description of the error and a full stack trace. This allows the developer to handle-and-re-throw exceptions on the server and still gracefully deal with them on the client.

The following web page shows how the information can be used - results are displayed using a simple alert as well as accessing a text box from the client side.

 

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

 

<!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 id="Head1" runat="server">

    <title>AJAX Web Service Page</title>

 

    <script type="text/javascript">

        var txtResultsID = '<% =txtResults.ClientID %>';

 

        function CheckNameAvailability(info)

        {

            var checkName = $get("txtUserName").value;

            BlogDemo.Utility.BlogDemoService.IsNameTaken(checkName, OnCheckNameSuccess, OnCheckNameFailure, info);

        }

        function OnCheckNameSuccess(results, userContext, methodName)

        {

            alert("Success using method: " + methodName);

            alert("This data was passed with the call: " + userContext);

            if(results)

            {

                $get(txtResultsID).value = "Name is taken";

            }

            else

            {

                $get(txtResultsID).value = "Name is available";

            }

        }

        function OnCheckNameFailure(exception, userContext, methodName)

        {

            alert("Failure using method: " + methodName);

            alert("This data was passed with the call: " + userContext);

            $get(txtResultsID).value = exception._message;

        }

    </script>

 

</head>

<body>

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

    <asp:ScriptManager ID="ScriptManager1" runat="server">

        <Services>

            <asp:ServiceReference Path="~/Services/BlogDemoService.asmx" />

        </Services>

    </asp:ScriptManager>

    <div>

        <asp:TextBox ID="txtUserName" runat="server"></asp:TextBox><br />

        <asp:Button ID="btnSendBasicInfo" runat="server" Text="Send Basic" OnClientClick="CheckNameAvailability('Just the basics'); return false;" />

        <asp:Button ID="btnSendMoreInfo" runat="server" Text="Send More" OnClientClick="CheckNameAvailability('Very detailed information'); return false;" /><br />

        <asp:TextBox ID="txtResults" runat="server" Text="" Width="350px" ReadOnly="true"></asp:TextBox>

    </div>

    </form>

</body>

</html>

That's it for this time - hope you found it useful.

Posted: Dec 08 2008, 12:32 AM by JohnF | with no comments
Filed under: ,
Converting Strongly Typed Collections to Generics: Part 3

In Part 1, the idea of converting your strongly typed collections to Generics was introduced.  Backward compatibility and existing client support was maintained along with compiler time type safety.  Part 2 demonstrated a reduction in code for new strongly typed collection classes utilizing lambda expressions and still maintaining compiler time type safety.  Here in part 3 Language Integrated Queries (Linq) will replace lambda expressions, compiler time type safety will of course be maintained.

Language Integrated Queries

Linq is SQL like searching expressions that can be used with, among other entities, objects that implement IEnumerable<T>.   The Linq expression is strongly typed and therefore maintains type safe checking at compiler time.  Consider the following code snippet.

 

BaseGenericCollection<Student> _students = LoadStudents();//Load up a Generic collection of Student objects

//Use a Linq expression to sort the students
var students = from student in _students orderby student.Major select student;

//The Students are ordered using the Linq expression above
foreach (var student in students)
{

    Console.WriteLine("{0,-10} \t{1,-10} \t{2,-10} \t{3,-10:d} \t{4,-10:D} ", student.FirstName,

    student.LastName, student.Major, student.EnrollmentDate, student.GraduationDate);

}

//First define the major we are looking for
Program._majorToFind = "Physics";

 

//Use a Linq expression to find the students with the desired major

var studentsWithMajor = from student in _students where student.Major == Program._majorToFind select student;

//Now we can loop thru the collection returned from using a Linq expression to query the Generic collection
foreach (var student in studentsWithMajor)

{

    Console.WriteLine("{0,-10} \t{1,-10} \t{2,-10} \t{3,-10:d} \t{4,-10:D} ", student.FirstName,

    student.LastName, student.Major, student.EnrollmentDate, student.GraduationDate);

}

 

//Now we can loop thru the collection returned by the "FindByLastName" methods

Program._lastNameToFind = "Valenti";

 

//Use a Linq expression to find the student with the desired last name

Student studentToFind = (from student in _students

  where student.LastName == Program._lastNameToFind

  select student).ToList<Student>()[0];

 

Console.WriteLine("{0,-10} \t{1,-10} \t{2,-10} \t{3,-10:d} \t{4,-10:D} ", studentToFind.FirstName, studentToFind.LastName, studentToFind.Major, studentToFind.EnrollmentDate, studentToFind.GraduationDate);

The ordering lambda expression from Part 2 (_students.OrderBy(student => student.Major)) is replaced with a Linq expression.  The Linq expression is also type safe and provides a different syntax for sorting thru a Generic collection.  The Find and FindAll methods have also be replaced with Linq expressions.  Notice that the Linq expression that looks for a last name.   The entire expression is cast to a List<Student> and the zeroth element is returned.   This allows for immediate execution so we don’t have to use a foreach loop to retrieve the instance(s).

Linq, like lambda expressions, can reduce the amount of code that legacy strongly typed collection classes would normally have.  Business requirements inevitably change and Low maintenance of middle tier objects is desired.   Linq is extensible and provides flexibility in its uses such that the code can be slightly modified to search over a dataset instead of a strongly typed collection or many other storage mechanisms.  This flexibility can reduce maintenance and can lower the amount of code in data tiers by reducing the logic needed to determine the correct persistent store.