Hanalei, Hawaii 9/2/2010
438 Posts and Counting

MVC Storefront: Dependency Injection

Tuesday, June 03, 2008 -

This is a long one! I sat with Jeremy Miller (of StructureMap/CodeBetter fame) for over 2 hours, talking about DI, Singletons, kids, and other things and what came of it is, in my opinion, the best webcast in this series.

Steal This Webcast
I got this comment on my blog the other day from Ryan:

...release the stuff that is unedited. It might sound crazy, but when you said you had 2 hours of hashing [out] Structure Map with Jeremy Miller, I thought "wow, that would have been two hours I would pay for." So let us go through the "a ha!" moments with you and release the unedited stuff.

So you got it! The only thing I did to this session was to edit out the mumbling, grumbling, and occasional gaff from yours truly (and some height jokes Jeremy kept throwing towards Bellware). I tried to make this as seamless development experience as possible - please do let me know what you think.

Your Feedback Is Critical, More Than Ever
So far the feedback has been great, and it's allowed me some pretty good leeway with what we're doing here. If you're hesitant to leave a comment here, please send me an email - I really do want to know (good or bad) what you think of this series.

Yes, I Love MVC Contrib Too.
I know that MVC Contrib has some nice code surrounding StructureMap (and other DI components) but I felt it was better to implement this from scratch and have Jeremy walk me through it so people who don't know DI nor how it can work with MVC can benefit.

Also, I should mention that the way we've set it up, you're absolutely free to implement your own DI as needed with minimal changes.

Watch The Webcast Here (59 Minutes, 82 Megabytes).

Grab The Code Here.

 

Technorati Tags:

Related


Gravatar
[mRg] - Tuesday, June 03, 2008 -

Good work Rob in putting the whole thing up, sometimes more is actually more :) Also at 1h and 82 minutes .. these are the 90 minute hours my boss keep trying to make me work or is that the secret how you microsoft guys get so much done :P

Gravatar
David - Tuesday, June 03, 2008 -

Hi Rob,

I tried emailing this to avoid cluttering your blog with useless comments, but MS's mail servers either think compliments are spam or won't accept emails from Gmail :-\

Undeterred, I wanted to send a quick thanks to you (and Jeremy) for this. Best... screen cast... ever. After watching this I finally understand what DI offers other than *just* testability. Thanks a tonne, and keep up the great work!

Gravatar
West - Tuesday, June 03, 2008 -

Struggling to get it downloaded. Firefox, IE and wget are failing at downloading it :-( Any news on when it will be up on asp.net?

Keep up the good work Rob!

Cheers,

W

Gravatar
Ryan - Tuesday, June 03, 2008 -

Thank you so much Rob for putting this out there unedited. I have been waiting for this, I have always thought that there are two type of screen casts:

1. The screen cast from an amateur trying his best to seem like a professional producer (and some pull it off).

2. The screen cast that just shows the process, the thoughts, every mistype, error, and idiosyncrasy of the process.

Personally, I like the second screen cast, because in the end, we are all human, and we all care about the process because I think we all right bad code and want to feel like others do it as well.

Gravatar
Ken - Tuesday, June 03, 2008 -

Rob this is a great set of videos. I wanted to see some other examples of MVC. For example what if you wanted to implement a "compare" feature in this store, which would allow comparing two or more products. How would something like that be implemented? All the product codes would have to passed in via the routing URL. Should we be concerned of the if the routing URL's get too long?

Gravatar
Mike D - Tuesday, June 03, 2008 -

Rob and Jeremy,

Fantastic Work!

I got a little lost at the end, however with a code download and 5 minutes of reveiew I got it.

Best DI and IoC info I have seen, please go deeper.

Gravatar
Alex Simkin - Tuesday, June 03, 2008 -

@Rob "...some height jokes Jeremy kept throwing towards Bellware..."

What height jokes?

Gravatar
Mark Heath - Tuesday, June 03, 2008 -

thanks Rob, it is really helpful watching this kind of thing be added into an existing app rather than there from the start. I am also glad to see DI frameworks moving away from XML config files.

It would have been nice to see what this meant for the unit tests. Were you going to construct objects manually, or use StructureMap to provide the fake test repositories? I'll download the code and see whether there were any changes

Gravatar
David Alpert - Tuesday, June 03, 2008 -

Great 'cast, Rob. I really enjoyed watching your process as it unfolded, typos and all; found it easier to follow than a quick tour de force through completed code. Also, humour makes it go down easier.

Very good intro to DI.

The one part i was missing, similar to Mark's feedback, was how your StructureMap architecture impacts your unit tests and, specifically, how to tell StructureMap to use a different registry when running under your test harness. Or have i just answered my own question?

Perhaps it's not so much the "how" - i think i can figure that out from your screencast - but the "where", as in where do i initialize and configure StructureMap when running under test?

Does the unit-test-specific registry or StructureMap bootstrapper live in each Unit Test Fixture constructor?

Gravatar
Jeremy D. Miller - Tuesday, June 03, 2008 -

@David,

Try NOT to allow StructureMap to affect your unit tests. If you use Dependency Injection for your dependencies, the container doesn't need to exist in unit tests at all. Regardless of your choice of container, you shouldn't need or want the container involved in unit testing very often.

Assuming that you ignored the sentence above, or you're in a case where you have a hard dependency on StructureMap in your code, you've got a couple more options:

// One service at a time

StubOfSomeService stub = new StubOfSomeService();

ObjectFactory.Inject<ISomeService>(stub);

or use a "Profile" to configure multiple modes of operation:

ObjectFactory.Profile = "Stubbed";

I swear that I'll get this documented soon.

Gravatar
Rickey - Tuesday, June 03, 2008 -

Outstanding Rob! Keep showing us the full path you took to get where you are. The journey is invaluable. I am one of those 40 year old guys that have a lot of "old style" built in and this really shows the light. I hope to give the full series to my team once you have a versioned product.

Gravatar
Meisinger - Tuesday, June 03, 2008 -

Great piece.

You and Jeremy did a great job and I can't think of a better "walk through" that have covered DI so well.

One question (or a comment rather) about the LINQ to SQL object (or DB object)

I thought that this should only be "alive" for a single unit of work. By sticking the DB in the HttpContext or CallContext is this object not sitting around waiting to be used?

I would think that you would want to set this up on a per call basis... right?

I guess that is one great thing about StructureMap is that you can control that :)

Gravatar
Miha Valencic - Tuesday, June 03, 2008 -

@Jeremy: which version of StructureMap are you two using in this screencast? It seems different than 2.0 release and I could not find any details of 2.5 on the StructureMap website (sf.net).

An excellent screencast and intro to DI. Thanks!

Gravatar
Jero - Tuesday, June 03, 2008 -

Great stuff Rob. Another winner. I haven't had a chance to do anything with DI to date so a practical intro to it like this is invaluable.

One thing I didn't understand was how the singleton SQLRepository relates to the per-HttpContext DB (database context).

It seems to me that when StructureMap creates the singleton SQLRepository it also has to create a DB and plugs it in to the SQLRepository.

It doesn't matter if StructureMap creates another DB for different sessions, the SQLRepository will still use the first DB that was bound to it? Is that correct? or am I missing something?

Gravatar
Paul - Wednesday, June 04, 2008 -

@Miha: I had trouble getting the Bootstrapper set up in my project because the ForRequestedType method was not known. To solve the problem I have downloaded Rob's sample code from CodePlex and that has a copy of StructrureMap.dll V2.5 in it. Copy that dll in to my project, remove and re-add reference and everything seems to be OK now.

Gravatar
Yitzchok - Wednesday, June 04, 2008 -

This Webcast was Fantastic++

@Miha

You can download the source from structuremap.svn.sourceforge.net/.../trunk that should be v2.5

Gravatar
Robert G - Wednesday, June 04, 2008 -

Rob, Jeremy. That was excellent. The .CacheBy stuff is great - didn't know about that. Sounds almost like the old COM+ object caching, but without all the ugliness.

I have a couple of points/questions.

#1. Given that the point of DI is to be able to use different implementations interchangeably, can you spend a bit of time showing us how to swap your implementation for another one?

#2. Why is XML configuration bad? Is that not the fastest/cleanest way to tell the DI framework which implementation to use, without having to recompile the code?

#3. Finally, some hair splitting. You mentioned in the beginning that DI could be used to swap out Log4Net for EnterpriseLib, or SqlDataReader for SubSonic. I don't think that would be very easy or practical. SqlDataReader approach and SubSonic do not inherit from the same interface or base class, thus you'd be writing wrapper classes all day to make them respond to the same set of commands.

Keep up the excellent work.

Gravatar
Rob Conery - Wednesday, June 04, 2008 -

Hi Robert:

>>>Sounds almost like the old COM+ object caching<<<

Ummm...

RE #1 - implementations of the DI? Or of the bits? Not sure of the question - if the latter you can simply change "TheDefaultIs<>"...

RE #2 - No, it's not. Compiled code is usually faster in every case - moreover one of the main issues with XML is that it's not supposed to be human-readable, but when you use it for configs, that's what you make it. Some don't mind, others (like me) absolutely hate it. An ini does the same thing and it's much easier to read.

In terms of recompilation - not sure that's much of an issue, but it's a fair point.

>>>You mentioned in the beginning that DI could be used to swap out Log4Net for EnterpriseLib<<<

Yep

>>>SqlDataReader approach and SubSonic do not inherit from the same interface or base class<<<

If your repository implements these (like I'm doing with LinqToSql) then you've abstracted it. If you're using the Repository Pattern - this is all the more apparent. In essence you "writing wrapper classes all day" should be what you're doing anyway :).

Your point is taken though - my main thought was that "1) write your code more modular and 2) use DI to manage it".

Hope that makes sense.

Gravatar
Miha Valencic - Wednesday, June 04, 2008 -

@Paul, Yitzchok: thanks. I have the DLL Rob has in the sources, but was seeking also _documentation_ on 2.5 features (like AddInstances and so on). Thanks for the pointers to SVN.

Again, an excellent screencast -- I'd love to see some more advanced StructureMap from Jeremy D. Miller, if possible. Jermey, that's a hint. :)

Thanks,

Miha.

Gravatar
Firefly - Wednesday, June 04, 2008 -

Here is my take on DI, first it's all about architecture. I am a big architecture guy so I look at the big picture here. Surely performance matter but if the application is architect right a few extra millisecond won't be the bottleneck anyway.

There is going to be dependency somewhere in your application. You can't get rid of it :). Truth is DI abstract it to the configuration level where it should be.

Do what work for you. If you can read and write XML code like it is your native language then more power to you. For the rest of us we need some strong type configuration file with IntelliSense support :)

@Rob, Again another great job Rob. There are many way to architect an application so I won't get into that. I really enjoy the aha moment and the thought process. This is the part that make your screencast invaluable so please keep it up. That Cache context is interesting. So if I got it right it define the lifetime of that cache right? Few free to correct me if I am wrong here.

Gravatar
Allan N - Wednesday, June 04, 2008 -

Dude(s). Great job. Far superior to reading a book/article with finished hello world type examples. Listening and watching the question and answer process is fabulous. Best intro to dependency injection I've seen. My teams will be eating up a bunch of your bandwidth watching this. Hope MS is footing the bill. :)

Gravatar
Jason Stangroome - Wednesday, June 04, 2008 -

Hi Rob,

You create a StructureMapControllerFactory and tell Mvc to use it via ControllerBuilder.Current.SetControllerFactory. This is nice.

However, for your UserSessionController you copy-and-paste-reimplement Html.RenderComponent as RenderMappedComponent to use StructureMap instead of Activator.CreateInstance. Can we expect to see Mvc support the idea of a ComponentBuilder.Current.SetComponentFactory method to achieve the same as above with much cleaner code?

Regards,

Gravatar
Jamie - Wednesday, June 04, 2008 -

I second Jero's question. I was a bit confused about having an instance of a request-scoped object attached to a singleton. Not sure how it knows (or even if it knows) to replace that object when the request context changes.

Gravatar
Rob Conery - Wednesday, June 04, 2008 -

@Jason - yes I'm hoping to be able to add some love to RenderComponent - we'll see what happens there.

@Jamie/Jero - very good question. May have to remove the Singleton bits for this reason (which is not a big deal really).

Gravatar
Erik - Wednesday, June 04, 2008 -

Rob,

I have a couple Questions about the Structure/Heiarchy of your App.

1. If the Idea is that you can swap out the Data Access Layer Later, then doesn't just about everything except the Repositories Belong in The Service Layer (Or some higher layer)? Then Make your Data Access Layer Reference your Service Layer Instead of the other way around? That way you don't have to implement your Smart Cart in Every Single Data Access Layer you plug in? Your Data Access Layer just provides Implementations of your Repository Interfaces Defined in your service layer (or some higher layer).

2. Would there be any benefit to implementing a standard Pattern for the Repository Interfaces? Something like

public interface IQuerytory<T>

{

void Create (IEnumerable<T> ItemsNew );

void Create (T Itemnew);

IQueryable<T> Get();

void Save (T ItemToSave);

void Delete (T ItemToDelete);

}

Just wondering what you see as the up and downside for something like this. I guess one downside is now your Icatalogrepository def might look like this

public interface ICatalogRepository : IQuerytory<Categories>, IQuerytory<Products> ,IQuerytory<ProductReview> , IQuerytory<ProductImages>,IQuerytory<ProductCategoryMap>,

IQuerytory<ProductRelatedMap>

{}

and you will have a lot of not implemented exceptions until you need management/crud on the other types.

Thanks,

Erik

Gravatar
Stephen - Wednesday, June 04, 2008 -

I'd like to see maybe a bit more depth, this seemed more of a 'no idea what di is?' sorta thing..

Also, I'd liked to of seen what features you required for this project, that unity couldn't do..

Its a major nitpick for structuremap (I've never used it) but I didn't like the lowercase configure(..) method override ;)

Case is king!

Gravatar
Rob Conery - Wednesday, June 04, 2008 -

@Erik - I'm sort of confused RE moving of layers around - more detail?

@Stephen - >>>I'd like to see maybe a bit more depth, this seemed more of a 'no idea what di is?' sorta thing..<<<

Well, I went from having no DI and a vague notion of what it is to a full implementation of it, with a complete explanation of it within an hour. What else, exactly, are you looking for here?

>>>Also, I'd liked to of seen what features you required for this project, that unity couldn't do..<<<

The hard part about that is that you get into comparisons and I didn't want to do that - but I'm sure if you head over the alt.net discussion group on Yahoo you'll find out :).

>>>Its a major nitpick for structuremap (I've never used it) but I didn't like the lowercase configure(..) method override ;)<<<

Yah, that's a major nitpick :). Case is king in the land of C...

Gravatar
Erik - Wednesday, June 04, 2008 -

Rob

Regarding The Layers,

I Guess I was Picturing The Data Access Layers doing nothing more than implementing your IRepository Interfaces that you Define in you Business/Service (or some other) Layer. All Your Classes ShoppingCart, ShoppingCartItem, etc. and Interfaces IShoppingCartRepository, IUserRepository

would be defined in a layer that is persistance technology ignorant (The Business Layer or some other layer). Then if you want to change your data access layer all you have to do is replace your DataAccess Layer with a different Data Access layer that does nothing more than Implements your IRepository Interfaces.

Thats what I was thinking anyway,

Erik

Gravatar
Don M - Thursday, June 05, 2008 -

Hi Rob,

This series has been great. I have a couple ideas that I think would be interesting.

I'm still getting a little confused by your layers and the different classes involved. I think it would be nice if you had a quick little overview of all the classes, assemblies and layers involved. Maybe even a handy diagram would be nice.

Second: I think it would be interesting if you looked at the code coverage of your unit tests.

Is there anything that is annoying your about the current design? Any bad code smells? A screen cast of just refactoring might be interesting. By the way, that class name of 'DB' is driving me crazy.

I think I am in the minority, but I would just like to put in a vote for the more edited screen casts.

Thanks,

Don

Gravatar
Nagarajan - Friday, June 06, 2008 -

Hi Rob,

What software you are using for Recording and remote Pair Programming?

Regards,

Nagarajan.

Gravatar
Paul Linton - Friday, June 06, 2008 -

Hi Rob,

This series is the best thing since sliced bread! The screencast on DI really "turned the light on" for me. Many thanks.

I would vote for the @Don M request concerning some overview comments. I was thinking that some comments on each of the major namespaces would be great. Eg. For Commerce.Mvc.Services could be something like

// Provides persistence services for Commerce.Mvc.Data objects

// All public classes return objects from Commerce.Mvc.Data (or collections thereof)

// Interacts with backing store via IXXXRepository interfaces.

I am also voting for a refactoring episode. When implementing DI on my own project I started with exactly the same approach as you and Jeremy demonstrated. I quickly refactored to have a XXXRegistry class in each project. There is now no Registry class at all in my equivalent of Commerce.MVC.Web. My version of ConfigureStructureMap takes an enum (Repositories) as a parameter. The enum is either SQL or Test. Depending on the value it adds the SQLRepositoryRegistry or TestRepositoryRegistry, it always adds the ServicesRegistry.

Now, in Global.asax.cs I call Bootstrapper.ConfigureStructureMap(Repositories.SQL);

but in my test classes I call Bootstrapper.ConfigureStructureMap(Repositories.Test);

from the [TestInitialize] method. Instead of NEWing a controller in a test I call

ObjectFactory.GetInstance<myController>() as myController;

Keep up the good work.

Gravatar
Mike Moore - Friday, June 06, 2008 -

What codec is this file using? I don't get a video display in Windows Media Player 10 on XP.

Gravatar
Eric - Saturday, June 07, 2008 -

Rob, you are forgetting to do a complete run of all your unit test before check-in the source (or posting it) which is need in TDD. If you run the test UserService_Can_Register_User(), it fails.

Gravatar
IKKI - Monday, June 09, 2008 -

Hi Rob,

Afterdownloading the storefront of Ver 7608,I restore the database on Sql Server 2005 Express on my localhost,the I restore the commerce.mvc db.I edited the connectionstring in the webconfig file ,but I still can't connect to the db.

I have searched this Problem on the website ,and I saw some one have the same error with me on the asp.net forum, the I did as some one said to Enable remote connections and Browser service ,but it doesn't work :(

Have any one met this problem and solve it ?

Thanks a lot!

Gravatar
Jimit Ndiaye - Monday, June 09, 2008 -

This series just keeps getting better and better. Keep it up Rob.

Question: Could you elaborate on the deficiencies you discovered in Unity that made you go with Structuremap instead? Why StructureMap vs other IoC containers like Spring.NET and Castle? I know that's a bit of a religious issue, but I'm asking for your own personal experiences and views on the subject rather than a "this ones's better than that one. Period!" kinda thing. What works for you mayn't necessarily work for me. But since the whole spirit of this series seems to be focussed around the thought processes leading to problem-solving decisions, I'm hoping you'll be willing to share.

Personally, I'm trying to decide whether to go with Unity or with Spring.Net with which I at least have some passing familiarity.

Gravatar
Rob Conery - Monday, June 09, 2008 -

@IKKI - I don't think I follow you. You restored the DB twice? If you're having connection string issues I might suggest the ASP.NET forums - there's some really good advice there.

@Jimit (and others): I had to pick one, unfortunately, and I'm in the undesirable position here of having to state "why". I hate to do it but I'm going to sidestep that because no matter what I say it will look like I'm saying one is better than the other.

It simply came down to what people are familiar with, and what's been around longer. As for technical limitations I'm going to gracefully claim the 5th :).

Gravatar
Joel - Tuesday, June 10, 2008 -

Hey Rob what's up next for the MVC-Storefront? When and what are are we going to see part 14.

Thanks for your work, this has been very educational!

Gravatar
Joel - Tuesday, June 10, 2008 -

Nevermind rob, I see you posted part 14. Thanks!!

Gravatar
hj - Sunday, June 15, 2008 -

>> It simply came down to what people are familiar with, and what's been around longer. <<

Good enough... but when choosing between Linq2Sql vs. NHibernate you didn't apply the above rule.

Gravatar
Wes - Monday, June 16, 2008 -

What screenrecorder/voip/desktop sharing software are you using to make your screencasts?

Gravatar
Rob Conery - Tuesday, June 17, 2008 -

@hj: NHib didn't have IQueryable when I created the app :). I will make a nice NHib Repo as well as SubSonic when all is said and done... no worries there!

I'm using Camtasia to capture the screencast and my audio. When I do a pair session I use SharedView (a new, free MS collab thinger).

I make the person I'm talking to record their voice using SoundRecorder (Accessories tool). This creates a WAV file that I then overlay on the video.

I have to edit stuff some - Vista has a weird sound lag which puts my stuff out of synch...