Archive for the 'Base4' Category

01MayNBlogr Presentation in Wellington


Tonight I got the chance to present my nblogr application to a larger audience. Unfortunately I’m in the process of fixing bugs in NBlogr and one of those bugs required me to make a change to NBlogr.Web/views/default/shared/mainmenu.boo . I had made this change on sunday around midnight right before I went to bed. Of course I forgot to test the application because and it wouldn’t run on my presentation.  When I got home it took me about 3 minutes to fix. I had to import a reference to Base4.Storage in the mainmenu.boo file.

I’d like to thank everybody for coming, their patience and listening to my ramblings.

Anyway I’ve included my slide deck in this post and I think it might be a good idea to post a couple more links to some of the people I mentioned in my talk.
http://www.base4.net  – Alex James, Auckland
http://blog.bittercoder.com – Alex Henderson, Auckland
http://www.ayende.com/blog
http://hammet.castleproject.org

http://www.castleproject.org
http://www.nunit.org
http://www.nblogr.com

svn repository:
https://svn.koolkraft.net/nblogr/trunk

NBlogr-Wellington 02 _05_2007.ppt (440 KB)

To get nblogr running on your machine follow these steps :

Make sure you have a subversion client installed or subversion itself.

C:\Projects> svn co https://svn.koolkraft.net/nblogr/trunk
C:\Projects> osql -E
1> create database nblogr
2> go
1> quit

open the nblogr solution.

change the connection string in web.config

The different configuration options are explained in the web.config

If you want to use a different extension than aspx you have to change the httphandler configuration and set the extension in nblogr/routing

if you want urls to be rewritten without an extension you will have to enable wildcard handling.

hit ctrl-f5 and it should take you through the configuration. If ctrl-f5 doesn’t work try setting up the application in IIS.

Update:
James Hippolite from telecom was so kind to blog most of the bullet points of my slides. Which can be found here http://tvornz.spaces.live.com/blog/cns!A93B6100E328706D!388.entry?_c=BlogPart&_c02_owner=1

18OctBase4 and Castle… the controller

The next bit for pages in general is that often they represent a list. Often this list is a really long list that you’d like to page through.

I put this functionality into a generic base controller class. The whole idea of my set up is to provide a technique called progressive enhancement of forms.  In short you create an application that works completely without javascript using hyperlinks for gets and submit buttons etc.  Then you attach some css selector classes to the different bits of functionality and you attach these behaviors to the html elements on your page.

I thought that that is a really nice way of enriching the experience of people that allow it to be enriched ;)   And that is the explanation of the ajaxCall bool variable on some of the methods

The first thing is the interface for the class :

using System;

namespace NBlogr.Presenter

{

    public interface INBlogrController

    {

        bool IsCompositeView{get;}

        void Delete(T item, int pageNumber, int pageSize);

        void Delete(T item, int pageNumber, int pageSize, bool ajaxCall);

        void Edit(Guid Id);

        void Edit(Guid Id, bool ajaxCall);

        void JumpToPage(int pageNumber, int pageSize);

        void JumpToPage(int pageNumber, int pageSize, bool ajaxCall);

        void List();

        void List(bool ajaxCall);

        void NavigateBack(int pageNumber, int pageSize);

        void NavigateFirst(int pageSize);

        void NavigateNext(int pageNumber, int pageSize);

        void NavigateBack(int pageNumber, int pageSize, bool ajaxCall);

        void NavigateFirst(int pageSize, bool ajaxCall);

        void NavigateNext(int pageNumber, int pageSize, bool ajaxCall);

        void Show();

        void Show(bool ajaxCall);

        void Save(T item, int pageNumber, int pageSize);

        void Save(T item, int pageNumber, int pageSize, bool ajaxCall);

        void CreateNew();

        void CreateNew(bool ajaxCall);

    }

}

And the next thing is the base class again :

using System;

using System.Collections.Generic;

using System.Text;

using Base4.Storage;

 

namespace NBlogr.Presenter.Abstract

{

    public abstract class AbstractAdminController : AbstractController, INBlogrController where T: class, IItem, new()

    {

        bool compositeView;

        int _pageSize;

 

        public AbstractAdminController()

            : base()

        {

            this.compositeView = false;

            _pageSize = 10;

        }

 

        public AbstractAdminController(bool compositeView) : base()

        {

            this.compositeView = compositeView;

            _pageSize = 10;

        }

 

        internal abstract void getList(int pageNumber, int pageSize, bool skipLayout);

 

 

        internal void getList(int pageNumber, int pageSize)

        {

            getList(pageNumber, pageSize, false);

 

        }

        #region INBlogrController Members

 

        public bool IsCompositeView

        {

            get

            {

                return compositeView;

            }

        }

        public int PageSize

        {

            get

            {

                return _pageSize;

            }

            set

            {

                _pageSize = value;

            }

        }

 

        public void Delete(T item, int pageNumber, int pageSize)

        {

            Delete(item,pageNumber,pageSize,false);

        }

 

        public abstract void Delete(T item, int pageNumber, int pageSize, bool ajaxCall);

 

        public void CreateNew()

        {

            CreateNew(false);

        }

 

        public virtual void CreateNew(bool ajaxCall)

        {

            Edit(Guid.NewGuid(), ajaxCall);

        }

 

        public void Edit(Guid Id)

        {

            Edit(Id, false);

        }

 

        public abstract void Edit(Guid Id, bool ajaxCall);

 

        public void JumpToPage(int pageNumber, int pageSize)

        {

            getList(pageNumber, pageSize);

        }

 

        public virtual void JumpToPage(int pageNumber, int pageSize, bool ajaxCall)

        {

            getList(pageNumber, pageSize, ajaxCall);

        }

 

        public void List()

        {

            getList(1, _pageSize);

        }

 

        public virtual void List(bool ajaxCall)

        {

            getList(1, _pageSize, ajaxCall);

        }

 

        public void NavigateBack(int pageNumber, int pageSize)

        {

            getList(–pageNumber, pageSize);

        }

 

        public void NavigateFirst(int pageSize)

        {

            getList(1, pageSize);

        }

 

        public void NavigateNext(int pageNumber, int pageSize)

        {

            getList(++pageNumber, pageSize);

        }

 

        public virtual void NavigateBack(int pageNumber, int pageSize, bool ajaxCall)

        {

            getList(–pageNumber, pageSize, ajaxCall);

        }

 

        public virtual void NavigateFirst(int pageSize, bool ajaxCall)

        {

            getList(1, pageSize, ajaxCall);

        }

 

        public virtual void NavigateNext(int pageNumber, int pageSize, bool ajaxCall)

        {

            getList(++pageNumber, pageSize, ajaxCall);

        }

 

        public void Show()

        {

            getList(1, _pageSize);

        }

 

        public virtual void Show(bool ajaxCall)

        {

            getList(1, _pageSize, ajaxCall);

        }

 

 

        public void Save(T item, int pageNumber, int pageSize)

        {

            Save(item, pageNumber, pageSize, false);

        }

 

        public abstract void Save(T item, int pageNumber, int pageSize, bool ajaxCall);

 

 

        #endregion

    }

}

Now onto the concrete implementation of my controller class

 

using System;

using System.Collections.Generic;

using System.Text;

using NBlogr.Core;

using NBlogr.Service;

using Base4.Storage;

using Castle.MonoRail.Framework;

using NBlogr.Common.Base4Integration;

using Castle.Services.Transaction;

 

namespace NBlogr.Presenter

{

 

    public class BlogController : Abstract.AbstractAdminController<Blog>

    {

        BlogService blogService;

        

        public BlogController(IService<Blog> blogService)

            : base(true)

        {

            this.blogService = blogService as BlogService;

             

             

        }

 

        private void internalGetList(int pageNumber, int pageSize)

        {

            int pageCount;

 

            IItemList<Blog> blog = blogService.GetAll(“Name”, pageNumber, pageSize, out pageCount);

 

            internalMapProperties(blog , pageNumber,pageSize, pageCount);

        }

 

        private void internalMapProperties(IItemList<Blog> blogs, int pageNumber, int pageSize, int pageCount)

        {

            int totalCount = blogs.Count;

 

            if (PropertyBag["blog"] == null)

                PropertyBag.Add(“blog”, new Blog());

            

            PropertyBag.Add(“blogs”, pageNumber);

            PropertyBag.Add(“index”, pageNumber);

            PropertyBag.Add(“count”, totalCount);

            PropertyBag.Add(“pageCount”, pageCount);

            PropertyBag.Add(“pageSize”, pageSize);

        }

 

        internal override void getList(int pageNumber, int pageSize, bool skipLayout)

        {

 

            internalGetList(pageNumber, pageSize);

 

            if (!skipLayout)

                RenderView(“Show”, false);

            else

                RenderView(“List”, true);

        }

 

 

 

 

        public override void Edit(Guid Id, bool ajaxCall)

        {

            Blog blog = blogService.GetById(Id);

 

            PropertyBag.Add(“blog”, blog);

             

            if (!ajaxCall)

            {

                getList(1, 0);

            }

            else

                RenderView(“Save”, ajaxCall);

 

        }

 

        public override void Delete([DataBind("blog")] Blog item, int pageNumber, int pageSize, bool ajaxCall)

        {

            blogService.Delete(item);

 

            if (!ajaxCall)

            {

                getList(1, 0);

            }

            else

                RenderText(getJsonResponse(“Contract deleted successfully”));

 

        }

 

        public override void Save([DataBind("blog")] Blog item, int pageNumber, int pageSize, bool ajaxCall)

        {

            PropertyBag.Add(“blog”, blogService.Save(item));

 

            if (!ajaxCall)

            {

                getList(1, 0);

            }

            else

                RenderText(getJsonResponse(“Contract saved successfully”));

        }

 

        private string getJsonResponse(string message)

        {

            return “{result: true, content: ‘” + message + “‘}”;

        }

 

    }

}

17OctBase4 and Castle … The service

UPDATE: THE SERVICE CLASS HAS CHANGED AGAIN.
Scratch the update.. it assumes that the object is already in the database which isn’t always the case. For this type of synchronisation to work I need some more time. So I reverted this back to the old version

This post continues my previous posts on using base4 and castle together.

I’m sorry but there is no Active record in the base4 way of doing things.

The previous posts you would be intrested in can be found here :

Hosting base4 inside your web application
Base4 and Castle continued… The facility

Today I want to show you the abstract service class that I use so the controller only talks to the service and never to the dataobject directly. 

It is not a very big class but i found it pretty useful.  As it turns out almost all my service classes in a previous project started to look very much alike so I grouped that functionality in an abstract class. There is one thing you have to look out for and that is if you have something like audit fields (Created, LastModified,…..) you need to first get the object from the datastore and then set just the changed properties on the retrieved object.

The first thing you need is the contract/interface for the service. I expect this interface to grow over time so keep checking NBlogr for updates but this where I am at now :)

using System;

namespace NBlogr.Service

{

    public interface IService

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

    {

        void Delete(T item);

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

        T GetById(Guid Id);

        T Save(T item);

    }

}

And here’s the abstract class :

using Base4.Storage;

using Castle.Core.Logging;

using NBlogr.Common.Base4Integration;

 

using User = NBlogr.Core.User;

using Castle.Services.Transaction;

using Base4.Storage.Utils;

 

namespace NBlogr.Service.Abstract

{

 

    [Transactional]

    public abstract class AbstractService : IService where T : class,IItem,new()

    {

        internal readonly ILogger logger;

        internal IDataObject dao;

 

 

        public AbstractService(ILogger logger, IDataObject dao)

        {

            this.logger = logger;

            this.dao = dao;

        }

 

        [Transaction(TransactionMode.Requires)]

        public virtual T Save(T item)

        {

            return dao.Save(internalPrepareSave(item));

        }

 

        internal abstract T internalPrepareSave(T item);

 

        [Transaction(TransactionMode.Requires)]

        public virtual void Delete(T item)

        {

            dao.Delete(item);

        }

 

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

        {

            return dao.FindAll(sortExpression, pageNumber, pageSize, out pageCount);

        }

 

        public virtual T GetById(Guid Id)

        {

            return dao.GetById(Id);

        }

 

 

    }

}

And the last bit could be an implementation of this service.  I don’t have companies in NBlogr. I took this class from another project :

using System;

using Castle.Services.Transaction;

using Castle.Core.Logging;

using NBlogr.Common.Base4Integration;

using NBlogr.Core;

 

namespace NBlogr.Service

{

    [Transactional]

    public class BlogService : Abstract.AbstractService<Blog>

    {

 

        public BlogService(ILogger logger, IDataObject<Blog> dao)

            : base(logger, dao)

        {

 

        }

 

        internal override Blog internalPrepareSave(Blog item)

        {

            Blog itemToSave = GetById(item.Id);

 

            if (!itemToSave.Internals.InDatabase)

            {

                itemToSave.Created = DateTime.Now;

                itemToSave.Creator = CurrentUser;

            }

 

            itemToSave.AkismetKey = item.AkismetKey;

            //TODO: finish mapping properties

 

            return itemToSave;

        }

    }

}

This concludes the service for use with base4.  I hope you find it as useful as I do.
If somebody knows improvements etc. Please let me know I am always keen to learn.

I also realise that I can just call save on an IItem object but i like every tier to have it’s specific task so the dataobject doesn’t do much else than call IItem.Save() for now

16OctBase4 on Castle continued… The facility

Much of what I’m going to show today has been borrowed from Alex Henderson on the storage facility.

This post continues the hosting base4 inside your web application post

To integrate base4 in castle you can register either components or create a facility which allows it to hook into some bits of the castle life-cycle.

It doesn’t make such a big difference when actually writing code except for the fact that you have transactions managed by castle, caching etc practically for free.

The ObjectTransaction that is available in base4 is built on the transaction scope and uses TransactionOptions.Required. Translated freely this means it will attach itself to an existing transaction if one exists if not it will create one.

So below I’ll first put the code for the storage facility and the base4TransactionManager and the configuration in the config files.  The full version of these files and the classes can be found in the source control repository of NBlogr

The storage facility

namespace NBlogr.Common.Base4Integration

{

    public class Base4StorageFacility : AbstractFacility

    {

        protected override void Init()

        {

            // If no context has been set yet (but should be done in application_start) set the default context.

            if (StorageContext.Default == null)

            {

                string base4Context = FacilityConfig.Attributes["base4Context"];

 

                if (string.IsNullOrEmpty(base4Context))

                {

                    throw new StorageException(“The Base4StorageFacility requires a \”base4Context\” attribute to be set”);

                }

 

                StorageContext.SetDefault(base4Context);

            }

 

            // Add the transactionmanager to the registered components

            Kernel.AddComponent(“base4.transactionManager”, typeof(ITransactionManager), typeof(Base4TransactionManager));

 

            // Add the IItemcontext to the registered components

            Kernel.AddComponentInstance(“base4.defaultContext”, typeof(IItemContext), StorageContext.Default);

 

            // Add the base4Dataobject

            Kernel.AddComponent(“base4.dataObject”, typeof(IDataObject<>), typeof(BaseDataObject<>));

 

        }

    }

}

 

 

The transaction manager

 

 

namespace NBlogr.Common.Base4Integration

{

    [PerThread]

    public class Base4TransactionManager : DefaultTransactionManager

    {

    }

}

 

The IDataObject interface

 

 

public interface IDataObject : IBaseDataObject

    where T : class, IItem, new()

    {

        void Delete(T item);

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

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

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

        Base4.Storage.IItemList Find(string oPath);

        Base4.Storage.IItemList Find(ObjectPath oPath);

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

        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, params object[] parameters);

        T GetOne(string oPath);

        T GetOne(ObjectPath oPath);

        T GetOneUsingSQL(string SQL);

        T GetOneUsingSQL(string SQL, ObjectScope scope);

        T GetOne(string opath, ObjectScope scope);

        T GetOne(ObjectPath path, ObjectScope scope);

        T Save(T item);

        string SortExpression { get; set; }

        void DeleteAll();

        void Delete(ObjectPath path);

        void Delete(string path);

        void Delete(string path, params string[] replaces);

        IItemList Find(ObjectPath path, ObjectScope scope);

        IItemList FindUsingSQL(string SQL);

        IItemList FindUsingSQL(string SQL, ObjectScope scope);

        IItemList Find(ObjectPath path, ObjectScope scope, string sortExpression, int pageNumber, int pageSize, out int pageCount);

        IItemList FindAll(ObjectScope scope, string sortExpression, int pageNumber, int pageSize, out int pageCount);

    }

 

The facilities.config file

 

 

<configuration>

 

  <facilities>

   

14OctSome 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.

12OctHosting 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 :

<%@ Application Inherits="NBlogr.Presentation.ASPGlobal" Language="C#" %>

11OctBase4 and NLog

As you know already I like base4 a lot

Alex Henderson has got a nice post on integrating base4 much prettier than I did in castle.  Later on today I’ll post what I made of it

I tried to use log4net but didn’t succeed.  So I switched to nlog which I like a lot.

Now to integrate nlog with base4 wasn’t all that hard.

This is the type from my schema which just stores about anything i would want to know about a particular event. and probably more in my case :)

 

    <Type FullName=NBlogr.Core.AppEvent baseName=Base4.Storage.ItemImpl keyProperty=Id version=1 mode=Rich>

      <Property name=ApplicationContext typeName=Base4.Storage.ContentStream nullable=True />

      <Property name=EventTime typeName=System.DateTime />

      <Property name=Exception typeName=System.String nullable=True length=1025 />

      <Property name=Id typeName=System.Guid unique=True />

      <Property name=Level typeName=System.String length=256 />

      <Property name=LoggerName typeName=System.String length=256 />

      <Property name=Message typeName=System.String length=1025 />

      <Property name=Sequence typeName=System.Int32 nullable=True />

      <Property name=StackTrace typeName=System.String nullable=True length=1025 />

      <Property name=UserStackFrame typeName=System.String nullable=True length=1025 />

    Type>

 

The actual target :

 

namespace NBlogr.Common.Base4Integration

{

    ///

    /// This is a target for the nlog logging library.

    /// This is dependent on the NBlogr.Core.xml file and Base4.

    ///

    [Target("Base4Target")]

    public class Base4Target : TargetWithLayout

    {

        private string _host = “tcp://server:@localhost:999/Base4_Default”;

 

        public string Base4Context

        {

            get { return _host; }

            set { _host = value; }

        }

 

        protected override void Write(LogEventInfo logEvent)

        {

            string logMessage = CompiledLayout.GetFormattedMessage(logEvent);

 

            if(StorageContext.Default == null)

                StorageContext.SetDefault(Base4Context);

 

            AppEvent appEvent = new AppEvent();

            appEvent.Sequence = logEvent.SequenceID;

 

            if(logEvent.Context != null && logEvent.Context.Count > 0)

                appEvent.ApplicationContext.Content = GetZippedBytes(logEvent.Context);

 

            appEvent.EventTime = logEvent.TimeStamp;

 

            if(logEvent.Exception != null) appEvent.Exception = logEvent.Exception.ToString();

 

            if(logEvent.StackTrace != null) appEvent.StackTrace = logEvent.StackTrace.ToString();

            if (logEvent.UserStackFrame != null) appEvent.UserStackFrame = logEvent.UserStackFrame.ToString();

 

            appEvent.Level = logEvent.Level.Name;

            appEvent.LoggerName = logEvent.LoggerName;

            appEvent.Message = logMessage;

 

            appEvent.Save();

 

 

        }

 

        private byte[] GetZippedBytes(IDictionary evt)

        {

            MemoryStream ms = new MemoryStream();

 

            BinaryFormatter formatter = new BinaryFormatter();

 

            formatter.Serialize(ms, evt);

 

            GZipStream zipStream = new GZipStream(ms, CompressionMode.Compress);

 

            BinaryReader bRdr = new BinaryReader(zipStream);

 

            return bRdr.ReadBytes((int)zipStream.Length);

 

        }

    }

}

23SepBase4 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<T>

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

    {

        void Delete(T item);

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

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

        Base4.Storage.IItemList<T> Find(string oPath);

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

        Base4.Storage.IItemList<T> FindAll(string sortExpression);

        Base4.Storage.IItemList<T> FindAll();

        Base4.Storage.IItemList<T> 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<T> : Base.DataObject, Contract.Data.IDataObject<T> 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<T> Find(string oPath)

        {

            //set the default sort expression to none

            this.m_SortExpression = string.Empty;

 

            //Get my stuff

            return StorageContext.Find<T>(initialiseObjectPath(new ObjectPath(oPath)));

        }

 

        ///

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

        ///

        /// The Object path.

        /// The sort expression.

        ///

        public virtual IItemList<T> Find(string oPath, string sortExpression)

        {

            //Set the default sort expression

            this.m_SortExpression = sortExpression;

 

            //Get the data out

            return StorageContext.Find<T>(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<T> 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<T>(path);

        }

 

        ///

        /// Finds all items.

        ///

        ///

        public virtual IItemList<T> FindAll()

        {

            this.m_SortExpression = string.Empty;

            return StorageContext.Find<T>(initialiseObjectPath());

        }

 

        ///

        /// Finds all the items sorted.

        ///

        /// The sort expression.

        ///

        public virtual IItemList<T> FindAll(string sortExpression)

        {

            this.m_SortExpression = sortExpression;

            return StorageContext.Find<T>(initialiseObjectPath());

        }

 

        ///

        /// Finds all.

        ///

        /// The sort expression.

        /// The page number.

        /// Size of the page.

        /// The page count.

        ///

        public virtual IItemList<T> 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<T>(path);

        }

 

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

        protected int getCount()

        {

            return StorageContext.FindAll<T>().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<T>(new ObjectPath(oPath));

        }

 

        ///

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

        ///

        /// The id.

        ///

        public virtual IItemList<T> FindById(Guid Id)

        {

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

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

        }

 

        ///

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

        ///

        /// The id.

        ///

        public virtual T GetById(Guid Id)

        {

            IItemList<T> 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<Timesheet>

    {

    }

}

31AugObjectdatasource, gridview and custom paging

I’ve spent the last couple of hours trying to work something out that boggled my mind.

I have a base4 class that I wrapped in a Dataobject in my Businesslayer.

On my page (actually in a user control) i have a gridview that binds to an object datasource and stores the list of retrieved values in the viewstate. The business object is paged server side and supports sorting.

The business object looks at it’s simplest like this :

There are 2 methods for every retrieval function. the first method is the method that fetches the list of data to display and the second method just gives the full row count. There are 2 methods because their signatures need to be the same.

What i then did was handle the objectSelected event of the object datasource and pass the e.ReturnValue to a property of my control that stores the list in viewstate.
When i select something in the gridview I always got an exception thrown telling me that the variable in viewstate was null.

After a lot of debugging sessions (in a solution that takes about 10 minutes or a little longer to build) I found out that i get a value in the viewstate but then lost it again in the same operation.

And that’s when it hit me. The object datasource selected event gets also fired for the count method and empties the viewstate. So now I have a second round trip to my database to stick the values in the viewstate and everything works.

So if anybody comes across a similar problem this is how i got around it.
I do realize the importance of caching ;)

The objectdatasource definition:

“ObjectDataSource1″ runat=“server” DataObjectTypeName=“Smap.Data.Contact”
EnablePaging=“True” MaximumRowsParameterName=“pageSize” OldValuesParameterFormatString=“original_{0}”
SelectCountMethod=“GetByCompanyNameCount” SelectMethod=“GetByCompanyName” SortParameterName=“sortExpression”
TypeName=“Smap.Businesslogic.Contacts.ContactSource” EnableViewState=“true” OnSelected=“ObjectDataSource1_Selected”>

“SearchList” Name=“searchString” PropertyName=“Text”
Type=“String” />
“sortExpression” Type=“String” />
“startRowIndex” Type=“Int32″ />
“pageSize” Type=“Int32″ />

And the objectdatasource selected event :

    protectedvoid ObjectDataSource1_Selected(object sender, ObjectDataSourceStatusEventArgs e)

    {

        if (e.OutputParameters.Keys.Count > 0)

        {

            foreach (object key in e.OutputParameters.Keys)

            {

                Response.Write(string.Format(“Key: {0}, Value: {1}, Type: {2}
,key,e.OutputParameters[key],e.OutputParameters[key].GetType()));

            }

        }

        Contacts = source.GetByCompanyNameByPage(SearchList.Text, gvContacts.SortExpression, gvContacts.PageIndex, gvContacts.PageSize) asItemList<Contact>;

    }




The business object :

using System;

using System.Collections.Generic;

using System.Text;

using System.ComponentModel;

using Smap.Data;

using Base4.Storage;

 

namespace Smap.Businesslogic.Contacts

{

    [DataObject]

    publicclassContactSource

    {

        [DataObjectMethod(DataObjectMethodType.Select,true)]

        publicIItemListContact> GetByCompanyName(string searchString, string sortExpression, int startRowIndex, int pageSize)

        {

            //Set the default sortexpression is none is provided.

            if (string.IsNullOrEmpty(sortExpression))

                sortExpression = “CompanyName”;

 

            //The objectdatasource returns the index of the first row that is to be retrieved

            //Base4 needs the page number

            int pageNumber = getPageNumber(startRowIndex, pageSize);

 

            //initialise the object path with the sort expression

            ObjectPath path = initialiseObjectPath(sortExpression);

 

            //Add our parameter

            path.New(“CompanyName”).LIKE(string.Format(“%{0}%”, searchString));

 

            //Tell base4 which pages that need to be retrieved.

            path.PageNumber = pageNumber;

            path.PageSize = pageSize;

 

            //Return our list to the object datasource

            returnStorageContext.FindContact>(path);

        }

 

        [DataObjectMethod(DataObjectMethodType.Select, true)]

        publicIItemListContact> GetByCompanyNameByPage(string searchString, string sortExpression, int pageNumber, int pageSize)

        {

            //Set the default sortexpression is none is provided.

            if (string.IsNullOrEmpty(sortExpression))

                sortExpression = “CompanyName”;

 

            //initialise the object path with the sort expression

            ObjectPath path = initialiseObjectPath(sortExpression);

 

            //Add our parameter

            path.New(“CompanyName”).LIKE(string.Format(“%{0}%”, searchString));

 

            //Tell base4 which pages that need to be retrieved and their length.

            //The gridview returns the page index which is zero-based, base4 asks for a page number which starts at 1.

            path.PageNumber = ++pageNumber;

            path.PageSize = pageSize;

            returnStorageContext.FindContact>(path);

        }

 

 

        publicint GetByCompanyNameCount(string searchString, string sortExpression, int startRowIndex, int pageSize)

        {

            //Gets the count of all the contacts.

            returnStorageContext.FindAllContact>().Count;

        }

 

 

        privateObjectPath initialiseObjectPath(string sortExpression)

        {

            ObjectPath path = newObjectPath();

            if (sortExpression.Trim().Length > 0)

            {

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

 

                foreach (string s in sortParams)

                {

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

 

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

 

 

                    path.AddOrderBy(orderby, direction);

                }

            }

 

            return path;

        }

 

        privateint getPageNumber(int startRowIndex, int pageSize)

        {

            //if the start index is smaller than 0 return 0 otherwise return the index of the current page.

            int number = startRowIndex <= 0 ? 0 : (int)Math.Ceiling(Convert.ToDouble(startRowIndex / pageSize));

 

            //make our zero-based index into a number starting at 1;

            return ++number;

        }

 

    }

}

29AugA generic builder for unit tests

I’ve been using base4 quite a lot lately :) . And obviously I like it. But anyway for unit testing i found myself writing
virtually the same builder class over and over again.

And since it is just test data that needs to be removed later it is always
very similar. I started thinking about my problem and came to the conclusion
that I could easily enough build a generic class that iterates over the object
and takes all the properties that belong to that type and not to any of the
parent types and fill them with valid data for their returntype.

I got to work and not so long after that I came up with the following class:

using System;

using System.Collections.Generic;

using System.Text;

using Base4.Storage;

 

namespace NBlogr.NUnitTests.HelperClasses

{

    publicclassBuilder where T : class,IItem,new()

    {

        privateList items;

 

        publicList Items

        {

            get

            {

                if (items == null) items = newList();

                return items;

            }

            set { items = value; }

        }

 

        publicvirtual T Add()

        {

            return Add(null);

        }

 

        public T Add(int? index)

        {

            T t = new T();

            return Add(t, index, true);

        }

 

        publicvirtual T Add(T t, int? index, bool generateValues)

        {

            IItem item = t;

            if (generateValues)

            {

                foreach (PropertyImpl p in item.TypeDefinition.Properties)

                {

                    switch (p.ReturnTypeName)

                    {

                        case“bool”:

                        case“Boolean”:

                        case“System.Boolean”:

                            item[p.Name] = index.HasValue;

                            break;

                        case“string”:

                        case“String”:

                        case“System.String”:

                            if (index.HasValue)

                                item[p.Name] = string.Format(“Unittest {0} {1}”, item.TypeDefinition.Name, index);

                            else

                                item[p.Name] = string.Format(“Unittest {0}”, item.TypeDefinition.Name);

                            break;

                        case“uint”:

                        case“short”:

                        case“int”:

                        case“long”:

                        case“Int16″:

                        case“Int32″:

                        case“Int64″:

                        case“System.Int16″:

                        case“System.Int32″:

                        case“System.Int64″:

                            item[p.Name] = index.HasValue ? index.Value : newRandom().Next();

                            break;

                        case“byte”:

                        case“Byte”:

                        case“System.Byte”:

                            item[p.Name] = index.HasValue ? Convert.ToByte(index.Value) : newbyte();

                            break;

 

                        case“double”:

                        case“Double”:

                        case“System.Double”:

                            item[p.Name] = index.HasValue ? Convert.ToDouble(index.Value) : newRandom().NextDouble();

                            break;

 

                        case“byte[]“:

                        case“Byte[]“:

                        case“System.Byte[]“:

                            Byte[] bytes = newbyte[128];

                            Random rnd = newRandom();

                            rnd.NextBytes(bytes);

                            item[p.Name] = bytes;

                            break;

 

                        case“Guid”:

                        case“System.Guid”:

                            item[p.Name] = Guid.NewGuid();

                            break;

                    }

                }

            }

            item.Save();

 

            items.Add((T)item);

 

            return item as T;

        }

 

        publicvoid BuildList()

        {

            BuildList(5);

        }

 

        publicvoid BuildList(int length)

        {

            if (items == null) items = newList();

 

            for (int i = 0; i < length; i++)

            {

                int index = i + 1;

 

                Add(index);

            }

 

        }

 

        publicvoid CleanUp()

        {

            if (items != null && items.Count> 0)

            {

                foreach (IItem item in items)

                {

                    item.Delete();

 

                }

            }

        }

    }

}

Recent Flickrs

    Blogroll

    Recent Listening

    Scrobbler