Tuesday, September 02, 2008
So I received a question recently via email from someone following the container tutorials, which read like so:

Read through you tutorials and great work!

Have a question for you though, that I can't seem to find an answer in google. On decorators. How do you provide state dependencies that are unknown at configuration time?

So I ask for an IRepository and I have configuration setup to wrap it in a IValidator and maybe an ISecurity. However, ISecurity has a dependency on a runtime determined role (say from multiple sources, possibly including a state value on IWidget) and the user id (for argument sake isn't available on the context).

I want to call T Get() on IRepository. How do you get it all setup?

Many Thanks!

As I see it there were two distinct questions asked:
  • How to wire up generic decorator chains (though I suspect they already know how to do that).
  • How to pass in parameters/dependencies at run time.
So Let's look at doing these two things, I'm going to steer clear of xml configuration because that's so 2 years ago ;o)

First off let's create the repository interface:

public interface IRepository<T>

    where T : class, new()

{

    T Get(int id);

}


Then the root implementation (we can't keep chaining forever, at some point we have to hit an implementation which can actually return the results we want).

public class StubRepository<T> : IRepository<T>

    where T : class, new()

{

    public T Get(int id)

    {

        return new T();

    }

}


And finally a decorator for "security"...

public class SecurityDecorator<T> : IRepository<T>

    where T : class, new()

{

    private readonly IRepository<T> _inner;

 

    public SecurityDecorator(IRepository<T> inner)

    {

        _inner = inner;

    }

 

    public T Get(int id)

    {

        return _inner.Get(id);

    }

}


better have a widget too... for good measure:

public class Widget

{

}


At this point we can write a test - I'm an xUnit fanboy these days (typing less == good) so let's take a look:

public class ContainerTests

{

    private readonly IWindsorContainer container;

 

    public ContainerTests()

    {

        container = new WindsorContainer();

        container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (SecurityDecorator<>)));

        container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (StubRepository<>)));

    }

 

    [Fact]

    public void GetRepository_ForWidget_ReturnsSecurityDecoratorOfTypeWidget()

    {

        var widgetRepository = container.Resolve<IRepository<Widget>>();

        Assert.True(widgetRepository is SecurityDecorator<Widget>);

    }

}


Notice we register the components in top to bottom order i.e. decorators first, followed by the underlying implementation, for something as simple as this you don't really need to use the fluent interface for registering components - but I find it's good to be consistent.

Now, the second question is about injecting "context" - this is really just another way of saying "some of my dependencies can't be known until just before I attempt to resolve the service" ... no problem... so let's make some modifications:

First off I'm going to make a user...

public interface IUser

{

}


Next thing I'm going to do is add a User property to my security context (ugh, this seems like a better job for some kind of "ICurrentUserHolder" service, but that's beside the point).

public class SecurityDecorator<T> : IRepository<T>

    where T : class, new()

{

    private readonly IRepository<T> _inner;

 

    public SecurityDecorator(IRepository<T> inner)

    {

        _inner = inner;

    }

 

    public T Get(int id)

    {

        return _inner.Get(id);

    }

 

    public IUser User { get; set; } // <-- the current user

}


Now let's add another test to ensure everything is being injected properly...

public class ContainerTests

{

    private readonly IWindsorContainer container;

    private readonly IUser user = MockRepository.GenerateStub<IUser>();

 

    public ContainerTests()

    {

        container = new WindsorContainer();

        container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (SecurityDecorator<>)));

        container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (StubRepository<>)));           

    }

 

    [Fact]

    public void GetRepository_ForWidget_ReturnsSecurityDecoratorOfTypeWidget()

    {

        var widgetRepository = container.Resolve<IRepository<Widget>>();

        Assert.True(widgetRepository is SecurityDecorator<Widget>);

    }

 

    [Fact]

    public void GetRepository_ForWidget_WhenSupplyingUserInjectsUserIntoSecurityRepository()

    {

        var securityDecoratorForWidget = (SecurityDecorator<Widget>) container.Resolve<IRepository<Widget>>(new {User = user});

        Assert.Same(user, securityDecoratorForWidget.User);

    }

}


Notice the additional argument of an anonymous class being passed to Resolve, this allows us to provide additional parameter dependencies (in this case a stub user is being supplied).

Finally what about passing in some roles... this is much of the same, but I'll include it for completeness... so we add a role interface:

public interface IRole

{

    bool IsMember(IUser user);

}


Then we'll add a collection of roles to the decorator and provide a rather primitive check against the roles when attempting to get a widget instance:

    public class SecurityDecorator<T> : IRepository<T>

        where T : class, new()

    {

        private readonly IRepository<T> _inner;

 

        public SecurityDecorator(IRepository<T> inner)

        {

            _inner = inner;

        }

 

        public T Get(int id)

        {

            CheckPermission();

            return _inner.Get(id);

        }

 

        public IUser User { get; set; }

 

        public IList<IRole> Roles { get; set; } // <-- the roles to check

 

        private void CheckPermission()

        {

            if (User == null || Roles == null) return;

 

            if (Roles.Any(role => !role.IsMember(User)))

            {

                throw new Exception("You do not have permission");

            }

        }

    }


And finally we update our test with checks for both passing and failing on the permissions check.

public class ContainerTests

{

    private readonly IWindsorContainer container;

    private readonly IUser user = MockRepository.GenerateStub<IUser>();

    private readonly IRole failingRole = MockRepository.GenerateStub<IRole>();

    private readonly IRole passingRole = MockRepository.GenerateStub<IRole>();

 

    public ContainerTests()

    {

        container = new WindsorContainer();

        container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (SecurityDecorator<>)));

        container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (StubRepository<>)));

        passingRole.Stub(stub => stub.IsMember(user)).Return(true);

    }

 

    [Fact]

    public void GetRepository_ForWidget_ReturnsSecurityDecoratorOfTypeWidget()

    {

        var widgetRepository = container.Resolve<IRepository<Widget>>();

        Assert.True(widgetRepository is SecurityDecorator<Widget>);

    }

 

    [Fact]

    public void GetRepository_ForWidget_WhenSupplyingUserInjectsUserIntoSecurityRepository()

    {

        var securityDecoratorForWidget = (SecurityDecorator<Widget>) container.Resolve<IRepository<Widget>>(new {User = user});

        Assert.Same(user, securityDecoratorForWidget.User);

    }

 

    [Fact]

    public void Get_ForWidgetWhenUserMatchesAllRoles_ReturnsWidget()

    {

        var securityDecoratorForWidget =

            (SecurityDecorator<Widget>) container.Resolve<IRepository<Widget>>(new {User = user, Roles = new List<IRole> {passingRole}});

         Assert.NotNull(securityDecoratorForWidget.Get(1));

    }

 

    [Fact]

    public void Get_ForWidgetWhenUserDoesNotMatchAllRoles_ThrowsException()

    {

        var securityDecoratorForWidget =

            (SecurityDecorator<Widget>) container.Resolve<IRepository<Widget>>(new {User = user, Roles = new List<IRole> {passingRole, failingRole}});

         var exception = Assert.Throws<Exception>(() => securityDecoratorForWidget.Get(1));

        Assert.Equal("You do not have permission", exception.Message);

    }

}


And that's it... could not be simpler.


posted @ Tuesday, September 02, 2008 5:11:06 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
Hi All,

I'm afraid I'm going to have to postpone the Architecture chat until next week, due to other commitments on Thursday.

So it's now rescheduled for next Thursday - 11th September - if anyone has any topics, or saw anything cool at code camp or teched this week then leave a comment on this post and I'll add to the list of topics for next week.




posted @ Tuesday, September 02, 2008 3:45:13 AM (New Zealand Standard Time, UTC+12:00)    Comments [2] | Trackback |
 Wednesday, August 27, 2008
It's been a back and forth discussion on the OAuth list for a while now - and with some people (zealots? ;o) having ideas they weren't even willing to contribute to the OAuth group until the IPR was sorted I'm glad to finally see it's been completed, this should hopefully help to improve the longevity and adoption of the standard by some who have been fence sitting.

So what's happened?

Well all all parties involved in building the original spec have signed an agreement of non-assertion, so now OAuth can be safely implemented anywhere without concern about lawsuits related to the IP in the spec.

OAuth is a pretty elementary standard in it's version 1 state - so in some ways it was inevitable that this would happen (or at least I thought so) - there wasn't much to gain by any of the contributors blocking the progress of it becoming an open standard - but it's involved a lot of work to get it there by all accounts, so full credit goes to all involved!

For a detailed writeup check out the post from Eran Hammer-Lahav or the post on Read/write web.

Conspicuous by it's absence is Microsoft, but for no other reason than they did not contribute to the OAuth standard - and so didn't have to sign - but of course LiveId does tackle delegated authentication - so in some ways they have a competing platform for handling delegation, presumably because OAuth doesn't provide a rich enough set of features at this stage to handle some of the more complex scenarios around scalability, signing message bodies etc. - though I'm just hazarding a guess, LiveId was presented at the OAuth summit earlier this year.

 |  | 
posted @ Wednesday, August 27, 2008 1:24:58 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Tuesday, August 19, 2008
Only just catching up on my blog reading from the last week or so this evening - so only just came across this, but its pretty cool! - it's like deep zoom for power point - the project is pptPlex from the OfficeLabs team.

I wonder if anyone at teched / codecamp in New Zealand this year will be using it... I normally do a mind map when I'm structuring a presentation, proposal for a client/whatever - be great to actually present the mind map itself then zoom in to show the details...mmm

posted @ Tuesday, August 19, 2008 8:41:15 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Monday, August 18, 2008
Hi all, there's an Architecture chat this Thursday - 21st August @ 11:30am onwards.

Some things that I've caught my eye since last time:
  • .Net 3.5 SP1 and VS2008 RTM are here
  • VS2K8SP1 and SQL2K8 installs are a big mixed bag, some people no problem, other tearing hair out!
  • And so are the war stories such as regressions and critical changes - doh!
  • Visibility and trouble with non-developers being unable to quantify the quality of developer outputs - sparked off by this post by Casey.
  • Resharper 4.01 RC1 is out.
  • ASP.NET MVC now and in the future (i.e. where it's going, and perhaps a discussion on future of monorail vs. MVC and Monorail 2??).
  • Security practices on MVC, WCF etc.
  • Redmine - an interesting (and nicer) alternative to Trac - wonder if there's an easy transition path for existing Trac sites?
Edit: updated this list with some suggestions from others.

If anyone has any topic suggestions - just make a post on this entry, or send me an email / IM message.

Details of previous posts and directions etc. can be found here on the wiki.

posted @ Monday, August 18, 2008 10:47:10 AM (New Zealand Standard Time, UTC+12:00)    Comments [5] | Trackback |
Here's the write-up for Architecture Chat #32 (from Thursday 7th August 2008) ... some of the things we discussed:
  • Jabl / Jass  (Javascript abstraction language) - we discussed this approach of writing languages that transform into another language - the tradeoffs of debug experience vs. productivity etc.
  • Debug experiences in DSL's and in particular the lack of support in these language rewriting/transformation projects.
  • The magic bullet language i.e. two-way debugging experience, language independent refactoring support, modular/pluggable language support (sorta like Boo).
  • Code camp at the end of this month.
  • Self explaining code / blaming code (i.e. code that can explain the decisions it makes in english, or at least identify the blame (i.e. steps) that lead to the result it selected.  Though we didn't bring it up, I quite like the way Rhino Security does this.
  • xUnit thoughts after a month of using it on a commercial project.
  • Ice ZeroC - WCF alternative?
  • Sql Server partitioned tables, and the simpler query plans / improvements in 2008.
See the wiki for write up's of previous chats, thanks to all those who attended.

posted @ Monday, August 18, 2008 6:22:54 AM (New Zealand Standard Time, UTC+12:00)    Comments [4] | Trackback |
 Friday, August 15, 2008
Yesterday afternoon I presented a quick 20 minute presentation to the Enterprise Architect user group - it was an interesting opportunity to talk with both an Enterprise Architect lead developer and analysts/BA's etc. who are using Enterprise Architect on a daily basis - there's nothing quite like doing something and then even more so presenting on what you've done to really firm up some conclusions / ideas around it (and as is often the case with me, spark 20 ideas for new products I could build to make it better/smarter).

For anyone who's interested here's the slide deck I presented - and also some links to things that were discussed:
Thanks to catch for hosting the group and providing the video conferencing facilities to link Auckland / Wellington (small tip, if you are presenting to two groups be sure to sit at the end of the table looking towards the camera, or your spend your whole time ping-ponging your head towards one group and the other ;) - and also thanks to everyone who came along and listened.

Also of interest was the discussion after the presentation around providing a number of example/sample MDA transformations through Sparx Systems New Zealand site - which should mean that before the end of the year you will be seeing both guidance and examples on developing MDA transformations targeting NHibernate, NHibernate search, ActiveRecord, Monorail and RhinoSecurity starting to emerge (what I tend to loosely call the "Castle stack" for want of a better term.) - which I'll post about it as it starts to happen.

posted @ Friday, August 15, 2008 2:19:21 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Wednesday, August 06, 2008
There's a few things going on in Auckland over the next month or so, just to summarize if you haven't been paying attention :)
So plenty of things going on!

I would suggest signing up for the code camp sooner rather then later if you don't want to miss out - also if you know of any other events that I've left off this list, drop me a comment and I'll add them to it.

posted @ Wednesday, August 06, 2008 7:23:04 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
Architecture chat tomorrow at 11:30am... I'm going to leave it fairly open for topics so all come along with something interesting to say ;o) ... or leave a comment on this post if you'd like to give me or anyone else a heads up on what you'd like to talk about.

Some things I'd personally be interested:
  • Auckland recruitment environment.
  • Must read books for both new and seasoned developers alike.
  • Implementing code that can explain itself - for example security mechanisms able to explain (in English) why you do or do not have access, DSL's that give meaningful reasons for the decisions made, and how to flow those messages through the context of operations etc.
All are welcome - drop me an email if you're a new comer and we'll keep an eye out for you!

Information regarding the location and previous chat write-ups can be found here.

posted @ Wednesday, August 06, 2008 3:22:42 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | Trackback |
 Monday, July 28, 2008
This is a writeup for the last 2 architecture chats - both were pretty free-form, with little of the topics mentioned in the posts getting much discussion as we all had own things to talk about!

As a brief summary:

Plenty of talk about Lightweight code-gen and run-time vs. post-compile IL weaving, debugging integration etc. Hard to cover all the little facets that were explorer - but it's been interesting - it seems like more developers are starting to dabble with IL.

We talked about approaches for introducing cross-cutting behavior such as versioning and history to your data access and approaches for flowing metadata from your domain model up to the UI (including searching, validation etc.) and ways to index, query and flow the information across boundaries in the application.

As a tangent to this I've been talking about how I've been using MDA/MDG to drive the domain model generation (including things like validation, search annotations etc.).

We talked about the recent S3 outages and approaches for placing resources on both European and US data centers simultaneously, and possible ways to mitigate the double-upload bandwidth costs.

Discussions (sparked originally from a email discussion on the NZ dotnet user group) around hiding the implementation details of your ORM from the rest of your application - and the practicalities of how deep this needs to go, using linq through boundaries etc.

Discussions around injecting logic into generated source code, both in asp.net/winforms generated code as well as possible ways to intercept custom tool generation so you could manipulate the output.

Spartan programming got a mention - Peter felt it aligned with alot of his current coding style.

Embedding NHaml as a view engine in non-MVC applications, and the general experience with different view engines including Brail, ASP.NET MVC's default ASPX View engine etc.  (Including the error reporting and debugging experience) - We also talked briefly about the Spark view engine, which looks to be like it could be quite palatable to non developers while still offering a useful syntax for developers.

If anyone has any topic suggestions for next weeks chat just leave a comment on this post or flick me an email.

posted @ Monday, July 28, 2008 6:38:09 AM (New Zealand Standard Time, UTC+12:00)    Comments [5] | Trackback |
Search
FeedCount

Tags...
Who am I?
Alex Henderson
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited

"Self Confessed Coding Junky for 15 years"
View Alex Henderson's profile on LinkedIn
 
Mobile: +64-21-402-969
Email: bittercoder 'at' gmail 'dot' com
MSN: bittercoder_nz@hotmail
Skype: alex.devdefined
Navigation