Click here to Skip to main content
15,892,737 members
Articles / Web Development / ASP.NET

A Simple Object Collaboration Framework

Rate me:
Please Sign up or sign in to vote.
4.71/5 (7 votes)
17 Feb 2009CPOL22 min read 46.3K   189   39  
A library that simplifies complex interactions between objects by providing a new mechanism of instance discovery and lifetime management. It is an extension of the .NET CallContext or HTTPContext mechanism that provides a way of sharing objects within an execution code path.
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SOCF;
using NorthwindDataModel;

namespace TestCollaborations
{
    /// <summary>
    /// This test demonstrates the behavior of IdentityMap as well as 
    /// how it is used as a collaboration context.
    /// </summary>
    [TestClass]
    public class TestIdentityMap
    {
        public TestIdentityMap()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        #region Tests
        /// <summary>
        /// Create a simple identity map collaboration context, and cache
        /// some products in it.  Then try accessing those inside a nested method call.
        /// </summary>
        [TestMethod]
        public void TestIdentityMapSimple()
        {
            // Create a simple scope for caching product objects.
            // Everyting within the using() block will be able to access this map.
            using (var map = new IdentityMap<Product>(IdentityMapScope.Local))
            {
                CacheProducts(1, 2, 3);
                map.DumpObjects();  // Dump objects to debug output.
                ProductsMustExist(1, 2, 3);
                ProductsMustNotExist(4, 5, 6);
                UncacheProducts(1, 2, 3);
                map.DumpObjects();  // Dump objects to debug output.
                ProductsMustNotExist(1, 2, 3);
            }
        }

        /// <summary>
        /// Create 4 levels of nested identity maps.
        /// For demonstration purposes nestings are in the same method,
        /// but they could just as well be placed in other methods, or even
        /// methods of other classes.
        /// An identity map is specific to a type.  Separate types will have entirely
        /// separete nesting hierarchies without any entanglement with maps of other types.
        /// </summary>
        [TestMethod]
        public void TestNestedIdentityMap()
        {
            // Topmost scope
            using (var map1 = new IdentityMap<Product>(IdentityMapScope.Local))
            {
                CacheProducts(1, 2, 3);
                map1.DumpObjects();  // Dump objects to debug output.
                ProductsMustExist(1, 2, 3);

                // Second level nested scope
                using (var map2 = new IdentityMap<Product>(IdentityMapScope.AllParents))
                {
                    CacheProducts(4, 5, 6);
                    map2.DumpObjects();
                    ProductsMustExist(4, 5, 6);     // Products of local scope
                    ProductsMustExist(1, 2, 3);     // Products of the parent scope must also be accessible here

                    // Third level nested scope
                    using (var map3 = new IdentityMap<Product>(IdentityMapScope.AllParents))
                    {
                        CacheProducts(7, 8, 9);
                        map3.DumpObjects();
                        ProductsMustExist(7, 8, 9);     // Products of local scope
                        ProductsMustExist(4, 5, 6);     // Products of the parent scope must also be accessible here
                        ProductsMustExist(1, 2, 3);     // Products of the top scope must also be accessible here

                        // Fourth level nested scope
                        using (var map4 = new IdentityMap<Product>(IdentityMapScope.Parent))    // Notice that this can only access the immediate parent scope and no more than that.
                        {
                            CacheProducts(10, 11, 12);
                            map4.DumpObjects();
                            ProductsMustExist(10, 11, 12);  // Products of local scope
                            ProductsMustExist(7, 8, 9);     // Products of the immediate parent scope are also accessible here
                            ProductsMustNotExist(4, 5, 6);  // Products of the further parent scopes are not accessible here
                            ProductsMustNotExist(1, 2, 3);     // Products of the further parent scopes are not accessible here
                        }
                    }
                }

                ProductsMustNotExist(4, 5, 6);      // Products of the nested scope must not exist here
                ProductsMustNotExist(7, 8, 9);      // Products of the nested scope must not exist here
                ProductsMustNotExist(10, 11, 12);   // Products of the nested scope must not exist here
            }
        }

        #endregion

        #region Helpers

        private void ProductsMustExist(params int[] productIDs)
        {
            foreach (int productID in productIDs)
            {
                Product product = IdentityMap<Product>.Get(productID);
                Assert.IsNotNull(product);
                Assert.AreEqual(product.ProductID, productID);
            }
        }

        private void ProductsMustNotExist(params int[] productIDs)
        {
            foreach (int productID in productIDs)
            {
                Product product = IdentityMap<Product>.Get(productID);
                Assert.IsNull(product);
            }
        }

        private void CacheProducts(params int[] productIDs)
        {
            foreach (int productID in productIDs)
                IdentityMap<Product>.Set(productID, new Product() { ProductID = productID, ProductName = "Product " + productID.ToString(), UnitPrice = productID * 10 });
        }

        private void UncacheProducts(params int[] productIDs)
        {
            foreach (int productID in productIDs)
                IdentityMap<Product>.Set(productID, null);
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Netsoft-USA
United States United States
Technical Architect at Netsoft-USA. Developed Netsoft USA Framework (A software factory approach for developing object oriented + service based, data driven enterprise scale applications). Check out my new app VocaTalk Personal Podcast (A cool app that generates podcasts using Text-to-speech, background music and effects)

Comments and Discussions