Monday, July 12, 2010

SSIS and WCF – The Devil in the Wsdl

I want to elaborate on a fix that wasn't so obvious to me...

The plan seemed simple enough. Current Application requires email reports to sent, some from the web GUI, others according to certain conditions and schedules. Instead of duplicating the report logic in multiple places, let's place it all in one WCF Service application (sending the reports offline via MSMQ) and then call the service from both the web GUI and an SSIS job that runs according to the conditions and schedules.

Not too much to ask, right?

Enter SSIS.

Web Service Task

SSIS offers a task for calling web services - you guessed it: the Web Service Task - which claims to support WCF too so long as the WCF uses Basic Http Binding.

So you add the Web Service Task, configure the Wsdl url and then...error:

Item has already been added. Key in dictionary: 'anyType' Key being added: 'anyType'

Error

Some friendly souls encountered this error before and offered sage advice here and here but the solution requires some spelling out.

The Wsdl needs to contain type definitions for the service methods and data contracts etc. These are split over a number of xsd files, all referenced in the Wsdl:

Wsdl file with Xsd references

Here’s the catch: Wcf generates Wsdl that creates circular references within the xsd files.

Here’s the content of Xsd2:

Xsd2

Note that Xsd2 refers to Xsd3 and Xsd1 even though they are already referenced in the Wsdl.

The result: SSIS in Visual Studio blindly builds a list of valid types based on these Xsd files and thus tries to add some types twice – and fails on validation.

This validation is usually a good thing, but flags Wcf-generated Wsdl content as a false positive.

The Solution

The way out of this mess?

  1. Look through the Xsd references in your Wsdl
  2. Peek at the Xsd files too (copy the urls to your browser of choice)
  3. Eliminate from the Wsdl file all references to Xsd files already referenced in earlier Xsd files.

In my case this meant deleting all the Xsd references from the Wsdl except for the first one.

[The irony, of course, is that I encountered a row of other issues – setting the Input and Output parameters for the Task, for starters – and decided to ditch the Web Service Task in favor of a Execute Script Task, which uses an old-fashioned web service reference in the script editor.

So much for that…]

Monday, May 24, 2010

JavaScript: Search an Array of Objects

The Object of your Desire

Ajax aficionados often find themselves with heaps of Json data, often arrays of data, fresh from the server, which they then magic into Html client-side.

A number of options exist for searching for a specific item in an array:

But what if you have an array of objects?

You can use JavaScript’s built-in indexOf(obj) method for arrays to compare for object identity:

arr.indexOf(obj);

But this requires the entire hotly-sought object and, apparently, this may not work in some browsers, such as IE6, without a creative work-around.

A Generic (and Perhaps Obvious) Solution

Recently, I wrote the following function:

function ArrayIndexOf(a, fnc) {
if (!fnc || typeof (fnc) != 'function') {
return -1;
}
if (!a || !a.length || a.length < 1) return -1;
for (var i = 0; i < a.length; i++) {
if (fnc(a[i])) return i;
}
return -1;
}

ArrayIndexOf(a, fnc) takes two parameters:

  • the array
  • a function of signature: bool f(item) {}

ArrayIndexOf compares each array item with, well, whatever you want, and returns the index of the item in the array, or -1 if there is no match. This approach gives you the flexibility to search for whatever specific field, or fields, you desire.

Sample usage:

var i = ArrayIndexOf(arrMovies, function(obj) {
return obj.MovieTitle == 'The Matrix';
});
if (-1 != i) {
alert('Found it! (Psst: take the blue pill!)');
}

Disclaimer:

  • I haven’t tested this code for performance, so if your arrays are immense, test it out
  • Handle with care. JavaScript’s type-insensitivity means you better be sure the object properties you test against exist if you don’t want to crash and burn.

Thursday, April 22, 2010

Iron Speed: To Generate or Not to Generate?

The Virtues of Laziness

If necessity is the mother of all invention, then laziness is a doting aunt, especially where developers are concerned.
Our desire to do as little work as possible has spawned, paradoxically, impressive feats of ingenuity.
We replaced our spaghetti-code subroutines with re-usable, elegant objects (OOP) figuring why do many times what can be done once; we abandoned our hard-coded data-layer drudgery in favor of drag-and-drop ORMs (ala Linq To Sql and Entity Framework); we even fled from manual GUI code (perish the thought!) and found refuge in the warm welcoming arms of template-driven web pages (Dynamic Data); we leverage Http Modules and fancy new Design Patterns whenever humanly possible (do I hear Inversion of Control?).
All-in-all, our laziness has paid off. Our code is more modular, maintainable and we get to use the battle cry DRY (don’t repeat yourself) when nobody’s looking.
The next evolutionary step, one might think, is code generation. Why write code at all when someone (or something) can do it for you?


Code Generation

For our purposes code generation refers to:
any tool that generates a fully-functional web application based on a set of database objects.
The generator creates web pages based on database tables and uses foreign key relationships between tables to create links between the web pages.




logo
Iron Speed is one such code generator for ASP .NET.
The generation process involves 5 steps:
  1. Select a design theme (menu above or at the side, color scheme)
  2. Select the page types you require -  record display, table display, reports, emails, workflows, etc. – and select the relevant database tables or views
    Wizard-PagesAndDB
  3. Select a few configuration settings (code language, Sql or stored procedures, etc)
  4. Let Iron Speed generate the web pages, data and business layer code in under a minute or two. LivewPreview
    Each page involves 5 files:
    - an html layout file
    - settings stored as xml
    These are used to generate the other files:
    - an aspx file
    - a code behind file (page.cs for C#)
    - a code file with classes for each Iron Speed control on the page (page.Controls.cs)
  5. Customize! (Rarely will Iron Speed guess correctly which fields you want to display.)
The last step is the most time-consuming. Customization involves two activities:
  • Using the Iron Speed designer – this makes changes to the html and xml files. When you re-build the site, the code files will also change.
  • Change page behavior by overriding methods in the code files in the designated sections. These changes will not be overwritten when you next build the site.

Pros and Cons

The advantages are obvious:
  • Quick development time
  • Rich GUI applications: paging, export to Excel etc., menu’s, reports
  • Object-oriented code design
  • Data layer can be configured to use either straight SQL or Stored Procedures
  • Online forums for troubleshooting
  • Simple if limited authentication-authorization infrastructure for forms or Active Directory-based security.
Immediate downsides include:
  • Expensive – licenses are in the thousands of dollars
  • Restrictive licensing policy – licenses are connected to specific users so forget about transferring a license from one team member to another even if the former has moved to Timbuktu.
But the more important disadvantages emerge only further down the road.




Iron Speed Gotchas

  • Customizations made via the Designer are lost when even minor changes are made. This can be a serious setback for application maintenance of customization-heavy pages. A minor tweak becomes a start-from-scratch task.
  • IronSpeed version upgrades often break code and require recoding.
  • Stored procedures are overwritten, not altered, and thus will lose their permissions properties each build. The procedures are based on dynamic queries and thus you’ll need to grant permissions to the actual tables in addition to the procedures.
  • GUI design is limited. Forget about moving your menus from below the logo to above – you’ll have to wade through pages of “theme” code – partly in XSL – which is littered with misleading obsolete code files. You may resort to very complex customizations and workarounds that defeat the purpose of code generation. Good luck!
    ”Why, o why,” your users will whine, '”can’t you just move the button to the other side?”
  • Simultaneous development is a major headache. The designer makes seemingly random changes that make code merges a nightmare if not practically impossible. The end result: features that “disappear” after a merge.
  • Users with minimal privileges may have empty table columns where buttons and values have been hidden. “Why can’t you just hide the damn table column?” is another familiar user complaint.

Conclusions

For small applications that follow the database table structure closely and require little updating, Iron Speed is a pleasure.
However, when it comes to a monster application delivered to demanding users and implemented by a multi-member Agile development team over multiple phases – think twice. The time you save on your first iteration will be devoured by your second, third and so on.
You may want to roll your own site or even tinker with Dynamic Data, which, being a template infrastructure as opposed to code generator, will offer the flexibility and predictability you seek, at the cost of fewer bells and whistles out the box.
Bottom line: laziness has a dark side too.

Sunday, April 11, 2010

Click Once Only - Dealing with Obsessive Compulsive Users

Click. Click. Clickclickclick...

Some users just can’t control themselves. They see a button, they click it. And once is never enough.

It’s no coincidence that the only group of professionals, besides programmers, who refer to their clientele as users are drug dealers.

Harmless enough in the privacy of ones home, this frenetic clicking behavior can wreak havoc on web applications, which, stateless as they are, handle each form submission as a separate request.

The Usability Straight Jacket

One way of saving our poor users from themselves is to disable that darn submit button, post click and post haste.

Our first impulse is to add some sneaky JavaScript to the submit button:
onclick="this.disabled=true;return true;"

However, you’ll soon notice a problematic side effect for even trivial forms such as this:

<asp:ValidationSummary runat="server" ID="vldSummary" HeaderText="Please correct the errors below:"
ShowSummary="false" DisplayMode="BulletList" ShowMessageBox="true"  />

<asp:Label runat="server" ID="lblFirstName" Text="First Name" AssociatedControlID="txtFirstName"></asp:Label>

<asp:TextBox runat="server" ID="txtFirstName" ></asp:TextBox>

<asp:RequiredFieldValidator runat="server" ID="reqValFirstName" ControlToValidate="txtFirstName" Display="Dynamic" Text="*" ErrorMessage="Enter a First Name" EnableClientScript="true"></asp:RequiredFieldValidator>
<br/>

<asp:Button runat="server" ID="btnSave" Text="Save" OnClick="btnSave_Click" />

Note the RequiredFieldValidator control. If validation errors occur on submission, the user will never get a second chance to submit the form because we disable the submit button onclick!


A 3-Step Solution

Obviously, more work is required. To cut a long story short:

  1. Change the submit button to a regular button that will not trigger form validation

    <asp:Button runat="server" ID="btnSave" Text="Save" CssClass="button" OnClick="btnSave_Click" OnClientClick="submitOnce(this);" UseSubmitBehavior="false" CausesValidation="false" />

    Skip this step, as some online articles do, and form validation will fire twice - you'll receive the “errors” popup twice

  2. Disable the button only if the form is valid

    function submitOnce(myButton){
    // Client side validation
    if (typeof(Page_ClientValidate) == 'function') {
    if (Page_ClientValidate() == false)
    { 
    
    return false; 
    }
    }
    
    //make sure the button is not of type "submit" but "button"
    if (myButton.getAttribute('type') == 'button') {
    // disable the button
    myButton.disabled = true;
    myButton.value = "processing...";
    }
    return true;
    }




  3. Since our button no longer has validation functionality built-in, we need to enforce validation in the server-side handler as well.

    protected void btnSave_Click(object sender, EventArgs e)
    {
    //VALIDATE
    Page.Validate();
    if (!Page.IsValid) return;
    
    //...do your magic...
    
    }
Thus our trigger-happy users click away to their hearts' content without fear of bringing on an apocalypse.

Introducing…

Response.Write("Hello World!"); 

Now that we’ve got that out of the way, a confession.

Since the turn of the millenium I have worked behind a monitor and keyboard as a programmer for Internet and Intranet systems, using mainly Microsoft technologies.

And I’m not the blogging sort.

The drive for this blog is two-fold:
  • To record coding solutions and deliberations for future reference
  • To alleviate chronic workplace boredom, the unlucky fate of all those who dabble daily in zeros and ones
If this site accomplishes either of the above for you, it has fulfilled its purpose in life.

Feel free to leave your comments, corrections, questions,  insights and other miscellaneous feedback.

Enjoy the ride…