Archive for the '.NET 3.5' Category Page 2 of 2

26DecNew view engines in the MvcContrib project for asp.net mvc

When I got back from visiting my parents over the christmas holiday I checked the MvcContrib project to find out that both Andrew Peter’s NHAML view engine and my XSLT view engine have been accepted in the trunk of those projects.

What’s left to do for me is provide a sample site that shows usage of the view engine.  This has been a very rewarding experience so far :) . I found out about IViewSourceLoader to get the path to the current view file for example.

I also learnt a new trick to increase my test coverage and be able to test the content of the rendered view.

To get the mvc contrib project you can either download it from the releases section on the codeplex site.

Or you can check out the source code and build it yourself from the subversion repository

del.icio.us Tags: ,

Technorati Tags:

16DecImplementing filters in asp.net mvc

One of the things I wanted for the framework I’m building for Xero was to implement filters.

I have a first pass of those ready.. didn’t take me to long to implement either.  I only tested the before filters I haven’t gotten round to testing the After filter. I have to do a demo today that demonstrates databinding (like the castle project solved it.)  What I’m putting on my blog here is very much a proof of concept implementation and you should not use this in a production environment.

Here’s how I went about it. In this post I’ll show how I implemented a filter that directs anonymous users to the login page.

1. Define a couple enumerations

    public enum Execute

    {

        Before,

        After,

        BeforeAndAfter

    }

 

    public enum SecureFor

    {

        None,

        Anonymous,

        PerUser

    }

 

2. Create an IFilter interface

 

using System.Web;

 

namespace Xero.Mvc.Extensions.Filters

{

    public interface IFilter

    {

        Execute WhenToExecute { get; }

        IHttpContext HttpContext { get; set; }

        void Execute();

    }

}

3. Create an AbstractFilter base class

using System;

using System.Web;

namespace Xero.Mvc.Extensions.Filters

{

    [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]

    public abstract class AbstractFilter : Attribute, IFilter

    {

        private readonly Xero.Mvc.Extensions.Execute whenToExecute;

        private IHttpContext httpContext;

 

        public AbstractFilter(Xero.Mvc.Extensions.Execute whenToExecute)

        {

            this.whenToExecute = whenToExecute;

        }

 

        public IHttpContext HttpContext

        {

            get { return httpContext; }

            set { httpContext = value; }

        }

 

        public Xero.Mvc.Extensions.Execute WhenToExecute

        {

            get { return whenToExecute; }

        }

 

 

        public abstract void Execute();

    }

}

 

4. Create a SecureFilter base class

using System;

using System.Web;

using System.Collections.Generic;

 

namespace Xero.Mvc.Extensions.Filters

{

    [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]

    public abstract class AbstractSecureFilter : AbstractFilter, IFilter

    {

        private readonly SecureFor secureFor;

 

        public AbstractSecureFilter(Xero.Mvc.Extensions.Execute whenToExecute, SecureFor secureFor)

            : base(whenToExecute)

        {

            this.secureFor = secureFor;

        }

 

        public SecureFor SecureFor

        {

            get { return secureFor; }

        }

 

        protected void RedirectToLogin()

        {

            HttpContext.Response.Redirect(“~/”, true);

        }

    }

}

 

5. Implement the concrete AnonymousUsersFilter

using Xero.Mvc.Extensions.Filters;

using Xero.Mvc.Tasklist.Model.EntityClasses;

using Xero.Mvc.LLBLGenIntegration.Services;

using System;

using System.Collections.Generic;

using Xero.Mvc.Extensions;

 

namespace Xero.Mvc.Tasklist.Filters

{

    [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]

    public class AnonymousUsersFilter : AbstractSecureFilter

    {

        private User[] users;

        private DataService<User> userService;

 

        public AnonymousUsersFilter(Xero.Mvc.Extensions.Execute whenToExecute, SecureFor secureFor) : this(whenToExecute, secureFor, null) { }

 

        private AnonymousUsersFilter(Xero.Mvc.Extensions.Execute whenToExecute, SecureFor secureFor, User[] users)

            : base(whenToExecute, secureFor)

        {

            this.users = users;

            this.userService = new DataService<User>();

        }

 

        public AnonymousUsersFilter(Xero.Mvc.Extensions.Execute whenToExecute, User[] users) : this(whenToExecute, SecureFor.PerUser, users) { }

 

 

        public User[] Users

        {

            get { return users; }

        }

 

        public override void Execute()

        {

            if (SecureFor == Xero.Mvc.Extensions.SecureFor.Anonymous && HttpContext.Session["userId"] == null)

            {

                RedirectToLogin();

            }

 

            if (SecureFor == Xero.Mvc.Extensions.SecureFor.PerUser && Users == null)

                RedirectToLogin();

 

            if (SecureFor == Xero.Mvc.Extensions.SecureFor.PerUser)

            {

                User currentUser = userService.FindOneById((Guid)HttpContext.Session["userId"]);

                List<User> allowedUsers = new List<User>(Users);

 

                if (allowedUsers.Find(usr => usr.Name.ToUpperInvariant() == currentUser.Name.ToUpperInvariant()) == null)

                RedirectToLogin();

            }

        }

    }

}

 

6. Implement the filter on a controller

[AnonymousUsersFilter(Xero.Mvc.Extensions.Execute.Before, SecureFor.Anonymous)]

    public abstract class SecureControllerBase : SmartXeroController

 

7. There are a couple of places where you can implement the execution of the filter logic. I chose to do it before the actual controller class is being loaded. To do that I had to create a handler and a routehandler

7.a The MvcHandler

using System.Web.Mvc;

using System;

using Xero.Mvc.Core.Exceptions;

using Xero.Mvc.Extensions.Filters;

using System.Linq;

 

namespace Xero.Mvc.Extensions

{

    public class XeroMvcHandler : MvcHandler

    {

        protected override void ProcessRequest(System.Web.IHttpContext httpContext)

        {

            if (this.RequestContext == null)

            {

                throw new NoRequestContextException();

            }

            string controllerName = this.RequestContext.RouteData.Values["controller"].ToString();

            Type controllerType = this.GetControllerType(controllerName);

            if (controllerType == null)

            {

                throw new NoControllerFoundException(this.RequestContext.HttpContext.Request.Path);

            }

 

            IFilter[] filters = controllerType.GetCustomAttributes(typeof(IFilter), true) as IFilter[];

 

            filters

                .Where(attr => attr.WhenToExecute == Xero.Mvc.Extensions.Execute.Before || attr.WhenToExecute == Xero.Mvc.Extensions.Execute.BeforeAndAfter)

                .ToList()

                .ForEach(attr =>

                {

                    if (attr != null)

                    {

                        attr.HttpContext = httpContext;

                        attr.Execute();

                    }

                });

 

            IController controllerInstance = this.GetControllerInstance(controllerType);

 

            ControllerContext controllerContext = new ControllerContext(this.RequestContext, controllerInstance);

            controllerInstance.Execute(controllerContext);

 

            filters

                .Where(attr => attr.WhenToExecute == Xero.Mvc.Extensions.Execute.After || attr.WhenToExecute == Xero.Mvc.Extensions.Execute.BeforeAndAfter)

                .ToList()

                .ForEach(attr =>

                {

                    if (attr != null)

                    {

                        attr.HttpContext = httpContext;

                        attr.Execute();

                    }

                });

        }

    }

}

 

7b. The Route Handler

using System.Web.Mvc;

using System.Web;

 

namespace Xero.Mvc.Extensions

{

    public class XeroMvcRouteHandler : IRouteHandler

    {

 

        #region IRouteHandler Members

 

        public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)

        {

            return new XeroMvcHandler { RequestContext = requestContext };

        }

 

        #endregion

    }

}

 

8. And the last step is to tell your application that it needs to use the new route handler. You can do that in the global.asax.cs

protected override void SetupRoutes()

        {

            // Note: Change Url= to Url=”[controller].mvc/[action]/[id]” to enable

            //       automatic support on IIS6

 

            RouteTable.Routes.Add(new Route

            {

                Url = “Login/Default.aspx”,

                Defaults = new { controller = “Login”, action = “Index”, id = (string)null },

                RouteHandler = typeof(XeroMvcRouteHandler) // Our custom route handler

            });

 

            RouteTable.Routes.Add(new Route

            {

                Url = “[controller]/[action]/[id]“,

                Defaults = new { action = “Index”, id = (string)null },

                RouteHandler = typeof(XeroMvcRouteHandler)

            });

 

            RouteTable.Routes.Add(new Route

            {

                Url = “Default.aspx”,

                Defaults = new { controller = “Login”, action = “Index”, id = (string)null },

                RouteHandler = typeof(XeroMvcRouteHandler)

            });

 

        }

 

del.icio.us Tags: ,,

Technorati Tags:

kick it on DotNetKicks.com

14DecASP.NET MVC XsltViewEngine, patch submitted to the contrib project

I just submitted a patch to the mvc contrib project that contains the xslt view engine I wrote for Xero without any of the dependencies from our own libraries or commercial components.

The bulk of the work is done in a class called XmlResponseBuilder which builds the xml document that is going to be transformed by the xsl stylesheet. Almost all the rest of the code is there just to build up this document.

The implementation of IView and IViewFactory were the easy bits :)

To use the View engine you need to take the following steps:

1. Get the MVC Contrib project from google code

repository url: http://mvccontrib.googlecode.com/svn/trunk/

2. If the patch hasn’t been applied yet you can download it from: http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=MVCContrib&DownloadId=23748

After downloading the patch you can apply it to the downloaded mvc contrib project.

3. I use a base controller to ensure that the correct data is passed to the view factory. This is the base controller class:

public abstract class XeroControllerBase : Controller

    {

        private readonly XsltViewData vData = new XsltViewData();

 

        protected IHttpSessionState Session

        {

            get { return ControllerContext.HttpContext.Session; }

        }

 

        public XeroControllerBase()

        {

            ViewFactory = new XsltViewFactory();  

        }

 

        #region Add datasource methods

 

        protected void AddDataSource(IXmlConvertible dataSource)

        {

            vData.DataSources.Add(new XslDataSource(dataSource));

        }

 

        protected void AddDataSource(IXmlConvertible dataSource, string rootName)

        {

            vData.DataSources.Add(new XslDataSource(rootName, dataSource));

        }

 

        #endregion

 

        #region Add variable methods

 

        protected void AddPageVar(string key, string value)

        {

            vData.PageVars.Add(key, value);

        }

 

        #endregion

 

        #region Add message methods

 

 

        protected void AddErrorMessage(string message)

        {

            vData.Messages.Add(new ErrorMessage(message));

        }

 

        protected void AddErrormessage(string message, string controlID)

        {

            vData.Messages.Add(new ErrorMessage(message, controlID));

        }

 

        protected void AddInfoMessage(string message)

        {

            vData.Messages.Add(new InfoMessage(message));

        }

 

        protected void AddInfoMessage(string message, string controlID)

        {

            vData.Messages.Add(new InfoMessage(message, controlID));

        }

 

        protected void AddAlertMessage(string message)

        {

            vData.Messages.Add(new AlertMessage(message));

        }

 

        protected void AddAlertMessage(string message, string controlID)

        {

            vData.Messages.Add(new AlertMessage(message, controlID));

        }

 

        protected void AddInfoHtmlMessage(string message)

        {

            vData.Messages.Add(new InfoHtmlMessage(message));

        }

 

        protected void AddInfoHtmlMessage(string message, string controlID)

        {

            vData.Messages.Add(new InfoHtmlMessage(message, controlID));

        }

 

        protected void AddErrorHtmlMessage(string message)

        {

            vData.Messages.Add(new ErrorHtmlMessage(message));

        }

 

        protected void AddErrorHtmlmessage(string message, string controlID)

        {

            vData.Messages.Add(new ErrorHtmlMessage(message, controlID));

        }

 

        protected void AddAlertHtmlMessage(string message)

        {

            vData.Messages.Add(new AlertHtmlMessage(message));

        }

 

        protected void AddAlertHtmlMessage(string message, string controlID)

        {

            vData.Messages.Add(new AlertHtmlMessage(message, controlID));

        }

 

        #endregion

 

        #region RenderView method hides

 

        protected new virtual void RenderView(string viewName)

        {

            RenderView(viewName, string.Empty, vData);

        }

 

        protected new void RenderView(string viewName, string masterName)

        {

            RenderView(viewName, string.Empty, vData);

        }

 

        protected new void RenderView(string viewName, object viewData)

        {

            RenderView(viewName, string.Empty, vData);

        }

 

        #endregion 

    }

 

del.icio.us Tags:
 
kick it on DotNetKicks.com

12DecASP.NET mvc taken for a test drive

A couple of days ago Microsoft released a CTP of the much discussed ASP.NET MVC handler. I decided to take it for a test drive.

At first I just wanted to have a look at how to use the MVC handler with the ADO.NET Entities but quickly found that I can easily replace like the view engine.

So I diverted my intentions and wanted to look at how hard it would be to plug it straight into the architecture of xero.

At Xero we currently use a 2 step view approach where each page transforms its output through xsl and renders html that way.  Our O/R Mapper of choice is LLBLGen Pro, who does a great job at mapping stuff but the API could be a lot nicer IMHO.

I’ll make my application available soon, as soon as I removed the dependencies on LLBLGen and some of our custom classes. I have to do it this way because we’re a publicly listed company and I’m not allowed to give out that information.

Aaanyway in all it took me about 4 hours to plug in an xslt view engine and implement attribute based filters.

Overall I’m quite happy with what I’m seeing that’s in there. A couple of convenience methods like RenderText(…) would be nice. It would also be cool if it could find out the name of the requested action and then pass that as the current view so you don’t have to specify the name of which view you want to render all the time.

We did run into some trouble while writing unit tests apparently we can’t pass the view context a temp data dictionary but I’m sure that will be fixed soon.

So my conclusion is: There did go a fair bit amount of thought into the handler. I like what I see very much and I’ll definitely keep a close eye on new developments in that space.

27NovRe: The difference between meta programming and IL weaving

Ayende replied to my post from this morning. His point is that the in order to be able to do meta programming Reflection.Emit isn’t enough because it happens after the compilation has taken place. And in order to do meta programming you need to be able to do that during the compilation step. This is my reply, hence the title :)

Meta-programming can be achieved by having the language implementation change classes or generate classes at some point. In dynamic languages that is generally at run time, it’s most common use is where the data format drives the code ie. a database, csv files etc. For the sake of this discussion i’m going to keep it at runtime, if meta programming occurs at compilation time it loses a lot of its power, how is it going to respond to changes at runtime like changes in the data schema.

You could do this by having an interface of your implementation, If you’re going to use an interface implementation you can just as well generate the class or implement the class. Another thing you need for meta programming is duck typing. So for meta programming to happen you would have to forgo things like type checking, looking for existing methods on classes etc. You would lose the biggest advantage of a statically typed language and one of the biggest reasons for having a compiler at all. So, with all due respect, I wonder at that point why use a static typed language implemented on a compiler, that will make things really hard for you, at all when you can achieve the same things in other dynamically typed languages with hardly any effort.

If all you want is ruby with c# syntax, then you will lose exactly what makes ruby so attractive its more natural syntax. At this moment the IronRuby implementation still needs a lot of work but you could use Ruby.NET and get a good working version of Ruby that runs and compiles on the CLR. Or use ironpython that implementation is a lot more usable at this moment and you can do interop with .NET assemblies.

With Reflection.Emit you can get similar things. You can’t modify existing classes but when you would be using something like an IoC container that keeps track of dynamic proxy wrappers that are being generated so that it can always use the latest proxy wrapper, that way you could achieve almost the same thing. This won’t be the fastest method around but it would give you most the needed abilities. You would still need at least some interfaces and know about those interfaces upfront. After all MSIL is much like a dynamic language.

I still wouldn’t exactly call it meta programming but it can come close, you wouldn’t be able to modify existing classes but you would be able to add functionality to classes. It also won’t be the most easy thing to implement correctly but in theory it can be done.

Method missing in ruby works because the ruby interpreter walks up its tree of objects looking for an implementation of method_missing but that’s also what makes method missing not the fastest mechanism around.

This whole discussion made me think of a generalization Greenspun’s 10th law: “any sufficiently complicated program in a statically-typechecked language contains an ad-hoc, informally-specified bug-ridden slow implementation of a dynamically-checked language.” ;)

What would the implementation of IDynamicObject be ? Would it suddenly drop the type checking for implementing classes and defer that to runtime? How would you like to see IDynamicObject happening without losing static typing along the way ? I would like to find out these things interest me tremendously, I’m always looking for ways to make C# more dynamic but I don’t want to lose static typing along the way.  I would like to use C# instead of C++ for speed and use IronRuby for the rest for example, shifting those languages one era along.

26NovGetting mixin like behavior in C# 3.0

UPDATE: I titled this post wrong. I should have said that you can mimic Mixins to a certain extend with extensions methods.  But extension methods are exactly that, Exten(d)sions of classes. These methods only have access to the public interface of a class you. You also need to specify a using statement with the namespace of your extension class to every class you want to be using the extended object in. Extension methods are syntactic sugar for what you used to do with static helper methods.  That are IMHO the most important differences with a mixin because instead of mixing in functionality you are now extending an existing objects. So the title of the post used to be Mixins in C# 3.0.  And now is getting mixin like behavior in C# 3.0

Yesterday Jeremy Miller put a post up with a list of features he would like to see added to the next version of C#. I don’t agree with everything on that list and some of it is already here.

I’ll take his points and add my comments to them.:

1. Mixins (I’ll demonstrate how to get mixin like behavior in C#)

2. Symbols => useless, a symbol is nothing but an interned string. C# is a static language why on earth would you want to go and add non statically typed features to that language

3. Hashes => Hashes are already a languages feature in C# 3.0, they are called dictionaries.

4. Automatic delegation => as Ayende said: Mixins

5. Metaprogramming => no objection here although you can do it now with reflection emit

6. Make virtual the default to make mocking easier.

 

Ayende has got a similar reply up on his blog and he adds a couple of features.
I agree with his features so I won’t be commenting on them except for asking when do we get those?

Now the bigger problem I’ve got with this is I quite like the distinction of capabilities from one language to the next. Like say Ruby vs. C# there are things that can be easily or better done using c# and there are things that are easier using ruby. However why aren’t you using Ruby if all you want are language features from Ruby in C# ? Ruby is a beautiful language and it’s not just because of the features, they make it even nicer. It’s because of the syntax and the freedom.

I think Ayende clearly gets the benefits because he uses boo a lot. I tend to use Ruby a lot more than I do boo.

Now let’s get on to what is the title of this post.

The way I see it a Mixin is a way to add additional and common logic to classes, you can’t do that in C# at this moment but you can get mixin like behavior by using extension methods.

And this can be achieved by using extension methods in 2 different ways. The first approach has been documented by Bill Wagner but for the record I only found out about it after I had written my little test application to show you what I think is the best way of implementing Mixins. A mixin is often compared to an interface and it’s implementation (you can’t use an abstract class because that could break your inheritance chain in the long run, interfaces are the correct way to implement them)

The first method is to extend an interface and by adding that interface and the Extension methods namespace to your code file you get all those methods mixed into your class. Without the interface it doesn’t work. For simplicity I’ll use a IList in reality I would have somewhat more complex objects. There is only one thing that doesn’t feel too right to me and that is that every class you’re going to use it in needs to know about the extension methods location. I would like to see that if you implement it  on a class it gets propagated whenever you use an instance of that class. Anyway let’s see some code:

The first step is to define an interface that we can extend later.

using System.Collections.Generic;

 

namespace Mixins.Mixins

{

    public interface IAuditable

    {

        IList<string> Auditors{ get; }

    }

}

 

The next step is to define the extension methods

using System.Collections.Generic;

 

namespace Mixins.Mixins.Auditable

{

    public static class AuditableMixin

    {

        public static bool HasBeenAudited(this IAuditable targetClass)

        {

            return targetClass.Auditors.Count > 0;

        }

 

        public static bool HasBeenAuditedBy(this IAuditable targetClass, string name)

        {

            return targetClass.Auditors.Contains(name);

        }

 

        public static IList<string> AddAuditor(this IAuditable targetClass, string name)

        {

            targetClass.Auditors.Add(name);

            return targetClass.Auditors;

        }

 

        public static IList<string> RemoveAuditor(this IAuditable targetClass, string name)

        {

            if (HasBeenAuditedBy(targetClass, name))

            {

                targetClass.Auditors.Remove(name);

            }

            return targetClass.Auditors;

        }

    }

}

And the last step is to create an actual object that will have our mixin.

using Mixins.Mixins;

using System.Collections.Generic;

 

//Extend our object with the mixin methods

using Mixins.Mixins.Auditable;

 

namespace Mixins

{

    public class DataRecord : IAuditable

    {

        private List<string> auditors;

 

        public DataRecord()

        {

            auditors = new List<string>();

        }

 

        public string Name

        {

            get;

            set;

        }

 

        public string Email

        {

            get;

            set;

        }

 

 

        #region IAuditable Members

 

        public IList<string> Auditors

        {

            get { return auditors; }

        }

 

        #endregion

    }

}

 

Now to test it I used this console app:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

// Extend our object with the mixin methods

using Mixins.Mixins.Auditable;

 

namespace Mixins

{

    class Program

    {

        static void Main(string[] args)

        {

            DataRecord record = new DataRecord();

            record.AddAuditor(“Ivan Porto Carrero”);

            record.AddAuditor(“Kirk Jackson”);

 

            Console.WriteLine(“The current auditors are: “);

            record.Auditors.ToList().ForEach(auditor => Console.WriteLine(auditor));

 

            Console.WriteLine();

 

            record.RemoveAuditor(“Kirk Jackson”);

            Console.WriteLine(“The current auditors are (after removal): “);

            record.Auditors.ToList().ForEach(auditor => Console.WriteLine(auditor));

 

        }

    }

}

The second way I had in mind doesn’t provide everything I get from this first way and was by extending a base class. I’ll drop that explanation and just go for the conclusion.

 

As I said before the only thing that doesn’t make extension methods to be complete mixins is the fact that you can’t actually mix it into a class, you can get really close but not all the way there. Now that isn’t such a huge problem, it gives you a bit more granular control. Another thought I have about this is, extension methods don’t have access to the private variables of your class only to the public interface of your class. That is also a limitation that proper mixins don’t have.

 

What do you think ?

 

del.icio.us Tags: ,,

19NovRuby-In-Steel is giving intellisense for ironruby in VS

The guys over at Sapphire Steel have been doing great work with the current implementation of IronRuby

Today they put a blog post online showing you how far they got for implementing intellisense.

 

I’m pretty happy with the progress ironruby is making there are a whole bunch of people contributing. The guys from the Mono team have been following the development as well to make sure you can run ironruby on MS .NET or on Mono which makes it a really good alternative to the C-ruby implementation as soon as Ironruby has matured enough.

If you have some free time and are interested in helping some really smart people implementing a programming language I suggest you check out the ironruby.net website and join the mailinglist on rubyforge.

03NovBoot camp session

I just finished my session at Boot Camp. A code camp organised on the south island in Christchurch.

I’d like to thank everybody for coming to listen to me, and I’d like to thank Ivan Towlson for his help on getting me started with wpf and for elaborating on the section mixins during my talk.

As promised I’ve put my slides and demos online.

Powerpoint 2003 version
Powerpoint 2007 version

Demo

Hope to see you again soon!

del.icio.us tags: , ,

Recent Flickrs

    Blogroll

    Recent Listening

    Scrobbler