Jeffrey Palermo (.com)

Sponsors

The Lounge

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
SmartBag for ASP.NET MVC, take two

Earlier, I announced the advent of the SmartBag for the ASP.NET MVC Framework.  Quite a few folks commented on it, and it has been improved as a result of the comments.  For more from me, add my feed at http://feeds.feedburner.com/jeffreypalermo.

The main problem with the SmartBag prior to today was that they actual type of the object passed was used as the key.  This created a problem for polymorphism because proxied objects would be recorded as the actual type, and then when the view asked for them by the intended type, the object would not be found.  I fixed this by having the Add method be generic and accept the intended type.  This still looks pretty clean, allows multiple initialization, and supports proxied and subclassed objects.  The full source code is still only in CodeCampServer, so you can swipe it from there.

Rather than address every capability, I think the tests best illustrate the current capabilities.  If you'd like to see real code using the SmartBag, every controller and view in CodeCampServer are currently employing it.  I'm really close to moving it to MvcContrib and providing a sample there so that it can be used more generically as well as be integrated into ConventionController.  I really think this ends up being a nicer experience both on the controller and the view.

   1: [Test]
   2: public void ShouldRetrieveSingleObjectByType()
   3: {
   4:     SmartBag bag = new SmartBag();
   5:     Url url = new Url("/asdf"); //arbitrary object
   6:     bag.Add(url);
   7:  
   8:     Assert.That(bag.Get<Url>(), Is.EqualTo(url));
   9:     Assert.That(bag.Get(typeof (Url)), Is.EqualTo(url));
  10: }
  11:  
  12: [Test, ExpectedException(ExceptionType = typeof (ArgumentException),
  13:     ExpectedMessage = "You can only add one default object for type 'System.Security.Policy.Url'.")]
  14: public void AddingTwoDefaultObjectsOfSameTypeThrows()
  15: {
  16:     Url url1 = new Url("/1");
  17:     Url url2 = new Url("/2");
  18:  
  19:     SmartBag bag = new SmartBag();
  20:     bag.Add(url1);
  21:     bag.Add(url2);
  22: }
  23:  
  24: [Test, ExpectedException(typeof (ArgumentException),
  25:     ExpectedMessage = "No object exists with key 'System.Security.Policy.Url'.")]
  26: public void ShouldGetMeaningfulExceptionIfObjectDoesntExist()
  27: {
  28:     SmartBag bag = new SmartBag();
  29:     Url url = bag.Get<Url>();
  30: }
  31:  
  32: [Test]
  33: public void ShouldReportContainsCorrectly()
  34: {
  35:     SmartBag bag = new SmartBag();
  36:     bag.Add(new Url("/2"));
  37:  
  38:     Assert.That(bag.Contains<Url>());
  39:     Assert.That(bag.Contains(typeof (Url)));
  40: }
  41:  
  42: [Test]
  43: public void ShouldManageMoreThanOneObjectPerType()
  44: {
  45:     SmartBag bag = new SmartBag();
  46:     bag.Add("key1", new Url("/1"));
  47:     bag.Add("key2", new Url("/2"));
  48:  
  49:     Assert.That(bag.Get<Url>("key1").Value, Is.EqualTo("/1"));
  50:     Assert.That(bag.Get<Url>("key2").Value, Is.EqualTo("/2"));
  51: }
  52:  
  53: [Test, ExpectedException(typeof (ArgumentException), 
  54:     ExpectedMessage = "No object exists with key 'foobar'.")]
  55: public void ShouldGetMeaningfulExceptionIfObjectDoesntExistByKey()
  56: {
  57:     SmartBag bag = new SmartBag();
  58:     Url url = bag.Get<Url>("foobar");
  59: }
  60:  
  61: [Test]
  62: public void ShouldCountNumberOfObjectsOfGivenType()
  63: {
  64:     SmartBag bag = new SmartBag();
  65:     Assert.That(bag.GetCount(typeof (Url)), Is.EqualTo(0));
  66:  
  67:     bag.Add("1", new Url("/1"));
  68:     bag.Add("2", new Url("/2"));
  69:     bag.Add("3", new Url("/3"));
  70:  
  71:     Assert.That(bag.GetCount(typeof (Url)), Is.EqualTo(3));
  72: }
  73:  
  74: [Test]
  75: public void ShouldBeAbleToInitializeBagWithSeveralObjects()
  76: {
  77:     Url url = new Url("/1");
  78:     GenericIdentity identity = new GenericIdentity("name");
  79:  
  80:     SmartBag bag = new SmartBag().Add(identity).Add(url);
  81:     Assert.That(bag.Get(typeof (GenericIdentity)), Is.EqualTo(identity));
  82:     Assert.That(bag.Get(typeof (Url)), Is.EqualTo(url));
  83: }
  84:  
  85: [Test]
  86: public void ShouldHandleProxiedObjectsByType()
  87: {
  88:     MailMessage stub = MockRepository.GenerateStub<MailMessage>();
  89:     SmartBag bag = new SmartBag();
  90:     bag.Add(stub);
  91:     MailMessage message = bag.Get<MailMessage>();
  92:  
  93:     Assert.That(message, Is.EqualTo(stub));
  94: }
  95:  
  96: [Test]
  97: public void ShouldInitializeWithProxiesAndResolveCorrectly()
  98: {
  99:     MailMessage messageProxy = MockRepository.GenerateStub<MailMessage>();
 100:     XmlDocument xmlDocumentProxy = MockRepository.GenerateStub<XmlDocument>();
 101:  
 102:     SmartBag bag = new SmartBag().Add(messageProxy).Add(xmlDocumentProxy);
 103:  
 104:     Assert.That(bag.Get<MailMessage>(), Is.EqualTo(messageProxy));
 105:     Assert.That(bag.Get<XmlDocument>(), Is.EqualTo(xmlDocumentProxy));
 106: }
 107:  
 108: [Test]
 109: public void ShouldInitializeWithKeys()
 110: {
 111:     SmartBag bag = new SmartBag().Add("key1", 2).Add("key2", 3);
 112:     Assert.That(bag.ContainsKey("key1"));
 113:     Assert.That(bag.ContainsKey("key2"));
 114: }

Posted Thu, Jan 24 2008 11:06 PM by Jeffrey Palermo

[Advertisement]

Comments

Ken Egozi wrote re: SmartBag for ASP.NET MVC, take two
on Fri, Jan 25 2008 3:28 AM

I like the tests, I don't like the intent they reveal.

why use the type as key?

I like using the DictionaryAdapter and an interface-per-view approach much better. could make testing easier, too.

Introducing the SmartBag for ASP.NET MVC. . . and soliciting feedback - Jeffrey Palermo [MVP] wrote Introducing the SmartBag for ASP.NET MVC. . . and soliciting feedback - Jeffrey Palermo [MVP]
on Fri, Jan 25 2008 8:09 AM

Pingback from  Introducing the SmartBag for ASP.NET MVC. . . and soliciting feedback - Jeffrey Palermo [MVP]

Jeffrey Palermo wrote re: SmartBag for ASP.NET MVC, take two
on Fri, Jan 25 2008 8:14 AM

@Ken,

I use the type as the key in order to provide a way to pull out the default object of a given type.  The generic usage eliminates the need for casting, and I believe we have an 80% solution here.

Please elaborate on what you like about DictionaryAdapter and what you gain by defining an interface for each view.

Jeffrey Palermo wrote re: SmartBag for ASP.NET MVC, take two
on Fri, Jan 25 2008 8:27 AM

@Ken,

The SmartBag is definitely not compatible with DictionaryAdapter, but it makes it easy to work in the view.

I think another capability that MvcContrib should provide is a ViewBase class that leverage's Castle's DictionaryAdapter.  

My thinking behind this is that I see value in both approaches and that I don't think the world (or MvcContrib users) will all use the same approach.

I read up on your blog about AspView and Dictionary Adapter.

Greg wrote re: SmartBag for ASP.NET MVC, take two
on Fri, Jan 25 2008 12:39 PM

I am morbidly curious how this test actually works ...

[Test]

public void ShouldHandleProxiedObjectsByType() {

    MailMessage stub = MockRepository.GenerateStub<MailMessage>();

    SmartBag bag = new SmartBag();

    bag.Add(stub);

    MailMessage message = bag.Get<MailMessage>();

}

to add a proxied object shouldn't I need to say bad.Add<MailMessage>(someProxiedObject)

 93:     Assert.That(message, Is.EqualTo(stub));

 94: }

Greg wrote re: SmartBag for ASP.NET MVC, take two
on Fri, Jan 25 2008 1:26 PM

ugh yucky type inference ...

Jeffrey Palermo wrote re: SmartBag for ASP.NET MVC, take two
on Fri, Jan 25 2008 2:10 PM

@Greg,

If I'm still not addressing your concern, please post a unit test that illustrates your desired behavior.  OR, submit a patch to CodeCampServer that fixes SmartBag to your liking.  It would help me understand your need.

Garry Shutler wrote re: SmartBag for ASP.NET MVC, take two
on Fri, Jan 25 2008 5:04 PM

I've put together my own version of a SmartBag which is tailored more to my liking to add to the conversation.

garryshutler.spaces.live.com/.../cns!63AE3374C229159C!152.entry

DotNetKicks.com wrote SmartBag take 2
on Tue, Feb 5 2008 10:43 PM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

theQueue wrote Resources from my ASP.NET MVC talk at RockNUG (2/13/08)
on Thu, Feb 14 2008 9:15 PM

Resources from my ASP.NET MVC talk at RockNUG (2/13/08)

Steve Sanderson’s blog » Blog Archive » ASP.NET MVC: Making strongly-typed ViewPages more easily wrote Steve Sanderson&#8217;s blog &raquo; Blog Archive &raquo; ASP.NET MVC: Making strongly-typed ViewPages more easily
on Fri, Feb 22 2008 3:44 AM

Pingback from  Steve Sanderson&#8217;s blog  &raquo; Blog Archive   &raquo; ASP.NET MVC: Making strongly-typed ViewPages more easily