Run. Your. Business.
Call Us: 877.824.2524

Blog

NetQuarry Version 2.1.5 Released

COSTA MESA, Calif. – May 18, 2009 – NetQuarry, Inc. announces release of v2.1.5 of its NetQuarry Enterprise Application Platform.

The v2.1.5 release is a maintenance release with various minor enhancements and bug fixes including:

  • UI fixes,
  • Import enhancements,
  • Scheduler fixes.

About NetQuarry

NetQuarry develops and licenses the NetQuarry Enterprise Application Platform. The NetQuarry platform helps professional software development teams develop significantly better enterprise and hosted applications.

NetQuarry is privately held. For more information, call (877) 824-2524, email info@netquarry.com, or visit our website at www.netquarry.com.

NetQuarry Version 2.1.4 Released

COSTA MESA, Calif. – April 23, 2009 – NetQuarry, Inc. announces release of v2.1.4 of its NetQuarry Enterprise Application Platform.

The v2.1.4 release is a maintenance release with various minor enhancements and bug fixes including:

  • Browser compatibility improvements,
  • UI improvements,
  • Wizard improvements,
  • Performance improvements.

About NetQuarry

NetQuarry develops and licenses the NetQuarry Enterprise Application Platform. The NetQuarry platform helps professional software development teams develop significantly better enterprise and hosted applications.

NetQuarry is privately held. For more information, call (877) 824-2524, email info@netquarry.com, or visit our website at www.netquarry.com.

IssueTrak Movie

We’ve just uploaded a short, recorded demo of building the IssueTrak application. The demo is available from the homepage (click on the large, friendly blue button) or by (clicking here).

The movie demonstrates how you can quickly generate a working application that is not only completely functional, but looks great as well.

How To Configure SSL Host Headers in IIS 6

At NetQuarry, we write software. We sell a software product – the NetQuarry Platform – that we wrote and own and we support the customers that use our product. Software. That’s it. So, it may seem a little surprising that a blog about IIS and SSL is even here, and more surprising, especially if you know me, that I’m the one writing about it.

We recently wanted to install an SSL certificate on our main build server so that multiple sites hosted on that server could (and in some cases must) use SSL. So, I bought a $199 “wildcard” certificate from GoDaddy.com and installed it onto our Windows 2003 / IIS 6.0 build machine. Everything worked until I tried to add the same certificate to multiple sites on the same server. I started searching for an answer – “SSL certificate IIS subdomain multiple” and found that it wasn’t possible. Host headers – the thing you use to allow one IP address to act like different sites – doesn’t work with IIS 6.0.

I eventually bumped into this article: http://www.sslshopper.com/article-how-to-configure-ssl-host-headers-in-iis-6.html that solved the problem. Turns out it’s pretty simple, but you can’t do it using the MMC IIS snap-in.

Here’s the script (run from /inetpub/adminscripts):

cscript.exe adsutil.vbs set /w3svc/<site ID>/SecureBindings ":443:<host header>"

Note that I found that you had to install your wildcard certificate, run the script, and restart IIS before everything worked.

Ryan

NetQuarry Version 2.1.3 Released

 

COSTA MESA, Calif. – March 4, 2009 – NetQuarry, Inc. announces release of v2.1.3 of its NetQuarry Enterprise Application Platform.

The v2.1.3 release is a maintenance release with various minor enhancements and bug fixes including:

  • Browser compatibility enhancements,
  • Datasheet enhancements,
  • Studio enhancements,
  • Improved Screen Reader support.

About NetQuarry

NetQuarry develops and licenses the NetQuarry Enterprise Application Platform. The NetQuarry platform helps professional software development teams develop significantly better enterprise and hosted applications.

NetQuarry is privately held. For more information, call (714) 881-4574, email info@netquarry.com, or visit our website at www.netquarry.com.

Master Pages, AJAX, and Javascript

We recently decided to add support for MasterPages to the NetQuarry Enterprise Application Platform. The platform provides a set of .aspx “templates” that are used to host content in various configurations. The standard templates include Wizard, Console, and several flavors of Subform templates as well as support for custom templates. The basic idea is to support hosting templates in .master pages. Note that NetQuarry is currently using .Net 2.0.

Everything started out well enough. I created a master page called minimal.master and added it to my project. The .master file was very simple:

<%@ Master Language=”C#” AutoEventWireup=”true” CodeBehind=”minimal.master.cs” Inherits=”NetQuarry.minimal” %>

<%@ Register TagPrefix=”eap” Namespace=”NetQuarry.WebControls” Assembly=”EAP.WebControls” %>

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN” >

<html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
<title runat=”server” id=”pageTitle”>Untitled Page</title>
<asp:ContentPlaceHolder id=”header” runat=”server”>
</asp:ContentPlaceHolder>
</head>

<body runat=”server” id=”body” class=”background”>
<esp:ContentPlaceHolder id=”content” runat=”server”/>
</body>
</html>

I made a few quick modifications to my templates wrapping my original header and body contents in appropriate asp:Content controls:

<asp:Content ID=”header” ContentPlaceHolderID=”header” runat=”Server”>
</asp:Content>

<asp:Content ID=”content” ContentPlaceHolderID=”content” runat=”Server”>
</asp:Content>

A bit more tweaking, the basics were there, but I still had problems. The big problem was that the NetQuarry platform is used to create web applications, not web sites. Our applications include a fair amount of javascript and AJAX and using master pages had broken lots of script. It didn’t take long for me to figure out that the main problem was that all my client-side elements now had mangled names. For example, instead of a textbox being named something like “first_name”, it was being rendered into the HTML as “ctl00_content_first_name”. This mangling broke our script, and badly.

The cause of the mangling is the .Net NamingContainer idea. NamingContainers allow a page to host multiple instances of an object by automatically generating unique client-side names that represent the control hierarchy on the server. In this case, the MasterPage class itself was a NamingContainer as well as the ContentPlaceHolder control. Since I hadn’t provided an ID for my MasterPage .Net named it ctl00. I had named the ContentPlaceHolder for the main page content “content”. So, since my existing page content was all contained in the “content” ContentPlaceHolder and it was in turn contained in the “ctl00” MasterPage, .Net composed a unique client-side name for the any control in the “content” prefixed with “ctl00_content_” and, voila, broken script.

Now NamingContainers are a great feature of .Net and they allow a lot of things to work seamlessly. However, in this case I didn’t want any stinking NamingContainers. Unfortunately, there’s no way to turn off the NamingContainer feature of any control marked as a NamingContainer (a control is marked as a NamingContainer by deriving from the INamingContainer marker interface). Hint to Microsoft, this would be a good feature.

I actually spent about two days fighting with this and scouring the internet to see if anyone else had come up with a solution. I did find several partial solutions that helped me move in the right direction. First there was a good article about MasterPages in general on www.OdeToCode.com ASP.Net 2.0 – Master Pages: Tips, Tricks, and Traps. A bit more digging and I found a partial solution on Rick Strahl’s Web Log – Overriding ClientID and UniqueID on ASP.NET controls. I’ve found Rick’s blog to be very helpful in the past. And, that article pointed me to one other helpful blog on glJakal blog – Getting rid of the Naming Container in asp.net 2.0.

Together these articles showed how to defeat the NamingContainer for client-side naming. The full code of the final solution is below, but defeating the NamingContainer for client-side id mangling involved overriding the ClientID, UniqueID, and ID properties on the MasterPage and ContentPlaceHolder classes to return null, and the NamingContainer property on the ContentPlaceHolder class to return null. With that my pages rendered well and my javascript worked!

Alas, what didn’t work was any postbacks. The problem was that the id’s of the client-side controls no longer matched the control hierarchy on the server! It didn’t take me long to figure out that what I needed to do was figure out a way to make the server-side control hierarchy match my client-side naming. Essentially this meant making the server-side hierarchy look like my pre-MasterPage hierarchy, as far as NamingContainers go that is.

After a day of failed attempts, I was able to work out how to accomplish this. The secret was to rearrange the control tree during the page PreInit event. The PreInit event is available only to Page objects and is the only time that you can rearrange controls in the way I needed to. Eventually I figured out that two things needed to be done: 1) move the controls out of the MasterPage and ContentPlaceHolder controls so that .Net can match up the server-side controls with the unmangled client-side id’s, and 2) leave the controls in the MasterPage and ContentPlaceHolder controls for rendering purposes so that the contents are rendered correctly with respect to other elements in the MasterPage.

May 20, 2009 update: Thanks to Ritchie Annand for discovering a problem in the original code when run with .Net tracing enabled (via the <trace> tag) and pointing the way to a fix.  The code now includes a fix to ensure that all hosted controls get an ID which is required when tracing (see the call to AssignIDs() in TemplateMaster::OnPreRender()).  Note that there is still a glitch that affects our platform under certain circumstances when .Net tracing is enabled and pageOutput is turned on.

To use the code below you need to do just a few things:

  • Include the code below in your project,
  • Derive your master page from TemplateMaster instead of MasterPage,
  • Use the <eap:ContentPlaceHolder> tag in place of <asp:ContentPlaceHolder>,
  • In your master page .designer file, use the new ContentPlaceHolder instead of the .Net ContentPlaceHolder, and
  • In your page’s PreInit event, call the TemplateMaster.Rehost() method, something like this:

protected override void OnPreInit(EventArgs e)
{
    //--- Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the 
    //--- Page itself.  This has the effect of cancelling the NamingContainer effect of 
    //--- these controls on the server. 

    if (this.Master is TemplateMaster)
    {
        (this.Master as TemplateMaster).Rehost();
    }

    base.OnPreInit(e);
}

And finally, here’s the code:

//---------------------------------------------------------------------------------------
// Copyright (c) 2005-2009 by NetQuarry, Inc.
// All rights reserved.
//
// Licensed under the Eiffel Forum License, version 2:
//
// 1. Permission is hereby granted to use, copy, modify and/or
// distribute this package, provided that:
// * copyright notices are retained unchanged,
// * any distribution of this package, whether modified or not,
// includes this license text.
// 2. Permission is hereby also granted to distribute binary programs
// which depend on this package. If the binary program depends on a
// modified version of this package, you are encouraged to publicly
// release the modified version of this package.
//
// THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT WARRANTY. ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THIS PACKAGE.
//
// www.netquarry.com
//---------------------------------------------------------------------------------------

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Collections.Generic;

[assembly: TagPrefix("NetQuarry.WebControls", "eap")]

namespace NetQuarry.WebControls
{
    /// <summary> 
    /// Base class that must be used for any master page hosting platform templates. 
    /// </summary> 
    public abstract class TemplateMaster : System.Web.UI.MasterPage
    {
        private class ContentContainer : Control
        {
            protected override void Render(HtmlTextWriter writer)
            {
                //base.Render(writer);  // Ignore the normal render. 
            }

            public void ExternalRender(HtmlTextWriter writer)
            {
                base.Render(writer);    // Now render! 
            }

            protected override void OnPreRender(EventArgs e)
            {
                base.OnPreRender(e);

                int nIDIndex = 0;

                AssignIDs(this, this.ID, ref nIDIndex);
            }

            /// <summary>
            /// In .Net TRACE enabled every control in the hierarchy MUST have and ID and our juggling rehosting 
            /// controls messes up .Net's id assignment.  Here we recursively search through the specified control
            /// and provide unique ID's to any controls so lacking.
            /// </summary>
            /// <param name="ctrl">The control whose hierarchy should be scanned and assigned.</param>
            /// <param name="baseName">The base name for any subcontrols.</param>
            /// <param name="idIndex">The ID index to use when assigning a unique ID.</param>
            private void AssignIDs(Control ctrl, string baseName, ref int idIndex)
            {
                if (string.IsNullOrEmpty(ctrl.ID))
                {
                    ctrl.ID = baseName + idIndex.ToString().PadLeft(3, '0');
                    idIndex++;
                }

                if (ctrl.Controls != null)
                {
                    foreach (Control child in ctrl.Controls)
                    {
                        AssignIDs(child, baseName, ref idIndex);
                    }
                }
            }
        }

        private class ContentRenderer : Control
        {
            ContentContainer _container = null;

            public ContentRenderer(ContentContainer container)
            {
                _container = container;
            }

            protected override void Render(HtmlTextWriter writer)
            {
                if (_container != null) _container.ExternalRender(writer); // Ask associated container to render. 
            }
        }

        /// <summary> 
        /// Defeat the effect of the .Net MasterPage being a NamingContainer with regard 
        /// to client-side NAME and ID attributes rendering by always returning a null ClientID. 
        /// </summary> 
        public override string ClientID
        {
            get { return null; }
        }

        /// <summary> 
        /// Defeat the effect of the .Net MasterPage being a NamingContainer with regard 
        /// to client-side NAME and ID attributes rendering by always returning a null UniqueID. 
        /// </summary> 
        public override string UniqueID
        {
            get { return null; }
        }

        /// <summary> 
        /// Defeat the effect of the .Net MasterPage being a NamingContainer with regard 
        /// to client-side NAME and ID attributes rendering by always returning a null ID. 
        /// </summary> 
        public override string ID
        {
            get { return null; }
            set { base.ID = value; }
        }

        /// <summary> 
        /// Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the 
        /// Page itself.  This has the effect of cancelling the NamingContainer effect of 
        /// these controls on the server.  
        /// </summary> 
        /// <param name="parent">The parent control whose children should be rehosted.</param>
        /// <param name="idIndex">The ID index to use when providing ID's to controls so lacking.</param>
        private void MoveControlsToPage(Control parent, ref int idIndex)
        {
            if (base.Page != null && this.Controls.Count > 0)
            {
                List<Control> lst = new List<Control>(this.Controls.Count);
                ContentContainer container = new ContentContainer();                // Container will host the controls w/out a NamingContainer. 
                ContentRenderer renderer = new ContentRenderer(container);        // Renderer will render contents of container. 

                //--- In .Net TRACE enabled every control in the hierarchy MUST have
                //--- and ID and our juggling rehosting controls messes up .Net's id assignment.

                container.ID = "ctlcont" + idIndex.ToString().PadLeft(3, '0');
                renderer.ID = "ctlrend" + idIndex.ToString().PadLeft(3, '0');
                idIndex++;

                //--— Create collection of all controls to move.

                for (int ii = 0; ii < parent.Controls.Count; ii++)
                {
                    lst.Add(parent.Controls[ii]);
                }

                //--— Determine index of this container. 

                Control root = parent;

                while (root != null && root.Parent != null && !(root.Parent is Page))
                {
                    root = root.Parent;
                }

                int nIndex = (root == null) ? -1 : root.Parent.Controls.IndexOf(root);

                //--— Remove controls from original parent and add them to new container. 

                for (int ii = 0; ii < lst.Count; ii++)
                {
                    Control ctrl = lst[ii];

                    parent.Controls.Remove(ctrl);
                    container.Controls.AddAt(ii, ctrl);
                }

                //--— Add new renderer to replace original controls and new container to the page itself. 
                //—-- The container is used to extablish the control hierarchy and in this way collapsing  
                //—-- the MasterPage so that it doesn’t act as a NamingContainer for the purposes of the 
                //—-- control hierarchy.  The container will ignore the control’s normal Render() method. 
                //--— The renderer has no controls, just a reference to the container.  When the renderer’s 
                //--— Render() method is called it will have the container render in its place.

                parent.Controls.Add(renderer);                    // Render controls as if contained in master. 
                Page.Controls.AddAt(nIndex + 1, container);        // But host them flat on the page instead of nested in NamingContainers. 
            }
        }

        /// <summary> 
        /// Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the 
        /// Page itself.  This has the effect of cancelling the NamingContainer effect of 
        /// these controls on the server.  
        /// </summary> 
        /// <param name="parent">The tree of controls from which to rehost.</param>
        /// <param name="idIndex">The ID index to use when providing ID's to controls so lacking.</param>
        private void RehostMasterControls(Control parent, ref int idIndex)
        {
            //--— Find all ContentPlaceHolder controls and rehost the children to the page itself. 

            foreach (Control ctrl in parent.Controls)
            {
                if (ctrl is NetQuarry.WebControls.ContentPlaceHolder)
                {
                    MoveControlsToPage(ctrl, ref idIndex);        // Rehost children to page. 
                }
                else
                {
                    RehostMasterControls(ctrl, ref idIndex);    // Recurse. 
                }
            }
        }

        /// <summary>
        /// Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the
        /// Page itself.  This has the effect of cancelling the NamingContainer effect of
        /// these controls on the server. 
        /// </summary>
        public void Rehost()
        {
            int nIDIndex = 0;        // Need to provide unique ID's for controls so lacking.

            RehostMasterControls(this.Page.Master, ref nIDIndex);
        }
    }

    /// <summary> 
    /// Replacement control for System.Web.UI.WebControls.ContentPlaceHolder for use when it is desired 
    /// to NOT have the MasterPage, Content, and ContentPlaceHolder controls behave as naming 
    /// containers.  There are two aspects to this: 1) the effect a NamingContainer has on the  
    /// client-side control NAME and ID mangling, and 2) the control hierarchy on the server. 
    /// </summary> 
    public class ContentPlaceHolder : System.Web.UI.WebControls.ContentPlaceHolder
    {
        /// <summary> 
        /// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard 
        /// to client-side NAME and ID attributes rendering by always returning a null NamingContainer. 
        /// </summary> 
        public override Control NamingContainer
        {
            get { return null; }
        }

        /// <summary> 
        /// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard 
        /// to client-side NAME and ID attributes rendering by always returning a null ClientID. 
        /// </summary> 
        public override string ClientID
        {
            get { return null; }
        }

        /// <summary> 
        /// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard 
        /// to client-side NAME and ID attributes rendering by always returning a null UniqueID. 
        /// </summary> 
        public override string UniqueID
        {
            get { return null; }
        }

        /// <summary> 
        /// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard 
        /// to client-side NAME and ID attributes rendering by always returning a null ID. 
        /// </summary> 
        public override string ID
        {
            get { return null; }
            set { base.ID = value; }
        }
    }
}

Fresh Beginnings

One of the things I hear myself saying nearly all the time sounds something like “if I were starting over…” If you make a living writing software, building websites, building databases, or writing reports you must have, on a regular basis, one of these moments.

For me, the reason I feel this way is because there are always parts of an application that aren’t quite right. I’d like a chance to make it better.

Since this isn’t always possible we’ve made a huge effort to allow for a way to add and remove parts of your application in a simple, safe, and discoverable way. In fact, this idea of “feature versions” is a first class concept in the Platform.

A feature version allows you to add metadata and code and tag it with a name that won’t be available in your live application unless you enable the version. This works for all important metadata objects – pages, mappers, fields, and extensions. Because it works with extensions you can actually write code, add it to the build, installer, and publish it to your live site without any risk of the code kicking in before the feature is absolutely ready.

Feature versions allow you to make your Great New Feature – the one you got to “start over” on – show up at several levels. The simplest way is by setting the version on an extension – for example, say you’ve built Version 1.0 of a task queue feature and you’ve written an extension for Version 2.0 that does much, much more. In this scenario, you would set the MinVersion value on the ‘task’ version to 1 and the MaxVersion to 1. Then you set the MinVersion for the next extension to 2.

When you set the value of the version to 2 your new extensions automatically kicks in. Simple, safe. You’ve just started over.

If you are lucky enough to be starting a new project then you really, really should take a good look at the NetQuarry Platform today. Contrary to the popular thinking of project managers and software architects, custom applications do NOT require custom infrastructure. Really. Spend a few minutes with us – talk to one of our customers. It’ll be short. We promise.

NetQuarry – Start Right.

iLUXCARS

iLUXCARS is online network for dealers trading luxury and exotic vehicles at wholesale. This includes Ferrari, Lamborghini, Rolls Royce, Bentley, Porsche, Maserati, Aston Martin, Mercedes-Benz, BMW, and more.

http://www.iluxcars.com

TypedMappers

A TypedMapper is a helpful, extrememly lightweight type-safe wrapper class around a NetQuarry Mapper object.

You typically use a TypedMapper as a helper class in an extension. You can create a TypedMapper and attach it to the sender (IMapper) of the event or you can use the TypedMapper derivative to create a new mapper – either for the purpose of creating a new row or reading/updating an existing one. Connecting a TypedMapper via one of the constructors or TypedMapper.Attach is very inexpensive and generally a safer way to work with a mapper.

The TypedMapper is an abstract base class, which means that you have to use our generator to generate derived classes that wrap your mappers. The ONLY potential drawback to using a TypedMapper derivative vs. the Mapper as is is that you will need to update (re-generate) the classes as you make metadata changes. On the applications that we (NetQuarry) are personally managing we are putting the generation code after we save the metadata and check-in the class file. We are recomending that you keep the generated classes more or less stand-alone (e.g. in its own assembly) and without any dependencies on other code.

TypedMapper objects that have custom functionality added to them should all be placed in the Data project. This allows that functionality to be shared with other consumers. You can add TypedMapper objects anywhere in your code base and add different functions to each instance. That is not recommended.

You create a typed mapper object by deriving the class from the equivalent generated template typed mapper object. The template object gives you all the type safe declarations for fields on the mapper that are on the mapper when flavor 0 is applied to the mapper. All fields with an include flavor are not in a generated TypedMapper.

To declare a typed mapper, you derive your class from the generated class template:

public class People : Comensura.Data.Generated.people<People>
public class CompaniesTemplates : Comensura.Data.Generated.companies_templates<CompaniesTemplates>

Or, more generally:

public class TName : Application.Data.Generated.TBase<TName>

You give your typed mapper class the name almost exactly derived from the generated class name, removing any underscores and proper casing the letters for legibility. Your template object is your class. Then just treat your object like any other class and add public and private methods as appropriate.

Code in Extension or TypedMapper?

A commonly asked question is where to put your business logic. The temptation is to add business logic to Mapper extensions. Well, the basic rule of thumb is that only decision/workflow/UI logic is put in the extension and data manipulation/business logic is performed in the TypedMapper object.

Having said that, there is nothing inherently wrong with putting data manipulation code in an extension as long as it’s self contained.

If you add data manipulation code that is likely to be shared then you should probably think about putting that code as a method on the TypedMapper object. The alternative to sharing code via the TypedMapper is to share the code in the Common class, but as a static method.

So, back to the TypedMapper object. Remember a TypedMapper is just a mapper and whenever you call your TypedMapper functions, your logic is going to read and write data from the current row. Of course there are many things you can do in your functions but they all relate to some operation controlled or directed by the values in the current row.

NetQuarry Version 2.1.2 Released

COSTA MESA, Calif. – January 27, 2009 – NetQuarry, Inc. announces release of v2.1.2 of its NetQuarry Enterprise Application Platform.

The v2.1.2 release includes a number of relatively minor bug fixes, primarily to AJAX handling and the UI.

About NetQuarry

NetQuarry develops and licenses the NetQuarry Enterprise Application Platform. The NetQuarry platform helps professional software development teams develop significantly better enterprise and hosted applications.

NetQuarry is privately held. For more information, call (877) 824-2524, email info@netquarry.com, or visit our website at www.netquarry.com.

Page 5 of 8« First...34567...Last »