OneTrueError - Automated exception handling

Introducing griffin.editor – a jQuery textarea plugin

I’ve tried to find a jQuery editor plugin which works out of the box without configuration. The WMD editor used by stackoverflow.com looked nice but I couldn’t find a version that I got running. My main issue with most editors was that I didn’t figure out how to configure custom image and link dialogs. I’ve therefore done my own.

Highlights:

  • Markdown (currently the only format supported)
  • Preview pane (see generated HTML live)
  • Syntax highlighting (live), using highlightjs or google prettify
  • Expanding textarea (which also goes back to original size on blur)
  • jQueryUI dialogs for links/images
  • Access keys (default browser modifier or CTRL if activated)
  • Plug & Play (just include additional scripts to activate features)

The basic setup looks like this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<head>
  <title>Editor demo</title>
  <script type="text/javascript" src="scripts/jquery-1.6.2.min.js"></script>
  <script type="text/javascript" src="scripts/jquery.markdown-0.2.js"></script>
  <script type="text/javascript" src="../Source/textselector.js"></script>
  <script type="text/javascript" src="../Source/jquery.griffin.editor.js"></script>
  <script type="text/javascript" src="../Source/jquery.griffin.editor.markdown.js"></script>
  <style type="text/css">
   .editor .area { width: 600px; height: 200px; }
   .editor .toolbar { padding: 0px;  }
 </style>
</head>
<body>
<div class="editor">
	<div class="toolbar">
		<span class="button-h1" accesskey="1" title="Heading 1"><img src="../Source/images/h1.png" /></span>
		<span class="button-h2" accesskey="2" title="Heading 2"><img src="../Source/images/h2.png" /></span>
		<span class="button-h3" accesskey="3" title="Heading 3"><img src="../Source/images/h3.png" /></span>
		<span class="button-bold" accesskey="b" title="Bold text"><img src="../Source/images/bold.png" /></span>
		<span class="button-italic" accesskey="i" title="Italic text"><img src="../Source/images/italic.png" /></span>
		<span class="divider">&nbsp;</span>
		<span class="button-bullets" accesskey="l" title="Bullet List"><img src="../Source/images/bullets.png" /></span>
		<span class="button-numbers" accesskey="n" title="Ordered list"><img src="../Source/images/numbers.png" /></span>
		<span class="divider">&nbsp;</span>
		<span class="button-sourcecode" accesskey="k" title="Source code"><img src="../Source/images/source_code.png" /></span>
		<span class="button-quote" accesskey="q" title="Qoutation"><img src="../Source/images/document_quote.png" /></span>
		<span class="divider">&nbsp;</span>
		<span class="button-link" accesskey="l" title="Insert link"><img src="../Source/images/link.png" /></span>
		<span class="button-image" accesskey="p" title="Insert picture/image"><img src="../Source/images/picture.png" /></span>
	</div>
	<textarea class="area">Hello world</textarea>
</div>
<script type="text/javascript">
	$(function(){
		$('.editor').griffinEditor();
	});
</script>
</body>
</html>

All of that is required. (Just a simple copy/paste). The idea is that you should easily be able to customize it’s layout. The script generates the following layout:

Basic layout

Dialogs

The basic setup uses browser dialog boxes:

Dialog box

Not so sexy. Include jQueryUI and the integration script:

  <link rel="stylesheet" href="Styles/jquery-ui-1.8.16.custom.css">
  <script type="text/javascript" src="scripts/jquery-ui-1.8.16.custom.min.js"></script>
  <script type="text/javascript" src="../Source/jquery.griffin.editor.dialogs.jqueryui.js"></script>

.. to automatically reconfigure the plugin to use jQueryUI:

Using jQueryUI for dialogs

You can use your own dialogs by implementation the following function:

$.griffinEditorExtension.imageDialog = function(options)
{
    //options.title & options.url contains info specified in the editor

   // invoke when done
   options.success({ title: 'Some title', url: 'Some url';}) when you are done
}

Same goes for the link dialog.

Preview pane

The preview pane is automatically configured when you add a div with a special id:

<div class="editor" id="myeditor">
//all the editor code
</div>
<div id="myeditor-preview">
</div>

This allows you to place the preview pane wherever you like. The included demo scripts places the preview to the right:

Preview pane

You can also add support for syntax highlighting by including additional script & stylesheet:

  <script src="http://yandex.st/highlightjs/6.1/highlight.min.js"></script>
  <link rel="stylesheet" href="http://yandex.st/highlightjs/6.1/styles/idea.min.css">

The script inclusion will activate those features, no additional configuration is required.

Access keys

The default access key implementation uses the browser specific implementation. For instance Win+Chrome uses ALT+Key to activate it. Hence no additional information in the tooltip:

Default access keys

That can be changed by adding a hotkeys script:

  <script type="text/javascript" src="scripts/jquery.hotkeys.js"></script>

Which reconfigures the tooltips and allows you to use CTRL+key to access the toolbar features. The key is still controlled by the accesskey attribute on the toolbar icons.

Better hotkeys

Summary

The codez & all examples are available at github.

Posted in CodeProject | Tagged , | 8 Comments

Generic repositories – A silly abstraction layer

This post is all about GENERIC repositories as in Repository, not about all types of repositories. Repositories are a great way to abstract away the data source. Doing so makes your code testable and flexible for future additions.

My recommendation is against generic repositories, since they don’t give you any additional value compared to regular repository classes. “Regular” repositories are usually written specifically for the requirements that your project have.

Let’s look at what generic repositories give you:

You can change OR/M implementation at any time.

Seriously?

  1. If you find yourself having switch OR/M during a project you have not done you homework before you started the project.
  2. The OR/M choice doesn’t matter since you have abstracted away the features of the chosen OR/M

imho you’ll stick with one OR/M during a project and switch for the next one (if you have to switch).

You have to write less code.

Here is a Generic repository (nhibernate implementation) from a SO question:

public interface IRepository<T> : IQueryable<T>
{
  void Add(T entity);
  T Get(Guid id);
  void Remove(T entity);
}

public class Repository<T> : IQueryable<T>
{
  private readonly ISession session;

  public Repository(ISession session)
  {
    session = session;
  }

  public Type ElementType
  {
    get { return session.Query<T>().ElementType; }
  }

  public Expression Expression
  {
    get { return session.Query<T>().Expression; }
  }

  public IQueryProvider Provider
  {
    get { return session.Query<T>().Provider; } 
  }  

  public void Add(T entity)
  {
    session.Save(entity);
  }

  public T Get(Guid id)
  {
    return session.Get<T>(id);
  }

  IEnumerator IEnumerable.GetEnumerator()
  {
    return this.GetEnumerator();
  }

  public IEnumerator<T> GetEnumerator()
  {
    return session.Query<T>().GetEnumerator();
  }

  public void Remove(T entity)
  {
    session.Delete(entity);
  }   
}

Take a look at the methods. All they do is to call methods in nhibernate. You do not win anything by doing so. All you get is an abstraction layer that removes the good things with nhibernate/ef/whatever.

It’s better to create a proper base class and move all repeated (DRY) functionality into it (and therefore still be able to take advantage of the features in your favorite OR/M).

Summary

Did I miss something that a generic repository gives you? Please make a comment.

Posted in Architecture, CodeProject | Tagged | 5 Comments

Repositories, Unit Of Work and ASP.NET MVC

There are a lot of posts discussing repository implementations, unit of work and ASP.NET MVC. This post is an attempt to give you and answer which addresses all three issues.

Repositories

Do NOT create generic repositories. They look fine when you look at them. But as the application grow you’ll notice that you have to do some workarounds in them which will break open/closed principle.

It’s much better to create repositories that are specific for an entity and it’s aggregate since it’s much easier to show intent. And you’ll also only create methods that you really need, YAGNI.

Generic repositories also removes the whole idea with choosing an OR/M since you can’t use your favorite OR/Ms features.

Unit Of Work

Most OR/Ms available do already implement the UoW pattern. You simply just need to create an interface and make and adapter (google Adapter pattern) implementation for your OR/M.

Interface:

    public interface IUnitOfWork : IDisposable
    {
        void SaveChanges();
    }

NHibernate sample implemenetation:

    public class NHibernateUnitOfWork : IUnitOfWork
    {
        private readonly ITransaction _transaction;

        public NHibernateUnitOfWork(ISession session)
        {
            if (session == null) throw new ArgumentNullException("session");
            _transaction = session.BeginTransaction();
        }

        public void Dispose()
        {
            if (!_transaction.WasCommitted)
                _transaction.Rollback();

            _transaction.Dispose();
        }

        public void SaveChanges()
        {
            _transaction.Commit();
        }
    }

ASP.NET MVC

I prefer to use an attribute to handle transactions in MVC. It makes the action methods cleaner:

[HttpPost, Transactional]
public ActionResult Update(YourModel model)
{
    //your logic here
}

And the attribute implementation:

public class TransactionalAttribute : ActionFilterAttribute
{
    private IUnitOfWork _unitOfWork;

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        _unitOfWork = DependencyResolver.Current.GetService<IUnitOfWork>();

        base.OnActionExecuting(filterContext);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // let the container dispose/rollback the UoW.
        if (filterContext.Exception == null)
            _unitOfWork.SaveChanges();

        base.OnActionExecuted(filterContext);
    }
}
Posted in Architecture, CodeProject | Tagged , | 3 Comments

Localizing jQuery plugins

I’ve spent some time to figure out how to localize my jQuery plugins and I’ve just found out a way that works just fine. Disclaimer: I’m not 100% sure of how namespacing works in jQuery so this might not be the correct way.

I’m using the meta header accept-language to control which language to use. It allows me to select the language in my backend (using user settings or whatever) instead of just using the languages defined by the browser. An ASP.NET MVC3 header would look like this in the layout:

<meta name="accept-language" content="@System.Globalization.CultureInfo.CurrentCulture.Name" />

You should be able to do the same thing in PHP or whatever language you use.

Next thing to do is to add the localization structure to your plugin script file:

(function($) {
    //globals
    $.yourPluginName = {
        texts: {
            title: 'Please wait, loading..'
        },
        translations: []
    };
    
    var methods = {
		// your methods here.
	};

    $.fn.yourPluginName = function(method) {

        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.yourPluginName');
        }

    };

})(jQuery);

That will make the plugin work if no languages are loaded. The translations will be loaded into the $.yourPluginName.translations array by another script.

We got one thing left to do before we can use the texts in your script. We need to load the correct language. Create another script called jquery.yourpluginnamne.localization.js and load it after$.yourPluginName.texts.anyTextName in your plugin to use the localized strings.

Posted in Architecture, CodeProject | Tagged , , | Leave a comment

Get an unique session in each browser tab

I got a lot to do at work, hence the silence. I got a lot to blog about, but so little time ;/ I found an interesting question at stackoverflow which this answer is for (also to show you that the blog is not forgotten).

A user wanted to store browser tab specific data which can be a problem since most browsers shares a session between different tabs. The solution is to create a new route which generates a GUID and then
use that guid to fetch and store session information. Keep in mind that you need to routes: One that works for users which just surfed into the site, and one that loads an existing guid.

Here is the route class:

public class GuidRoute : Route
{
	private readonly bool _isGuidRoute;

	public GuidRoute(string uri, object defaults)
		: base(uri, new RouteValueDictionary(defaults), new MvcRouteHandler())
	{
		_isGuidRoute = uri.Contains("guid");

		DataTokens = new RouteValueDictionary();
	}

	public override RouteData GetRouteData(HttpContextBase httpContext)
	{
		var routeData = base.GetRouteData(httpContext);
		if (routeData == null)
			return null;

		if (!routeData.Values.ContainsKey("guid") || routeData.Values["guid"].ToString() == "")
			routeData.Values["guid"] = Guid.NewGuid().ToString("N");

		return routeData;
	}

	public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
	{
		return !_isGuidRoute ? null : base.GetVirtualPath(requestContext, values);
	}
}

Replace the default route in global.asax with it:

/*routes.MapRoute(
	"Default", // Route name
	"{controller}/{action}/{id}", // URL with parameters
	new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);*/

routes.Add("Default", new GuidRoute(
	"{controller}/{action}/{id}", 
	new { controller = "Home", action = "Index", guid = "", id = UrlParameter.Optional }));

routes.Add("GuidRoute", new GuidRoute(
	"g/{guid}/{controller}/{action}/{id}", 
	new { controller = "Home", action = "Index", guid = "", id = UrlParameter.Optional }));

And finally some extension methods to make life easier in the controllers:

public static class ControllerExtensionMethods
{
	public static string GetGuid(this Controller controller)
	{
		return controller.RouteData.Values["guid"].ToString();
	}

	public static void SetGuidSession(this Controller controller, string name, object value)
	{
		controller.Session[controller.GetGuid() + "_" + name] = value;
	}

	public static object GetGuidSession(this Controller controller, string name)
	{
		return controller.Session[controller.GetGuid() + "_" + name];
	}
}

One thing left though: Any browser bookmarks will use an old GUID. Should not be a problem in most cases (unless the user opens the bookmark in multiple tabs = sharing the session between the tabs). Same
thing goes for opening a link in a new tab = shared.

Posted in Architecture, CodeProject | Tagged | 14 Comments

Introducing my logging library

I’ve just published the first version (consider it a beta) of my logging library to the official nuget server(s).

Why another library when there are existing ones as log4net and nlog? Because it should be easier to get started and you should still have the power to customize the logging if needed. Griffin.Logging do not have a configuration file, everything is configured through code.

Simple syntax

The easiest approach only requires one line to configure the framework:

SimpleLogManager.AddFile(@"D:LogFilesMyLog.log");

You can swap the AddFile method to AddConsole if you would like.

Fluent syntax

Use the fluent syntax if you need more power:

var config = new FluentConfiguration()
  .LogNamespace("Fadd.Test").AndChildNamespaces.ToTargetNamed("Console")
  .LogNamespace("System").AndChildNamespaces.ToTargetNamed("DefaultFile")
  .AddTarget("Console")
	  .As.ConsoleLogger().Filter.OnLogLevelBetween(LogLevel.Info, LogLevel.Error)
	  .Done 
  .AddTarget("DefaultFile")
	  .As.FileLogger("ErrorsOnly").Filter.OnLogLevel(LogLevel.Error)
	  .As.FileLogger("Everything")
	  .Done
  .Build();

Usage

public class MyClass
{
    ILogger logger = LogManager.GetLogger<MyClass>();

    public MyClass()
    {
        // Built in formatting for cleaner syntax.
        logger.Info("Welcome {0}!.", user.Name);
    }
    public void HideError()
    {
        try
        {
            throw new InvalidOperationException("No no", new OutOfScopeException("Can't thing anymore"));
        }
        catch (Exception err)
        {
            // Log an exception. The inner exceptions are logged too (recursive)
            logger.Warning("Ooops, we got an exception.", ex);
        }
    }

}

Code

Check the homepage for more information or just install the nuget package “griffin.logging“.

Posted in Libraries | Tagged , , | Leave a comment

How to handle errors in ASP.NET MVC

There are several blog posts regarding error handling for ASP.NET MVC. They use everything from Application_Error to exception handling in the base controller. With this post I’ll show how you can use the built in features in MVC to treat errors.

Continue reading

Posted in CodeProject | Tagged , | 9 Comments

First draft of my alternative HTML helpers

I’m getting closer to a first release of my ASP.NET MVC contribution project called Griffin.MvcContrib. I’ve just committed my first draft of the alternative HTML helpers. I’ve focused on helpers for Form tags in this commit. If you are wondering what’s wrong with the original helpers, please see my previous blog entry about using extension as an important part of a framework.

Here are some new features that my HTML providers add:

Extensible

By using extension methods there is no way to extend the functionality in them. I’ve solved this in two ways. First and foremost there aren’t any extension methods. My HtmlHelper class is just a facade that tries to use the DependencyResolver to find the proper generators. It will also create the default implementations if no extended ones are found.

To extend one of the helpers, simply derive it and make the changes you like. The following sample with add a “title” attribute to all text areas (which then can be picked up by a jquery script to create a nice tool tip)

    public class MyCustomTextAreaGenerator : TextAreaGenerator
    {
        public MyCustomTextAreaGenerator(ViewContext viewContext) : base(viewContext)
        {
        }

        protected override IEnumerable<NestedTagBuilder> GenerateTags()
        {
            var generatedTags = base.GenerateTags().ToArray();
            generatedTags[0].MergeAttribute("title", "You are so dirty!");
            return generatedTags;
        }
    }

and then register it in your current inversion of control container. Here is a sample for autofac:

containerBuilder
    .RegisterType<MyCustomTextAreaGenerator>()
    .AsImplementedInterfaces();

The following generators do currently exist:

  • CheckBoxGenerator
  • RadioButtonGenerator
  • SelectGenerator
  • TextAreaGenerator
  • TextBoxGenerator

Post processing generated HTML tags

You can also add more generic adapters which can be used to transform the generated HTML tags. The sample project which is included in github shows you how to:

  • create watermarks for textboxes
  • Add tooltips
  • Transform all age fields into UI sliders

Here is the watermark example:

    public class WatermarkAdapter : IFormItemAdapter
    {
        public void Process(FormItemAdapterContext context)
        {
            // there is a "Watermark" metadata but it cannot currently be set.
            // unless you are using a custom metadata provider like the one in the localization demo.
            if (string.IsNullOrEmpty(context.Metadata.Description) || !context.TagBuilder.Attributes.ContainsKey("class") || !context.TagBuilder.Attributes["class"].Contains("watermark"))
                return;

            context.TagBuilder.MergeAttribute("title", "Watermark:" + context.Metadata.Description);
        }
    }

And the jquery script creating the actual watermark (uses the jquery watermark plugin):

function watermark() {
    $('[title*="Watermark:"]').each(function () {
        $(this).watermark($(this).attr('title').substr(10));
        $(this).removeAttr('title');
    });
}

Enum galore

Are you using enums? Sure you do. The html helpers in Griffin.MvcContrib can generate lists, checkboxes and radio buttons automatically for them.

The following code:

@Html2.CheckBoxesFor(model => model.InputType) <br />
@Html2.RadioButtonsFor(model => model.InputType) <br />
@Html2.DropdownFor(model => model.InputType) <br />

Generates the following HTML:

HTML generated by enum html helpers

Lets format that dropdown

Dropdowns are something else that I’ve tried to improve. You can use formatters to determine how the select lists should be generated.

The following example are using a custom formatter which has been made to transform user objects:

@Html2.DropdownFor(model => model.CurrentUser, Select.From<UserFormatter>(Model.Users))

And the actual formatter:

    public class UserFormatter : ISelectItemFormatter
    {
        public SelectListItem Generate(object itm)
        {
            var item = (User)itm;
            return new SelectListItem
            {
                Text = string.Format("{0} {1}", item.FirstName, item.LastName),
                Value = item.Id.ToString()
            };
        }
    }

There are to formatters built into MvcContrib:

  • IdTitle
  • IdName

They uses reflection to find the proper properties.

Summary

All mentioned helpers should work without any problems. But I’m not done with the helpers yet. This post is most about me wanting feedback. Have I made any stupid mistakes? Do you have any suggestions how I can improve the code?

Please take a look at the sample project

The actual source code for all helpers can be found here

Posted in Uncategorized | Tagged , | 2 Comments

A more structured MembershipProvider.

If you take a look at the official documentation that tells you how to create your own custom MembershipProvider you’ll notice that the documentation is mostly about describing:

  • how you should throw exceptions and when
  • Which events you should invoke and when
  • How the logic in each method should work.

Let’s stop here for a moment. What are the most typical reason for creating a custom membership provider? Is it to change the behaviour(/contract) of the provider? Or maybe change the password handling? No. The most common reason is to add support for a custom data source.

Back to the MembershipProvider class. As I see it, it has four responsibilites:

  1. Be able to handle all members (login, register etc)
  2. Load/Store information from/in a data source
  3. Keep track of account/password policies and handle those.
  4. Handle passwords (encrypt/hash/compare)

And that’s why it’s such a tedious task to create a custom MembershipProvider: You need to implement all of those responsibilities.

Griffin.MvcContrib to the rescue!

With the MembershipProvider in Griffin.MvcContrib you do not need to know all of those details. Our MembershipProvider uses DependencyResolver (a built in
Service Locator in MVC3) to lookup the dependencies that it needs. You need to register the following services in your inversion of control container:

IAccountRepository

Used to retrieve/store membership accounts from/to a data source. It’s the only thing you need to implement to get support for a custom data source (like a database or a web service).

Source code

IPasswordStrategy

Used to handle passwords (comparing them, encrypting, decrypting). There are three strategies available in the framework:

  • ClearTextStrategy – Store passwords as clear text in the database
  • HashedPasswordStrategy – Hash passwords before they are stored.
  • TripleDesPasswordStrategy – Use TripleDes to encrypt/decrypt passwords.

Source code

IPasswordPolicy

Defines how passwords should be treated. For instance the minimum length, number of attempts before locking the account etc.

Two policy implementations exist. One who loads the policies from web.config and one “normal” class which you can create and assign the properties in.

Source code

How to use it

Disclaimer: You should know that Account Administration Tools won’t work since the provider has a dependency on DependencyResolver. Other than that, the provider works like any other provider.

Start by modifying your web.config to specify the new provider:

    <membership defaultProvider="GriffinMembershipProvider">
      <providers>
        <clear />
        <add name="GriffinMembershipProvider" type="Griffin.MvcContrib.Providers.Membership.MembershipProvider" applicationName="/" />
      </providers>
    </membership>

Then you need to register the dependencies in your inversion of control container. Here is a sample for Autofac:

protected void Application_Start()
{
	ContainerBuilder builder = new ContainerBuilder();
	builder.RegisterType<HashPasswordStrategy>().AsImplementedInterfaces();
	builder.RegisterType<RavenDbAccountRepository>().AsImplementedInterfaces();
	builder.RegisterInstance(new PasswordPolicy
		 {
			 IsPasswordQuestionRequired = false,
			 IsPasswordResetEnabled = true,
			 IsPasswordRetrievalEnabled = false,
			 MaxInvalidPasswordAttempts = 5,
			 MinRequiredNonAlphanumericCharacters = 0,
			 PasswordAttemptWindow = 10,
			 PasswordMinimumLength = 6,
			 PasswordStrengthRegularExpression = null
		 }).AsImplementedInterfaces();
								 
	// the rest of the initialization
}

If you like to switch from hashed passwords to encrypted passwords you just need to register TripleDesStrategy in the container instead. Or implement your own strategy.

Summary

The code is available at github and can be installed using nuget install-package griffin.mvccontrib.

Posted in Architecture, CodeProject | Tagged , , | Leave a comment

Why extension methods should not be used as part of a framework.

Two of my favorite frameworks/libraries uses extension methods heavily. Autofac uses extension methods during registration and ASP.NET MVC3 for their HTML Helpers. Since extension methods are static, they are closed for extension. Which are one of the most important principles for object oriented programming.

For MVC I would like to be able to add a tooltip automatically for all editors and labels. It’s really simple, I just want to add a “title” attribute to all generated HTML elements where the ModelMetadata contains a “Description”. The source code for LabelFor looks like this:

    public static class LabelExtensions {
        public static MvcHtmlString Label(this HtmlHelper html, string expression) {
            return LabelHelper(html,
                               ModelMetadata.FromStringExpression(expression, html.ViewData),
                               expression);
        }

        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression) {
            return LabelHelper(html, 
                               ModelMetadata.FromLambdaExpression(expression, html.ViewData), 
                               ExpressionHelper.GetExpressionText(expression));
        }

        public static MvcHtmlString LabelForModel(this HtmlHelper html) {
            return LabelHelper(html, html.ViewData.ModelMetadata, String.Empty);
        }

        internal static MvcHtmlString LabelHelper(HtmlHelper html, ModelMetadata metadata, string htmlFieldName) {
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
            if (String.IsNullOrEmpty(labelText)) {
                return MvcHtmlString.Empty;
            }

            TagBuilder tag = new TagBuilder("label");
            tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
            tag.SetInnerText(labelText);
            return tag.ToMvcHtmlString(TagRenderMode.Normal);
        }
    }

Hence it’s impossible to do anything about the helper. I do understand why they use extension methods. It’s great since it’s very easy to find all available helpers. The problem is that you can’t do anything do modify the data that they generate.

The solution

Convert all extension methods to facades for the real implementation, and use DependencyResolver in the extension methods to find the proper classes. Create some interfaces and default implementations for all generators.

The new LabelHelper:

internal static MvcHtmlString LabelHelper(HtmlHelper html, ModelMetadata metadata, string htmlFieldName)
{

    var labelGenerator = DependencyResolver.Resolve<ILabelGenerator>();
    return labelGenerator.Create(html, metadata, htmlFieldName);
}

The default implementation (simplified example):

	public class LabelGenerator : ILabelGenerator
	{
	
		public virtual void Create(HtmlHelper html, ModelMetadata metadata, string htmlFieldName)
		{
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
            if (String.IsNullOrEmpty(labelText)) {
                return MvcHtmlString.Empty;
            }

            TagBuilder tag = new TagBuilder("label");
            tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
            tag.SetInnerText(labelText);
			ProcessTag(tag);
            return tag.ToMvcHtmlString(TagRenderMode.Normal);
		}
			
		protected virtual void ProcessTag(TagBuilder tag, ModelMetaData metaData)
		{
		}
	}

Which would allow me to create the following implementation:

	public class LabelWithTitlesGenerator : LabelGenerator
	{
		protected override void ProcessTag(TagBuilder tag, ModelMetaData metaData)
		{
			if (metaData.Description != null)
				tag.Attributes.Add("title", metaData.Description);
		}
	}

The only thing left is to inject it in my container and create a small jquery script which creates the actual tooltip using the “title” attribute.

Summary

Extension methods are closed for extension. Once declared you can not do anything to extend the functionality that they provide. It’s the same as if you would develop a framework where you put sealed on all your classes.

Extension methods were created to be able to make life easier by proving convenience methods for existing classes. The intention was not that you should use them as a part of your framework since you close down that part for extension if you do. The extension methods become locking out methods ;O

Posted in Architecture, CodeProject | Tagged , , | 1 Comment