Monthly Archives: October 2008

ASP.NET MVC: LogError Action Filter

I am messing about with the ASP.NET MVC Beta, and have stumbled into the Action Filter arena.  Specifically, I was checking out the HandleError Attribute which redirects to a local or shared error page if an appropriately attributed controller thows an error.  This is similar to the rescue stuff in Rails/MonoRail, and it’s nice.

However, we also want to log the error, so I started to put a logger in the Application_Error method of the Global application, but I am not wild about that option.  It either forces me to handle every exception the exact same way or leads me down the path of the Huge Swtich Statement and neither of those paths really blows my skirt up.  If I could just augment the HandleError functionality, which I like, with some configurable logging functionality, which I want, then life would be good.

As you might imagine, this is very easy.  In fact, I bet I haven’t even found the easiest way, but I’ll write what I did anyway.  Simply subclassing the HandleErrorAttribute class to a new LogErrorAttribute class and overriding OnException does the job.

public class LogErrorAttribute: HandleErrorAttribute

{

private readonly ILog _logger;

public LogErrorAttribute()

{

log4net.Config.BasicConfigurator.Configure();

_logger = log4net.LogManager.GetLogger(GetType());

}

public override void OnException(ExceptionContext filterContext)

{

_logger.Error(filterContext.Exception.Message);

base.OnException(filterContext);

}

}

I am using log4net here, which means I have to put a <log4net> section in my web.config.  It also means that I can change out where/how things are logged using the awesome log4net configuration options.  Very nice.  Also, since I inherit from HandleErrorAttribute, the redirect to the Error views (default and specified) is still in play.  Me likey.  Just attribute your Controller classes and/or methods with [LogError] and the logging just works.

My guess is some of the big brains out there have a better/cleaner way to do this, since I am pretty new to the ASP.NET MVC world.   If so, put it in the comments please.

Reblog this post [with Zemanta]

The Bitter Coder Tutorials, Binsor Style: XIV Startable Facilities

Previous posts in the series:

The last (until Alex writes more) of our Bitter Binsor tutorials is here.  Today, we focus on the Startable Facility, which is explained in Alex’s post.  The link to the wiki in Alex’s post is no good, so try here for more info on the facility.  Basically, something is startable if it has the Start/Stop controllable lifecycle, like a web server.  In Castle, to be considered Startable you have to implement the IStartable interface:

/// <summary>

/// Interface for components that wish to be started by the container

/// </summary>

public interface IStartable

{

/// <summary>

/// Starts this instance.

/// </summary>

void Start();

/// <summary>

/// Stops this instance.

/// </summary>

void Stop();

}

Once you register the Startable Facility with the Windsor Container, it will attempt to create and call .Start() on any startable component, provided all the dependencies have been satisfied.  So, every time a component is registered with the container, Windsor checks to see if a startable component has all dependencies satisfied and can be started.  Alex discusses the startable facility more in his post, so make sure you read it too.
Let’s create the LameHttpServer using this code:

public class LameHttpServer:IStartable

{

private string _path;

private HttpListener _listener;

private Thread _listenerThread;

private ILogger _logger;

public ILogger Logger

{

get

{

if (_logger == null)

_logger = NullLogger.Instance;

return _logger;

}

set { _logger = value; }

}

public LameHttpServer(string prefix, string path)

{

_path = path;

_listener= new HttpListener();

_listener.Prefixes.Add(prefix);

}

public void Start()

{

Logger.Debug(“Starting LameWebService…”);

_listener.Start();

_listenerThread = new Thread(RequestWorker);

_listenerThread.Start();

Logger.Info(“LameWebService started…”);

}

public void Stop()

{

Logger.Debug(“Stopping LameWebService…”);

_listenerThread.Abort();

_listener.Stop();

Logger.Info(“LameWebService stopped.”);

}

private void RequestWorker()

{

while (true)

{

HttpListenerContext _context = null;

try

{

_context=_listener.GetContext();

} catch (ObjectDisposedException ex)

{

return;

}

ServeContext(_context.Response, _path);

}

}

private void ServeContext(HttpListenerResponse response, string _path)

{

string content = File.ReadAllText(_path);

byte[] buffer = Encoding.UTF8.GetBytes(content);

response.ContentLength64 = buffer.Length;

Stream output = response.OutputStream;

output.Write(buffer, 0 , buffer.Length);

output.Close();

}

}

Looking at the class, we need a couple of configuration parameters as well as a dependency on  ILogger.  We’ll use the Castle Logging Facility for that, which is probably the facility I use most.  You should check it out.  Anyway, here’s our Binsor:
facility "startable.facility", StartableFacility

facility "logging.facility",LoggingFacility:
  loggingApi=LoggerImplementation.Console

component "lame.http", LameHttpServer:
    prefix="http://*:8089/"
    path="lame.html"

So, we register the facilities discussed earlier.  BTW, in order to resolve the facilities, I had to add the following to the top of Windsor.boo, in the import section:

import Castle.Facilities.Startable from Castle.MicroKernel
import Castle.Facilities.Logging

Also, I added  a reference to the Castle.Facilites.Logging assembly.  I already had a reference for Castle.MicroKernel from a previous post.

Let’s look at our console code to crank up the server:

public static void Main(string[] args)

{

container = new WindsorContainer().Install(BinsorScript.FromFile(“windsor.boo”));

GetPage();

container.Dispose();

GetPage();

}

private static void GetPage()

{

Console.WriteLine(“\r\nClient: requesting http://localhost:8089/…&#8221;);

try

{

WebClient client = new WebClient();

string content = client.DownloadString(http://localhost:8089/&#8221;);

Console.WriteLine(“Client: success, content follows.\r\n\r\n {0}”, content);

} catch (WebException ex)

{

Console.WriteLine(“Client: Exception occurred, message {0}”,ex.Message);

}

}

So, as can be seen above, we

  1. Create the container, which kicks off the server, coz it’s all Startable and stuff.
  2. Call GetPage().
  3. Dispose of the conatainer.
  4. Call GetPage() again.
  5. Wonder aloud of Alex minds plagiarism.

Here’s the results:

[Debug] 'BitterCoder.Tutorials.Binsor.Core.LameHttpServer' Starting LameWebService...
[Info] 'BitterCoder.Tutorials.Binsor.Core.LameHttpServer' LameWebService started...

Client: requesting http://localhost:8089/...
Client: success, content follows.

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
        <head>
                <title></title>
        </head>
        <body>
             <h1>Lame.html</h1>
        <h2>Welcome to lame.html file</h2>
        <p>This is the contents of the lame.html file, neat huh?</p>
        </body>
</html>
[Debug] 'BitterCoder.Tutorials.Binsor.Core.LameHttpServer' Stopping LameWebService...
[Info] 'BitterCoder.Tutorials.Binsor.Core.LameHttpServer' LameWebService stopped.

Client: requesting http://localhost:8089/...
Client: Exception occurred, message Unable to connect to the remote server

The error at the end of the results is due to us disposing of the container, which decommisions all the components in the container.  Alex explains this well…so read what he said.

So, I am gonna modify Alex’s final example where he demonstrates lifestyles and their effect on Startable facilities.  The only difference, really, is I am  going to show you what the Binsor looks like to control the lifestyle of a component.

Here’s our StartableExperiment:

public class StartableExperiment : IStartable

{

private static int _count;

private readonly int _number;

public StartableExperiment()

{

_number = ++_count;

}

#region IStartable Members

public void Start()

{

Console.WriteLine(“Started #{0}”, _number);

}

public void Stop()

{

Console.WriteLine(“Stopped #{0}”, _number);

}

#endregion

}

And the Binsor:

component "startable.exp", StartableExperiment:
    @lifestyle=LifestyleType.Transient

(You need to import Castle.Core to get the LifestyleType enum)

Running the following program code:

StartableExperiment exp1 = container.Resolve<StartableExperiment>();

container.Release(exp1);

StartableExperiment exp2 = container.Resolve<StartableExperiment>();

container.Release(exp2);

yields:

Started #1
Started #2
Stopped #2
Started #3
Stopped #3
Stopped #1

If I change the @lifestyle attribute in the Binsor to LifestyleType.Singleton, I get:

Started #1
Stopped #1

And that’s Startable Facilities and their lifestyles, from a Binsor point-of-view.

So, I hope someone enjoyed the series.  Thanks again to Alex for his tutorials.  They were a big rung in my learning ladder for Windsor.

I created a VS.NET project with all the code from this series.  If you’re interested, hit me at glenn(dot)goodrich(at)gmail.com.


The Bitter Coder Tutorials, Binsor Style: Injecting Service Arrays

Previous posts in the series:

This post feeds off off Part 12 and is based on Alex’s post here.  We are going to rework the last post and remove the decorator pattern.  Instead, we’ll create a calculator that manages any number of other calculators, which are injected as an array.

So, in keeping with my shameless plagirizing of Alex’s code, here is the abstract class for our new calculators:

namespace BitterCoder.Tutorials.Binsor.Core

{

public abstract class AbstractCalculator

{

public abstract decimal Calculate(decimal currentTotal, Order order);

}

}

And now our total calculator:

using System.Linq;

 

namespace BitterCoder.Tutorials.Binsor.Core

{

public class TotalCalculator : AbstractCalculator

{

private static decimal CalculateTotal(Order order)

{

return order.Items.Sum(item => item.CostPerItem*item.Quantity);

}

 

public override decimal Calculate(decimal currentTotal, Order order)

{

return currentTotal + CalculateTotal(order);

}

}

}

And the GST calculator:

namespace BitterCoder.Tutorials.Binsor.Core

{

public class GSTCostCalculatorNoDecorator : AbstractCalculator

{

private decimal _gstRate = 1.125m;

 

public decimal GstRate

{

get { return _gstRate; }

set { _gstRate = value; }

}

 

private static bool IsNewZealand(Order order)

{

return (order.CountryCode == “NZ”);

}

 

public override decimal Calculate(decimal currentTotal, Order order)

{

if (IsNewZealand(order))

{

return (currentTotal*_gstRate);

}

return currentTotal;

}

}

}

The shipping calculator:

namespace BitterCoder.Tutorials.Binsor.Core

{

public class ShippingCalculatorNoDecorator : AbstractCalculator

{

private decimal _fragileShippingPremium = 1.5m;

private decimal _shippingCost = 5.0m;

 

public decimal ShippingCost

{

get { return _shippingCost; }

set { _shippingCost = value; }

}

 

public decimal FragileShippingPremium

{

get { return _fragileShippingPremium; }

set { _fragileShippingPremium = value; }

}

 

private decimal GetShippingTotal(Order order)

{

decimal shippingTotal = 0;

return order.Items.Sum(item =>

{

decimal itemShippingCost = ShippingCost*item.Quantity;

if (item.IsFragile) itemShippingCost *= FragileShippingPremium;

return shippingTotal += itemShippingCost;

});

}

 

public override decimal Calculate(decimal currentTotal, Order order)

{

return currentTotal + GetShippingTotal(order);

}

}

}

Lastly, our calculator of calculators, the reworked DefaultCalculator:

public class DefaultCalculatorNoDecorator : ICostCalculator

{

private readonly AbstractCalculator[] _calculators;

 

public DefaultCalculatorNoDecorator(AbstractCalculator[] _calculators)

{

this._calculators = _calculators;

}

 

 

public decimal CalculateTotal(Order order)

{

decimal currentTotal = 0;

 

return _calculators.Sum(calc => calc.Calculate(currentTotal, order));

}

}

 

So, we’ll inject an array of calculators (total, shipping, and gst) into our default calculator. Binsor, away!

component "default.calculator", ICostCalculator,DefaultCalculatorNoDecorator:
    _calculators=[@total.calculatornodec,@shipping.calculatornodec,@gst.calculatornodec]

component "total.calculatornodec", AbstractCalculator,TotalCalculator

component "gst.calculatornodec", AbstractCalculator, GSTCostCalculatorNoDecorator:
    GstRate=Convert.ToDecimal(1.20)

component "shipping.calculatornodec", AbstractCalculator, ShippingCalculatorNoDecorator:
    FragileShippingPremium=Convert.ToDecimal(0.0)

Just like we did in our post on arrays, we inject an array of dependencies.  Changing the order is just a matter of switching the order in the binsor.  All good.

Running the program gives the same output as the last post.

Next post, which is the last in the series until Alex writes more (whew), is on the “Startable” facility.

Reblog this post [with Zemanta]

The Bitter Coder Tutorials, Binsor Style: Part XII, Decorators

UML Class diagram of the decorator pattern

Image via Wikipedia

Previous posts in the series:

Today’s post focuses on Decorators.  The Decorator Pattern is a well-known design pattern where functionality is added to a class by wrapping it with another class.  Like an onion, sorta.  Anyway, copying Alex, we are going to use this pattern with Windsor to chain implementations together.

Here is our Order and OrderItem classes:

public class Order

{

private readonly List<OrderItem> _items = new List<OrderItem>();

public List<OrderItem> Items

{

get { return _items; }

}

public string CountryCode { get; set; }

}

public class OrderItem

{

public OrderItem(string name, int quantity, decimal costPerItem, bool isFragile)

{

Name = name;

Quantity = quantity;

CostPerItem = costPerItem;

IsFragile = isFragile;

}

public bool IsFragile { get; set; }

public int Quantity { get; set; }

public decimal CostPerItem { get; set; }

public string Name { get; set; }

}

And an interface to calculate the cost of an order:

public interface ICostCalculator

{

decimal CalculateTotal(Order order);

}

Our default cost calculator (Side note: I like LINQ):

public class DefaultCostCalculator:ICostCalculator

{

public decimal CalculateTotal(Order order)

{

return order.Items.Sum(ord => ord.CostPerItem*ord.Quantity);

}

}

Our Binsor for the DefaultCostCalculator:

component "default.calculator", ICostCalculator,DefaultCostCalculator

Now, the program itself:

static void Main(string[] args)

{

var order1 = new Order

{

CountryCode = “NZ”,

Items =

{

new OrderItem(“water”, 10, 1.0m, false),

new OrderItem(“glass”, 5, 20.0m, true)

}

};

var order2 = new Order

{

CountryCode = “US”,

Items =

{

new OrderItem(“sand”, 50, 0.2m, false)

}

};

var _calc = container.Resolve<ICostCalculator>();

Console.WriteLine(“Cost to deliver Order 1: {0}”, _calc.CalculateTotal(order1));

Console.WriteLine(“Cost to deliver Order 2: {0}”, _calc.CalculateTotal(order2));

}

Running the program, gives us:

Cost to deliver Order 1: 110.0
Cost to deliver Order 2: 10.0

Now, let’s go to New Zealand where we have to pay the Goods and Services Tax.  Here is our cost calculator for that:

public class GstCostCalcualtorDecoarator : ICostCalculator

{

private readonly ICostCalculator _innerCalculator;

private decimal _gstRate = 1.125m;

public GstCostCalcualtorDecoarator(ICostCalculator innerCalculator)

{

_innerCalculator = innerCalculator;

}

public decimal GstRate

{

get { return _gstRate; }

set { _gstRate = value; }

}

#region ICostCalculator Members

public decimal CalculateTotal(Order order)

{

decimal innerTotal = _innerCalculator.CalculateTotal(order);

if (IsNewZealand(order))

{

innerTotal = (innerTotal*_gstRate);

}

return innerTotal;

}

#endregion

private bool IsNewZealand(Order order)

{

return (order.CountryCode == “NZ”);

}

}

And here’s the Decorator pattern.  The GstCostCalculatorDecorator class accepts another ICostCalculator, then modifies the result by adding the GST.  The DefaultCostCalculator is clueless to the GST, which is the beauty inherit in the pattern.

Let’s wire up the Binsor:

component "gst.calculator", ICostCalculator, GstCostCalculatorDecorator:
    innerCalculator=@default.calculator

component "default.calculator", ICostCalculator,DefaultCostCalculator

We put the GST calculator first, so it’s the default implementation, and run the program:

Cost to deliver Order 1: 123.7500
Cost to deliver Order 2: 10.0

So, the US one hasn’t changed, as expected.  Finally, let’s add a shipping calculator:

public class ShippingCostCalculatorDecorator : ICostCalculator

{

private readonly ICostCalculator _innerCalculator;

public decimal ShippingCost { get; set; }

public decimal FragileShippingPremium { get; set; }

public ShippingCostCalculatorDecorator(ICostCalculator innerCalculator)

{

_innerCalculator = innerCalculator;

ShippingCost = 5.0m;

FragileShippingPremium = 1.5m;

}

#region ICostCalculator Members

public decimal CalculateTotal(Order order)

{

decimal innerTotal = _innerCalculator.CalculateTotal(order);

return innerTotal + GetShippingTotal(order);

}

#endregion

private decimal GetShippingTotal(Order order)

{

return order.Items.Sum(item =>

{

var itemShippingCost = ShippingCost*item.Quantity;

if (item.IsFragile) itemShippingCost *= FragileShippingPremium;

return itemShippingCost;

});

}

}

And add our Binsor, making sure it’s the first ICostCalculator implementation in the file:

component "shipping.calculator", ICostCalculator, ShippingCostCalculatorDecorator:
    innerCalculator=@gst.calculator

Run it.

Cost to deliver Order 1: 211.2500
Cost to deliver Order 2: 260.0

As Alex points out, we are calculating our GST before shipping, which is kinda stoopid.  The Decorator Pattern saves our bacon here, as we can just swap things around (oh, and we change some parameters too):

component "gst.calculator", ICostCalculator, GstCostCalculatorDecorator:
    innerCalculator=@gst.calculator
    GstRate=1.20

component "shipping.calculator", ICostCalculator, ShippingCostCalculatorDecorator:
    innerCalculator=@default.calculator
    FragileShippingPremium=0.0

component "default.calculator", ICostCalculator,DefaultCostCalculator

Run it one more time:

Cost to deliver Order 1: 211.2500
Cost to deliver Order 2: 260.0

So, that’s that.  Alex has some great comments in his post about other stuff you can do with the Decorator pattern, so I highly recommend you read his all the way through.

Next time we’ll do this stuff without decorators….

Reblog this post [with Zemanta]