# Wednesday, July 16, 2008

NAnt Solution Task bug - Error checking whether 'xxx' is an enterprise template project.

Just spent a little while looking into this.  I thought I'd be clever and add my build script to the solution it builds so I can get some intellisense from Resharper (although it's somewhat limited).  This added the file into 'Solution Items' which is a virtual folder.

The error appears because NAnt expects to find valid project files in the solution folders.  I had the same error previously with Web Site Projects (as these are also 'special folders'). 

I'm using NAnt 0.86 (Build 0.86.2898.0; beta1; 8/12/2007), and from the bug report it seems that it's fixed in 0.86 beta 2 (not yet out) so you'll have to get a nightly build if you're desperate.

My workaround for the moment is to use the NAntContrib MSBuild task to build my Web Deployment project (which in turn builds all the dependencies), as follows:

<target name="build.webdeploy" description="Compiles a Web Deployment Project using MSBuild">
  <msbuild project="${project.dir}\mydeploydir\mydeployproj.wdproj" verbosity="Detailed" >
     <arg value="/p:Configuration=${build.configuration}" />
  </msbuild>
</target>


You can fill in the blanks yourself with the parameters.

posted on Wednesday, July 16, 2008 1:00:04 PM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Friday, July 11, 2008

Feelgood Friday - Refactoring with .NET Generics

As it's Friday I thought - let's do some cleaning up.  The following exercise is refactoring a class from an app I'm maintaining at the moment.  The app's fine (functional etc), and was originally a .NET 1.1 build.  A combination of this, a previous, straight conversion to .NET 2.0 (with the minimum of mods) and a variety of historical developers (mostly junior) means that the code has a certain amount of 'odour' in numerous places. 

Lack of consistency isn't the main problem, it's more about doing things smartly rather than taking the path of least resistance with your current knowledge.  The latter generally means you don't learn much, get much satisfaction or pride in your work, and you may end up a tad confused as to why you always end up with the 'less glamourous' projects.

Here's the original code.  A simple collection class containing custom MenuItem objects. 

    /// <summary>
    /// Represents a collection of MenuItems.
    /// </summary>
    
public class MenuItems
    {
        
private readonly ArrayList palMenuItems = new ArrayList();


        
// Add a MenuItem to the Collection
        
public void Add(MenuItem objMenuItem)
        {
            palMenuItems.Add(objMenuItem)
;
        
}

        
// Retrieve a MenuItem from the Collection
        
public MenuItem Item(string strTitle)
        {
            
if (palMenuItems.Count > 0)
            {
                
foreach (MenuItem objMenuItem in palMenuItems)
                {
                    
if (objMenuItem.Title.ToLower() == strTitle.ToLower())
                    {
                        
return objMenuItem;
                    
}
                }
            }
            
return new MenuItem();
        
}

        
// Returns True if the specified Key exists in the collection
        
public bool Exists(string strTitle)
        {
            
if (palMenuItems.Count > 0)
            {
                
foreach (MenuItem objMenuItem in palMenuItems)
                {
                    
if (objMenuItem.Title.ToLower() == strTitle.ToLower())
                    {
                        
return true;
                    
}
                }
            }
            
return false;
        
}

        
// Remove a MenuItem from the Collection
        
public void Remove(string strTitle)
        {
            
if (palMenuItems.Count > 0)
            {
                
foreach (MenuItem objMenuItem in palMenuItems)
                {
                    
if (objMenuItem.Title.ToLower() == strTitle.ToLower())
                    {
                        palMenuItems.Remove(objMenuItem)
;
                        break;
                    
}
                }
            }
        }

        
// Clear the collections contents
        
public void Clear()
        {
            palMenuItems.Clear()
;
        
}

        
// Return the Number of MenuItems in the Collection
        
public int Count()
        {
            
return palMenuItems.Count;
        
}

        
// Access to the enumerator
        
public MenuItemEnumerator GetEnumerator()
        {
            
return new MenuItemEnumerator(this);
        
}

        
#region MenuItem Enumaration Class

        
//=================================================================================================
        // Inner Enumeration Class:
        //=================================================================================================
        
public class MenuItemEnumerator
        {
            
private readonly MenuItems pMenuItems;
            private int 
position -1;

            public 
MenuItemEnumerator(MenuItems objMenuItems)
            {
                pMenuItems 
objMenuItems;
            
}

            
public MenuItem Current
            {
                
get return (MenuItem) pMenuItems.palMenuItems[position]}
            }

            
// Declare the MoveNext method required by IEnumerator:
            
public bool MoveNext()
            {
                
if (position < pMenuItems.palMenuItems.Count - 1)
                {
                    position++
;
                    return true;
                
}
                
else
                
{
                    
return false;
                
}
            }

            
// Declare the Reset method required by IEnumerator:
            
public void Reset()
            {
                position 
-1;
            
}

            
// Declare the Current property required by IEnumerator:
        
}

        
#endregion
    
}


Colorized by: CarlosAg.CodeColorizer

OK - Here's the issues I see with the code.

  1. You can spot some room for improvement immediately with variable naming (a weird variation of hungarian notation) - palMenuItems, objMenuItems etc.
  2. This is a simple wrapper implementation.  In conjunction with the naming you may conclude this is an ex-VB programmer who hasn't quite grasped object-oriented concepts yet (an observation - not a criticism).  If the developer knew about inheritance then they would have hopefully just inherited from one of the many applicable classes in System.Collections.  This would have also removed the need for implementing a custom Enumerator class.  Note that neither class actually inherits from any useful base class.  This is copy/paste pseudo-inheritance, and is rarely a wise idea.
  3. The Exists and Item methods use a simple loop mechanism to find the item they're looking for.  This is potentially wasteful with many items, and goes back to the 'path of least resistance' thought.  It's also using the inefficient 'ToLower' implementation to do comparison of what should be a key.  In practice the match doesn't need to be case-insensitive, and if it did then a String.Compare should be used with the appropriate 'ignorecase' argument).  The developer clearly isn't familiar (or maybe just not comfortable) with dictionaries or hashtables where access to items via a key is supported and far more efficient.
  4. The Count implementation is a method rather than a property (aargh!)
  5. It could be argued that the menuitem class itself (not shown here) is redundant as the ASP.NET framework does define a similar MenuItem class.  In reality the whole implementation could be replaced with a sitemap, a menu control, and some custom code, but I'll leave that out of scope for now.
That gives some pointers as to what 'could' have been done in .NET 1.1.  .NET 2.0 of course introduced generics and so let's follow that path.

The MenuItems class is used in a few places:

  • A menu control (that renders menu items)
  • Many pages that load items into the control (I already refactored some of this into inherited menu controls, where all pages shared the same 'dynamic' menu), but there's plenty more improvements to be made.

The first thing is to say...

I don't need a collections class...

The following is now in the Menu Control:

        //private MenuItems menuItems = new MenuItems(); - Out with the Old
        
private Dictionary<string, MenuItem> menuItems = new Dictionary<string, MenuItem>()//In with the new

        
public Dictionary<string, MenuItem> MenuItems
        {
            
get return menuItems}
            
set { menuItems = value; }
        }


Colorized by: CarlosAg.CodeColorizer

This simply uses a generic Dictionary object with a string key (as we find items by title).  Anywhere that references this dictionary will now need to add a 'key' in certain places (e.g. Add method), and the Item method will no longer work as that's gone.  That needs to change to a class indexer.

Fortunately Visual Studio's find and replace can cope with all of this as the code is largely consistent...

A quick compile should show all the patterns (from the errors) if there's any inconsistencies.  There were probably about 200 references to patch here with about 4 different variations of naming and scope - but it took about 5 minutes to patch (including writing this text :-))

We then have to patch all the 'Item' references.  These are almost always setting a 'selected' property (Stopwatch on...)

As there's only a few references here (about 20), I could patch them manually, but this could be done entirely by using regular expressions to do the find and replace.  http://msdn.microsoft.com/en-us/library/2k3te2cs.aspx shows all the options available.  I tend to only use regexp for large volume stuff where I get a return on my time investment to work out the expression! 

I'm just doing it in two steps without regexp as follows:

The code

            Menu1.MenuItems.Item(UserMenu.MyCommunicationItems).Selected = true;

becomes

            Menu1.MenuItems[UserMenu.MyCommunicationItems].Selected = true;

For extra points you then use Resharper to rename all of the obj and pal references to something reasonable, e,g, objMenuItem becomes menuItem.

Oh - and use Resharper's 'Find Usages' on the MenuItems class to confirm it can be deleted.

And relax.....


In hindsight I would have used Resharper to 'change signature' on the methods in MenuItems (to patch all the references first), then converted to the generic Dictionary.  Could have been a bit quicker.

Hope this gives someone some courage to get in there and improve their code.  I firmly believe you've just got to 'want' to do it and then you're biggest problem will be stopping yourself!


posted on Friday, July 11, 2008 10:06:52 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [2]
# Wednesday, July 09, 2008

Test out String.Format options online

Love this little tool.  It's making me think about writing some stuff for Silverlight!

I just plain can't remember the options for String.Format and standard/custom strings so being able to try them out is great.  Nice work!

I'd normally use John Sheehan's excellent Cheat Sheet, but I'll probably stick to the tool in future.

posted on Wednesday, July 09, 2008 5:13:49 PM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [1]

Who needs Internet Explorer when you can use it in Firefox?

I love Firefox and its addons, although I still habitually use Internet Explorer.  IE6 at work (which always provides some nice CSS challenges!) and IE7 at home.

I'm a bit slow off the mark with using firefox, but the latest addon that someone sent me yesterday may have tipped the balance.

The IE Tab addon actually uses the IE rendering engine to render in a new tab in Firefox.  It's quite amusing when you right-click and get the IE context menu.

The really great thing about this is that you can then use the power of the other Firefox addons to develop for IE.  Here's my list of 'must haves'.

  • Firebug.  This is quite simply the best addon.  Hit F12 and you can instantly see (and manipulate) all sorts of things in the comfort of your own browser.
  • YSlow.  Great Javascript profiler
  • FireCookie. See and change your cookies (for development purposes of course! - Good to test the security of your apps)
  • Web Developer.  Bit of overlap with Firebug but some cool features.

The IE Developer Toolbar is still a pretty good tool, but Firebug just gives you more info when you're debugging CSS (which is inevitable with IE).

 

posted on Wednesday, July 09, 2008 12:24:40 PM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Tuesday, July 08, 2008

Search SQL Server Stored Procedures for any text string

Here's the SQL script I probably use most when I'm trying to work out dependencies and scope of development changes.  Query Analyzer allows you to search objects (hit F4 - it's cool!) and find objects by 'name', but there's no obvious way to search stored procs for a particular string.

SQL Server hides Stored Procedure code in the sysComments table (in each database), and so it's possible to search.  This is another script I found from not sure where (so can't really take credit).  It does a great job of scanning and even gives you line numbers.  It would be great to be able to just shove this into the master database, but you need to be in the context of the database you're searching in (or it would have to be amended somewhat to run some more 'dynamic' SQL). 

I have previously front-ended this for development databases with an ASP.NET page that simply runs the query substituting a parameter for the search text and connecting to the correct database.  The results show nicely in a grid.

Here's the code - just paste into a new query in your chosen database, change @SearchTerm and away you go...

 

SET NOCOUNT ON
GO

declare 
@dbname sysname
,@SearchTerm    varchar(100)
,@BlankSpaceAdded   
int
,@BasePos       int
,@CurrentPos    int
,@TextLength    int
,@LineId        int
,@AddOnLen      int
,@LFCR          int --lengths of line feed carriage return
,@DefinedLength int
,@obj_name    varchar(255)
,@prev_obj_name 
varchar(255)


/* NOTE: Length of @SyscomText is 4000 to replace the length of
** text column in syscomments.
** lengths on @Line, #CommentText Text column and
** value for @DefinedLength are all 255. These need to all have
** the same values. 255 was selected in order for the max length
** display using down level clients
*/
,@SyscomText    nvarchar(4000)
,@Line          
nvarchar(255)

set @SearchTerm 'MyTable'
set @dbname db_name()


set @SearchTerm '%' + @SearchTerm + '%'

Select @DefinedLength 255
SELECT @BlankSpaceAdded /*Keeps track of blank spaces at end of lines. Note Len function ignores
                             trailing blank spaces*/
CREATE TABLE #CommentText
(obj_name 
varchar(255)
 ,LineId    
int
 
,Text  nvarchar(255collate database_default)

/*
**  Make sure the @objname is local to the current database.
*/
if @dbname is not null and @dbname <> db_name()
        
begin
                raiserror
(15250,-1,-1)
        
end

    begin

        DECLARE 
ms_crs_syscom  CURSOR LOCAL
        FOR SELECT 
so.name, sc.text FROM syscomments sc
    
inner join sysobjects so
    
on so.id = sc.id
    where 
so.type 'P'
    
AND sc.encrypted 0
                
ORDER BY number, colid

        
FOR READ ONLY
    
end

/*
**  Get the text.
*/
SELECT @LFCR 2
SELECT @LineId 1


OPEN ms_crs_syscom

FETCH NEXT FROM ms_crs_syscom into @obj_name, @SyscomText

WHILE @@fetch_status >0
BEGIN

    SELECT  
@BasePos    1
    
SELECT  @CurrentPos 1
    
SELECT  @TextLength = LEN(@SyscomText)

    
IF @prev_obj_name <> @obj_name
        
--start again
        
SELECT @LineId 1
    
    
WHILE @CurrentPos  !0
    
BEGIN
        
--Looking for end of line followed by carriage return
        
SELECT @CurrentPos =   CHARINDEX(char(13)+char(10), @SyscomText, @BasePos)

        
--If carriage return found
        
IF @CurrentPos !0
        
BEGIN
            
/*If new value for @Lines length will be > then the
            **set length then insert current contents of @line
            **and proceed.
            */
            
While (isnull(LEN(@Line),0) + @BlankSpaceAdded + @CurrentPos-@BasePos + @LFCR) > @DefinedLength
            
BEGIN
                SELECT 
@AddOnLen @DefinedLength-(isnull(LEN(@Line),0) + @BlankSpaceAdded)
                
INSERT #CommentText VALUES
                
( @obj_name,
          @LineId,
                  
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @AddOnLen), N''))
                
SELECT @Line = NULL, @LineId @LineId + 1,
                       @BasePos 
@BasePos + @AddOnLen, @BlankSpaceAdded 0
            
END
            SELECT 
@Line    = isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @CurrentPos-@BasePos + @LFCR), N'')
            
SELECT @BasePos @CurrentPos+2
            
INSERT #CommentText VALUES( @obj_name, @LineId, @Line )
            
SELECT @LineId @LineId + 1
            
SELECT @Line = NULL
        END
        ELSE
        
--else carriage return not found
        
BEGIN
            IF 
@BasePos <@TextLength
            
BEGIN
                
/*If new value for @Lines length will be > then the
                **defined length
                */
                
While (isnull(LEN(@Line),0) + @BlankSpaceAdded + @TextLength-@BasePos+1 ) > @DefinedLength
                
BEGIN
                    SELECT 
@AddOnLen @DefinedLength - (isnull(LEN(@Line),0) + @BlankSpaceAdded)
                    
INSERT #CommentText VALUES
                    
( @obj_name,
              @LineId,
                      
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @AddOnLen), N''))
                    
SELECT @Line = NULL, @LineId @LineId + 1,
                        @BasePos 
@BasePos + @AddOnLen, @BlankSpaceAdded 0
                
END
                SELECT 
@Line = isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @TextLength-@BasePos+1 ), N'')
                
if LEN(@Line) < @DefinedLength and charindex(' ', @SyscomText, @TextLength+1 ) > 0
                
BEGIN
                    SELECT 
@Line @Line + ' ', @BlankSpaceAdded 1
                
END
            END
        END
    END
    
--Save previous name
    
SET @prev_obj_name @obj_name
    
FETCH NEXT FROM ms_crs_syscom into @obj_name, @SyscomText
END

IF 
@Line is NOT NULL
    INSERT #
CommentText VALUES( @obj_name, @LineId, @Line )

select from #CommentText 
where  patindex(@SearchTerm, text) <> 0

CLOSE  ms_crs_syscom
DEALLOCATE     ms_crs_syscom

DROP TABLE     #CommentText


Colorized by: CarlosAg.CodeColorizer
posted on Tuesday, July 08, 2008 9:38:31 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]

Generate SQL Inserts from existing data

This is one from the archives that obviously got away.  I had need for this today so thought I'd post so I don't have to look so hard next time!

It's pretty much a case of create the SP in your chosen database and run with a tablename as the parameter.  I originally found this on one of the SQL sites (probably SQLServerCentral), and amended it slightly to add some basic filtering in the @where parameter.

There's a few limitations from memory - with blob, image and text fields, but for your average tables this will probably do the trick just fine.

I've also used a different method that basically builds up a single INSERT with SELECT 'literal values' UNION SELECT 'literal values'.  That works fine and is potentially easier to control transaction-wise as everthing's in a single statement.  Anyway here's the code....

if exists (select from dbo.sysobjects where id = object_id(N'[dbo].[usp_InsertGenerator]'and OBJECTPROPERTY(idN'IsProcedure'1)
drop procedure [dbo].[usp_InsertGenerator]
GO


CREATE PROC 
dbo.usp_InsertGenerator
(@tableName 
varchar(100), @where varchar(1000= NULLas
 
--Declare a cursor to retrieve column specific information for the specified table
DECLARE cursCol CURSOR FAST_FORWARD FOR 
SELECT 
column_name,data_type FROM information_schema.columns WHERE table_name @tableName
OPEN cursCol
DECLARE @string nvarchar(3000--for storing the first half of INSERT statement
DECLARE @stringData nvarchar(3000--for storing the data (VALUES) related statement
DECLARE @dataType nvarchar(1000--data types returned for respective columns
SET @string='INSERT '+@tableName+'('
SET @stringData=''
 
DECLARE @colName nvarchar(50)
 
FETCH NEXT FROM cursCol INTO @colName,@dataType
 
IF @@fetch_status<>0
 
begin
 print 
'Table '+@tableName+' not found, processing skipped.'
 
close curscol
 
deallocate curscol
 
return
END
 
WHILE 
@@FETCH_STATUS=0
BEGIN
IF 
@dataType in ('varchar','char','nchar','nvarchar')
BEGIN
 SET 
@stringData=@stringData+''''+'''+isnull('''''+'''''+'+@colName+'+'''''+''''',''NULL'')+'',''+'
END
ELSE
if 
@dataType in ('text','ntext'--if the datatype is text or something else 
BEGIN
 SET 
@stringData=@stringData+'''''''''+isnull(cast('+@colName+' as varchar(2000)),'''')+'''''',''+'
END
ELSE
IF 
@dataType 'money' --because money doesn't get converted from varchar implicitly
BEGIN
 SET 
@stringData=@stringData+'''convert(money,''''''+isnull(cast('+@colName+' as varchar(200)),''0.0000'')+''''''),''+'
END
ELSE 
IF 
@dataType='datetime'
BEGIN
 SET 
@stringData=@stringData+'''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+',121)+'''''+''''',''NULL'')+'',121),''+'
END
ELSE 
IF 
@dataType='image' 
BEGIN
 SET 
@stringData=@stringData+'''''''''+isnull(cast(convert(varbinary,'+@colName+') as varchar(6)),''0'')+'''''',''+'
END
ELSE 
--presuming the data type is int,bit,numeric,decimal 
BEGIN
 SET 
@stringData=@stringData+''''+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+')+'''''+''''',''NULL'')+'',''+'
END
 
SET 
@string=@string+@colName+','
 
FETCH NEXT FROM cursCol INTO @colName,@dataType
END
DECLARE 
@Query nvarchar(4000)
 
SET @query ='SELECT '''+substring(@string,0,len(@string)) + ') VALUES(''+ ' substring(@stringData,0,len(@stringData)-2)+'''+'')'' FROM '+@tableName
IF @where IS NOT NULL
 SET 
@query @query + ' where ' + @where
 
exec sp_executesql @query
 
CLOSE cursCol
DEALLOCATE cursCol
GO

Colorized by: CarlosAg.CodeColorizer
posted on Tuesday, July 08, 2008 9:18:47 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Monday, July 07, 2008

Upgrading TortoiseSVN, Subversion 1.5 and AnkhSVN.

I thought I'd upgrade to v1.5 of TortoiseSVN this morning (leaving the server on V1.4.x) - of course completely forgetting that I use AnkhSVN in Visual Studio. 

New versions of TortoiseSVN and Subversion tend to upgrade the format for Working Copies.  This means AnkhSVN (1.02) was no longer compatible with my 'new' Working Copy and I got the following error...

This client is too old to work with Working copy 'xxx'. Please get a newer Subversion client.

Thankfully AnkhSVN 2.0 is on the way and I downloaded a nightly build (2.0.4523.91) and installed (without uninstalling 1.0.2).  I usually do this to 'test' whether people write good installers.  Most people do the right thing with AutoUpgrade and 1.0.2 dutifully disappeared.

I loaded up Visual Studio with the same solution and - 'Where's my AnkhSVN menus gone?'.  As V2.0 is not even Alpha yet there's not much in the way of obvious help on the Collabnet site.  The community area may have more, but I luckily didn't need it.

I noticed in the application folder that there's now an Ankh.Scc.dll.  Well blow me if they haven't gone and made it a 'standard' Visual Studio SCC Provider!  Tools --> Options --> Source Control --> Plug-in Selection.  There it is.

Once you've got over that, then you might find a few little errors here and there, but the main difference is that instead of an ANKH menu on Tools and in the Solution Explorer context menu - you get a Subversion context menu. 

I'm liking it so far.  I think it's probably stable enough to put your faith in and make the jump to SVN 1.5.

Update (08/07/2008) 
I submitted a bug report yesterday on an error I encountered (from the nice 'send error details' link) and got a reply saying 'fixed in latest build' the next day.  This bodes well!!!  Reasons to pay money for VisualSVN now disappearing fast...

Update (23/07/2008)

AnkhSVN v2.0 now officially out (that was a quick alpha/beta phase!)

posted on Monday, July 07, 2008 10:37:45 AM (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]
# Monday, June 30, 2008

Del.icio.us - FavPal.NET is dead?

This sounds pretty unlikely, but I'm a new (and very enthusiastic) del.icio.us user (and have to think hard about where to put the dots every time I type it).  I guess you can't jump on 'every' bandwagon.  I tend to discover stuff that I 'need' these days rather than get too 'wowed' by yet another networking site.

I developed a tool called FavPal.NET (don't worry - I'm sure you haven't heard of it!), a few years back as I saw there was nothing that allowed you to search through browser bookmarks with any degree of speed or accuracy.  It was a tray app that kept a 'cache' pool of IE instances (as load time was pretty bad back then), and allowed you to search through your favourites, then load up URL's into a cached instance in double-quick time.  This served two purposes

  1. Search Favourites
  2. Load IE quickly

Del.icio.us obviously more than scores with requirement 1 as it allows you to keep your bookmarks centrally (BTW - I also use the IGoogle bookmarks gadget for 'home page' access to my most frequently used stuff).  One thing was still lacking - an 'integrated' search within the browser (or rather a search without having to point your browser to del.icio.us), but now there's an IE extension (for IE6/7) that sits as a sidebar (nice).

I noticed there's a Delicious.NET framework, and I'm still not terribly satisfied with the initial application load speed of any browser (even Firefox and Safari), so maybe FavPal's not quite dead.  The search functionality could now simply hook into del.icio.us and still use the cache.  With tabbed browsing on IE7 now though the object model may well have changed.  If anyone wants to have a crack at it you're more than welcome, and I'll send you the code, as it got removed from the late lamented gotdotnet workspaces.

Of course the load speed will ineviatably go up with the more plugins like del.icio.us you bloat the browser with - d'oh!

posted on Monday, June 30, 2008 8:24:27 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]