Ray asked a great question a couple weeks ago that I meant to reply to but just never got around to it. He asked why ASP.NET doesn’t include an <asp:query> tag to enable developers to quickly embed SQL queries into an ASP.NET page. The responses seemed to agree with Ray’s assessment that the lack of an <asp:query> tag was shortcoming of ASP.NET, but I think it’s something more than that. If you look closely at the tags (oops! ‘controls’) that Microsoft chose to include in the System.Web.UI.WebControls namespace, you’ll notice that *none* of them give you the ability to declare variables, read a file, query a database, or send email. In fact, all of the controls are about outputting either form components (buttons, drop down lists, checkboxes, etc..) or regular HTML (like images, table cells, table rows, etc.) Microsoft didn’t leave it out because they didn’t have time or money to do it, they left it out because they don’t think you should be writing web applications using tags/controls. Using a code-behind class and controls leaves you with a much cleaner page, one that contains very little, if any scripting code and one where the design is truly separated from the logic. Not one to shy away from an example, compare these two blocks of code that create a drop down list in a form from a query. First in ColdFusion:
<cfquery name="users" datasource="#mydatasource#">
select id,username FROM users
</cfquery>
<select name="userid">
<cfloop query="users">
<cfoutput><option value="#userid#">#username#</option></cfoutput>
</cfloop>
</select>
and then in ASP.NET:
// in code behind class, MyDBWrapper.Query returns a DataSet object
DataSet users = MyDBWrapper.Query("select id, username FROM users");
userid.DataSource = users;
<!--- asp.net page --->
<asp:dropdownlist id="userid" runat="server">
That’s a pretty lame example, but the main takeaway from it is that all of the ASP.NET controls can be manipulated from the code behind class, which is something you cannot do in ColdFusion. You can declare a drop down list in your code behind, bind it to a datasource, modify the selected value, toggle it’s visibility, or modify any of the other 20 or so properties that exist for a drop down list. To me this provides true separation of presentation from logic. Page designers can drop in ASP.NET controls and I can sit in a dark room and modify anything and everything on those controls from my codebehind. You can’t do that in ColdFusion.
Does this mean that ASP.NET is better than ColdFusion? Nope. Notice that I have to create a code behind (technically I could write my code in a <script runat=”server”> block) and that I have to create my own database wrapper class. ASP.NET takes a little bit more work. ColdFusion is much faster to develop in but arguably encourages you to intermingle code with display. ASP.NET takes a bit longer, but developed correctly, encourages you to separate your logic and display code.
Cheers!
AJ, this is a damn good example, and I think I understand the reasoning behind what MS did. However, I will point out that you can easily build a cf_dropdownlist custom tag. The one thing that ASP does offer, it seems, is the automatic “tie” between page A and the code behind class. Would you agree with that? One could argue CF also has the “tie” in that any call to cf_X will run code at X.cfm, outside of your current page.
AJ: I think you’re right on about the separation of presentation and logic being a feature, not a bug. Ever since the EJB 1.1 days, even the ability of JSP to contain arbitrary scriptlets has been considered a huge design mistake by most of the J2EE community. Whether you agree with the forced segregation philosophy or not, it’s certainly the current popular wisdom, at least in the Java camp–and you can be sure the designers of ASP.NET knew it.
Ray: I think the relationship between the code-behind class and the ASP.NET template is more subtle and interesting than you might think. The class generated from the ASP.NET template is derived from (i.e. “extends” in Java-speak) the code-behind class. That doesn’t sound like a big deal, but it means the interaction between the code and the events/data of the page’s controls can often be statically checked by the compiler, which to my knowledge, isn’t really possible in other web development models (certainly not CF which of course is interpreted). So data doesn’t have to be passed from the request data to the logic using structs and scopes; the logic simply sees the controls as members of its class, the same way a traditional GUI app sees UI widgets as class members.
And this is useful not only for getting properties from the controls, but also *setting* properties as well! For example, this will cause a text box’s value to be uppercased:
<!— in page —>
<asp:TextBox id=”department” runat=”server”>
// in code behind
department.Text = department.Text.ToUpper();
The equivalent CF code would be much less direct–you’d have to read the value from the URL/form and “set” it by inlining a default value in the text box’s HTML–and certainly couldn’t be checked at compile time. And as the examples get more complex, I think the advantages of code-behind would only become more evident. (I don’t know, I haven’t written any real ASP.NET apps…)
I’ve always been a fan of the ‘looseness’ & ‘freeformedness’ of the CFQUERY tag. I do a lot of “creative dynamic embedded” SQL and the last thing I want getting in the way is a lot of ” sql = sql + ” ” garbage. I can also run a script or dump the results of another query within my SQL string.
I’d be more likely to switch to JSP/ASP if I could continue developing this way and maintain my productivity.
Now that Verity doesn’t work on my CFMX 6.1 platform and I’m replacing it with Lucene … CFQUERY is my #1 reason for sticking with CF.
You could put your DB code in a custom tag and pass back the query result to a formating page which then simply separates your logic, just like in JSP and or ASP, you could even use a CFC
Just my two cents, CF does work just fine just have to know how to use it, same goes for all languages
If you’re coding your CF with CFCs then your example doesn’t fit. CF can be just as abstracted as .NET. For example:
<!— Get a book object —>
<cfset Book = CreateObject("component", "cfcs.Book").init(URL.bid)>
<!— Get a query —>
<cfinvoke
component="cfcs.Queries"
method="getPhases"
returnvariable="rsPhaseList"></cfinvoke>
<cfform>
<cfselect
name="PhaseIDs"
label="Assigned Phases: "
query="rsPhaseList"
value="PhaseID"
display="PhaseName"
selected="#Book.getPhaseIDs()#"
size="10"
multiple="yes"
></cfselect>
</cfform>
No procedural code at all…
Well, before putting such questions you shoud read a little about the separation between the logic and the persentation. That’s why you will never see an asp:query tag. The database access is to be implemented in the “logic” (code-behind) layer not in the “presentation” (asp.net page).