<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-706849474835530339</id><updated>2011-11-27T23:55:09.701Z</updated><category term='HttpStatus'/><category term='xor'/><category term='reflection'/><category term='MVC'/><category term='javascript'/><category term='smart'/><category term='web'/><category term='static method'/><category term='window.open'/><category term='singleton'/><category term='303'/><category term='model view controller'/><category term='UI'/><category term='hd2'/><category term='concrete implementation'/><category term='interfaces'/><category term='Winforms'/><category term='http'/><category term='phone'/><category term='validation'/><category term='extension methods'/><category term='302'/><category term='deployment project'/><category term='BLL'/><category term='encryption'/><category term='inheritance'/><category term='request object'/><category term='Domain object model'/><category term='RouteData'/><category term='ActionFilter'/><category term='mobile phone'/><category term='windows mobile'/><category term='HttpRequestBase'/><category term='HttpRequest'/><category term='DAL'/><category term='windows phone'/><category term='PRG'/><category term='maintainable code'/><category term='Webforms'/><category term='enum'/><category term='internet explorer'/><category term='Nokia'/><category term='user controls'/><category term='htc'/><category term='sample application'/><category term='decoupling'/><category term='smartphone'/><category term='static class'/><category term='instance'/><category term='regular expression'/><category term='class library'/><category term='C#'/><category term='filterContext'/><category term='VB.net'/><category term='post redirect get'/><category term='subsonic'/><category term='fuel consumption'/><category term='generics'/><category term='reusable'/><category term='DescriptionAttribute'/><category term='request'/><category term='Redirect'/><category term='ASP.net'/><title type='text'>Real Web Developers</title><subtitle type='html'>Developers working in the real world</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-8763030097245092606</id><published>2010-11-17T09:01:00.004Z</published><updated>2010-11-17T09:12:19.287Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='regular expression'/><category scheme='http://www.blogger.com/atom/ns#' term='Domain object model'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='subsonic'/><category scheme='http://www.blogger.com/atom/ns#' term='validation'/><title type='text'>Domain object model base class with validation</title><content type='html'>&lt;code&gt;&lt;pre&gt;// &amp;lt;copyright file="DomBase.cs" company="Real Web Developers Limited"&gt;&lt;br /&gt;//  Real Web Developers Limited&lt;br /&gt;// &amp;lt;/copyright&gt;&lt;br /&gt;// &amp;lt;author&gt;Scott Rickman&amp;lt;/author&gt;&lt;br /&gt;namespace RealWebDevelopers.DomainObjectModel&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using System.Collections.Generic;&lt;br /&gt;    using System.Collections.ObjectModel;&lt;br /&gt;    using System.ComponentModel;&lt;br /&gt;    using System.Diagnostics;&lt;br /&gt;    using System.Linq;&lt;br /&gt;    using System.Text;&lt;br /&gt;    using SubSonic.SqlGeneration.Schema;&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&gt;&lt;br /&gt;    /// A base class providing validation rules. All domain objects should inherit from this class.&lt;br /&gt;    /// &amp;lt;/summary&gt;&lt;br /&gt;    public class DomBase : IDataErrorInfo&lt;br /&gt;    {&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// A list of validation rules to run against the object.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        private List&amp;lt;ValidationRule&gt; validationRules;&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets or sets the created date time.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;value&gt;The created date time.&amp;lt;/value&gt;&lt;br /&gt;        public DateTime CreatedDateTime { get; set; }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets or sets the id of the object.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;value&gt;The id of the object.&amp;lt;/value&gt;&lt;br /&gt;        public int Id { get; set; }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets or sets a value indicating whether this instance is deleted.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;value&gt;&lt;br /&gt;        /// &amp;lt;c&gt;true&amp;lt;/c&gt; if this instance is deleted; otherwise, &amp;lt;c&gt;false&amp;lt;/c&gt;.&lt;br /&gt;        /// &amp;lt;/value&gt;&lt;br /&gt;        public bool IsDeleted { get; set; }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets or sets the updated date time.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;value&gt;The updated date time.&amp;lt;/value&gt;&lt;br /&gt;        public DateTime UpdatedDateTime { get; set; }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets or sets the validation rules.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;value&gt;The validation rules to run against this object.&amp;lt;/value&gt;&lt;br /&gt;        [SubSonicIgnore]&lt;br /&gt;        public List&amp;lt;ValidationRule&gt; ValidationRules&lt;br /&gt;        {&lt;br /&gt;            get&lt;br /&gt;            {&lt;br /&gt;                return this.validationRules;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            set&lt;br /&gt;            {&lt;br /&gt;                this.validationRules = value;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets a value indicating whether this instance is valid.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;value&gt;&amp;lt;c&gt;true&amp;lt;/c&gt; if this instance is valid; otherwise, &amp;lt;c&gt;false&amp;lt;/c&gt;.&amp;lt;/value&gt;&lt;br /&gt;        [SubSonicIgnore]&lt;br /&gt;        public virtual bool IsValid&lt;br /&gt;        {&lt;br /&gt;            get&lt;br /&gt;            {&lt;br /&gt;                return this.Error == null;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets an error message indicating what is wrong with this object.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;returns&gt;An error message indicating what is wrong with this object. The default is null.&amp;lt;/returns&gt;&lt;br /&gt;        [SubSonicIgnore]&lt;br /&gt;        public virtual string Error&lt;br /&gt;        {&lt;br /&gt;            get&lt;br /&gt;            {&lt;br /&gt;                string result = this[string.Empty];&lt;br /&gt;                if (result != null &amp;&amp; result.Trim().Length == 0)&lt;br /&gt;                {&lt;br /&gt;                    result = null;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                return result;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets a &amp;lt;see cref="System.String"/&gt; containing the validation description of the specified property name.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;param name="propertyName"&gt;The name of the property to test.&amp;lt;/param&gt;&lt;br /&gt;        [SubSonicIgnore]&lt;br /&gt;        public virtual string this[string propertyName]&lt;br /&gt;        {&lt;br /&gt;            get&lt;br /&gt;            {&lt;br /&gt;                string result = string.Empty;&lt;br /&gt;&lt;br /&gt;                foreach (ValidationRule validationRule in this.GetBrokenRules(propertyName))&lt;br /&gt;                {&lt;br /&gt;                    if (propertyName == string.Empty || validationRule.PropertyName == propertyName)&lt;br /&gt;                    {&lt;br /&gt;                        result += validationRule.Description;&lt;br /&gt;                        result += Environment.NewLine;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                result = result.Trim();&lt;br /&gt;                if (result.Length == 0)&lt;br /&gt;                {&lt;br /&gt;                    result = null;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                return result;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets the broken rules for this object.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;returns&gt;A list of broken validation rules&amp;lt;/returns&gt;&lt;br /&gt;        public virtual ReadOnlyCollection&amp;lt;ValidationRule&gt; GetBrokenRules()&lt;br /&gt;        {&lt;br /&gt;            return this.GetBrokenRules(string.Empty);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets the broken rules for the property.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;param name="property"&gt;The property to test.&amp;lt;/param&gt;&lt;br /&gt;        /// &amp;lt;returns&gt;A list of broken validation rules.&amp;lt;/returns&gt;&lt;br /&gt;        public virtual ReadOnlyCollection&amp;lt;ValidationRule&gt; GetBrokenRules(string property)&lt;br /&gt;        {&lt;br /&gt;            // If we haven't yet created the rules, create them now.&lt;br /&gt;            if (this.validationRules == null)&lt;br /&gt;            {&lt;br /&gt;                this.validationRules = new List&amp;lt;ValidationRule&gt;();&lt;br /&gt;                this.validationRules.AddRange(this.CreateRules());&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            List&amp;lt;ValidationRule&gt; brokenRules = new List&amp;lt;ValidationRule&gt;();&lt;br /&gt;&lt;br /&gt;            foreach (ValidationRule validationRule in this.validationRules)&lt;br /&gt;            {&lt;br /&gt;                // Ensure we only validate a rule &lt;br /&gt;                if (validationRule.PropertyName == property || property == string.Empty)&lt;br /&gt;                {&lt;br /&gt;                    bool isRuleBroken = !validationRule.ValidateRule(this);&lt;br /&gt;                    Debug.WriteLine(DateTime.Now.ToLongTimeString() + ": Validating the rule: '" + validationRule.ToString() + "' on object '" + this.ToString() + "'. Result = " + ((isRuleBroken == false) ? "Valid" : "Broken"));&lt;br /&gt;                    if (isRuleBroken)&lt;br /&gt;                    {&lt;br /&gt;                        brokenRules.Add(validationRule);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return brokenRules.AsReadOnly();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Creates the rules to validate this object.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;returns&gt;A list of validation rules.&amp;lt;/returns&gt;&lt;br /&gt;        protected virtual List&amp;lt;ValidationRule&gt; CreateRules()&lt;br /&gt;        {&lt;br /&gt;            return new List&amp;lt;ValidationRule&gt;();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;code&gt;&lt;pre&gt;// &amp;lt;copyright file="ValidationRule.cs" company="Real Web Developers Limited"&gt;&lt;br /&gt;//  Real Web Developers Limited&lt;br /&gt;// &amp;lt;/copyright&gt;&lt;br /&gt;// &amp;lt;author&gt;Scott Rickman&amp;lt;/author&gt;&lt;br /&gt;namespace RealWebDevelopers.DomainObjectModel&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using System.Collections.Generic;&lt;br /&gt;    using System.Linq;&lt;br /&gt;    using System.Text;&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&gt;&lt;br /&gt;    /// An abstract class that validation rules inherit&lt;br /&gt;    /// &amp;lt;/summary&gt;&lt;br /&gt;    public abstract class ValidationRule&lt;br /&gt;    {&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Initializes a new instance of the &amp;lt;see cref="ValidationRule"/&gt; class.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;param name="propertyName"&gt;Name of the property being validated.&amp;lt;/param&gt;&lt;br /&gt;        /// &amp;lt;param name="description"&gt;The description of the error.&amp;lt;/param&gt;&lt;br /&gt;        public ValidationRule(string propertyName, string description)&lt;br /&gt;        {&lt;br /&gt;            this.PropertyName = propertyName;&lt;br /&gt;            this.Description = description;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets or sets the name of the property being validated.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;value&gt;The name of the property.&amp;lt;/value&gt;&lt;br /&gt;        public string PropertyName { get; set; }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets or sets the description of the error.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;value&gt;The description of the error.&amp;lt;/value&gt;&lt;br /&gt;        public string Description { get; set; }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Validates the rule against the object.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;param name="obj"&gt;The object being validated.&amp;lt;/param&gt;&lt;br /&gt;        /// &amp;lt;returns&gt;True if the object matches the rule otherwise false.&amp;lt;/returns&gt;&lt;br /&gt;        public abstract bool ValidateRule(DomBase obj);&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Returns a &amp;lt;see cref="System.String"/&gt; that represents this instance.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;returns&gt;&lt;br /&gt;        /// A &amp;lt;see cref="System.String"/&gt; that represents this instance.&lt;br /&gt;        /// &amp;lt;/returns&gt;&lt;br /&gt;        public override string ToString()&lt;br /&gt;        {&lt;br /&gt;            return this.Description;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Returns a hash code for this instance.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;returns&gt;&lt;br /&gt;        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. &lt;br /&gt;        /// &amp;lt;/returns&gt;&lt;br /&gt;        public override int GetHashCode()&lt;br /&gt;        {&lt;br /&gt;            return this.ToString().GetHashCode();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;code&gt;&lt;pre&gt;// &amp;lt;copyright file="SimpleRule.cs" company="Real Web Developers Limited"&gt;&lt;br /&gt;//  Real Web Developers Limited&lt;br /&gt;// &amp;lt;/copyright&gt;&lt;br /&gt;// &amp;lt;author&gt;Scott Rickman&amp;lt;/author&gt;&lt;br /&gt;namespace RealWebDevelopers.DomainObjectModel&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using System.Collections.Generic;&lt;br /&gt;    using System.Linq;&lt;br /&gt;    using System.Text;&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&gt;&lt;br /&gt;    /// A delegate containing the method that validates the property.&lt;br /&gt;    /// &amp;lt;/summary&gt;&lt;br /&gt;    /// &amp;lt;returns&gt;True from the method.&amp;lt;/returns&gt;&lt;br /&gt;    public delegate bool SimpleRuleDelegate();&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&gt;&lt;br /&gt;    /// A validation rule using a delegate to perform the validation.&lt;br /&gt;    /// &amp;lt;/summary&gt;&lt;br /&gt;    public class SimpleRule : ValidationRule&lt;br /&gt;    {&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// A validation rule.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        private SimpleRuleDelegate ruleDelegate;&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Initializes a new instance of the &amp;lt;see cref="SimpleRule"/&gt; class.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;param name="propertyName"&gt;Name of the property.&amp;lt;/param&gt;&lt;br /&gt;        /// &amp;lt;param name="description"&gt;The description of the error.&amp;lt;/param&gt;&lt;br /&gt;        /// &amp;lt;param name="ruleDelegate"&gt;The rule delegate.&amp;lt;/param&gt;&lt;br /&gt;        public SimpleRule(string propertyName, string description, SimpleRuleDelegate ruleDelegate)&lt;br /&gt;            : base(propertyName, description)&lt;br /&gt;        {&lt;br /&gt;            this.ruleDelegate = ruleDelegate;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Gets or sets the rule delegate.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;value&gt;The rule delegate.&amp;lt;/value&gt;&lt;br /&gt;        protected virtual SimpleRuleDelegate RuleDelegate&lt;br /&gt;        {&lt;br /&gt;            get { return this.ruleDelegate; }&lt;br /&gt;            set { this.ruleDelegate = value; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Validates the rule against the object.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;param name="obj"&gt;The object being validated.&amp;lt;/param&gt;&lt;br /&gt;        /// &amp;lt;returns&gt;&lt;br /&gt;        /// True if the object matches the rule otherwise false.&lt;br /&gt;        /// &amp;lt;/returns&gt;&lt;br /&gt;        public override bool ValidateRule(DomBase obj)&lt;br /&gt;        {&lt;br /&gt;            return this.ruleDelegate();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;code&gt;&lt;pre&gt;// &amp;lt;copyright file="RegexRule.cs" company="Real Web Developers Limited"&gt;&lt;br /&gt;//  Real Web Developers Limited&lt;br /&gt;// &amp;lt;/copyright&gt;&lt;br /&gt;// &amp;lt;author&gt;Scott Rickman&amp;lt;/author&gt;&lt;br /&gt;namespace RealWebDevelopers.DomainObjectModel&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using System.Collections.Generic;&lt;br /&gt;    using System.Linq;&lt;br /&gt;    using System.Reflection;&lt;br /&gt;    using System.Text;&lt;br /&gt;    using System.Text.RegularExpressions;&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&gt;&lt;br /&gt;    /// A validation rule using a regular expression.&lt;br /&gt;    /// &amp;lt;/summary&gt;&lt;br /&gt;    public class RegexRule : ValidationRule&lt;br /&gt;    {&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// A field containing the regular expression used in the validator.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        private string regex;&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Initializes a new instance of the &amp;lt;see cref="RegexRule"/&gt; class.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;param name="propertyName"&gt;Name of the property being validated.&amp;lt;/param&gt;&lt;br /&gt;        /// &amp;lt;param name="description"&gt;The description of the error.&amp;lt;/param&gt;&lt;br /&gt;        /// &amp;lt;param name="regex"&gt;The regex being used to validate the property.&amp;lt;/param&gt;&lt;br /&gt;        public RegexRule(string propertyName, string description, string regex)&lt;br /&gt;            : base(propertyName, description)&lt;br /&gt;        {&lt;br /&gt;            this.regex = regex;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &amp;lt;summary&gt;&lt;br /&gt;        /// Validates the rule against the object.&lt;br /&gt;        /// &amp;lt;/summary&gt;&lt;br /&gt;        /// &amp;lt;param name="obj"&gt;The object being validated.&amp;lt;/param&gt;&lt;br /&gt;        /// &amp;lt;returns&gt;&lt;br /&gt;        /// True if the object matches the rule otherwise false.&lt;br /&gt;        /// &amp;lt;/returns&gt;&lt;br /&gt;        public override bool ValidateRule(DomBase obj)&lt;br /&gt;        {&lt;br /&gt;            PropertyInfo propertyInfo = obj.GetType().GetProperty(this.PropertyName);&lt;br /&gt;            return Regex.IsMatch(propertyInfo.GetValue(obj, null).ToString(), this.regex);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-8763030097245092606?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/8763030097245092606/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/11/domain-object-model-base-class-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8763030097245092606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8763030097245092606'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/11/domain-object-model-base-class-with.html' title='Domain object model base class with validation'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-8791182085669188956</id><published>2010-11-17T08:57:00.002Z</published><updated>2010-11-17T09:01:03.367Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='reflection'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='singleton'/><category scheme='http://www.blogger.com/atom/ns#' term='decoupling'/><category scheme='http://www.blogger.com/atom/ns#' term='instance'/><title type='text'>C# reflection get instance of singleton</title><content type='html'>&lt;code&gt;&lt;pre&gt;Type repositoryType = Type.GetType(config.RepositoryType);&lt;br /&gt;repository = (IRepository)repositoryType.GetProperty("GetInstance").GetValue(null, null);&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-8791182085669188956?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/8791182085669188956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/11/c-reflection-get-instance-of-singleton.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8791182085669188956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8791182085669188956'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/11/c-reflection-get-instance-of-singleton.html' title='C# reflection get instance of singleton'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-1683853610504140011</id><published>2010-10-05T10:54:00.007+01:00</published><updated>2010-10-05T11:55:30.499+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='class library'/><category scheme='http://www.blogger.com/atom/ns#' term='user controls'/><category scheme='http://www.blogger.com/atom/ns#' term='deployment project'/><category scheme='http://www.blogger.com/atom/ns#' term='reusable'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Build a re-usable UserControl library</title><content type='html'>&lt;p&gt;For the RealWebDevelopers &lt;abbr title="Content Management System"&gt;CMS&lt;/abbr&gt; project I wanted to be able to use the same user controls (.ascx) in two (and potentially more) web applications rather than having to write server controls.&lt;/p&gt;&lt;p&gt;The solution was to create a new web application project then to create a web deployment project for the web application project and finally to reference the output from the deployment project in the websites. The only 'trick' was to ensure that the deployment project was set to &lt;strong&gt;not&lt;/strong&gt; allow the precompiled website to be updatable and to select the option to Merge all pages and controls outputs to a single assembly.&lt;/p&gt;&lt;p&gt;Also note that when the deployment project is built it generates two assemblies both of which need to be referenced in the websites.&lt;/p&gt;&lt;p&gt;When using the user controls in the websites I added the deployment project output assembly to the system.web/pages/controls section of web.config noting that the namespace attribute needs to be ASP &lt;strong&gt;not&lt;/strong&gt; the namespace of the user controls as defined in code. You also need to know that the user controls types aren't namespaced and the file extension (ascx) is appended to the typename i.e. usercontrol_ascx. This can be initially confusing.&lt;/p&gt;&lt;p&gt;web.config&lt;/p&gt;&lt;code&gt;&lt;pre&gt;...&lt;br /&gt;&amp;lsaquo;system.web&amp;rsaquo;&lt;br /&gt;    &amp;lsaquo;pages&amp;rsaquo;&lt;br /&gt;        &amp;lsaquo;controls&amp;rsaquo;&lt;br /&gt;            &amp;lsaquo;add assembly="UserControlsLibrary" tagPrefix="ucl" namespace="&lt;strong&gt;ASP&lt;/strong&gt;"/&amp;rsaquo;&lt;br /&gt;...&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;Default.aspx&lt;/p&gt;&lt;code&gt;&lt;pre&gt;...&lt;br /&gt;&amp;lsaquo;ucl:leadin&lt;strong&gt;_ascx&lt;/strong&gt; ParagraphContent="this is the paragraph content"&lt;br /&gt;                    ImageSource="http://www.realwebdevelopers.com/i/logo.jpg"&lt;br /&gt;                    ImageAlternative="The RealWebDevelopers Logo"&lt;br /&gt;                    ImageSide="left"&lt;br /&gt;                    id="uiTestLeadin"&lt;br /&gt;                    runat="server" /&amp;rsaquo;&lt;br /&gt;...&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-1683853610504140011?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/1683853610504140011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/10/build-re-usable-usercontrol-library.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/1683853610504140011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/1683853610504140011'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/10/build-re-usable-usercontrol-library.html' title='Build a re-usable UserControl library'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-5715604313180311629</id><published>2010-09-04T09:00:00.003+01:00</published><updated>2010-09-04T09:43:59.463+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='internet explorer'/><category scheme='http://www.blogger.com/atom/ns#' term='window.open'/><title type='text'>Internet Explorer and window.open</title><content type='html'>&lt;p&gt;Internet Explorer will throw a JavaScript exception if the name parameter passed into JavaScripts &lt;code&gt;window.open(url, name [, options])&lt;/code&gt; method contains 'special' characters - which includes space and underscore.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;/* this will cause an error in IE */&lt;br /&gt;window.open('http://www.realwebdevelopers.com', 'Real Web Developers');&lt;br /&gt;/* this will work in IE */&lt;br /&gt;window.open('http://www.realwebdevelopers.com', 'RealWebDevelopers');&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-5715604313180311629?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/5715604313180311629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/09/internet-explorer-and-windowopen.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/5715604313180311629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/5715604313180311629'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/09/internet-explorer-and-windowopen.html' title='Internet Explorer and window.open'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-8832240942471430169</id><published>2010-08-16T08:03:00.006+01:00</published><updated>2010-08-16T09:20:53.178+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='class library'/><category scheme='http://www.blogger.com/atom/ns#' term='static method'/><category scheme='http://www.blogger.com/atom/ns#' term='static class'/><category scheme='http://www.blogger.com/atom/ns#' term='maintainable code'/><category scheme='http://www.blogger.com/atom/ns#' term='inheritance'/><category scheme='http://www.blogger.com/atom/ns#' term='generics'/><category scheme='http://www.blogger.com/atom/ns#' term='interfaces'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='concrete implementation'/><title type='text'>Generic interfaces and methods in the data access layer</title><content type='html'>&lt;p&gt;Generics have been in C# since v2.0 but it's only been recently that I've started to make use of them and appreciate their elegance and application.&lt;/p&gt;&lt;p&gt;I've been working on a conceptual CMS and to speed things along I'm using in-memory storage in the form of &lt;code&gt;List&amp;lt;&lt;em&gt;Type&lt;/em&gt;&gt;&lt;/code&gt;. This is a concrete implementation of my different &lt;code&gt;I&lt;em&gt;Type&lt;/em&gt;Manager&lt;/code&gt; interfaces. I quickly realised that for any given type in my object model I would need various but common &lt;abbr title="Create, Retrieve, Update and Delete"&gt;CRUD&lt;/abbr&gt; operations and so all these common operations needed to be in each of the interfaces for my various and numerous object types.&lt;/p&gt;&lt;h4&gt;Generics to the rescue&lt;/h4&gt;&lt;p&gt;Generics provided a much need solution to my repeating the methods in the interfaces with the same signature but just returning differing types. I created a general &lt;code&gt;IManger&lt;/code&gt; interface&lt;/p&gt;&lt;pre&gt;&lt;code&gt;public interface IManager&amp;lt;T&gt; {&lt;br /&gt;    T GetSingleById(Guid id);&lt;br /&gt;    IEnumerable&amp;lt;T&gt; GetManyByParentId(Guid parentId);&lt;br /&gt;    T Save(ref T t);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;which each of the &lt;code&gt;I&lt;em&gt;Type&lt;/em&gt;Manager&lt;/code&gt; interfaces would implement&lt;/p&gt;&lt;pre&gt;&lt;code&gt;public interface I&lt;em&gt;Type&lt;/em&gt;Manager: IManager&amp;lt;&lt;em&gt;Type&gt;&lt;/em&gt; {&lt;br /&gt;    // Additional methods required by the type specific manager&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So far I've managed to vastly reduce the amount of code that I have to write but (genuinely to my surprise) Visual Studio 2010 gave me even less work to do when creating the concrete implementations of the &lt;code&gt;I&lt;em&gt;Type&lt;/em&gt;Manager&lt;/code&gt; interfaces by generating the stub methods &lt;strong&gt;with the correct types!&lt;/strong&gt;&lt;/p&gt;&lt;code&gt;&lt;pre&gt;public class &lt;em&gt;Type&lt;/em&gt;Manager: I&lt;em&gt;Type&lt;/em&gt;Manager {&lt;br /&gt;    public &lt;em&gt;Type&lt;/em&gt; GetSingleById(Guid id) {&lt;br /&gt;        // type specific implementation&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public IEnumerable&amp;lt&lt;em&gt;Type&lt;/em&gt;&gt; GetManyByParentId(Guid parentId) {&lt;br /&gt;        // type specific implementation&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public &lt;em&gt;Type&lt;/em&gt; Save(&lt;em&gt;Type&lt;/em&gt; t) {&lt;br /&gt;        // type specific implementation&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;I was impressed both with the small amount of code that I had to write and the code generation tools within Visual Studio 2010, so I looked for more places where generics could help me to write less code (and, as it turned out, make my code more maintainable).&lt;/p&gt;&lt;h4&gt;Generic methods&lt;/h4&gt;&lt;p&gt;I can honestly say that until this past week I hadn't written a single generic method. In fact I had to enlist the help of the very helpful guys over at &lt;a href="http://www.stackoverflow.com"&gt;Stackoverflow.com&lt;/a&gt; to get this right.&lt;/p&gt;&lt;p&gt;I quickly identified that each and every one of my concrete implementations of &lt;code&gt;I&lt;em&gt;Type&lt;/em&gt;Manager&lt;/code&gt; included very similar code and &lt;abbr title="Language INtegrated Query"&gt;LINQ&lt;/abbr&gt; queries which had to be prime targets for generic methods.&lt;/p&gt;&lt;code&gt;&lt;pre&gt;...&lt;br /&gt;    public &lt;em&gt;Type&lt;/em&gt; GetSingleById(Guid id) {&lt;br /&gt;        return (from i in this.listOfItems where i.Id == id select i).SingleOrDefault();&lt;br /&gt;    }&lt;br /&gt;...&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;The example above was quickly moved into a new static method of a static class (pass in the list and the id and get the item or null if it doesn't exist).&lt;/p&gt;&lt;code&gt;&lt;pre&gt;public static class Manager {&lt;br /&gt;    public static T GetSingleById&amp;lt;T&gt;(List&amp;lt;T&gt; items, Guid id) {&lt;br /&gt;        return (from i in items where i.Id == id select i).SingleOrDefault();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;Initially I had some issues with the where clause; specifically it wouldn't compile since &lt;code&gt;object&lt;/code&gt; doesn't have an Id property for the where clause to operate on. Since all my object types have an Id property, I moved this into a base class &lt;code&gt;HasId&lt;/code&gt; with this property and added a base type condition to the method.&lt;/p&gt;&lt;code&gt;&lt;pre&gt;public static class Manager {&lt;br /&gt;    public static T GetSingleById&amp;lt;T&gt;(List&amp;lt;T&gt; items, Guid id) &lt;strong&gt;Where T: HasId&lt;/strong&gt; {&lt;br /&gt;        return (from i in items where i.Id == id select i).SingleOrDefault();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;Now all I had to do was to call this static method from within my concrete class passing in the in-memory list that it was using for storage.&lt;/p&gt;&lt;p&gt;Next I created a second base class &lt;code&gt;HasIdAndParentId&lt;/code&gt; subclassing &lt;code&gt;HasId&lt;/code&gt; by adding a new ParentId property which all but my root object types subclass. This enabled me to add generic methods to my static class like&lt;/p&gt;&lt;code&gt;&lt;pre&gt;public static class Manager {&lt;br /&gt;    public static T GetSingleById&amp;lt;T&gt;(List&amp;lt;T&gt; items, Guid id) Where T: HasId {&lt;br /&gt;        return (from i in items where i.Id == id select i).SingleOrDefault();&lt;br /&gt;    }&lt;br /&gt;    &lt;strong&gt;public static IEnumerable&amp;lt;T&gt; GetManyByParentId&amp;lt;T&gt;(List&amp;lt;T&gt; items, Guid parentId) Where T: HasIdAndParentId {&lt;br /&gt;        return from i in items where i.ParentId == parentId;&lt;br /&gt;    }&lt;/strong&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;and in turn call these from my concrete classes.&lt;/p&gt;&lt;p&gt;So why go to all this bother? Well firstly, I have written less code; for a single example it looks like I written far more code but, I also managed to add a method to my static class to save an object (does it already exist?, if so update it, if not create it, re-query the data store using the primary key and return the object) and replaced 20 or so lines of code in each of my concrete classes with a single call to my static class. And, secondly my code as become more maintainable since all the LINQ is in one file. If, say, I add a new property to HasId called IsRetired so that I can skip records that have been retired; I can implement this &lt;strong&gt;in all my concrete classes in one place&lt;/strong&gt;.&lt;/p&gt;&lt;code&gt;&lt;pre&gt;public static class Manager {&lt;br /&gt;    public static T GetSingleById&amp;lt;T&gt;(List&amp;lt;T&gt; items, Guid id) Where T: HasId {&lt;br /&gt;        return (from i in items where i.Id == id &lt;strong&gt;&amp;amp;&amp;amp; i.IsRetired == false&lt;/strong&gt; select i).SingleOrDefault();&lt;br /&gt;    }&lt;br /&gt;    public static IEnumerable&amp;lt;T&gt; GetManyByParentId&amp;lt;T&gt;(List&amp;lt;T&gt; items, Guid parentId) Where T: HasIdAndParentId {&lt;br /&gt;        return from i in items where i.ParentId == parentId &lt;strong&gt;&amp;amp;&amp;amp; i.IsRetired == false&lt;/strong&gt;;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;That's what I call maintainable.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-8832240942471430169?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/8832240942471430169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/08/generic-interfaces-and-methods-in-data.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8832240942471430169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8832240942471430169'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/08/generic-interfaces-and-methods-in-data.html' title='Generic interfaces and methods in the data access layer'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-8740583708857882363</id><published>2010-05-27T13:41:00.013+01:00</published><updated>2010-07-28T12:04:18.252+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fuel consumption'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.net'/><category scheme='http://www.blogger.com/atom/ns#' term='model view controller'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='sample application'/><category scheme='http://www.blogger.com/atom/ns#' term='UI'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Fuel consumption. Part II</title><content type='html'>&lt;p&gt;In &lt;a href="http://realwebdevelopers.blogspot.com/2010/05/fuel-consumption-part-i.html"&gt;Part I&lt;/a&gt; of this series we decided what our application should do and what data we needed to collect for our application to work, now, we need to turn our attention to how we actually collect the information.&lt;/p&gt;&lt;p&gt;We initially embarked on this project to use ASP.net MVC v2 so clearly we'll be building a web interface but is an application that records drivers fuel really useful on the web? Well, it is if you consider using a mobile phone to browse the web, drivers can record the data directly from the forecourt (or from the adjacent supermarket carpark).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-8740583708857882363?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/8740583708857882363/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/05/fuel-consumption-part-ii.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8740583708857882363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8740583708857882363'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/05/fuel-consumption-part-ii.html' title='Fuel consumption. Part II'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-8365058516869580085</id><published>2010-05-27T09:04:00.010+01:00</published><updated>2010-05-27T10:43:42.766+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fuel consumption'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.net'/><category scheme='http://www.blogger.com/atom/ns#' term='model view controller'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='sample application'/><category scheme='http://www.blogger.com/atom/ns#' term='UI'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Fuel consumption. Part I</title><content type='html'>&lt;p&gt;We've decided to embark on a sample web application using ASP.net MVC 2 and .net framework v4, written in C# v4 as a way to develop a template solution for future reference.&lt;/p&gt;&lt;p&gt;We realise that some of the technologies used will be superceded but this is about the application structure and development approach that we use, which (until the next development revolution) should remain valid.&lt;/p&gt;&lt;p&gt;So, where to begin? Well, we've decided that a simple web site to record fuel use and calculate fuel consumption should require all of the &lt;abbr title="user interface"&gt;UI&lt;/abbr&gt;, business logic, data logic and, data storage functionality to enable us to have a understandable end-to-end sample project.&lt;/p&gt;&lt;p&gt;Firstly we need to outline what our application will actually do and record the rules and formulae that the application wil adhere to.&lt;/p&gt;&lt;p&gt;The primary goal of our application is to provide drivers with a fuel consumption figure for their vehicle. It is quite common during development projects to actually forget what the application is supposed to be doing; it's unlikely in this simple scenario but, when projects run into months and years of development it's suprisingly easy to lose sight of the actual target of the project.&lt;/p&gt;&lt;p&gt;Given that we now know what we are trying to achieve we need to work out how to actually achieve our goal, not in terms of code or application structure but in terms of what information do we need to achieve our goal or, more specifically, how do we calculate the fuel consumption of a vehicle?&lt;/p&gt;&lt;p&gt;Well, as sample applications generally go, our calculations are fairly simple; fuel consumption figures are stated in distance per volume so to calculate the fuel consumption of a vehicle we need to know how far it has travelled (d) and how much fuel it used to travel that distance (f) giving it's fuel consumption as d / f.&lt;/p&gt;&lt;p&gt;Now we need to work out how we measure the distance that the vehicle has travelled and how much fuel it used to travel that distance. Since we are only providing the application to make the calculations surely we don't need to worry about these details? Well, yes and no; for our application to work we just need the raw data but, for our application to be useful we need to provide a way for the user to only have to provide easily obtainable information.&lt;/p&gt;&lt;p&gt;The mechanism that this sample application will use is to record the total distance that the vehicle has travelled and the amount of fuel required to put the vehicles fuel level to a known state; in simple terms, we record the odometer reading and the amount of fuel required to fill the tank. This allow us to calculate the two pieces of raw data that we require for our calculation.&lt;/p&gt;&lt;table summary="A sample of data recorded by the driver of a vehicle which can be used to calculate the fuel consumption of the vehicle"&gt;&lt;caption&gt;Sample recorded data&lt;/caption&gt;&lt;thead&gt;&lt;tr&gt;&lt;th scope="col"&gt;Odometer&lt;/th&gt;&lt;th scope="col"&gt;Distance&lt;/th&gt;&lt;th scope="col"&gt;Fuel Added&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;300&lt;/td&gt;&lt;td&gt;300&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;400&lt;/td&gt;&lt;td&gt;100&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;650&lt;/td&gt;&lt;td&gt;250&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;950&lt;/td&gt;&lt;td&gt;300&lt;/td&gt;&lt;td&gt;25&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;As we can see from the sample data above, if the driver records the odometer reading and how much fuel was required to fill the fuel tank we know the distance that the vehicle has travelled (the difference between the previously record odometer reading and the current odometer reading) and the volume of fuel used to travel this distance (the amount of fuel that had to be added to refil the fuel tank). Obviously calculations can only be made when we have a record of the previous odometer reading (when the fuel tank was full), the current odometer reading and the amount of fuel added to refil the tank but, this does not stop the driver adding fuel without filling the fuel tank as long as the addition of this fuel is recorded.&lt;/p&gt;&lt;table summary="A sample of data recorded by the driver of a vehicle which can be used to calculate the fuel consumption of the vehicle"&gt;&lt;caption&gt;Sample recorded data&lt;/caption&gt;&lt;thead&gt;&lt;tr&gt;&lt;th scope="col"&gt;Odometer&lt;/th&gt;&lt;th scope="col"&gt;Distance&lt;/th&gt;&lt;th scope="col"&gt;Fuel Added&lt;/th&gt;&lt;th scope="col"&gt;Tank Filled&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;300&lt;/td&gt;&lt;td&gt;300&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;400&lt;/td&gt;&lt;td&gt;100&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;650&lt;/td&gt;&lt;td&gt;250&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;950&lt;/td&gt;&lt;td&gt;300&lt;/td&gt;&lt;td&gt;25&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1150&lt;/td&gt;&lt;td&gt;200&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1200&lt;/td&gt;&lt;td&gt;50&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;We can see from the table above that at 1150 miles the driver added 10 litres of fuel but this didn't fill the tank but at 1200 miles the driver added 15 litres of fuel and this did fill the tank. We can still calculate the fuel consumption between 950 miles and 1200 miles; 250 miles travelled and a total of 25 litres of fuel added.&lt;/p&gt;&lt;h4&gt;Summary&lt;/h4&gt;&lt;p&gt;We decided to write an application that will calculate a vehicles fuel consumption. We discovered the formula for calculating a vehicles fuel consumption but discovered that it is not practical for the driver to access this raw data so we discovered how to calculate this raw data from data that the driver can access and noted how this will impact the availability of the fuel consumption results.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-8365058516869580085?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/8365058516869580085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/05/fuel-consumption-part-i.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8365058516869580085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8365058516869580085'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/05/fuel-consumption-part-i.html' title='Fuel consumption. Part I'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-1776482882472313657</id><published>2010-05-24T09:52:00.008+01:00</published><updated>2010-10-05T11:54:44.070+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='enum'/><category scheme='http://www.blogger.com/atom/ns#' term='reflection'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.net'/><category scheme='http://www.blogger.com/atom/ns#' term='extension methods'/><category scheme='http://www.blogger.com/atom/ns#' term='encryption'/><category scheme='http://www.blogger.com/atom/ns#' term='DescriptionAttribute'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='xor'/><title type='text'>Useful extension methods</title><content type='html'>&lt;p&gt;This method is useful for hiding plain text; note that it is &lt;em&gt;not&lt;/em&gt; a secure encryption method, to the casual passer-by the output will be meaningless, to the seasoned hacker it will be decrypted in seconds.&lt;/p&gt;&lt;p&gt;Note that by using 129 as the key all the output characters from using [a-zA-Z0-9] as input characters will be valid XML.&lt;/p&gt;&lt;p&gt;If you run this method on string A to get string B then run the method on string B you will be returned string A; it is fully reversible.&lt;/p&gt;&lt;code&gt;&lt;pre&gt;public static string Xor(this string text)&lt;br /&gt;{&lt;br /&gt;    int key = 129;&lt;br /&gt;    StringBuilder inSb = new StringBuilder(text);&lt;br /&gt;    StringBuilder outSb = new StringBuilder(text.Length);&lt;br /&gt;    char c;&lt;br /&gt;    for (int i = 0; i &lt; text.Length; i++)&lt;br /&gt;    {&lt;br /&gt;        c = inSb[i];&lt;br /&gt;        c = (char)(c ^ key);&lt;br /&gt;        outSb.Append(c);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return outSb.ToString();&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;This method retrieves the [Description()] attribute from an enum.&lt;/p&gt;&lt;code&gt;&lt;pre&gt;public static string GetDescription(this enum value)&lt;br /&gt;{&lt;br /&gt;    FieldInfo fi = value.GetType().GetField(value.ToString());&lt;br /&gt;    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttributes), false);&lt;br /&gt;    if (attributes.Length &gt; 0)&lt;br /&gt;    {&lt;br /&gt;        return attributes[0].Description;&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;        return value.ToString();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;I also had a need to write this in VB.net with caching (reflection is expensive so why not?) inside a module.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Private _enumDescriptions As New Dictionary(Of [Enum], String)&lt;br /&gt;&lt;br /&gt;&amp;lsaquo;Extension()&amp;rsaquo; _&lt;br /&gt;Public Function GetDescription(ByVal value As [Enum]) As String&lt;br /&gt;    If Not _enumDescriptions.ContainsKey(value) Then&lt;br /&gt;        Dim fieldInfo As Reflection.FieldInfo = value.GetType().GetField(value.ToString())&lt;br /&gt;        Dim attributes As DescriptionAttribute() = DirectCast(fieldInfo.GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())&lt;br /&gt;        If attributes.Length &gt; 0 Then&lt;br /&gt;            _enumDescriptions.Add(value, attributes(0).Description)&lt;br /&gt;        Else&lt;br /&gt;            _enumDescriptions.Add(value, value.ToString)&lt;br /&gt;        End If&lt;br /&gt;    End If&lt;br /&gt;    Return _enumDescriptions(value)&lt;br /&gt;End Function&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-1776482882472313657?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/1776482882472313657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/05/useful-extension-methods.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/1776482882472313657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/1776482882472313657'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/05/useful-extension-methods.html' title='Useful extension methods'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-8009660265640903328</id><published>2010-04-22T14:05:00.011+01:00</published><updated>2010-10-05T11:57:53.730+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='static class'/><category scheme='http://www.blogger.com/atom/ns#' term='static method'/><category scheme='http://www.blogger.com/atom/ns#' term='DAL'/><category scheme='http://www.blogger.com/atom/ns#' term='Webforms'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='decoupling'/><category scheme='http://www.blogger.com/atom/ns#' term='UI'/><category scheme='http://www.blogger.com/atom/ns#' term='BLL'/><category scheme='http://www.blogger.com/atom/ns#' term='concrete implementation'/><category scheme='http://www.blogger.com/atom/ns#' term='class library'/><category scheme='http://www.blogger.com/atom/ns#' term='reflection'/><category scheme='http://www.blogger.com/atom/ns#' term='Winforms'/><title type='text'>Decoupling data access in C#</title><content type='html'>&lt;p&gt;This is nothing new; it's just a reminder for me and anyone else who want to bookmark this page.&lt;/p&gt;&lt;p&gt;The concept is to decouple the &lt;abbr title="user interface"&gt;UI&lt;/abbr&gt; from the &lt;abbr title="business logic layer"&gt;BLL&lt;/abbr&gt; and the BLL from the &lt;abbr title="data access layer"&gt;DAL&lt;/abbr&gt; to enable the UI to be updated and deployed independently of the BLL or to allow a new implementation of the UI (Winforms, Webforms, MVC, etc.) and to allow new implementations of the DAL without the BLL noticing.&lt;/p&gt;&lt;p&gt;So, easy things first; the UI. Simply ensure that &lt;em&gt;ALL&lt;/em&gt; the business logic is contained within the BLL with a completely and descriptively documented API so the UI &lt;em&gt;ONLY&lt;/em&gt; deals with presentation. This isn't so much decoupling (the UI will still have a reference to the concrete implementation in the BLL) but more encapsulating; still it make for good practice.&lt;/p&gt;&lt;p&gt;Now, the DAL. In the DAL we need to seperate the logical methods i.e. GetProduct, from the implementation i.e. SELECT * FROM Product. This is achieved using interface programming and a bit of reflection in the BLL and interface implementation in the DAL.&lt;/p&gt;&lt;p&gt;The process is:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;UI calls static methods within BLL&lt;/li&gt;&lt;li&gt;BLL uses configuration settings to initialize a concrete implementation of an interface&lt;/li&gt;&lt;li&gt;BLL calls methods against the concrete implemention in the DAL&lt;/li&gt;&lt;li&gt;The DAL returns data to the BLL&lt;/li&gt;&lt;li&gt;The BLL processes the data from the DAL and returns the processed data to the UI&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Some code then; first in the DAL.&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;namespace Demo.DAL;&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using ...;&lt;br /&gt;&lt;br /&gt;    public interface IProductManager&lt;br /&gt;    {&lt;br /&gt;        Product GetProduct(int id);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;namespace Demo.DAL.Sql&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using ...;&lt;br /&gt;&lt;br /&gt;    public class SqlProductManager : IProductManager&lt;br /&gt;    {&lt;br /&gt;        public Product GetProduct(int id)&lt;br /&gt;        {&lt;br /&gt;            Product product = new Product();&lt;br /&gt;            // do SQL stuff with the product&lt;br /&gt;            return product;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;namespace Demo.DAL.Memory&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using ...;&lt;br /&gt;&lt;br /&gt;    public class MemoryProductManager : IProductManager&lt;br /&gt;    {&lt;br /&gt;        pubic Product GetProduct(int id)&lt;br /&gt;        {&lt;br /&gt;            Product product = new Product();&lt;br /&gt;            // do MEMORY stuff with the product&lt;br /&gt;            return product;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;The above code defines an interface IProductManager and two concrete implementations of the interface; SqlProductManager and MemoryProductManager. Since both classes implement the same interface we can write code in the BLL against the interface without any care of how it's implemented in the DAL.&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;namespace Demo.BLL&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using Demo.DAL;&lt;br /&gt;    using ...;&lt;br /&gt;&lt;br /&gt;    private static IProductManager dalManager;&lt;br /&gt;&lt;br /&gt;    static ProductManager()&lt;br /&gt;    {&lt;br /&gt;        // initialize dalManager&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class ProductManager&lt;br /&gt;    {&lt;br /&gt;        public static Product GetProduct(int id)&lt;br /&gt;        {&lt;br /&gt;            return dalManager.GetProduct(id);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;So far, so good; we have a nice static method to call from our UI in the BLL that hides all implementation from the UI and we're programming against an interface so the BLL doesn't care about the implementation in the DAL. The BLL does however care about which implementation in the DAL is used; it's up to the BLL to tell the DAL to use either the Sql implementation or the Memory implementation.&lt;/p&gt;&lt;p&gt;It's time for configuration to step in, and yet another set of classes. We can instruct the BLL to use a particular implementation of the DAL interfaces in our application or web configuration file. In the BLL we use a bit of reflection to initialize an instance of the particular type we require. Since the type implements the interface we know all the calls to dalManager.&lt;em&gt;methodName&lt;/em&gt; will be honored.&lt;/p&gt;&lt;p&gt;We could (but I don't recommend it) put a bunch of appSettings into the config file; but it's much cleaner to use a custom configuration section and a static manager to access it.&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;namespace Demo.Configuration&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using System.Configuration;&lt;br /&gt;    using ...;&lt;br /&gt;&lt;br /&gt;    public class ProductManagerConfiguration : ConfigurationSection&lt;br /&gt;    {&lt;br /&gt;        [ConfigurationProperty("type", IsRequired = true)]&lt;br /&gt;        public string Type&lt;br /&gt;        {&lt;br /&gt;            get { return (string)this["type"]; }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;namespace Demo.Configuration&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using System.Configuration;&lt;br /&gt;    using ...;&lt;br /&gt;&lt;br /&gt;    public static class ConfigurationManager&lt;br /&gt;    {&lt;br /&gt;        public static ProductManagerConfiguration ProductManagerConfiguration&lt;br /&gt;        {&lt;br /&gt;            get&lt;br /&gt;            {&lt;br /&gt;                return (ProductManagerConfiguration)ConfigurationManager.GetSection("demo/productManager");&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;Next we add our configuration section to our application or web config file.&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;&amp;lsaquo;?xml version="1.0"?&amp;rsaquo;&lt;br /&gt;&amp;lsaquo;configuration&amp;rsaquo;&lt;br /&gt;    &amp;lsaquo;configSections&amp;rsaquo;&lt;br /&gt;        &amp;lsaquo;sectionGroup name="demo"&amp;rsaquo;&lt;br /&gt;            &amp;lsaquo;section name="productManager" type="Demo.Configuration.ProductManagerConfiguration, Demo.Configuration" /&amp;rsaquo;&lt;br /&gt;        &amp;lsaquo;/sectionGroup&amp;rsaquo;&lt;br /&gt;    &amp;lsaquo;/configSections&amp;rsaquo;&lt;br /&gt;&lt;br /&gt;    &amp;lsaquo;demo&amp;rsaquo;&lt;br /&gt;        &amp;lsaquo;productManager type="Demo.DAL.SqlProductManager, Demo.DAL" /&amp;rsaquo;&lt;br /&gt;    &amp;lsaquo;/demo&amp;rsaquo;&lt;br /&gt;&amp;lsaquo;/configuration&amp;rsaquo;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;Finally we need to update the BLL.ProductManager class so that dalManager is initialized correctly.&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;namespace Demo.BLL&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using Demo.DAL;&lt;br /&gt;    using ...;&lt;br /&gt;&lt;br /&gt;    private static IProductManager dalManager;&lt;br /&gt;&lt;br /&gt;    static ProductManager()&lt;br /&gt;    {&lt;br /&gt;        // initialize dalManager&lt;br /&gt;        &lt;strong&gt;if (dalManager == null)&lt;br /&gt;        {&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                ProductManagerConfiguration productManagerConfiguration = ConfigurationManager.ProductManagerConfiguration;&lt;br /&gt;                Type type = Type.GetType(productManagerConfiguration.Type);&lt;br /&gt;                dalManager = (IProductManager)Activator.CreateInstance(type);&lt;br /&gt;            }&lt;br /&gt;            catch&lt;br /&gt;            {&lt;br /&gt;                // initialization failed&lt;br /&gt;            }&lt;br /&gt;        }&lt;/strong&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class ProductManager&lt;br /&gt;    {&lt;br /&gt;        public static Product GetProduct(int id)&lt;br /&gt;        {&lt;br /&gt;            return dalManager.GetProduct(id);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-8009660265640903328?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/8009660265640903328/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/04/decoupling-data-access-in-c.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8009660265640903328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8009660265640903328'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/04/decoupling-data-access-in-c.html' title='Decoupling data access in C#'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-8175821348511092368</id><published>2010-04-07T09:00:00.007+01:00</published><updated>2010-05-27T10:41:00.539+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='htc'/><category scheme='http://www.blogger.com/atom/ns#' term='smart'/><category scheme='http://www.blogger.com/atom/ns#' term='smartphone'/><category scheme='http://www.blogger.com/atom/ns#' term='phone'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile phone'/><category scheme='http://www.blogger.com/atom/ns#' term='hd2'/><category scheme='http://www.blogger.com/atom/ns#' term='windows phone'/><title type='text'>Living with the HTC HD2. Part II</title><content type='html'>&lt;p&gt;Communication is what a phone should be about but when it comes to smart phones communication is &lt;em&gt;really&lt;/em&gt; what a phone should be about. I want my phone to communicate with my GSM network for voice, with (preferably) my 3G or my GPRS network for mobile data and with my WiFi network (when available) for 'local' data. I'd also like it to be able to communicate with my VPN over WiFi or 3G and finally I'd like it to be able to communicate with my PC over USB.&lt;/p&gt;&lt;p&gt;Is all this reasonable? Well, I think so and that's why I have a smart phone. Now, down to the nitty gritty; how do I achieve all this?&lt;/p&gt;&lt;p&gt;The GSM and 3G / GPRS connections are no brainers; turn on the phone and we're done. Configuring a WiFi connection is straight forward too; it's just like any Windows based PC. But, if I've got WiFi coverage (and I want a data connection) how do I configure the phone to use this connection in preference to 3G / GPRS? Seriously, this is a question ... how? Next, when I want a VPN connection I can configure this in the connection settings and over 3G / GPRS it works; but when I then connect to my PC using USB I cannot use Active Sync, I have to actually delete the VPN connection on the phone to get Active Sync working!&lt;/p&gt;&lt;p&gt;Answers please!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-8175821348511092368?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/8175821348511092368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/04/living-with-htc-hd2-part-ii.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8175821348511092368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/8175821348511092368'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/04/living-with-htc-hd2-part-ii.html' title='Living with the HTC HD2. Part II'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-4163428414691647431</id><published>2010-03-25T12:13:00.004Z</published><updated>2010-04-22T15:10:07.610+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ActionFilter'/><category scheme='http://www.blogger.com/atom/ns#' term='Redirect'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.net'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='RouteData'/><category scheme='http://www.blogger.com/atom/ns#' term='filterContext'/><title type='text'>ASP.net MVC ActionFilter and Redirect</title><content type='html'>&lt;p&gt;Apply this filter to Methods that require authorisation&lt;/p&gt;&lt;code&gt;&lt;pre&gt;[AttributeUsage(AttributeTargets.Method)]&lt;br /&gt;public class AuthAttribute : ActionFilterAttribute, IAuthorizationFilter&lt;br /&gt;{&lt;br /&gt;    public void OnAuthorization(AuthorizationContext filterContext)&lt;br /&gt;    {&lt;br /&gt;        if (!Authorised) /* whatever Authorised does */&lt;br /&gt;        {&lt;br /&gt;            filterContext.Result = ((BaseController)filterContext.Controller).Redirect303(&lt;br /&gt;                    "Login", "Home", new { &lt;br /&gt;                        returnAction = filterContext.RouteData.GetRequiredString("action"), &lt;br /&gt;                        returnController = filterContext.RouteData.GetRequiredString("controller"),&lt;br /&gt;                        returnData = filterContext.RouteData.Values.ContainsKey("id") ? filterContext.RouteData.Values["id"] : string.Empty });&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;Then in&lt;/p&gt;&lt;code&gt;&lt;pre&gt;[AcceptVerbs(HttpVerbs.Get)]&lt;br /&gt;public ActionResult Login(string returnAction, string returnController, string returnData)&lt;br /&gt;{&lt;br /&gt;    /* blah */&lt;br /&gt;    string returnUrl = Url.Action(returnAction, returnController, new { id = returnData });&lt;br /&gt;    /* blah */&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;p&gt;Put returnUrl into a hidden form input in Login.aspx and then in&lt;/p&gt;&lt;code&gt;&lt;pre&gt;[AcceptVerbs(HttpVerbs.Post)]&lt;br /&gt;public ActionResult Login(FormCollection form)&lt;br /&gt;{&lt;br /&gt;    string returnUrl = Url.RouteUrl(new { controller = "Home", action = "Index" });&lt;br /&gt;    if (!string.IsNullOrEmpty(form["returnUrl"]))&lt;br /&gt;    {&lt;br /&gt;        returnUrl = form["returnUrl"];&lt;br /&gt;    }&lt;br /&gt;    /* blah */&lt;br /&gt;    // redirect to the original page&lt;br /&gt;    return Redirect303Url(returnUrl);&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-4163428414691647431?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/4163428414691647431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/03/aspnet-mvc-actionfilter-and-redirect.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/4163428414691647431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/4163428414691647431'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/03/aspnet-mvc-actionfilter-and-redirect.html' title='ASP.net MVC ActionFilter and Redirect'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-3529894413011456965</id><published>2010-03-24T10:00:00.005Z</published><updated>2010-04-22T15:10:36.595+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='HttpRequest'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.net'/><category scheme='http://www.blogger.com/atom/ns#' term='model view controller'/><category scheme='http://www.blogger.com/atom/ns#' term='request'/><category scheme='http://www.blogger.com/atom/ns#' term='HttpRequestBase'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='request object'/><title type='text'>ASP.net MVC reminders</title><content type='html'>&lt;ul&gt;&lt;li&gt;&lt;p&gt;To get the 'usual' HttpRequest object (rather than an HttpRequestBase object). This is usually required when calling methods (or services) provided by non-MVC ASP libraries.&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;System.Web.HttpContext.Current.Request&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-3529894413011456965?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/3529894413011456965/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/03/aspnet-mvc-reminders.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/3529894413011456965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/3529894413011456965'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/03/aspnet-mvc-reminders.html' title='ASP.net MVC reminders'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-1874451908937014349</id><published>2010-03-05T19:48:00.006Z</published><updated>2010-05-27T10:37:55.909+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='htc'/><category scheme='http://www.blogger.com/atom/ns#' term='smart'/><category scheme='http://www.blogger.com/atom/ns#' term='smartphone'/><category scheme='http://www.blogger.com/atom/ns#' term='phone'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile phone'/><category scheme='http://www.blogger.com/atom/ns#' term='hd2'/><category scheme='http://www.blogger.com/atom/ns#' term='windows phone'/><title type='text'>Living with the HTC HD2. Part I</title><content type='html'>&lt;p&gt;The HTC HD2 is an amazing Windows Mobile 6.5 Smartphone. There are plenty of resources around the 'net to tell you all about its specifications and functions but I have one and there's nothing better than first-hand experience to find out how it really works in the real world.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Firstly it's big, &lt;em&gt;really BIG!&lt;/em&gt;. I'd go so far as to say that it isn't pocket sized; not trouser pockets in any case. It'll live quite comfortably in your jacket or shirt pocket though but since you'll want to be playing with it almost constantly it doesn't really matter.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Secondly it's slick. The HTC interface is beautiful to look at and a pleasure to use. Everything just works how you might expect it to work, everything is where you might expect it to be, it's quite a feat of engineering. If you want to find out just how good the HTC interface is you can change it to the Default Windows Mobile interface; that's awkward, clunky and certainly not intuitive and if you really want to punish yourself there always the Windows Smartphone interface.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So have I discovered anything that I don't like about the HTC HD2? Well, yes. Firstly there's the fact that it's a touch screen, but I just said that the interface is really nice didn't I? Yes, it is, but that isn't what I mean; finger friendly isn't always ear friendly. I managed to switch on the speaker phone mid-conversation today; only embarrassing as it happened since I was walking the street having a personal conversation but, potentially damaging. There is supposed to be a method of detecting when you raise the phone to your ear which disables the touch screen until you lower the phone from your ear and, to be truthful, it generally works but one event in the first week? Even that seems a little too frequent for me but only time will tell.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The second thing that I've noticed is that the Digital Compass just doesn't seem to work; I've tried it in several places and it always complains about there being too much interference, and what is the move in a figure of 8 action supposed to do? I've stood there looking quite the pratt on several occasions and the phone just seems to ignore that action completely. Am I doing something wrong?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-1874451908937014349?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/1874451908937014349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/03/living-with-htc-hd2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/1874451908937014349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/1874451908937014349'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/03/living-with-htc-hd2.html' title='Living with the HTC HD2. Part I'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-706849474835530339.post-2657886211104038994</id><published>2010-02-17T12:02:00.010Z</published><updated>2010-04-22T15:11:04.462+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='http'/><category scheme='http://www.blogger.com/atom/ns#' term='Nokia'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.net'/><category scheme='http://www.blogger.com/atom/ns#' term='post redirect get'/><category scheme='http://www.blogger.com/atom/ns#' term='302'/><category scheme='http://www.blogger.com/atom/ns#' term='model view controller'/><category scheme='http://www.blogger.com/atom/ns#' term='303'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='HttpStatus'/><category scheme='http://www.blogger.com/atom/ns#' term='PRG'/><title type='text'>PRG &amp; Nokia Series 40 Browser</title><content type='html'>&lt;p&gt;In ASP.net &lt;abbr title="Model View Controller"&gt;MVC&lt;/abbr&gt; (or any other MVC framework) using the &lt;abbr title="Post Redirect Get"&gt;PRG&lt;/abbr&gt; pattern is quite common; the browser sends a POST to the controller, the controller returns a redirect and the browser GETs the redirect URI - simple, effective and widely used.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;However, the Nokia Series 40 browser doesn't quite behave properly when using the standard redirects in ASP.net MVC; the ASP.net MVC RedirectToAction method sends a HTTP status code 302 to the browser and expects the browser to GET the URI, the Nokia Series 40 browser rePOSTs the data from the original POST to the new URI. In ASP.net MVC controller actions have to be told to accept a HTTP POST (by default they only accept a HTTP GET) and since the browser has been asked to GET from the URI in the redirect there's every chance that the controller won't accept the POST. So the controller sends another redirect and around the loop we go again!&lt;br /&gt;The solution is to send a HTTP status code 303 to the browser, the Nokia Series 40 browser correctly GETs the URI in this case.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So now the problem moves to ASP.net MVC but thankfully the solution is straight forward; create a new class that inherits ActionResult and set the HTTP status code of the response to 303 and the response redirect location property to the desired GET URI.&lt;/p&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;public class Redirect303 : ActionResult&lt;br /&gt;{&lt;br /&gt;    private string url = string.Empty;&lt;br /&gt;&lt;br /&gt;    public Redirect303(string url)&lt;br /&gt;    {&lt;br /&gt;        this.url = url;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public override void ExecuteResult(ControllerContext context)&lt;br /&gt;    {&lt;br /&gt;        context.HttpContext.Response.StatusCode = 303;&lt;br /&gt;        context.HttpContext.Response.RedirectLocation = url;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;p&gt;It is clear from the code that the browser will be sent a HTTP status code of 303; just what the Nokia Series 40 browser needs but this class doesn't support the nice URI builder parameters that the MVC RedirectToAction method does. To make this class 'nice to use' just add public properties to your base controller class (you do have a base controller class that all your controllers inherit from don't you) that take the desired parameters and use the Url.Action method to get the MVC framework work out the URI for you.&lt;/p&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;public Redirect303 Redirect303(string actionName)&lt;br /&gt;{&lt;br /&gt;    return new Redirect303(Url.Action(actionName));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Redirect303 Redirect303(string actionName, object routeValues)&lt;br /&gt;{&lt;br /&gt;    return new Redirect303(Url.Action(actionName, routeValues));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Redirect303 Redirect303(string actionName, string controllerName)&lt;br /&gt;{&lt;br /&gt;    return new Redirect303(Url.Action(actionName, controllerName));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Redirect303 Redirect303(string actionName, string controllerName, object routeValues)&lt;br /&gt;{&lt;br /&gt;    return new Redirect303(Url.Action(actionName, controllerName, routeValues));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;code&gt;&lt;br /&gt;&lt;p&gt;There are actually 8 overloads for Url.Action so it wouldn't take long to build wrappers for all of them; once done you can forget RedirectToAction and use Redirect303 instead.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/706849474835530339-2657886211104038994?l=realwebdevelopers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://realwebdevelopers.blogspot.com/feeds/2657886211104038994/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/02/prg-nokia-series-40-browser.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/2657886211104038994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/706849474835530339/posts/default/2657886211104038994'/><link rel='alternate' type='text/html' href='http://realwebdevelopers.blogspot.com/2010/02/prg-nokia-series-40-browser.html' title='PRG &amp; Nokia Series 40 Browser'/><author><name>Real Web Developers</name><uri>http://www.blogger.com/profile/12097931712986289174</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
