Ivan Porto Carrero

IO(thoughts) flatMap (_.propagandize)

14

Oct
2006

Some News on Nblogr

NBlogr isn’t dead.. It just underwent a transformation for the better.

I also changed the title of the application from NBlogr - An atlas blogging engine to NBlogr - a blogging engine built on simplicity
The reason for this change is the fact that it is currently built using jquery as javascript library.  I will look at atlas again when it releases.

I moved NBlogr to run on castle.  During the course of the next week I’ll complete my posts on how to do Castle development with base4

If you’re interested in how it looks or you want a preview the last source in the repository builds and you should be able to run it in the development server of visual studio

I had a chat with JD a while ago and he asked me about plugins. At that time I knew already I wanted to provide something for users to be able to add plugin’s to the database.  But I hadn’t really given it much thought on how I would do that.

My reasoning on this subject is :
I want users to be able to add a plug in at runtime. Plugin’s for a blog are lately both server related client side. So I will create a plugin factory with a couple of providers like a google video provider, grouper video, flickr, bookmark services.  And you can write a plugin using javascript and ironpython code. The engine will evaluate that code at runtime and there has been no application restarting etc. If somebody has a better plan for doing a plugin infrastructure please let me know I haven’t done any of the ground work for this yet but create a schema in base4 so now would be the best time to stop me from making big mistakes.

Another improvement is the fact that when nblogr reaches release it will come with a couple of templates for you to chose from. I’ll try to include one that is built on the css scheme of csszengarden that way you’ll have an infinite repository of css to make your blog look differently instantaneously.

The next improvement is that a user is now able to mimic wildcard requests and nblogr will handle those. So there is no need for appending aspx to pages for rewriting (routing it is called in monorail)  You get the choice in the config file to have your webserver handle the wild card mapping or nblogr. When you choose for nblogr nblogr will need write access to 2 folders in your website and create a shadow folder structure to represent the rewrite tree structure. There is weaker point here and that is that the first default document in IIS must be set to Default.aspx If you can map an extension to aspnet_isapi.dll at your webserver then you can also have the urls rewritten using a branded extension.

I think that this are the 3 major changes for the moment to the engine.  This did set me back for the next release with a couple of weeks but in the end the final release can be done much more quickly than it would have been possible using the code I had before.

I also promise that this time things mostly stay as they are. There will be no more experimenting but just getting Nblogr to a proper release state and shipped.

12

Oct
2006

Hosting Base4 Inside Your Web Application

Following up on the post of yesterday.  To use base4 with asp.net often you do not have the possibility to host base4 as a windows service. But to host base4 in the same appdomain as you website isn’t all that hard.

I’ll just share my code and how to use it. The way to go is to create a class that extends the HttpApplicatin and handle the application start and end events.

I’ll also post the code i have to integrate this with castle.

This is my base HttpApplication, every web app inherits of this one.

using System;

using System.Collections.Generic;

using System.Text;

using System.Web;

using Base4.Storage.Server;

using System.Text.RegularExpressions;

using System.Reflection;

using System.Data.SqlClient;

using System.Configuration;

using Base4.Storage;

using System.Xml;

using System.IO;

 

namespace Flanders.Library.Base4Integration

{

    public class Base4HttpApplication : HttpApplication

    {

        ServerConfiguration config;

        IServerProxy proxy;

 

 

        public Base4HttpApplication()

        {

 

        }

 

        public virtual void Application_Start(object sender, EventArgs e)

        {

            //Build the base4 server configuration from the connection strings settings in the web.config

            config = new ServerConfiguration();

            config.Store.Root = Server.MapPath(“~/”);

            config.Store.Root = config.Store.Root.EndsWith(“") ? config.Store.Root

                + “App_Data\Base4” : config.Store.Root + “\App_Data\Base4”;

 

            //Set the application name of the store. In my case I define a title for my application in a

            //solution info file and use that as my app name

            //For this to work you will need to name your database the same as your applicationname

            if (Application[“AppName”] == null)

            {

                Assembly assembly = Assembly.GetCallingAssembly();

                Application[“AppName”] =

                    (AssemblyTitleAttribute.GetCustomAttribute(assembly, typeof(AssemblyTitleAttribute)) as AssemblyTitleAttribute).Title;

            }

 

            config.Store.Name = Application[“AppName”].ToString();

            config.Store.Provider = “SQL2005”;

 

            //Set the port for base4 to listen on.  This is defined in the web.config app settings

            if (Application[“AppPort”] == null)

                Application[“AppPort”] = string.IsNullOrEmpty(ConfigurationManager.AppSettings[“Base4.Port”]) ? 8809 :

                    int.Parse(ConfigurationManager.AppSettings[“Base4.Port”]);

 

            config.Store.Port = (int)Application[“AppPort”];

            //We are hosting base4 in the same process as the website. so localhost will do :)

            config.Store.MachineName = “localhost”;

 

            //Set the connection string for the base4 store

            string connectionStringName = ConfigurationManager.AppSettings[“DefaultConnection”];

            if (string.IsNullOrEmpty(connectionStringName) && ConfigurationManager.ConnectionStrings != null

                && ConfigurationManager.ConnectionStrings.Count > 0)

                connectionStringName = ConfigurationManager.ConnectionStrings[0].Name;           

 

            config.Store.ConnectionString = string.IsNullOrEmpty(connectionStringName) ?

                ConfigurationManager.AppSettings[“Store.ConnectionString”] :

                ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;

 

            //Set the master connection string

            SqlConnectionStringBuilder connStrBuilder = new SqlConnectionStringBuilder(config.Store.ConnectionString);

 

            connStrBuilder.InitialCatalog = “master”;

            config.MasterConnectionString = connStrBuilder.ToString();

 

            //Check if we have a directory to store the files generated by base4

            if(!Directory.Exists(config.Store.Root))

                Directory.CreateDirectory(config.Store.Root);

 

            //Actually start the server

            proxy = ServerFactory.StartServer(config, false);

 

            //Set the context for base4

            string base4Context = string.Format(“tcp://Server:@localhost:{0}/{1}”, Application[“AppPort”], Application[“AppName”]);

 

            Application[“Base4Context”] = base4Context;

 

            //Set the default storage context for base4

            StorageContext.SetDefault(base4Context);

 

        }

 

        public virtual void Application_End(object sender, EventArgs e)

        {

            proxy.Stop();

        }

 

    }

}

Now to integrate this with monorail then this is you application class in your website :

 

using System.Web;

using Castle.Windsor;

using Base4.Storage;

using System.Configuration;

using Flanders.Library.Base4Integration;

 

namespace NBlogr.Presentation

{

    public class ASPGlobal : Base4HttpApplication, IContainerAccessor

    {

        private static MonoRailContainer container;

 

        public override void Application_Start(object sender, System.EventArgs e)

        {

            base.Application_Start(sender, e);

            container = new MonoRailContainer();

        }

 

        public override void Application_End(object sender, System.EventArgs e)

        {

            container.Dispose();

            base.Application_End(sender, e);

        }

 

 

        #region IContainerAccessor Members

 

        public IWindsorContainer Container

        {

            get { return container; }

        }

 

        #endregion

    }

}

The global.asax should only contain one line :

<span class="asp"><%@ Application Inherits="NBlogr.Presentation.ASPGlobal" Language="C#" %></span>

28

Sep
2006

More on Logging

Earlier this week, about the same time that I was playing with health monitoring. I found out after a while that log4net isn’t working on Vista RC1.

Now I don’t know about you but log4net seemed like the obvious choice for logging for me.  Now I was forced to have a look around what else is there. And castle supports also nlog. I took a closer look at nlog and I like it a lot. It has much better integration with visual studio 2005 than log4net has.

The configuration was much easier. I wrote a “log provider” (log target in the nlog dictionary) for base4 in about 15 minutes.  Ah yes extensibility is great for this product.

It’s open source but it is a really tight project.  Maybe you too should investigate :)

27

Sep
2006

Custom Health Monitoring for Asp.NET Using Base4

It’s been pretty quiet on my blog the last couple of days. But I had something cooking :)

I think logging is a pretty important part of an application. I like to know what’s going on when for errors etc.

Asp.NET has a health monitoring service that does just that. With a couple of lines in the web.config you’re good to go.

I use base4 for my dataaccess and i want do do all my data access through base4. From the asp.net services I use Membership, roleManager, profiles and health monitoring.

This week I ported healthmonitoring, membership and rolemanager to Base4. I’ll post the health monitoring provider and when I have also completed the profile provider I’ll post a dll that contains all the providers and the Base4 schema’s if somebody is interested.

 

using System;

using System.Collections.Generic;

using System.Text;

using System.Collections.Specialized;

using Flanders.Library.Provider;

using System.Web.Management;

using System.Globalization;

using Seshat.Data;

using System.Collections;

using System.Threading;

using System.Configuration;

 

namespace Flanders.Library.Base4Integration

{

    public class Base4WebEventProvider : BufferedWebEventProvider

    {

        const int SQL_MAX_NTEXT_SIZE = 1073741823;

        const int NO_LIMIT = -1;

 

        int _maxEventDetailsLength = NO_LIMIT;

 

        DateTime retryDate = DateTime.MinValue; // Won’t try sending unless DateTime.UtcNow is > retryDate

 

        public Base4WebEventProvider() { }

 

        public override void Initialize(string name, NameValueCollection config)

        {

 

            string temp = null;

 

            SecUtility.GetAndRemoveStringAttribute(config, “connectionStringName”, name, ref temp);

 

 

            SecUtility.GetAndRemovePositiveOrInfiniteAttribute(config, “maxEventDetailsLength”, name, ref _maxEventDetailsLength);

            if (_maxEventDetailsLength == SecUtility.Infinite)

            {

                _maxEventDetailsLength = NO_LIMIT;

            }

            else if (_maxEventDetailsLength > SQL_MAX_NTEXT_SIZE)

            {

                throw new ConfigurationErrorsException(SR.GetString(SR.Invalid_max_event_details_length, name, _maxEventDetailsLength.ToString(CultureInfo.CurrentCulture)));

            }

 

            //SecUtility.GetAndRemovePositiveAttribute(config, “commandTimeout”, name, ref _commandTimeout);

 

            base.Initialize(name, config);

        }

 

        void FillParams(ApplicationEvent appEvent, WebBaseEvent eventRaised)

        {

            Exception exception = null;

            WebRequestInformation reqInfo = null;

            string details = null;

            WebApplicationInformation appInfo = WebBaseEvent.ApplicationInformation;

 

            appEvent.Id = eventRaised.EventID;

            appEvent.EventId = eventRaised.EventID.ToString(“N”, CultureInfo.InstalledUICulture) ;

            appEvent.EventTimeUtc = eventRaised.EventTimeUtc;

            appEvent.EventTime = eventRaised.EventTime;

            appEvent.EventType = eventRaised.GetType().ToString();

            appEvent.EventSequence = eventRaised.EventSequence;

            appEvent.EventOccurence = eventRaised.EventOccurrence;

            appEvent.EventCode = eventRaised.EventCode;

            appEvent.EventDetailCode = eventRaised.EventDetailCode;

            appEvent.Message = eventRaised.Message;

            appEvent.ApplicationPath = appInfo.ApplicationPath;

            appEvent.ApplicationVirtualPath = appInfo.ApplicationVirtualPath;

            appEvent.MachineName = appInfo.MachineName;

 

            // @RequestUrl

            if (eventRaised is WebRequestEvent)

            {

                reqInfo = ((WebRequestEvent)eventRaised).RequestInformation;

            }

            else if (eventRaised is WebRequestErrorEvent)

            {

                reqInfo = ((WebRequestErrorEvent)eventRaised).RequestInformation;

            }

            else if (eventRaised is WebErrorEvent)

            {

                reqInfo = ((WebErrorEvent)eventRaised).RequestInformation;

            }

            else if (eventRaised is WebAuditEvent)

            {

                reqInfo = ((WebAuditEvent)eventRaised).RequestInformation;

            }

            appEvent.RequestUrl = Convert.ToString((reqInfo != null) ? reqInfo.RequestUrl : Convert.DBNull);

 

            // @ExceptionType

            if (eventRaised is WebBaseErrorEvent)

            {

                exception = ((WebBaseErrorEvent)eventRaised).ErrorException;

            }

            appEvent.ExceptionType = Convert.ToString((exception != null) ? exception.GetType().ToString() : Convert.DBNull);

 

            // @Details

            details = eventRaised.ToString();

            if (_maxEventDetailsLength != NO_LIMIT &&

                details.Length > _maxEventDetailsLength)

            {

                details = details.Substring(0, _maxEventDetailsLength);

            }

            appEvent.Details= details;

        }

 

        void WriteToBase4(ICollection events, int eventsDiscardedByBuffer, DateTime lastNotificationUtc)

        {

            // We don’t want to send any more events until we’ve waited until the _retryDate (which defaults to minValue)

            if (_retryDate > DateTime.UtcNow)

            {

                return;

            }

 

            try

            {

                ApplicationEvent appEvent = new ApplicationEvent();

 

                try

                {

 

                    if (eventsDiscardedByBuffer != 0)

                    {

                        WebBaseEvent infoEvent = new Base4BaseEvent(

                            SR.GetString(SR.Sql_webevent_provider_events_dropped,

                                eventsDiscardedByBuffer.ToString(CultureInfo.InstalledUICulture),

                                lastNotificationUtc.ToString(“r”, CultureInfo.InstalledUICulture)),

                                null,

                                WebEventCodes.WebEventProviderInformation,

                                WebEventCodes.SqlProviderEventsDropped);

 

                        FillParams(appEvent, infoEvent);

                        appEvent.Save();

                    }

 

                    foreach (WebBaseEvent eventRaised in events)

                    {

                        FillParams(appEvent, eventRaised);

                        appEvent.Save();

                    }

                    EventProcessingComplete(events);

                }

                catch

                {

                    // Ignore all errors.

                }

            }

            catch

            {

                // For any failure, we will wait at least 30 seconds or _commandTimeout before trying again

                double timeout = 30;

                _retryDate = DateTime.UtcNow.AddSeconds(timeout);

                throw;

            }

        }

 

        public override void ProcessEventFlush(WebEventBufferFlushInfo flushInfo)

        {

            // Remove Debug.Trace from sample Debug.Trace(“SqlWebEventProvider”, “EventBufferFlush called: ” +

            WriteToBase4(flushInfo.Events, flushInfo.EventsDiscardedSinceLastNotification,

                flushInfo.LastNotificationUtc);

        }

        public override void ProcessEvent(WebBaseEvent eventRaised)

        {

            if (UseBuffering)

            {

                base.ProcessEvent(eventRaised);

            }

            else

            {

                 WriteToBase4(new Base4BaseEventCollection(eventRaised), 0, new DateTime(0));

            }

        }

 

        protected virtual void EventProcessingComplete(ICollection raisedEvents)

        {

        }

 

        public override void Shutdown()

        {

            try

            {

                Flush();

            }

            finally

            {

                base.Shutdown();

            }

        }

    }

    public class Base4BaseEvent : WebBaseEvent

    {

 

        public Base4BaseEvent(string message, object eventSource, int eventCode) : base(message, eventSource, eventCode) { }

        public Base4BaseEvent(string message, Object eventSource, int eventCode, int eventDetailCode)

            : base(message, eventSource, eventCode, eventDetailCode)

        { }

    }

    public sealed class Base4BaseEventCollection : ReadOnlyCollectionBase

    {

        public Base4BaseEventCollection(ICollection events)

        {

            if (events == null)

            {

                throw new ArgumentNullException(“events”);

            }

 

            foreach (WebBaseEvent eventRaised in events)

            {

                InnerList.Add(eventRaised);

            }

        }

 

        internal Base4BaseEventCollection(WebBaseEvent eventRaised)

        {

            if (eventRaised == null)

            {

                throw new ArgumentNullException(“eventRaised”);

            }

 

            InnerList.Add(eventRaised);

        }

 

        // overloaded collection access methods

        public WebBaseEvent this[int index]

        {

            get

            {

                return (WebBaseEvent)InnerList[index];

            }

        }

 

        public int IndexOf(WebBaseEvent value)

        {

            return InnerList.IndexOf(value);

        }

 

        public bool Contains(WebBaseEvent value)

        {

            return InnerList.Contains(value);

        }

    }

}

23

Sep
2006

Base4 and Castle

Something I found very useful to use in castle is Base4 

And as it so happens Nic Wise just asked me if you could use the 2 together. The answer is yes you can.

I know they support nhibernate but that is not really the same :)  Base4 just goes that extra mile.

Since data access is always the same. And the examples on the castle site use concrete implementations of data access objects. I thought I really don’t need a facility for the moment and can just use base4.

Anyway here is the class I use to do all my data access. it’s an abstract class that has concrete implementations so that I can extend the functionality if I need to.

The interface for the class (the colors look different on my screen I swear  the gray bits should be some type of blue and the yellow also isn’t quite right):

 

using System;

namespace TimeSheets.Application.Contract.Data

{

    public interface IDataObject

    where T : class, Base4.Storage.IItem, new()

    {

        void Delete(T item);

        Base4.Storage.IItemList Find(string oPath, string sortExpression, int pageNumber, int pageSize, out int pageCount);

        Base4.Storage.IItemList Find(string oPath, string sortExpression);

        Base4.Storage.IItemList Find(string oPath);

        Base4.Storage.IItemList FindAll(string sortExpression, int pageNumber, int pageSize, out int pageCount);

        Base4.Storage.IItemList FindAll(string sortExpression);

        Base4.Storage.IItemList FindAll();

        Base4.Storage.IItemList FindById(Guid Id);

        T GetById(Guid Id);

        T GetOne(string oPath);

        T Insert(T item);

        string SortExpression { get; set; }

        T Update(T item);

    }

}

 

And this is the abstract class :

 

using System;

using System.Collections.Generic;

using System.Text;

using Base4.Storage;

using System.ComponentModel;

 

namespace TimeSheets.Application.Base

{

 

    ///

    /// A generic class that handles data access through Base4

    ///

    ///

    public abstract class BaseDataObject : Base.DataObject, Contract.Data.IDataObject where T : class,IItem, new()

    {

        private string m_SortExpression;

 

        ///

        /// Gets or sets the sort expression.

        ///

        /// The sort expression.

        public virtual string SortExpression

        {

            get { return m_SortExpression; }

            set { m_SortExpression = value; }

        }

 

        ///

        /// Finds the specified in the object path.

        ///

        /// The Object path.

        ///

        public virtual IItemList Find(string oPath)

        {

            //set the default sort expression to none

            this.m_SortExpression = string.Empty;

 

            //Get my stuff

            return StorageContext.Find(initialiseObjectPath(new ObjectPath(oPath)));

        }

 

        ///

        /// Finds the specified Object path sorted by the provided sort expression.

        ///

        /// The Object path.

        /// The sort expression.

        ///

        public virtual IItemList Find(string oPath, string sortExpression)

        {

            //Set the default sort expression

            this.m_SortExpression = sortExpression;

 

            //Get the data out

            return StorageContext.Find(initialiseObjectPath(new ObjectPath(oPath)));

        }

 

        ///

        /// Finds the specified Object path with server side paging.

        ///

        /// The Object path.

        /// The sort expression.

        /// The page number.

        /// Size of the page.

        /// The page count.

        ///

        public virtual IItemList Find(string oPath, string sortExpression, int pageNumber, int pageSize, out int pageCount)

        {

            //initialise the pagecount parameter

            pageCount = 0;

 

            //Set the pagecount parameter tot he actual value

            pageCount = (int)Math.Ceiling(Convert.ToDouble(getCount() / pageSize));

 

            //if we got a sort expression do initialize with it please

            if (!string.IsNullOrEmpty(sortExpression))

                m_SortExpression = sortExpression;

 

            //initialise the object pathe with the provide oPath parameter and initialise the order by

            ObjectPath path = initialiseObjectPath(new ObjectPath(oPath));

 

            //Tell Base4 which page to retrieve

            path.PageSize = pageSize;

            path.PageNumber = pageNumber;

 

            //Get the items

            return StorageContext.Find(path);

        }

 

        ///

        /// Finds all items.

        ///

        ///

        public virtual IItemList FindAll()

        {

            this.m_SortExpression = string.Empty;

            return StorageContext.Find(initialiseObjectPath());

        }

 

        ///

        /// Finds all the items sorted.

        ///

        /// The sort expression.

        ///

        public virtual IItemList FindAll(string sortExpression)

        {

            this.m_SortExpression = sortExpression;

            return StorageContext.Find(initialiseObjectPath());

        }

 

        ///

        /// Finds all.

        ///

        /// The sort expression.

        /// The page number.

        /// Size of the page.

        /// The page count.

        ///

        public virtual IItemList FindAll(string sortExpression, int pageNumber, int pageSize, out int pageCount)

        {

            //initialise the pagecount parameter

            pageCount = 0;

 

            //Set the pagecount parameter tot he actual value

            pageCount = (int)Math.Ceiling(Convert.ToDouble(getCount() / pageSize));

 

            //if we got a sort expression do initialize with it please

            if (!string.IsNullOrEmpty(sortExpression))

                m_SortExpression = sortExpression;

 

            //initialise the object pathe with the provide oPath parameter and initialise the order by

            ObjectPath path = initialiseObjectPath();

 

            //Tell Base4 which page to retrieve

            path.PageSize = pageSize;

            path.PageNumber = pageNumber;

 

            //Get the items

            return StorageContext.Find(path);

        }

 

        //internal method that gives the rowcount of all items.

        protected int getCount()

        {

            return StorageContext.FindAll().Count;

        }

 

        protected ObjectPath initialiseObjectPath()

        {

            ObjectPath path = new ObjectPath();

            return initialiseObjectPath(path);

        }

 

        ///

        /// Initialises the object path.

        ///

        /// The path.

        ///

        protected ObjectPath initialiseObjectPath(ObjectPath path)

        {

            //Do we have a sort expression

            if (!string.IsNullOrEmpty(m_SortExpression) && m_SortExpression.Trim().Length > 0)

            {

                //Give me all the sort parameters

                string[] sortParams = m_SortExpression.Split(“,”.ToCharArray());

 

                //Now go work out their object path

                foreach (string s in sortParams)

                {

                    //Work out the direction

                    OrderByDirection direction = s.IndexOf(“DESC”) > -1 ? OrderByDirection.Descending : OrderByDirection.Ascending;

 

                    //Work out the column

                    string orderby = s.Substring(0, s.IndexOf(“DESC”) > -1 ? s.IndexOf(“DESC”) : s.Length);

 

                    path.AddOrderBy(orderby, direction);

                }

            }

 

            return path;

        }

 

        ///

        /// Gets the Item as an item through a specified Object path.

        ///

        /// The Object path.

        ///

        public virtual T GetOne(string oPath)

        {

            return StorageContext.FindOne(new ObjectPath(oPath));

        }

 

        ///

        /// Finds the item by id and returns a list.

        ///

        /// The id.

        ///

        public virtual IItemList FindById(Guid Id)

        {

            IItemList itemList = StorageContext.Find(“Id=’{0}’”, Id.ToString());

            return itemList.Count > 0 ? itemList : new ItemList() as IItemList;

        }

 

        ///

        /// Gets the item by id as an item.

        ///

        /// The id.

        ///

        public virtual T GetById(Guid Id)

        {

            IItemList itemList = FindById(Id);

            return itemList.Count > 0 ? itemList[0] : new T();

        }

 

        ///

        /// Inserts the specified item.

        ///

        /// The item.

        ///

        public virtual T Insert(T item)

        {

            ((IItem)item).Save();

 

            return item;

        }

 

        ///

        /// Updates the specified item.

        ///

        /// The item.

        ///

        public virtual T Update(T item)

        {

            ((IItem)item).Save();

 

            return item;

        }

 

        ///

        /// Deletes the specified item.

        ///

        /// The item.

        public virtual void Delete(T item)

        {

            ((IItem)item).Delete();

 

        }

    }

}

This is the concrete implementation:

 

using Fogcreek.FogbugzEx;

 

namespace TimeSheets.Application.Dao

{

    public class TimesheetDao : Base.BaseDataObject

    {

    }

}

23

Sep
2006

A Bit Further Down the Castle Track

I’ve been playing with castle all day yesterday and I can say the more I work with it the more I like it and start to see the full power of the framework.

My previous post was more about my frustrations when using the webforms model.

One of castle’s strengths is the Inversion of Control pattern, an introduction to IoC can be found on the Joy of code partI, partII.  In castle they apply it via the windsor container

An introduction to castle can be found on the codeproject :
Introducing castle part I
Introducing castle part II

If you’re creating a website that has not a lot of interaction or a very complex interface you probably won’t benefit too much from castle. However if you know your project will be growing a lot or the interface is becoming quite complex then you’re probably better of using castle.

Asp.NET gives you instant speed for development but this slows down as the project becomes larger and your pages more complex it loses it’s power and attraction, at least in my case.  If you have ever spent a couple of hours on a site figuring out why something doesn’t have a value that should have one etc. you’ll understand what I’m talking about probably.

Castle on the other hand starts to really shine the more complex you’re application gets.  You define something once and you can re-use it in your whole application.  This is nice it means I can define a master layout, have a standard layout render in that master so I have a page :)

If you then add a list to that page with a detail you’ll quickly see that you would be able to call that listview over and over again from anywhere.
Yes, I see the power of castle. The question is do you ?

Tomorrow I’ll start a series on how to create a master detail using castle if somebody is interested. One that walks you through all the steps involved because I had a hard time figuring some stuff out. Not too hard if you consider that it took me about 1 week to get started with asp.net and about 2 weeks to get started with the atlas library. I have a written a timesheet application in  a couple of hours

20

Sep
2006

Am I Too Late ?

Yesterday I had a discussion with Alex about asp.NET where I vented some of the frustrations I have building a CRM application on one form with multiple user controls that have enough functionality in them that other people would create separate pages for it.

I don’t like the fact that you loose information about something you’re working on because you need to change a small piece of a bigger whole.

Anyway my problem is that to do something that is more complex than just simply displaying one form on a page asp.NET gets pretty complicated. Events are firing all over the place. I have to take viewstate into account. (I turned viewsate off because it was about 50K half way through my app.) And then it became even more difficult to get stuff to respond the way I want them to respond.

All in all it takes a really long time before I get something done properly. Where all it is actually doing is rendering small portions html out to the browser.

I have also been discussing with Alex on how to create something that takes a view definition and merges it with base4 domain objects to get to a view.

Well enter the castle project. I looked at it before but never really saw the point. Yesterday I got down and dirty with it and let me tell you I DO see the point now.

The way they built their framework resembles very closely how I was going to build ours.

It provides a more natural way of creating webpages in my mind than trying to force a winform programming model into a stateless model. Not to mention the speed in which you get things done.

I’m not the only one who joins the party this late

17

Sep
2006

Underwear Goes Inside the Pants

On myspace there is a page dedicated to a song Underwear goes inside the pants by Lazy Boy

I got to this page via the blog of a friend of mine,Miel Van Opstal 

It’s worth a listen definitely. An excerpt of the lyrics would be:

There are homeless people everywhere.
This homeless guy asked me for money the other day.
I was about to give it to him and then I thought he was going to use it on drugs or alcohol.
And then I thought, that’s what I’m going to use it on.
Why am I judging this poor bastard.
People love to judge homeless guys. Like if you give them money they’re just going to waste it.
Well, he lives in a box, what do you want him to do? Save it up and buy a wall unit?

Enjoy.

16

Sep
2006

Open Source Project Management

Yesterday I got to meet an Argentinian guy who joined the NBlogr

He showed me a couple of really cool sites that I thought would be a good idea to share.

An open-source resource oriented project management system : Open Workbench

An open-source search engine (finds open source programs built on Lucence) : Krugle 

And last but not least an article on the codeproject :

This article describes a “script engine” for the C# language. Here are some of the key features of the presented scripting system:

  • Based on the full featured C#.
  • Full access to CLR and CTS.
  • Can be run with any version of CLR (.NET 1.1/2.0), even potentially with future releases.
  • Possibility of extending the functionality of any CLR application with “scripting”, by hosting the script engine in this application.
  • Integration with common IDEs and debuggers.
  • Integration with OS.
  • Availability of comprehensive documentation (local and online Help, tutorials, samples…).

http://www.codeproject.com/csharp/cs-script_for_cp…

15

Sep
2006

Adding a Dynamic Language to the Toolbelt

It may or may not be a surprise to people that read my blog but I do web development and really like it.  But lately I feel constricted in my programming environment so I want to add another language. But let me share some of my history first.

I started programming as a young boy and wrote my first menu system for my pc when I was 8 I think. It was nothing really complicated a series of batch scripts so that my mother could easily navigate the pc. She has been having problems with a computer for as long as I can remember :) 

After that I moved to GW BASIC like other people will have had the pleasure of jumping back and forth to line numbers. A couple of years later I wrote snake in that language and some game related to soccer.

Around that time they put QuickBasic on the market and this is the point where everything that has the name Basic in it just looses my attention. Dim variable type = value just does NOT feel natural to me and that is just a variable declaration.. Don’t get me started on the other stuff.

So I kind of lost track of pc for a while and got a bass guitar instead.  Also a lot of fun, and the coolnes factor is not to be underestimated.

Next I came in contact with TurboPascal (I’m still not talking Object Oriented here) I think Turbopascal 4 and 5 it was, that I used to program some stuff in. Turbo pascal was a cool language and i wrote Black jack in that as my end project for the IT course in year 9 (3rd year of high school).

Next I didn’t really program at night anymore due to family related things and the fact that I didn’t have a pc at home would have a lot to do with it. This situation remained until I was 20 something. I must say that I did meet a lot of girls and learnt how to pour cocktails etc :)
In school I did get to do some programming I learnt dbaseIV and access.

So then I lost track of pc / IT all together for a while until I got a job as a helpdesk officer at an ISP. Helpdesk officer ==> Team leader ==> Junior Network engineer ==> Own business as webdevelopment.

I hadn’t programmed in a long time 8+ years but had asked all the companies that hired me if I could get to some programming soon. Of course I could but never really got to do it. That’s why I started my own company and so I re-learnt programming 3 years ago. I started with .NET in visual basic.NET that lasted about 5 days and switched to C#.

Now 3 years later I know how to write C#, javascript, actionscript, xml, xsl, xsl-fo, T-SQL And that would be it. Not too much but also not too bad for 3 years working knowledge.

Lately there has been ruby on stage as THE buzzword for productivity in programming. I think that it is more dynamic languages that are the strong point. Things I like in javascript are the anonymous functions or whatever they are called (  mypage.doSomework(‘myVar’, function(){ do some other work in a function }); ) would be an example.

Although a couple of people have been complaining about Joel’s posts on ruby. And I do think that on ruby Joel doesn’t hit the nail on the head but generally he does. John Lam strongly disagrees but he wrote rubyclr so he’s allowed to be defending his camp.

Anyway I felt it was time to learn a new language. Since everything I know are mostly C-based languages I toyed with the idea of C++ but then I feel like I should practice a different strain of languages.
As you may or may not know, I talk quite a lot to Alex James of Base4. And he put me on to ironpython.  The choice falls on IronPython or Ruby at this point.  On investigating both languages i came to the constation that they are both very similar like java and c# or javascript and actionscript.

And tonight I made a decission on which language to learn and it is IronPython
Going by the rule if both sides of a dilemma are equal chose the one with the biggest emotional response :) So I chose IronPython because it is invented by Guido Van Rossum (on wikipedia) who is a dutch guy which coincidentally happens to be my native language but I’m from Belgium so a very different accent.

I’ll let you know how the python adventures go as i move through them.. But depending on the workload I have I might not be able to do much with it in a short period of time.

To top