Here's a fun one for all you LAMP fans out there. I have inherited a PHP/PostgreSQL based website from another company. Scenario:
-
UBuntu Linux 7.02
-
PHP 5
-
PostgreSQL 8.2
-
Apache 2.2
Beautiful setup, works great. Problem. I need PHP 4.4 for this project. I figured, no problem, just revert to PHP 4.4. No go. UBuntu doesn't do PHP 4.X anymore and PHP 5 breaks the code. I figured I would download and compile PHP 4.4. Stonewalled again. Apache 2.2 is not supported by PHP 4.X (or posssibly more accurately, Apache doesn't support PHP 4.X?) So now I have to revert the webserver. I realized that this was getting a little crazy. Since I dual boot my computer with Windows XP, I jumped over the XP, installed PHP 4.4 and PostgreSQL 8.2 had the site up in less than an hour. It was far simpler than trying to deal with Linux and the fact I would have to recompile PHP 4.X (and hope that I didn't miss a required module and have to re-configure / compile / install or get a configuration switch wrong, and other such problems). So I guess you could say I WIPP'd the LAMP. Yes, that's a bad joke, I'm a programmer not a comedian.
On a positive note though, I am quite impressed with Aptana for PHP editing. It is well done and made my work a lot easier. Now if only they could fix Ruby code completion (see previous articles about my adventures with Ruby on Rails). I am also trying to convince the stakeholders in the project that ASP.NET would be a better platform, but that will take time...
I had the pleasure of attending an information session with Bruce Tate, CTO of WellGood LLC, a die hard Ruby on Rails fan, and before that a die hard fan of Spring and Hibernate in the Java World, and before that a die hard Java fan :-) To be fair, Bruce is about doing things quickly and efficiently and I agree Ruby allows you to develop simple websites quickly that are mainly CRUD applications. So I understand why Bruce abandoned the Java world for the Ruby on Rails world, I left the Java world in favor of ASP.NET because of many of the same reasons that Bruce jumped on the Ruby on Rails bandwagon. But there are some things about Ruby to Rails that still bother me.
About 2 years ago, I looked into Ruby on Rails, even learned how to use it (loved the Pragmatic Programmer's books on Ruby and Rails), but it was a pig to host and get up and running on anything other than the infamous http://localhost:3000/ and don't even think about hosting a high volume website at that time. Now, Bruce told us that most websites do not deal with the scale that would require a more powerful platform like ASP.NET, and I agree. But fast foward 2 years to today and I asked Bruce the question "what about hosting?". His response? "That continues to be a thorn in my side.... but I've written a book." Thanks Bruce, I don't want a book, I want an answer. I'm sure it's a good book, but it is still a very telling thing that it is hard to get a good hosting environment. ASP.NET may be "big, bloated, and have a lot of configuration files", but have you seen what Apache magic you have to do to get this RoR thing hosted? Sure Ruby on Rails itself doesn't have a lot of configuration files, but Apache does and so does MySQL (the choice among open source developers). With Windows 2008 server coming down the pipe with IIS 7, configuration is much simpler than it used to be and the fully integrated ASP.NET pipeline makes for a very fast system.
The second question I asked him was about design, there are currently no Ruby specific WYSIWYG systems out there, but you can design your look in Dreamweaver and then edit in the dynamic content. That is how I used to do it with Java / Tapestry, so it's not new to me. But I've gone to ASP.NET and I don't want to give up my WYSIWYG with all the wizards that make my design life easier.
Finally, I asked him to show us an actual Ruby on Rails scaffold. He spent most of the time, granted he had a very short time, praising the Ruby language and ActiveRecord. Both of which I think are great, I wish I had ActiveRecord in ASP.NET. He quickly showed us a scaffold and how it works and I was impressed (especially with the new migration capabilities of ActiveRecord).
So the question is: Are all the great things they are saying about Ruby on Rails really worth switching? I'm sorry Microsoft, but ASP.NET is awesome for complex websites dealing with heterogeneous data sources within a clustered environment where the ability to monitor and manage the application and it's performance is important and where the pages are more complex than a simple data presentation... actually... well done Microsoft!! Being that our company develops for the DotNetNuke platform, and Ruby doesn't have anything approaching a Portal platform with modular components and full membership management and granular security model (asked Bruce he couldn't think of any), we feel that Ruby on Rails answers a particular set of questions / problems that were the blight of the Java world and in same cases of the ASP.NET world as well, and when we do a project from scratch that fits the bill, we will definitely look at Ruby on Rails as a possible solution.
So some people who know me and know Bruce, may be asking "What is Bruce Tate, a big name Ruby on Rails person from Texas, doing in New Brunswick, Canada?" Well, it's simple. A local company switched their whole operation to Ruby on Rails and moved one of the big internet success stories from an ASP platform to Ruby On Rails. PropertyGuys.com, a For-Sale-By-Owner website franchise started here in New Brunswick, moved from ASP to Ruby on Rails. They looked at ASP.NET / C# for their system but found that Ruby on Rails allowed them the speed, flexibility and readability they wanted to quickly and easily prototype their new applications (more or less their words, I paraphrased it).
So do I think PropertyGuys.com was right to make the move? Faced with current technologies, Yes. Wait. Wait. Don't start throwing the rotten vegetables yet. Notice I said, faced with current technologies. Microsoft, despite many people's opinions, hasn't been sticking it's head in sand. They have been working towards Visual Studio 2008, which I think shows a lot of promise in answering the issues that Ruby on Rails raised. So let's look at them:
ActiveRecord
For those of use who have been subjected to DataSets, anything had to be better. I have quite enjoyed developing with NHibernate Object Relational Mapper (ORM) and a visual design environment from Puzzle called ObjectMapper. Since it is open source, I have "hacked" it up to better match my "brand" of development (mainly that it didn't support NHibernate 1.2). It allowed me to define the data model and produce the NHibernate code from the same visual model. It works great, but ActiveRecord and Bruce Tate are right. It's too much. ObjectMapper doesn't do everything I want (and sometimes gets it wrong), so I have to dig into the XML description file and make some changes by hand, recompile the Class Library and restart the application. That is too much work.
ActiveRecord on the other hand, simply looks like this:
class Item < ActiveRecord::Base
end
And you're done. That's all you need for a full fledged ORM. You can do things like Item.find_all_by_name, Item.find_by_id and ActiveRecord interprets (because it's a scripting language) what you mean and runs the SQL to retrieve what you want. You can even say Item.find_all_by_name_and_price, it's that good at understanding what you want. I have to admit that ActiveRecord is a hard act to follow. So how does Microsoft answer the challenge? LINQ.
What I like about LINQ is that fact that I can open a database connection, drag a table onto a form, see it visually along with all it's relationships, and have that generate the code for me. Yes, it's more work than ActiveRecord, no it doesn't have migrations (migrations are a feature of ActiveRecord that allows you to define the versioning of your database and roll forward and backwards based on what you need, adding or deleting columns, indices, whole tables). Yes, migrations are specified in Ruby code and require seperate files and properly named classes (How was I supposed to know that a file named 001_Create_Item_Table.rb should contain a class called CreateItemTable...), but they are a neat idea and make it very easy to upgrade a production database to the current version of the site. Oh, sorry. Back to LINQ. So though LINQ is no ActiveRecord, it is definitely far better than DataSets and probably better than NHibernate in many respects. The fact that you will be able to use LINQ with NHibernate is cool. (LINQ doesn't have any built in caching ability like NHIbernate, at least as far as I know). There is enough stuff out on the web about LINQ, I won't bore you with the details.
Dynamic Language
Ruby as a language is quite cool. It supports continuations, method objects, enclosures, dynamic type system, the ability to extend classes on the fly by adding mixins and new methods. I can't argue with the language. But a lot of the things that are part of Ruby are now in Visual Studio 2008 (except I haven't heard anything about continuations). It has lambda statements, delegates, variable type. The only big thing it lacks is the ability to redefine a class on the fly. And there are many things in the standard Ruby library that I wish were in .NET APIs. But for the most part, Ruby's benefits are being answered in one way or another in C#. Some may say "too little, too late". To those I say "Well, Ruby runs on .NET thanks to IronRuby". Yes, you can run Ruby on .NET. It's not a full implementation yet and it's not as fast as it could be, but it's not done yet. And being that it is fully backed by Microsoft, it will be the best it can be when it's completed. (I know, it is the same company that gave us Windows, but their development department is really quite good.)
Scaffolds
I admit, I like the idea of being able to say "Generate Scaffold Item" and get a complete CRUD system that just works, that is until you change the database and have to regenerate the scaffold.... At least with the GridView in ASP.NET it could dynamically regenerate the Grid (including edit forms) and Details View (so you could insert) based on the underlying database changes. And with the addition of Dynamic Forms to Visual Studio 2008, you get the power of scaffolds and Grid View combined. So Scaffolds are less of an issue compared to Visual Studio 2008.
DRY
Every where I turn with Rails, people are talking about Do not Repeat Yourself. That means "If you do something once, you shouldn't have to redo it again." I actually find that kind of funny coming from a system that doesn't really support componentized development. You generate a scaffold, then have to edit it to make look the way you want, rinse and repeat with every form you need. Yes, you can make reusable components in Rails, but in every place they tell you you can do it, they say "Don't do it!! It's too slow. They are hard to manage." Hmm... I like the fact that I can develop full components and place them into a DLL and simply by referencing the DLL, the components become available for WYSIWYG insertion and configuration. Again, Ruby on Rails answers a particular challenge and answers it very well. But when you don't want to completely rebuild a site every time you get a new project, you might want to look DotNetNuke. With DotNetNuke, we can build a site very quickly, easily, and visually. Yes it probably takes me longer to build a new component, but then the component is fully reusable. Yes, DotNetNuke is a framework on top of ASP.NET, but Rails is a framework as well. So let's just say that DRY is an over used word.
Code completion and compile time error checking
There is one big advantage with Ruby, no compiling. There is one big problem with Ruby, no compiling. When you don't precompile an application, you don't find the logic errors until the line of code is run. When you don't compile, you don't have the benefit of true Code Completion (or at least all the IDEs I've tried don't have code completion that works / works right / actually tries to narrow the options to the selected class!!) Yes, I know that Ruby on Rails comes with a great code coverage tool... but it needs it!! If you don't test every line of code you don't know if you've made stupid mistakes. Yes, I know code coverage is a good idea and that everyone should do it, but if you need code coverage to find semantic errors.... well, let's just say I don't want to look like an idiot when my co-workers run the code coverage tests to find I can't spell :-)
So all in all. If I had to make a choice today, I might choose Ruby on Rails for new development. But for existing development and for projects that fit the portal model, I will definitely stick to DotNetNuke/ASP.NET. When Visual Studio 2008 comes out, I might be less inclined to go for Ruby on Rails.....
Still working on our company website, today I decided to try out the Authentication and Profile Services that are part of the ASP.NET AJAX Extensions. Basically (for those who don't know) the Authentication and Profile Services are a set of Javascript classes (Sys.Services.AuthenticationService and Sys.Services.ProfileService respectively) and some built in web services that are part of the extensions, that allow you to log in with actually have to refresh the page or redirect to a new page (and logout as well, but it redirects and/or refreshes the page after it asynchronously logs out) and access ASP.NET Profile properties (both read and write, more on that in a minute). So basically these services allow you to not have to reload pages to access information and manage your logged in state, which means faster response times and smoother user experiences.
So let's look at how we go about doing this. I will assume that you have started from an already existing ASP.NET AJAX-enabled website. (If not, just start Visual Studio 2005 and select ASP.NET AJAX-Enabled Web Site, if you don't see that option, you probably don't have the ASP.NET AJAX Extensions installed, go here to get them). You will also have to configure your website to use ASP.NET Authentication (I'm not going to cover that here, but you can go here for a good tutorial on Membership, Roles and Profiles (including authentication)).
Ok, let's begin. The first thing you need to do is turn on the services. In your web.config you will find a configuration section called <system.web.extensions> (you can actually search for that, including the brackets.) and within that section you will find two lines <authenticationService enabled="true" requireSSL="true|false"/> and <profileService enabled="true" readAccessProperties="" writeAccessProperties="" />. They are currently commented out. Uncomment them. The next thing you need to do is decide if you want to force your site to have to use SSL for the authentication process (to protect the username and password), if you can use SSL then go ahead and put true in requireSSL, otherwise put false. The next step is decide what properties you want to expose via the profileService. Let me explain this part in a bit more detail.
This is how my profile is defined:
<profile enabled="true">
<properties>
<group name="Address">
<add name="Street1" type="string"/>
<add name="Street2" type="string"/>
<add name="City" type="string"/>
<add name="Province" type="string"/>
<add name="Postal" type="string"/>
<add name="Country" type="string"/>
</group>
<group name="Contact">
<add name="Name" type="string"/>
<add name="Title" type="string"/>
<add name="Phone" type="string"/>
<add name="Cell" type="string"/>
<add name="Fax" type="string"/>
<add name="Website" type="string"/>
</group>
<add name="CompanyName" type="string"/>
</properties>
</profile>
So I decided that I wanted to be able to expose the Contact Name and the Company Name, so I wrote my readAccessProperties attribute like so readAccessProperties="Contact.Name,CompanyName". Notice how I accessed a property group by using dot notation (Contact as you can see above is a property group and Name is a property in the property group). In code, I would access the property via [Page].Profile.Contact.Name. If you want to give write access to Profile properties then place their names in the writeAccessProperties attribute.
The next step is setting up authentication in the page. The first thing I did was put two input boxes on the page and called one username and the other password. Then I placed a button on the form that when clicked would fire a javascript event called Login.
<table id="LoginBox">
<tr>
<td>Username: <input type="text" id="username" /></td>
<td>Password: <input type="text" id="password" /></td>
<td><input type="button" value="Log in" onclick="Login()" /></td>
</tr>
</table>
The next step is writing the login function:
var uid = $get("username").value;var pwd = $get("password").value;
Sys.Services.AuthenticationService.login(uid,pwd,false,null,null,OnLoginCompleted,OnCommunicationFailed, null);
Now we need to write the functions that handle if the login call was successful (not if logging in was successful, that's handled later) or not.
function OnLoginCompleted(isValid,userContext, methodName) {
if (isValid) {
LoadProfile(userContext);
}
else {
alert("Login failed.");
}
}
function OnCommunicationFailed(error, userContext, methodName){ alert("Attempt failed: " + error.get_message());}
Obviously, you can make these functions much more "elegant", but these will do for now. At this point (apart from the LoadProfile method call), you can log someone in and handle a successful login or a bad username/password. And if there is a communication failure with the server, it will call OnCommunicationFailed. Logging someone out is as simple as calling Sys.Services.AuthenticationService.logout(null, null, OnCommunicationFailed, null); If you want to redirect the user to a new page upon successful logout, then replace the first null with the location path. If you leave it as null it will refresh the page upon successful logout.
Profile Service
Now we will look at the profile service, which in my example is where the LoadProfile method call from the Authentication example above comes in. And here it is:
function LoadProfile(){
Sys.Services.ProfileService.load(null, OnProfileLoadCompleted, OnProfileFailed, null);
}
It is farily sipmlye call. What it does is call in the AJAX Extensions embedded web service to retrieve the profile properties that were specified in the web.config file. How these properties are accessed can be seen in the OnProfileLoadCompleted method:
function OnProfileLoadCompleted(numProperties, userContext, methodName){
$get("LoginBox").style.display = "none";
welcomeBox.innerHTML = "Welcome " + Sys.Services.ProfileService.properties.Contact.Name + "<input type='button' value='logout' onclick='LogOut()'>";
__doPostBack('UpdatePanel1', '');
}
As you can see it is very easy to access profile properties as they simply become part of the properties property on the ProfileService object (the second line of the function). Remember though that only the profile properties you specify in the web.config get exposed. The first line of the method above hides the login box. The second line replaces the login box with a welcome message that is personalized with the user's full name. The last line is interesting though. Once you are logged in, you want to display content that is specific to being logged in. How I did that in the website is refresh an AJAX UpdatePanel and that is what this line does. The Postback functionality of ASP.NET gets "hijacked" by the AJAX Extensions so that if an Async trigger (the UpdatePanel Trigger collection defines these) or an UpdatePanel is the target of the Postback, it stops the regular post back and performs an Async callback and reloads the specified UpdatePanel.
And that is basically my experience with Authentication and Profile Services within the AJAX Extensions. Simple, but powerful.
Well, I've been having some fun with AJAX and Flash CS3. Here is the scenario:
I had 4 pages that were all the same basically except for a block of text. Each of these pages had icons indicating short video clips (usually 4 per page). When you clicked these icons, the screen would grey out and a picture of a flat screen TV would come up over the web page and play the video, you could click on the OK button and the video would stop, the TV go away and the web page would go back to normal.
How I accomplished this was simply in the execution, but complex in the JavaScript :-) I simply used the ModalPopupExtender from the AJAX Control Toolkit to grey out the screen and popup the TV (which was simply a picture). In the middle of the TV, I put a Flash object to play the video. When you clicked the icon, two events were fired. The first one showed the Modal Popup, the second event sent a message via Flash's ExternalInterface to the Flash file telling it which video to play. When you clicked the button to close the Modal window, it sent another message to flash (again via the ExternalInterface in flash) to stop playing the video. This way, I didn't have to keep recreating / reloading the Flash file, it simply stayed in the page and starting the video was a fast and seemless process, until I tried to use AJAX, that is.
Like I said, the pages were the same except for a block of text and which videos the icons played. Being that the pages are graphically heavy and take 3-6 seconds to load to begin with, I figured it was a good candidate for AJAX, and it was. The load time for page changes went down to 1-2 seconds. I was quite pleased with myself, I clicked one of the icons, and the ModalPopup worked!! ... but the TV screen was "blank", there was a big hole where the Flash player should have been and Javascript was throwing errors.
The issue was this: When you update a block of text via AJAX that has embedded script tags, the script doesn't run. The way around this is to use the static methods on the ScriptManager class, specifically RegisterClientScriptBlock. The problem with that is that script that Flash CS3 generates to get around the "Click or press spacebar" message relies on inlining the script in the page. (Not the whole script, you make a method call to the function that produces the tags, but it does a document.write to insert the result at the point in the webpage where it was called). So I opened up the Javascript file, found the point in the code where it did the document.write and added a bit of code to replace the innerHTML of a target span (that could be specified as part of the list of parameters to the method). I then placed a span where I wanted the video to appear. I could have gotten around this by placing the asp:Panel that made up the TV outside of the UpdatePanel and it would have worked as is, but that would be too easy :-) Actually, I needed to clear the video between pages (the Audio demos page would end up with the last frame from the previous video showing as the audio demos are audio, not video, and flash has a glitch in it that I could not clear the last frame from the previous video without without running a new video or reloading the page).
It may not sound like much. But if you are not used to working with the strangeness that is embedded Javascript and AJAX UpdatePanels (not to mention that Flash itself is a little goofy). Actually, let me explain that statement. There is an issue in Flash CS3 where under Internet Explorer, the variable used to reference the Flash object doesn't get assigned (it has to do with the fact that when you create an element with an ID within a form, instead of creating a reference to it in the window object (ie. window.NewPortfolio), it creates it within the form only (ie. document.forms[0].NewPortfolio)). In my webpage, the Flash file is called NewPortfolio.swf, so I use an ID of NewPortfolio for the Flash object. You need to know this ID name because you access the Flash ExternalInterface's methods by simply (in this case) saying NewPortfolio.playVideo([path to swf]), very much like PageMethods in AJAX Extensions. So if the variable didn't get created in the correct place (on the window object), you get a ton of Javascript errors. The way around this is right after you make the call to the Javascript that Adobe provides for inserting the Flash object, write a line like this:
NewPortfolio = document.NewPortfolio
And everything goes back to working the way it's supposed to. (To make matters even more weird, under certain circumstances you have to write "<form></form>" right inside your <form runat="server"> tag to make Flash work right as well. I've managed to get around that by rewriting some of my HTML (what precisely I did, I can't remember. That "fix" was several months ago) and as outlined above. So I think that Adobe should really look at fixing this problem before in the next release of Flash (or maybe it's Microsoft's "problem", I never know who to blame :-)
For more information see:
ScriptManager.RegisterClientScriptBlock
The Oddness of IE / Flash
Good day ladies and gentlemen. Welcome to today's meeting of Programmers Anonymous where we seek to help those who are addicted to programming. My name is Adam Greene, and I am a programmer. Hello Adam.
Doesn't it feel at times like we like our work a little too much?? Maybe we are addicted to programming? I'm not sure, but I know I'm really digging ASP.NET and all the other cool Microsoft technologies.
Let me back up for a minute and introduce myself. My name is Adam Greene (which you already know), and I am the Lead Developer at Trimedia Atlantic Inc (which you probably didn't know). Trimedia does everything from Video and Audio for television to Print management. Basically we are a marketing company without the marketing part :-) My job here is to help move our clients from traditional medias to "New Media". What is new media, you ask? Good question. It is really just a buzz word. It means "take what you have always done and do it in a new way / medium". For us, it means moving our clients away from normal websites to what we call "Advanced Web Systems". Our goal is to help our clients leverage their websites to increase their customer interaction, retention, and satisfaction through Web 2.0 technologies and Rich Internet Experience technologies. Our technology of choice to that end is Microsoft ASP.NET, Silverlight, and Windows Presentation Framework. Basically all things Microsoft.
The purpose of this blog will be to catalog my adventures in New Media and how we apply Microsoft technologies to our day to day development challenges. I will also talk about Web 2.0 technologies in general, which will mean at times I will be talking about, dare I say it .... non-Microsoft technologies. The reason for this is that my other day job is "Media Programming Instructor" at McKenzie College. In the Media Programming course we will be teaching the students how to develop web games from start to finish in Flash CS3 / ActionScript 3.0 (along with basic E-Commerce, you can't make a penny at web games unless you have a website to put them in). We will also be teaching them PHP and MySQL (I know, I know. I tried to get them to teach MSSQL and ASP.NET, but being an "arts" college, they use Apple computers and are an Adobe licensed training center). If someone offered to give them the same deal (hint, hint) on Intel / Microsoft, I'm sure I could convince them to go for it.
More Posts