Storefront & ASP.NET MVC RC1

Last post 03-25-2009 2:50 AM by Paul Linton. 10 replies.

Sort Posts:

  • Storefront & ASP.NET MVC RC1

    02-26-2009, 6:33 PM
    • Member
      point Member
    • TobiR
    • Member since 02-17-2009, 8:48 AM
    • Posts 9

    Hi,

    Not sure if anyone is interested but I have got the project working on the latest MVC code drop - RC1. I guess everyone is waiting for the MIX09 version (everyone has gone quiet! very busy I guess?). Anyhow it was a good exercise to get up to speed with the changes. If there is any demand maybe Rob could upload this.

    Regards

    Tobi

  • Re: Storefront & ASP.NET MVC RC1

    02-26-2009, 7:05 PM
    • Participant
      846 point Participant
    • robconery
    • Member since 02-23-2005, 10:16 PM
    • Posts 192
    • AspNetTeam

    I have some goodness coming soon...

  • Re: Storefront & ASP.NET MVC RC1

    03-01-2009, 7:41 PM
    • Member
      532 point Member
    • pure.krome
    • Member since 05-28-2006, 4:45 AM
    • Melbourne, Australia
    • Posts 348

     Awesomesauce Rob -- i just bought a new helmet because your new goodness is going to blow my mind .... !!!! :)

     

    (hmm.. that sounds ... really ... dodgy ... )

     

     /me waits patiently :)

    :: Never underestimate the predictability of stupidity ::
  • Re: Storefront & ASP.NET MVC RC1

    03-22-2009, 9:43 PM
    • Contributor
      5,020 point Contributor
    • Paul Linton
    • Member since 04-29-2008, 11:16 PM
    • Posts 875

    I have MVC1.0 installed, I just downloaded the new Storefront source.  Opened the solution, set Microsoft.Web.Comemrce.UI as the startup project and hit the run button.  It works!

    Got a c# problem? Try .NET Book Zero from Charles Petzold, it's a free pdf.
  • Re: Storefront & ASP.NET MVC RC1

    03-22-2009, 10:18 PM
    • Member
      532 point Member
    • pure.krome
    • Member since 05-28-2006, 4:45 AM
    • Melbourne, Australia
    • Posts 348

    G'day Paul (and everyone else),

     i noticed the code sneaked into codeplex on the weekend so i checked it out, also :) Looks like i have a fair bit of catching up -- it's all confusing for me now :( ce la vie :)

     I hope Rob has at least one vid coming up, which can explain his refactor on a high level. Eg, what this infrastructure project is, etc. I know he talked about it a bit in his last (or 2nd last) vid, but now that he's finished the refactor, it would be good to get a refresh'd vid post :)

    what do you think of the latest release, Paul?

    :: Never underestimate the predictability of stupidity ::
  • Re: Storefront & ASP.NET MVC RC1

    03-23-2009, 12:56 AM
    • Contributor
      5,020 point Contributor
    • Paul Linton
    • Member since 04-29-2008, 11:16 PM
    • Posts 875

    I have been mainly interested in the way Rob approached having testable data access.  The "is it a repository according to Martin Fowler" question never bothered me.  I justed wanted to be able to test as much of the code as possible without hitting an actual database.  I have really only spent 10 minutes looking at this latest code but it is very obviously quite different in the data access area (that looks like SQL strings in there, how quaintly 2007Smile )

    I put a fair bit of effort into pausing the last few videos at strategic points so I could write down the code that scrolled past (took a while to find a pen, but I borrowed one from my kids).  From what I saw I put together a fairly satisfactory repository style setup.  I ended with a single repository for each aggregate which made use of an ISession implementation that I could swap using StructureMap for 'live' or 'testing' purposes.  It was certainly not ideal as I found several times that things tested OK against my InMemorySession but that the SQLSession gagged (LinqToSql puts some tough restrictions on what you can do).  But over the last few weeks I have found ways to work around the scenarios that caused problems and it is now full speed ahead developing my app.

    In all likelihood I may not look too closely at this latest incarnation of the StoreFront as it seems to be too different in the areas that I have put a lot of effort in to.  You are 100% right that some new screencasts will be needed to explain what is going on in this latest code drop and why it was decided on.

    Got a c# problem? Try .NET Book Zero from Charles Petzold, it's a free pdf.
  • Re: Storefront & ASP.NET MVC RC1

    03-23-2009, 1:38 AM
    • Member
      532 point Member
    • pure.krome
    • Member since 05-28-2006, 4:45 AM
    • Melbourne, Australia
    • Posts 348

     Interesting post Paul :)

     One of the first things i also tried to do, from Rob's early incarnations of the StoreFront, was to see if i could make the entire app without the use of my SQL 2008 DB :) so when i was ready, i can then just use StructureMap to inject the SqlRepositories instead of the TestRepositories. It's also for Unit Testing .... the StoreFront taught me the difference between Unit (no db, with regards to data) and intergration (intergrate with a db, re: data).. because unit tests need to be fast fast fast -> hence the in memory db :)

     This Aggregrate thingy i've never seen before so it's more learning for me.

    Here's hoping we can get some more vids :) I'm very open minded about this entire starter kit so i can't wait to spend some time in learning what was done and why and see if I like it or not and how it can make me/us/everyone save the world.

    :: Never underestimate the predictability of stupidity ::
  • Re: Storefront & ASP.NET MVC RC1

    03-23-2009, 1:44 AM
    • Contributor
      5,020 point Contributor
    • Paul Linton
    • Member since 04-29-2008, 11:16 PM
    • Posts 875

    Did you achieve being able to swap between SQL DB and InMemory DB?

    Aggregate is just a DDD buzzword which can be roughly translated as "Important class which other classes can hold a reference to"

    Got a c# problem? Try .NET Book Zero from Charles Petzold, it's a free pdf.
  • Re: Storefront & ASP.NET MVC RC1

    03-24-2009, 12:08 AM
    • Member
      532 point Member
    • pure.krome
    • Member since 05-28-2006, 4:45 AM
    • Melbourne, Australia
    • Posts 348

     Sure did Paul :) I thought this was the main reason people wanted to have Dependency injection. That was the first thing i saw DI being such a kewl thing, for me :) Then later I saw peeps use it for mocking, which is kewl also.

     If anything, I found it harder to do a simple in memory 'db' than a Linq2Sql one :P When i say DB, it's not at all. It's just a collection of IList<T> whatever's (eg. users, products, orders, inset-your-fav-stuff-here). The tough stuff was me trying to be tricky about how i generated the fake data in the fake repositories constructor. that's all really. I sorta stole Rob's mock test repositories and made them my main fake repository for my site. Site runs quick too :)

     then, i just change the code in the bootstrapper to inject either the real of fake (test) db when i'm ready. 

    I was convinced (and still am, to a certain degree) that you could have the entire site running of a fake in-memory 'db'. :) My (incomplete) site currently is :)

    It also made me think more TDD... forget the db .. we'll deal with that bi+chsnatch at the  end .. lets get this big mumma working first, starting with our test cases.

     

    What about you?

    :: Never underestimate the predictability of stupidity ::
  • Re: Storefront & ASP.NET MVC RC1

    03-24-2009, 12:19 AM
    • Member
      532 point Member
    • pure.krome
    • Member since 05-28-2006, 4:45 AM
    • Melbourne, Australia
    • Posts 348
    - double post - :(
    :: Never underestimate the predictability of stupidity ::
  • Re: Storefront & ASP.NET MVC RC1

    03-25-2009, 2:50 AM
    • Contributor
      5,020 point Contributor
    • Paul Linton
    • Member since 04-29-2008, 11:16 PM
    • Posts 875

    Isn't this fun, we seem to have our own private forum.

    I was bother that I seemed to be developing two sets of repositories, one for Sql and one for InMemory, each with large slabs of Linq stuff.  The InMemory one was getting tested but that just seemed to be testing the testing code if you see what I mean.  I took a step back and wrote single repositories which had an ISession value injected in to them.  One ISession for Sql/Server and one for InMemory.  ISession is just

    using System;
    using System.Linq;
    
    namespace Ltg.Support
    {
        [CLSCompliant(true)]
        public interface ISession
        {
            IQueryable<T> GetAll() where T : class;
            void SubmitChanges();
            void Rollback();
            void Insert(T item) where T : class;
            void Remove(T item) where T : class;
        }
    }
    

     

    The SqlSession implementation is pretty trivial

    using System.Data.Linq;
    using System.Linq;
    using Ltg.Support;
    
    namespace Lms.Services.Repositories
    {
        public class SqlSession : ISession
        {
            LmsDataContext _db;
            public SqlSession()
            {
                _db = new LmsDataContext();
            }
    
            #region ISession Members
    
            public IQueryable<T> GetAll() where T : class
            {
                return GetTable();
            }
    
            public void SubmitChanges()
            {
    
                try
                {
                    _db.SubmitChanges();
                }
                catch
                {
                    IdentityMap.FlushMap();
                    throw;
                }
            }
    
            public void Rollback()
            {
                _db.Transaction.Rollback();
            }
    
            public void Insert(T item) where T : class
            {
                GetTable().InsertOnSubmit(item);
            }
    
            public void Remove(T item) where T : class
            {
                GetTable().DeleteOnSubmit(item);
            }
    
            #endregion
    
            Table GetTable() where T : class
            {
                return _db.GetTable();
            }
        }
    }
    

     

    InMemorySession hurt my brain for a little while but this seems to work OK.  There are two layers of tables.  _permanent is meant to simulate table saved to a backing store whereas _tables represents the current 'in progress' transaction.  InitializePermanentDictionary (I wonder why I misspelt Initialize with a 'z'?) sets up my test data.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Ltg.Support;
    
    namespace Lms.Services.Repositories
    {
        public class InMemorySession : ISession
        {
            private static Dictionary<Type, Object> _permanent = new Dictionary();
            private  Dictionary _tables;
    
            public InMemorySession()
            {
                _tables = new Dictionary();
            }
    
            static InMemorySession()
            {
                InitializePermanentDictionary();
            }
    
            private IList listFor()
            {
                if (!_tables.ContainsKey(typeof(T)))
                {
                    if (!_permanent.ContainsKey(typeof(T)))
                        _permanent[typeof(T)] = new List();
                    IList permanentTable = (IList)_permanent[typeof(T)];
                    _tables[typeof(T)] = new List(permanentTable);
                }
                return (IList)_tables[typeof(T)];
            }
    
            #region ISession Members
    
            public IQueryable GetAll() where T : class
            {
                return listFor().AsQueryable();
            }
    
    
            public void SubmitChanges()
            {
                foreach (Type table in _tables.Keys)
                {
                    if (_permanent.ContainsKey(table))
                        _permanent.Remove(table);
                    _permanent[table] = _tables[table];
                }
                _tables = new Dictionaryobject>();
                return;
            }
    
            public void Rollback()
            {
                _tables = new Dictionaryobject>();
            }
    
            public void Insert(T item) where T : class
            {
                listFor().Add(item);
            }
    
            public void Remove(T item) where T : class
            {
                listFor().Remove(item);
            }
    
            #endregion
    
            #region Initialisation
            private static void InitializePermanentDictionary()
            {
                Blurb opening = CreateBlurb("OpeningBodyText", "Stuff on the body of the opening page");
                Blurb platitudes = CreateBlurb("OpeningPlatitudes", "Stuff that scrolls on the opening page");
    
                BlurbText openingText = CreateBlurbText(opening, "Welcome to our web site");
                BlurbText platitudeText = CreateBlurbText(platitudes, "Stuff that scrolls on the opening page");
    .
    .
    .
            }
    
            private static BlurbText CreateBlurbText(Blurb blurb, string text)
            {
                BlurbText temp = new BlurbText()
                {
                    BlurbTextGUID = Guid.NewGuid(),
                    BlurbGUID = blurb.BlurbGUID,
                    DisplayLanguage = System.Globalization.CultureInfo.CurrentUICulture.Name,
                    DisplayText = text,
                    LastModified = DateTime.Now
                };
                AddToPermanent(temp);
                return temp;
            }
    
            private static Blurb CreateBlurb(string name, string description)
            {
                Blurb temp = new Blurb()
                {
                    BlurbGUID = Guid.NewGuid(),
                    BlurbName = name,
                    BlurbDescription = description,
                    LastModified = DateTime.Now
                };
                AddToPermanent(temp);
                return temp;
            }
    .
    .
    .
            static void AddToPermanent(T item)
            {
                if (!_permanent.ContainsKey(typeof(T)))
                    _permanent[typeof(T)] = new List();
                ((List)_permanent[typeof(T)]).Add(item);
            }
            #endregion
        }
    }
    

     A typical repository looks like

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Ltg.Support;
    
    namespace Lms.Services.Repositories
    {
        class CourseRepository : Repository<Lms.Model.Course>
        {
            public CourseRepository(ISession session) : base(session) { }
    
            public override IEnumerable GetBySpecification(Func<Lms.Model.Course, bool> specification)
            {
                return GetCourses().Where(specification).MapIt();
            }
    
            public override void Save(Lms.Model.Course course)
            {
                Course dbCourse;
                bool newCourse = TranslateCourse(course, out dbCourse);
                if (newCourse)
                {
                    session.Insert(dbCourse);
                }
            }
    
            public override void Delete(Lms.Model.Course item)
            {
                throw new NotImplementedException("public override void  Delete(Lms.Model.Course item)");
            }
    
            #region Private methods
            IQueryable GetCourses()
            {
                return from c in session.GetAll()
                       let availableTo = GetAvailableToIds(c.CourseGUID)
                       let thePrice = new Money(c.Price??0, Currency.Xlk)
                       select new Lms.Model.Course
                       {
                           AvailableTo = new AggregateSet(availableTo, customerRepository.GetById, EntityInformation.GetIdForEntity),
                           Id = c.CourseGUID,
                           CreatedBy = personRepository.GetById(c.CreatorGUID ?? Guid.Empty),
                           CreationDate = c.CreationDate ?? new DateTime(2000, 1, 1),
                           Custom = c.Custom,
                           Description = c.CourseDescription,
                           Duration = new TimeSpan(c.Duration ?? 0),
                           Name = c.CourseName,
                           OrganizationId = c.OrganizationID,
                           Price = thePrice,
                           UrlName = c.UrlName,
                           UploadedFileName = c.UploadedFileName
                       };
            }
    
     

    Everything seems to hang together quite well as long as the repositories don't get too complex.  LinqToSql can't translate everything that I would like.

    I don't use the pipes and filters pattern but instead went for passing a 'specification' parameter to the Repository Get methods.  I am quite pleased with this as I had to get my head around lambda expressions and how to pass them around.  Once I got it embedded in my brain it has turned into a most satisfactory method.

    cheers

    (some time if I am coming to Melbourne I might look you up, I am interested to know if your Avatar is just your passport photo!)

    Got a c# problem? Try .NET Book Zero from Charles Petzold, it's a free pdf.
Page 1 of 1 (11 items)