# Wednesday, January 20, 2010

Deploying the minimum Oracle Instant Client files with ODP.NET

If you're looking for the smallest and least hassle deployment of Oracle client files with a .NET application, then forget about everything else you've been told - the following did the trick for me, and involves just 5 Oracle dll's.

Deploying ODP.NET with Oracle Instant client

One thing I found with this was that on my dev machine I already have (more than) one 'standard' Oracle installation and all the network config from that was really getting in the way meaning I couldn't connect for one reason or another - OR I was connecting, but not using the correct client, meaning deployed files wouldn't work on a 'virgin' machine.  All of this rather depends on how your company deploys Oracle server and clients I guess.

Rather than muck about with setting environment variables (that's so 80's) if you use a full connection string syntax as follows you can use your hostname and SID rather than try and fathom out service names. 

In your web.config

  <add name="MyDB" connectionString="Data Source=(DESCRIPTION = (ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = machinename)(PORT = 1521)))(CONNECT_DATA =(SID = mysid)));User Id=username;Password=password;" providerName="" />

Any other variation of the (mucho confusing) Oracle connection syntax just didn't work for me.

As an aside - I also kept getting System.OutOfMemoryException when building a web site project in Visual Studio 2008 when I was using the Oracle Basic client dll's (110mb +).  I switched to the smaller Basic 'Lite' versions and it was happy again.  I guess a single file of over 100mb blows the lid off the IDE.


posted on Wednesday, January 20, 2010 4:14:52 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Monday, June 15, 2009

Using JQuery with DotNetNuke 4.x

I'm currently doing a project using DotNetNuke, and we're using JQuery plugins to achieve certain content rotation and scroller functionality.  All was 'amost' good as I'd found a way to inject the JQuery script to the page header on a per-skin basis, but in 'edit' mode the actions button wasn't showing up at the top of containers in FireFox and was causing JavaScript errors in IE.

I'd already gone through the hoops of declaring jQuery.noConflict(), but it still appeared to be conflicting with the dnn:actions (solpartactions) control.  I'd read somewhere else about Solpart code being incompatible with JQuery.

I tried one last thing, adding the noConflict() call in the JQuery library script file itself - rather than running as a fragment on page load.  This fixed everything, as something else was obviously getting in and hijacking in the meantime.  Apparently with V5 this will all be fixed as JQuery's more integrated with the framework.  Anyway, for those interested here's what I had to do to get JQuery (and associated plugins) talking nicely whilst still allowing the actions menu to pop up on my containers...

  1. Amend the JQuery library (jquery.1.x.x.min.js) by adding the following line at the bottom...

    jQuery.noConflict();

  2. Amend the skin you want to load the jquery library (and plugins) in (we've got it only in specific skins to avoid the overhead where it's not required).  You could also do this in the module by checking 'if loaded', but here's the code for a skin (in ascx file)...

    <script runat="server">
        Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
            'add a script reference for Javascript to the head section
            AddScript("/js/jquery.scrollable-1.0.2.min.js")
            AddScript("/js/jquery.mousewheel.js")
            AddScript("/js/jquery-1.3.2.min.js")
        End Sub
       
        Private Sub AddScript(ByVal fileName As String)
            Dim oLink As New HtmlGenericControl("script")
            oLink.Attributes("language") = "javascript"
            oLink.Attributes("type") = "text/javascript"
            oLink.Attributes("src") = fileName
            Dim oCSS As Control = Me.Page.FindControl("CSS")
            If Not oCSS Is Nothing Then
                oCSS.Controls.AddAt(0, oLink)
            End If
        End Sub
    </script>


    The order is important, as we're adding the scripts to the 'top' of the scripts each time.  JQuery needs to be the first referenced.
  3. Make sure that anywhere you use jQuery you use the jQuery(xx) syntax, and not $(xx).
That's it.

posted on Monday, June 15, 2009 3:41:01 PM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Monday, March 16, 2009

ASP.NET Data Binding - Accessing a parent data item from within a nested repeater

I'm maintaining an app at the moment that uses quite a few nested repeaters, and found that headers were being output when there was no data present.  It was found that the header was being written in the ItemTemplate of an 'outer' repeater, rather than as the HeaderTemplate of the 'inner' repeater.  The next problem was how to reference the outer repeater from the 'inner' HeaderTemplate...

The following will bind to a field called HeaderDescription.

<%# DataBinder.Eval(Container.Parent.Parent, "DataItem.HeaderDescription") %>

The parent of the inner item is it's repeater, so you have to go to it's parent to get the right RepeaterItem.  Why don't you just do the following you ask?

<%# DataBinder.Eval(Container.Parent.Parent.DataItem, "HeaderDescription") %>

..'cos it doesn't work - The Eval method expects a 'Control' as its first parameter.  There's other ways to do this server-side, but the first option is probably the easiest.

To complete the picture and only show when there's data you can add the following to the 'inner' repeater declaration

OnItemDataBound="ItemDataBound" Visible="false"

then..

        protected void ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Item)
            {
                if (!e.Item.Parent.Visible)
                    e.Item.Parent.Visible = true;
            }

        }


This will ensure that you'll only show if you've bound a 'data' item (remember you're doing binding in the HeaderTemplate too).  You could also hook similar things into other events, but it's generally more convenient to put these things into events that relate to the actual control (pre_render's probably another good candidate as it will only get called once and you can check the count in the DataSource).


Technorati Profile
posted on Monday, March 16, 2009 10:28:27 AM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Thursday, November 20, 2008

Removing references to HttpModules from ASP.NET SubFolders in web.config

If you have ASP.NET applications that live as subfolders of a larger site, you may find yourself with issues when it tries to find assemblies and httpmodules that are referenced in the parent's web.config.

Fortunately this is something you can work around.  Matthew Nolton goes through how you 'remove' these references at the subfolder level using the <remove> element.

This is all fine until you get an even tastier situation like I encountered the other day...

ASP.NET application 'A' lives as subfolder 'B' of both parent site 'C' and 'D'.  The configuration of 'C' and 'D' is slightly different (modules, handlers, assemblies etc).  Why is this a problem you ask?  We were trying to be a bit clever (and failed :) ) by only deploying application 'A' once.  Virtual directories in site 'C' and 'D' both point to the same physical 'A' folder.  This effectively means that the stuff that needs to be removed from 'A' varies depending on which parent site you're accessing.

OK - I could just fix this by duplicating the installation, and varying the configuration but....

You can also remove all modules by adding a 'clear' element as follows...

<httpModules>
     <clear/>
</httpModules>


This is fine, BUT if you're using Session State or any other in-built features that are implemented as httpModules then you'll get exceptions as ASP.NET will give you a 'null' session for instance.

The following is probably a safe list of modules you'd normally need (maybe even only the session for simple apps), so just add them back in after the 'clear'....

<httpModules>
     <clear/>
     <add name="OutputCache" type="System.Web.Caching.OutputCacheModule"/>
     <add name="Session" type="System.Web.SessionState.SessionStateModule"/>
     <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule"/>
     <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule"/>
</httpModules>


This is nicer for a couple of reasons
  1. It shows what dependencies the application has on ASP.NET/external features, and...
  2. It gives you the power back to have the application consumed by multiple sites as you've effectively decoupled yourself from the parent's dependencies.

posted on Thursday, November 20, 2008 3:07:59 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Thursday, October 09, 2008

Serving SSL from localhost on IIS 5 on Windows XP using Self-Signed certificates

I've probably glossed past this a few times, but it turns out getting SSL working on your dev machine is less painful than you'd think...

  1. install iis60rkt.exe from http://www.microsoft.com/downloads/details.aspx?FamilyID=56fc92ee-a71a-4c73-b628-ade629c89499&DisplayLang=en on your local machine. It's intended for IIS 6.0 but it works in IIS 5.1.
  2. Select custom install if you only want to use SelfSSL. Otherwise, install all.There's a lot of other useful stuff there.
  3. Select Programs --> IIS Resources --> SelfSSL --> SelfSSL command prompt
  4. In the command prompt, you'll see a list of all possible command parameters..
    1. Type 'selfssl.exe /V:60'     This indicates the certificate is valid for 60 days
    2. Type Y to answer the question "Do you want to replace the SSL settings for site 1 (default website) ?
    3. Type 'iisreset' to restart IIS.
If your browser prompts something like 'Certification Authority not recognised' (in Firefox), just put the url in the exception list or override the warnings when viewing the page.

Thanks to Ricky for getting this info together.

posted on Thursday, October 09, 2008 9:56:33 AM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Monday, September 29, 2008

More reasons to love JQuery

I've only recently started using JQuery, but needless to say - it rocks!

for those that don't know it's a Javascript library that's basically revolutionising how you write client-side code.  My reasons to love JQuery.

  1. It's open source, well tested and an open design.  This means you write less code and you can rely on functionality just 'working' in different browsers - or gracefully failing if something's not right.
  2. It's really light (especially when 'packed' - 31kb)
  3. It's got a strong community with lots of really cool plugins (just take a look before you start developing that 'widget' in flash)
  4. It plays well with other libraries and code.  you just use it for what you need and plugins sit with other plugins.
  5. It's obviously gaining momentum, as Scott Hansleman announced Microsoft are going to ship it with ASP.NET MVC and Visual Studio (that's a pretty amazing move from Microsoft).
If you're just getting started with it, and you're familiar with Javascript already I'd start with the tutorials.  Some are better than others, but run through the first couple to understand how it works, then scan down the list to find something related to what you need to do.  Typically you'll be wanting to write a plugin, so I found this one quite good for starters.

You should find everything you need in the Documentation

you'll then spend most of your time in the API section, looking for specifics on how to do things. 

posted on Monday, September 29, 2008 11:21:34 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Friday, August 15, 2008

Issues with data binding, Typed Datasets, DataRows and Null Values

Had some fun this morning as we're trying to get a simple framework set up for a web app, that others can understand, using out-of-the-box functionality if possible.  I tried to avoid the normal tendency to put the 'architecture hat' on and overcook it.  If you can't be bothered to read all of this then just scroll to the bottom for the 'take home' on binding against typed datasets with null values.

We started off the prototype with a typed Dataset (including a couple of DB tables, and key relationships between each), a table adapter for each table, and a DetailsView at the front end, bound to an objectdatasource, which in turn talks to a business object that calls the TableAdapter.  That's a lot for one sentence so from top to bottom...

DetailsView --> ObjectDataSource --> BusinessService --> TableAdapter --> Database

This all sounds pretty straightforward, and it is - unless (as in this case) you decide to have your business object pass back a single (strongly typed) DataRow for your front end to bind against.  This seemed reasonable at the time because I only ever want to show one row here.

You'll basically get a StrongTypingException for every null field you try and bind, because by default a null field value will raise an exception when accessed through its generated property. 

We got distracted for a while exploring this as the natural tendency is to think 'ah - I'll make sure it doesn't raise the exception' - treating the symptom rather than the cause.

It turns out that any non-string field in a typed dataset table can't have a default of null (or anything other than 'raise exception').  If you stuff in a _null value directly in the XSD your fields will disappear from the public properties (rather curiously) when you compile - so that's not an 'enterprise' option.

I tried changing the return type in my business method to a generic DataRow to try and force the data binding to NOT use the strongly typed properties (getting warmer but still no dice.  I knew I was missing something really simple...

I then stumbled across a post (bottom of the page) that illustrated databinding will use different methods to bind based on what interfaces it finds.  The binding mechanism basically has no choice but to use the strongly typed public properties on a strongly typed or generic DataRow, as there's no way for it to successfully enumerate the values.  If you bind against almost anything else you'll most likely have no issues (it appears the databinding doesn't rely solely on ITypedList).  We're now binding against a typed DataTable (rather than generic DataView) and all's fine.  If you want (rather) more info on ITypedList then look here.

So...

Don't databind against a typed (or untyped) DataRow!

posted on Friday, August 15, 2008 1:45:43 PM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [1]
# Friday, July 04, 2008

Invalid Postback or Callback Argument - ASP.NET. One cause

Just been getting this error.  It's quite common, especially if you're using Ajax.  I got the error for an altogether more 'schoolboy error' reason.

I had a textbox control e.g. called 'customerName', and two radio buttons controlling whether to show the customer name.  These had a 'GroupName' of customerName, and this caused the error.  You need the GroupName to associate the radio buttons together, but the postback mechanism obviously sees that as the control identifier.  Silly boy. 

The naming was pretty bad in any case and actually prompted me to take more of a long hard look at the UI to tidy it up so no such conflict would arise.

posted on Friday, July 04, 2008 4:21:22 PM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Wednesday, July 02, 2008

ASP.NET - The name xxx does not exist in the current context

I recently converted a Web Site to a Web Application project, and as it had been a while I tripped up on a few things. 

First of all I made the mistake of creating a new Web Application and pasting all the web files in there (I was intending to split some of the site into another Class Library), and I wanted to port to another file structure.  I mistakenly thought it would be easier to do this 'before' changing to the WAP.

I then of course got a gazillion compiler errors (well - 1436 to be exact) on the new project.  The vast majority of which were 'The name xxx does not exist in the current context'.  Yes it does! (I protested).  Well.  That showed mistake number 2.

If you want to convert then use the 'Convert to Web Application' option on the Web Site properties (or on the individual pages if necessary).  This does a number of things:
  1. Sorts out your project structure
  2. Changes 'CodeFile' to 'CodeBehind' and other directives
  3. Adds a designer file for pages and controls
  4. Other stuff that you shouldn't bother yourself with etc...
The compiler errors were due to the fact that the WAP model expects pages to be structured in a certain way, and although the 'code' looks fine (and Resharper was green all the way) it won't compile 'cos the designer files are missing and hence so are the definitions the compiler's looking for.

See Steven Smith's post on some other tips for converting projects.

posted on Wednesday, July 02, 2008 11:07:48 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Thursday, June 19, 2008

Developer Highway Code - Building secure software with .NET

Had some security training yesterday (don't normally get training as a contractor so I was very happy to go along). 

The trainer mentioned the Developer Highway Code from Microsoft (seemingly originating from the UK based on the style of the publication).  Not only does it look cool, and have some rather amusing geek stuff (just see the 'Reduce Coffee Now' sign on the cover), it also has some really practical advice for people wanting to build secure applications.

Download it from Microsoft

posted on Thursday, June 19, 2008 10:23:35 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Wednesday, June 04, 2008

When is XHTML not XHTML?

Well you may think it's just a matter of rendering some well-formed markup and setting your doctype...

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

right?  Wrong!

Different browsers render in different ways.  What's common however is that unless your response's content type is "application/xhtml+xml" then you may not pass go and pick up $200.  You can force the browser to recognise the content type in two ways (in addition to the DOCTYPE declaration above):

  1. Name your file with an .xhtml extension (not really a solution as IE says 'what?')
  2. Set Response.ContentType = "application/xhtml+xml" (See here for more info)

The DOCTYPE is really an additional information item and not something modern browsers do much with on its own.  So how different are the browsers'  XHTML implementations?

Internet Explorer for instance takes the 'all comers' approach and will do the best it can given the markup, whilst degrading gracefully if it encounters errors.  great! I hear you say - saves me from actually testing this thing!

Firefox on the other hand will use a completely different parser once it knows you want to serve well-formed markup.  The good thing about this is that you immediately see any errors and the page won't render if there's invalid markup.  IE meanwhile continues to let you believe you're an XHTML master (note: it doesn't recognise the xhtml extension).

Firefox has some good resources about supported features.  A common one that catches people out is Javascript's document.write.  This isn't allowed in XHTML as the string input can't be guaranteed to be valid XML. 

Safari's not quite as advanced yet as Firefox's support, but it too will properly validate your markup and report errors.

If you really want to stick your neck out then place a link on your site to validate against the W3C's standards.  You're likely to get plenty of errors - like this page!

Other things to watch out for are Content Management systems that allow you to enter non-compliant html in text editors, and simply not having JavaScript blocks in CDATA sections).

 

posted on Wednesday, June 04, 2008 10:43:12 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Thursday, May 22, 2008

Getting the most out of ASP.NET Web Deployment Projects

In my ongoing love (but mostly) hate relationship with ASP.NET Web 'Site's' I've been using Web Deployment projects to make things more bearable. 

I currently swap in connection strings from 3 files - one for each build configuration (debug, test, release - connectionstrings.debug.config etc ).  This works fine as per the doco on WDP.  I use CruiseControl.NET and NAnt to automate builds, and a few nagging 'automated' pieces were missing from the puzzle. 

  1. Encryption of connectionStrings (or other web.config sections that you want to protect) - without affecting the 'source' file.  I've assumed here that 'internal' people are trusted. 
  2. Changing of other config stuff (like debug=false) in the test and release builds.  (My attempts to get this to work had previously failed as you don't seem to be able to specify system.web as a replaceable section.
  3. Encrypting Forms authentication passwords, using MD5 hash.  This isn't difficult, I just didn't have a tool to generate the hash value.

Encryption of config sections

OK - after re-reading Scott Gu's post on Web Deployment Projects, and K. Scott Allen's post on how to simply encrypt sections of config files, I realised that I could just add a post-build event (manually) in the wdproj file (right-click in solution explorer --> open project file). 

The build events are already in but commented at the bottom of the file.  I ended up with

<Target Name="AfterBuild">
<Exec WorkingDirectory="$(OutputPath)" 
Command="C:\windows\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis -pef connectionStrings ."
/>
<!-- Also remove our 'source' config files using the del command rather than the delete task as you
have to jump through hoops to specify wildcards -->
<Exec WorkingDirectory="$(OutputPath)" Command="del compilation*.config" />
<Exec WorkingDirectory="$(OutputPath)" Command="del connectionstrings*.config" />

</Target>

If I put this anywhere other than 'AfterBuild' it didn't seem to do anything.  I certainly learnt a bit more about aspnet_regiis, as I'd only used it previously to 'install' ASP.NET.  I also had to specify the path to aspnet_regiis, but you could obviously use a property for this (I'm new to MSBuild - only dipping in when I have to, so the framework path may already be a standard property?).

Replacement of system.web sections

The key thing here (which I don't believe was documented very well anywhere) is how to replace system.web elements.  Other typical replacements - e.g. appSettings or connectionStrings are children of the root config element.  You'd therefore assume that you need to replace the whole of system.web (which is a little inconvenient - but still worth it).  This doesn't work and you'll get a 'nice' WDP00002 error saying it can't find the system.web element (a bit like saying 'can't find printer' when it's right next to the computer!). 

You just have to go one level down as follows (in the Deployment --> Web.config file section replacements property page):

system.web/compilation=compilation.release.config

compilation.release.config may be as simple as...

<compilation debug="false"></compilation>

You might have a warning saying 'compilation' isn't a valid element, but this is just the intellisense barking as it validates against the config schema.

Encrypting Forms Authentication Passwords

This is pretty simple and there's lots of docs to support this, but I wanted a simple tool to generate the hash for a given string, and a quick google yielded a nice little command-line tool...

This way you can plug it into your build if you need to, but also replace for different environments using the techniques above.


posted on Thursday, May 22, 2008 9:57:27 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Monday, April 21, 2008

ASP.NET Web Site Project (WSP) vs Web Application Project (WAP)

ASP.NET 2.0 originally came without support for the 'traditional' Web Application project that everyone had become familiar with in ASP.NET 1/1.1.  Some people liked the new approach as it affords more 'on-the-fly' updates, but obviously enough people 'didn't' for Microsoft to release a patch for Visual Studio .NET 2005 to allow creation of WAP's.  The support was then formally re-added in VS 2005 SP1 (making the original patch redundant).

Info on the situation can be found here.

This post (as well as saving the links for me) is also a reminder of the limitations of the Web 'Site' model (hereafter known as WSP) and why I choose not to use it.

  • Namespaces.  WSP does not explicitly add a namespace to any page, class etc.  It uses 'special folders' with some implied names (e.g. App_Code) to determine the namespace hierarchy.  This whole situation can also lead to strange 'circular reference' errors with user controls - especially after converting from VS 2003.  At the very least you'll be pulling your hair out wondering why you can't reference some page or control from somewhere else in your site.
  • Code Reuse.  Only code in the App_Code folder (and below) can actually be referenced by another class in the project.  This forces a structure that you wouldn't otherwise choose.  You can of course create separate assemblies - and should in many cases.
  • Unit Testing support in VS 2005.  WSP does not build to a single assembly when built in VS 2005, and must be 'precompiled' using a Web Deployment Project which in turn uses the asp_merge (publish) utility in order to achieve this.  The standard publish function doesn't support a single assembly, although it's possible to get the App_Code into a single DLL. This all means that because you don't have an output at build time, you can't run unit tests in the WSP - regardless of how much code you're 'reusing' in the App_Code project.  You can jump through some hoops to call the NUnit Console runner, but why bother!?   
  • Included/Excluded files.  Because WSP doesn't have the concept of a project file to say what's 'in' and what's 'out', VS 2005 uses a rather nasty 'rename' method of excluding files - simply suffixing the file with .exclude to denote it should be disregarded.
  • References are actually just copied in.  If you create a reference to an external assembly, VS 2005 will actually just copy the file into your bin folder.  This means you'll end up putting all sorts of binaries in your source tree (under source control), that you maybe otherwise wouldn't
  • Automated Build.  NAnt and other automated build tools can't work out whether a Web Site project is some sort of 'enterprise template' project, or a tub of lard - because it's not really a project.  This means that you can't use the <solution> task with NAnt.  you have to call a custom <exec> task instead, calling the asp_merge.exe tool, then call all other projects separately too.  This all works, but again, why bother?  A cynic might conclude MS was trying to cause issues for NAnt, whilst getting people interested in MSBuild.

For me, any change that introduces new 'non-standard' tools, just so you can have the convenience of 'on-the-fly' updates just isn't worth it.  You'll actually find that this all goes out the window when you deploy to a server anyway, because depending on how you ran asp_merge, you probably won't be able to do any 'real' updates because the assembly names are generated in that process and you'll break the site by changing source files.  In my opinion if you are using this approach then use the Web Deployment project and build to a single assembly to minimse these issues.  If you've got any sort of structure around your production deployments (and you can't just 'copy over') then I see literally no advantage in the WSP model, as it just seems to provide too much pain for no visible gain.

posted on Monday, April 21, 2008 12:09:18 PM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Wednesday, April 16, 2008

ASP.NET Open Source Content Management Systems - The Winner

Well, it's been a little while since I first talked about Content Management Systems, but I can declare that

mojoPortal is the one for me.

There's a number of reasons, but I'll go through the main pro's than means it wins out over DotNetNuke

  1. It's XHtml compliant out of the box, and has minimal use of tables.  All the people producing skins for MojoPortal are also well evolved along the accessibility curve too.
  2. It uses standard .NET features.  This is due in no small part I'm sure to the fact that it started after DNN and more facilities were around in ASP.NET at the time.  This means that Skins, Themes, Master pages are all present and correct with MojoPortal, rather than the proprietary (but well documented) skins in DNN.
  3. It seems to be quick(er than DNN)
  4. The facilities are stable and work very nicely.  There are less modules, but the developer video tutorials are a really good way to get yourself into developing your own modules and edit pages.
  5. You can get involved and work with the code - after downloading from SVN (I fixed a small bug and felt really good about it!)
  6. Finally - and this is an easy clincher - the support for the product is just fantastic.  Joe Audette is like a man possessed on the forums, and you're likely to get a really well thought out answer to any query within a few hours (depending on the time zone!).  He's sorted me out on a few occasions and set me along the righteous path. 

In summary, mojoPortal is something I'm happy to be using for a client as I'm more keen to use standard .NET features than proprietary skinning.  I also like the philosophy more of the development community, and how Joe Audette's running the project

posted on Wednesday, April 16, 2008 5:10:30 PM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Tuesday, April 01, 2008

VB.NET - I know I shouldn't care but I just don't like it!

Aaargh! I thought to myself for the umpteenth time as I looked through my inherited VB.NET web site (it's bad enough that it was a web 'site' with dodgy auto-generated (i.e. NO) namespaces), but the following things are now officially going on my list of reasons I choose C# over VB.NET.  I know I shouldn't care as it all compiles to the same thing, but (just from this project) -

  • VB.NET still allows you to dodge the Option Strict and Option Explicit (definitely a 'Web Site', as there's no option in the property pages like for any other standard .NET project).  This means that you happily declare untyped variables, and do all sorts of dodgy late binding.  Some people obviously like this facility, but it's one of the things that holds VB programmers back in the world of object-oriented design.
  • Modules still exist!  OK you could argue this is just a public class with everything marked as static, but it's still 'global', and you don't need to reference the module name when you access a method or variable.  This often leads to the 'where the hell is that defined?' question
  • Variants still exist.  This is obviously an extension of the first one, but it's a big enough annoyance that people use to get themselves out of a (I don't know how to implement this properly using object-oriented techniques) hole
  • Syntax 'feel' - e.g. Me vs this, and MyBase vs base - it feels a bit 'Mickey Mouse'.
  • Verbose syntax causing RSI:
    • #Region "String Constant" vs #region whatever you like without having to put quotes around (C# regions can also be indented with the code unlike VB)
    • Global functions instead of operators like TryCast instead of 'as', CType instead of (Mytype)variable.  CStr, Cint etc still exist.  Not only is this more typing in many cases as you need to enter two or more parameters, it also feels like yet more 'baggage' from the bad old days, as you can still pass in your objects to generic 'library' functions rather than use methods on the object themselves (like ToString()).  Many VB programmers will lap this up because the language still allows them and they don't have to learn something new.
  • Case insensitivity.  OK I'll give you this one as it was one of the 'speed' things in VB6.  It does lead you back to the horrible pseudo-hungarian thing (for some people) though as you get naming conflicts with properties and variables if you follow the general pascal/camel C# standard (can't remember whether there's an option to switch that off though).  The alternative to the pseudo-hungarian notation is the _ prefix for class variables, but even that seems like too much of a concession.
  • Methods can still look like properties.  Call a method in VB without parameters and it will happily let you write MyMethod.  This just feels like inconsistency.
  • Tool support and productivity. 
    • VB.NET simply doesn't have the same support in Visual Studio or refactoring addins (ReSharper's only catching on to VB.NET now) This isn't the language's fault, but it's easier to be more productive through tools with C#.  (I know this is improved with every release of VS).
    • The default VS 2005 refactoring capability (limited but present in some form) for C# is basically non-existent for VB.NET.  Maybe Microsoft think VB programmers don't need refactoring support?
    • Intellisense is also generally rather lacking for VB.NET
    • XML Documentation comments (just now catching up, but was really lacking)
  • Angle brackets <> look uglier than square brackets [] for attributes (OK that's a bit picky!)

The bottom line is that VB.NET lets you be sloppy, like VB always did.  The problem is that a fair percentage of those who migrate from VB to VB.NET (not all I agree - don't shoot me!) take the same shortcuts that they always did - because they still can.  

My opinion is that on average you'll find more elegant design, better formatted and more object-oriented code from C# programmers as they're more likely to have come from a C++ or Java background.

Did I mention that I was a VB programmer for years, and have only dabbled a bit in Java and not really ever C++.  I loved VB6 (at the time) as I could get systems written quickly and well.  What I didn't love was how much backwards-compatible support it kept leaving in with each new version, just so people could upgrade their crap legacy code.  I've seen some very clear, consistent, well formatted and commented VB.NET code, but I've seen an awful lot more that's not.  The flip side is that C# coders often think they're great just because they're writing in C#.  I've seen plenty of horror stories there too, but the 'bad' percentage is much lower (sorry - it just is).

VB unfortunately doesn't encourage discipline in programmers, whereas C# benefits from a clean slate without the historical baggage.  I believe the slightly more formal language specification of C#, and the fact it attracts more 'OO' coders, tends to lead people to think a little more about design rather than just skipping straight to implementation (which is where the 'real' problem is :-) ).  You can write the same crap code in any language you like.  VB unfortunately just makes it easier.

posted on Tuesday, April 01, 2008 5:16:51 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Thursday, March 13, 2008

ASP.NET Extender Control for Expiring Content

I recently had a specific requirement to 'expire' some content on a web site.  There's a million ways to do this, but my previous use of ExtenderControl in Windows Forms development sparked my interest when I noticed the Ajax toolkit supports this (mainly for client-side functionality). 

After downloading System.Web.Extensions, and about half an hour later I'd got the 'ExpiringExtender' Control that can be added to your ASP.NET (2.0+) page to allow content to phase in or out. 

The only down side to this approach is that your source code becomes littered with expired code like the Earth's orbit does with old satellites!  This was therefore a quick solution to a specific problem - not an approach I'd advocate if this is a core requirement (you need a good Content Management System with built-in scheduling).

Anyway - here's the class (chuck it into your App_Code folder if you're using a Web Site project - as in my example).  The code's pretty simple - just set a couple of properties (defaulting to min and max dates if not supplied) and the control's visible property gets set appropriately.

using System;
using 
System.Web;
using 
System.Web.UI;
using 
System.Web.UI.WebControls;


namespace 
CodeBureau.WebControls
{


    
/// <summary>
    /// This control works as a simple Extender to any server or html control to allow crude time-based 
    /// show-hide functionality.  NOTE This requires the Ajax Toolkit.
    /// </summary>
    
[TargetControlType(typeof(Control))]
    
public class ExpiringExtender : ExtenderControl
    {

        
#region Private Attributes

        
private DateTime showFrom DateTime.MinValue;
        private 
DateTime showTo DateTime.MaxValue;

        #endregion

        #region
 Public Attributes

        
/// <summary>
        /// Gets or sets the show from date.  This indicates that the control should be visible from this date/time
        /// </summary>
        /// <value>The show from.</value>
        
public DateTime ShowFrom
        {
            
get return this.showFrom}
            
set this.showFrom = value; }
        }

        
/// <summary>
        /// Gets or sets the show to date.  This indicates that the control should be visible to this date/time
        /// </summary>
        /// <value>The show to.</value>
        
public DateTime ShowTo
        {
            
get return this.showTo}
            
set this.showTo = value; }
        }

        
#endregion

        #region
 Event Handlers

        
/// <summary>
        /// Raises the <see cref="E:PreRender"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        
protected override void OnPreRender(EventArgs e)
        {
            
base.OnPreRender(e);

            
Control control FindControl(this.Page, this.TargetControlID);
            if 
(control != null)
            {
                DateTime now 
DateTime.Now;
                if 
(now < showFrom || now > showTo)
                {
                    control.Visible 
= false;
                
}
            }

        }

        
#endregion        

        
/// <summary>
        /// Gets the script descriptors.
        /// </summary>
        /// <param name="targetControl">The target control.</param>
        /// <returns></returns>
        
protected override System.Collections.Generic.IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl)
        {
            
return null;
        
}

        
/// <summary>
        /// Gets the script references.
        /// </summary>
        /// <returns></returns>
        
protected override System.Collections.Generic.IEnumerable<ScriptReference> GetScriptReferences()
        {
            
return null;
        
}

        
/// <summary>
        /// Finds the given control (recursively).
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="id">The id.</param>
        /// <returns>the control if found (else null)</returns>
        
private Control FindControl(Control parent, string id)
        {
            Control recurse
;
            if 
(parent.ID == id)
            {
                
return parent;
            
}

            
foreach (Control child in parent.Controls)
            {
                recurse 
FindControl(child, id);
                if 
(recurse != null)
                {
                    
return recurse;
                
}
            }
            
return null;
        
}

    }

}


Colorized by: CarlosAg.CodeColorizer

And to use it in a page (I've got it within a master page here) you just add the registration for the extender control (note the Assembly="App_Code" - I had to google for a while to find that.

You also have to add the ScriptManager control (an Ajax requirement), then just make sure the content you want to phase in or out has runat="server" (it should work for HTML or Server controls).

<%@ Register Assembly="App_Code" Namespace="Coles.WebControls"  TagPrefix="uc1" %>


<asp:Content ID="Content2" ContentPlaceHolderID="body" Runat="Server">
<asp:ScriptManager id="ScriptManager1" runat="server"></asp:ScriptManager>
    
<uc1:ExpiringExtender runat="server" ID="a" TargetControlID="header" ShowTo="13 March 2008 16:15:00"></uc1:ExpiringExtender>

<h1 id="header" runat="server">Hey - I turn into a pumpkin at 4:15...</h1>

Colorized by: CarlosAg.CodeColorizer
posted on Thursday, March 13, 2008 5:04:26 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Saturday, March 08, 2008

ASP.NET Open Source Content Management Systems

I'm producing a site for a client at the moment, and it quickly became apparent that I'd have a number requirements that would lead me down the CMS path:

  1. Client makes direct updates to the site (with approval/preview possibilities if possible)
  2. Built-in membership, security, roles etc (why write this yourself? - I've got 2 kids and just don't have the time or inclination!)
  3. Skinning capability (OK ASP.NET gives you that 'kindof' for free - but I throw it in anyway)
  4. CSS-driven layout (rather than tables) - This is a technical requirement for me rather than the client, but I want to make the site accessible and SEO-friendly
  5. Capability to customise  and add generic hooks to other office-based systems
  6. Quick time to market (building all the above from scratch would be 'fun' I'm sure, but would also take time)

To be fair to the customer I couldn't really suggest that I do everything from scratch when there's plenty of open source and commercial CMS's that can do the job very well. 

I do .NET - so I'm sure there's plenty of great CMS's for other platforms, but I'm not about to use this as a re-skilling exercise, charging a customer for the pleasure (as I need to do some more 'significant' development around the site, so will be using .NET for that).

What follows is a personal view based on my requirements and my experience (rather than extensive research into each product).

DotNetNuke

This was the first one I considered as I'd had dealings with it a few years ago (a dev 'community' site at a previous employer).  After playing with just about every module on the planet at the time ('cos you do), we realised we just needed a blog, so converted to Community Server as that seemed a bit less cluttered.  (BTW if you want to run .NET blog without SQL Server (like me) then DasBlog's what you want.

Pro's

  • Price (free)
  • Supports pretty much everything I need (open architecture, skinning, module development etc)
  • Familiar from previous use
  • Easy to use and administer - very WYSIWYG
  • Documentation's comprehensive (if a little focused towards the high-level architectural view). 

Con's

  • Slow (I thought I imagined this as my own dev machine's not a 'beast' and it's running SQL 2005 express, but part of this is potentially partly due to the caching mechanism (as noted on the MojoPortal site)
  • Table-driven by default (if you want your skin to be CSS-driven you've either got to muck around for ages finding a 'good' CSS skin (there's plenty of bad/really basic ones).  This extends to the DNN standard controls, and it takes an awfully long time (using Firebug and the IE Dev toolbar) to work out why you've still got fixed size fonts when you've gone to great length in your skin to make everything sizable.  (I'm sure again the better CSS skins address this, but you there always appears to be something that gets in the way because the original DD design uses tabular layout throughout).
  • It's written in VB.NET (OK this isn't a 'real' reason, as there's no difference - I know!  You also shouldn't need to do much (if anything) in VB.NET if you're a C#'er and you want to extend things - I think I'm just a bit miffed I've got to work with a bit of VB.NET at work at the moment :-) )
  • Not that keen on the actual logical structure, and the limited url-rewriting.  The whole anonymous tab thing out of the box.  It seems to me that DNN was designed before lots of newer features became available and it's had to bolt them on as time's gone by.
  • Lastly - it doesn't feel very open source.  It's clear that the business model has evolved to keep the output freely available whilst making money out of books, consulting and conferences (fair play to Shaun Walker - he deserves the kudos for the product).  I just feel that things went a little 'corporate' a while ago, which turned me off.  I bought an iRiver rather than an iPod for the same reason (too much marketing noise that turned me off, almost trying to bombard you so you don't even consider other products, and also trying to deter competition).  There's also many people now trying to make money out of skins (most of which aren't terribly good) - another indicator that the 'community' isn't very focused on open source development.

MojoPortal

Until a couple of days ago I'd not heard of this, but the performance discussion (above) sparked my interest.  It's clearly got less out-of-the-box functionality and community support than DNN and is lacking more in the documentation department, but if you're after a no fuss implementation then this might be the way to go.

Pro's (from the site - not my experience)

  • Free and open source
  • Multi DB support (just about any DB you'd care to use)
  • Approval/workflow support (although haven't looked into this yet)
  • Provides major functionality required
  • Skinning uses standard ASP.NET theme-based approach
  • Aligned relatively well with accessibility guidelines (CSS layout) - XHTML compliancy 

Con's

  • Download is actually a little confusing.  You've got a number of zip files and you're left to work out which one/s you need.  I downloaded a couple then reaslied I only needed the mssql release. 
  • Documentation a little lacking (although installation pretty easy once you've just changed a config setting). 
  • More of a 'developer' product - some understanding of .NET required.  This makes it more difficult for non-techy people to get it off the ground  

Jury's still out on this one as I've literally installed and that's it.  I need to get to grips with the integration and skinning support, as I want to change the default 3 pane layout and remove the left panel, so we'll see how that goes...

Others (That I don't know anything about)

Rainbow Portal (looks like it might be more worth a look in a year or two when there's a bit more support

Umbraco (not all versions free)

 

So what am I going to do now?  Install MojoPortal and see if it 'feels' nicer than DotNetNuke.  I'm not really too worried about future support, and upgrades as I'm providing a site to a client who will run with it once I'm done (based on what it does 'now' - and how stable it is 'now').

I'll post the results - or add to the list when I've come to a conclusion after some more research

posted on Saturday, March 08, 2008 3:46:56 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Thursday, February 21, 2008

Using print stylesheets with ASP.NET Themes

ASP.NET themes are great (in principle), and allow you to have lots of control on how your pages look with theme-specific skins, stylesheets, images etc.  The only thing that's a little bit annoying is that you can't specify (without codebehind) what media the stylesheet should apply to. 

If you add a new stylesheet to your theme folder called 'printer.css', ASP.NET will omit the 'media' attribute when it's output to the <head> section, and it will then be subject to the normal order of precedence rules, affecting your screen output.

There may be other easy ways to do this, but W3C generally think of everything, and then the world catches up - so just use the @media rule to surround all your media-specific styles.  The easiest way to organise this is obviously in different style sheets if you've got a complex layout.  My simple 'printer.css' is below (along with the stylesheet link generated by ASP.NET). 

This simply knocks out the left nav, right side bar and the footer (all divs of course), leaving a relatively clean page for printing. 

<link href="../App_Themes/corporate/printer.css" type="text/css" rel="stylesheet" />

 

posted on Thursday, February 21, 2008 8:32:01 AM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Wednesday, February 06, 2008

Programmatically add Meta Tags to ASP.NET Master Pages using a SiteMap

I hadn't really used SiteMaps before, but it's a useful feature of ASP.NET 2.0 (most people using them to drive BreadCrumb controls and site navigation).

After realising there was no support for design of the sitemap (apart from the default text editor) I found a simple (and functional) SiteMap editor here.

I then realised that I needed to add meta tags for each page in the site (NOTE: this is a simple 'content' site, so don't come running to me if you have the need to generate specific tags based on what colour trousers the user is wearing!).

You can add new attributes very easily to the sitemap, and access them programmatically.  The editor has a nice little grid to make this extra easy for you.  In my example here we've added a 'keywords' attribute. 

Assuming you're using a treeview (or something similar) for navigation on your site and you're binding to the SiteMap data source, then you'll get the context of the current site map node in your page (or master page).

You can then use it to set your meta tags as follows:

You can also set Page.Title from currNode.Title etc.

This is actually quite a neat way to drive things like other standard properties of your master page - e.g. subheadings. 

posted on Wednesday, February 06, 2008 4:46:54 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]