Click here to Skip to main content
15,896,474 members
Home / Discussions / ASP.NET
   

ASP.NET

 
GeneralRe: MVP implementation questions Pin
Nathan Gloyn16-Jan-09 5:38
Nathan Gloyn16-Jan-09 5:38 
GeneralRe: MVP implementation questions Pin
Jon Rista16-Jan-09 5:59
Jon Rista16-Jan-09 5:59 
GeneralRe: MVP implementation questions Pin
Nathan Gloyn16-Jan-09 8:50
Nathan Gloyn16-Jan-09 8:50 
GeneralRe: MVP implementation questions Pin
Jon Rista16-Jan-09 9:21
Jon Rista16-Jan-09 9:21 
GeneralRe: MVP implementation questions Pin
Nathan Gloyn16-Jan-09 9:41
Nathan Gloyn16-Jan-09 9:41 
GeneralRe: MVP implementation questions Pin
Jon Rista16-Jan-09 10:02
Jon Rista16-Jan-09 10:02 
GeneralRe: MVP implementation questions Pin
Nathan Gloyn16-Jan-09 10:17
Nathan Gloyn16-Jan-09 10:17 
GeneralRe: MVP implementation questions Pin
Jon Rista16-Jan-09 10:58
Jon Rista16-Jan-09 10:58 
Yeah, that helps to clarify things a bit. I would say that your not really storing user state or dealing with context at all in that situation. What you are doing is caching. I still think that storing your state in the session directly is creating an undesired link between your model and the system and frameworks that display data from the model. The simplest solution is to abstract the caching a bit by creating a simple, mockable caching system:

// Contract of a cache
interface ICache
{
    void Add(string key, object toCache);
    object Get(string key);
    void Remove(string key);
}

// Session-based cache for live system
class SessionCache: ICache
{
    private HttpSessionState Session
    {
        get
        {
            if (HttpContext.Current != null)
                HttpSessionState.Current.Session;
            return null;
        }
    }

    private bool IsSessionAvailable
    {
        get { return HttpContext.Current != null; }
    }

    public void Add(string key, object toCache)
    {
        if (!IsSessionAvailable) throw new InvalidOperationException("Session cache is only available within an HttpContext.");
        
        Session[key] = toCache;
    }

    public object Get(string key)
    {
        if (!IsSessionAvailable) throw new InvalidOperationException("Session cache is only available within an HttpContext.");

        object item = Session[key];
        return item;
    }

    public void Remove(string key)
    {
        if (!IsSessionAvailable) throw new InvalidOperationException("Session cache is only available within an HttpContext.");

        Session.Remove(key);
    }
}

// Dictionary based cache for unit testing
class DictionaryCache: ICache
{
    private Dictionary<string,> m_cache;

    private Dictionary<string,> Cache
    {
        get 
        {
            if (m_cache == null)
            {
                Interlocked.CompareExchange(ref m_cache, new Dictionary<string,>(), null);
            }
            return m_cache;
        }
    }

    public void Add(string key, object toCache)
    {        
        Cache.Add(key, toCache);
    }

    public object Get(string key)
    {
        object item = Cache[key];
        return item;
    }

    public void Remove(string key)
    {
        Cache.Remove(key);
    }
}

// Facade that acts as a single access point to cache
static class CacheManager
{
    private static ICache s_cache;

    public static ICache CacheInstance
    {
        private get { return s_cache; }
        set { s_cache = value; }
    }


    public void Add(string key, object toCache)
    {
        CacheInstance.Add(key, toCache);
    }

    public object Get(string key)
    {
        return CacheInstance.Get(key);
    }

    public void Remove(string key)
    {
        CacheInstance.Remove(key);
    }
}

// Globa.asax.cs: Inject cache dependency into CacheManager facade
public class Global: HttpApplication
{
    public void Application_Start(object sender, EventArgs e)
    {
        ICache cache = new SessionCache();
        CacheManager.CacheInstance = cache;
    }
}

// Model object with lazy-loaded, cached data
public class ModelEntity
{
    public object LazyLoadedObject
    {
        object item = CacheManager.Get("LazyLoadedObject");
        if (item == null)
        {
            item = GetLazyLoadedObject();
            CacheManager.Add("LazyLoadedObject", item);
        }

        return item;
    }

    private object GetLazyLoadedObject()
    {
        // TODO: Place retrieval logic here
    }
}

// Unit tests
[TestClass]
public class ModelEntityTests
{
    public void LazyLoadedObject_Get_AlreadyCached()
    {
        ICache cache = new DictionaryCache();
        CacheManager.CurrentCache = cache;
        
        object originalInstance = new object();

        cache.Add("LazyLoadedObject", originalInstance);

        ModelEntity entity = new ModelEntity();
        
        object cachedInstance = entity.LazyLoadedObject;

        Assert.AreEqual(originalInstance, cachedInstance);
    }    
}


I am not sure the model entity and test represent exactly what your doing, but it should demonstrate the need to abstract where you store cached data from the activities of caching itself. If you do something like the example above, your model stuff is now bound to ICache and CacheManager...and the link to ASP.NET is gone...so your model should be more testable in isolation from the environment(s) it is used in/bound to. The example above isn't really ideal, either...I would say its probably better to cache at a lower level than the model objects themselves. I think there are some more blending of concerns in your system...I can't say exactly as I don't know enough about it. The list of Commands should probably be separated from the model objects as well: WorkItem and WorkItemData are entities...however, Commands is a persistance utility, and probably belongs in a separate facility that handles the persistence and retrieval of your entities separately. Thats really a different discussion though...even the discussion above isn't directly tied to MVP, although it does provide a useful abstraction that lets you keep ASP.NET elements out of your model objects, and makes it easier to put your Presenters in a separate library from your views and models in a separate library from both.
GeneralRe: MVP implementation questions Pin
Nathan Gloyn19-Jan-09 8:25
Nathan Gloyn19-Jan-09 8:25 
GeneralRe: MVP implementation questions Pin
Jon Rista19-Jan-09 9:55
Jon Rista19-Jan-09 9:55 
GeneralRe: MVP implementation questions Pin
Nathan Gloyn19-Jan-09 10:54
Nathan Gloyn19-Jan-09 10:54 
GeneralRe: MVP implementation questions Pin
Nathan Gloyn3-Feb-09 9:50
Nathan Gloyn3-Feb-09 9:50 
Questionaccess denied for CreateObject("Outlook.Application") Pin
NidhiKanu15-Jan-09 19:41
professionalNidhiKanu15-Jan-09 19:41 
AnswerRe: access denied for CreateObject("Outlook.Application") Pin
Rutvik Dave16-Jan-09 3:49
professionalRutvik Dave16-Jan-09 3:49 
AnswerRe: access denied for CreateObject("Outlook.Application") Pin
Christian Graus25-Jan-09 0:43
protectorChristian Graus25-Jan-09 0:43 
GeneralRe: access denied for CreateObject("Outlook.Application") Pin
NidhiKanu26-Jan-09 18:35
professionalNidhiKanu26-Jan-09 18:35 
Questiongridview rendering from 2 database tables Pin
billcodes15-Jan-09 19:35
billcodes15-Jan-09 19:35 
AnswerRe: gridview rendering from 2 database tables Pin
Abhijit Jana15-Jan-09 20:04
professionalAbhijit Jana15-Jan-09 20:04 
QuestionGridview Pin
kushalrshah15-Jan-09 19:29
kushalrshah15-Jan-09 19:29 
AnswerRe: Gridview Pin
Abhijit Jana15-Jan-09 19:37
professionalAbhijit Jana15-Jan-09 19:37 
Questioni have problem in displaying hover dynamically Pin
Rahul Gharat15-Jan-09 18:28
Rahul Gharat15-Jan-09 18:28 
AnswerRe: i have problem in displaying hover dynamically Pin
Christian Graus25-Jan-09 0:42
protectorChristian Graus25-Jan-09 0:42 
QuestionFile Upload Filter? in VB ASP .net Pin
saberbladez15-Jan-09 16:23
saberbladez15-Jan-09 16:23 
AnswerRe: File Upload Filter? in VB ASP .net Pin
N a v a n e e t h15-Jan-09 19:04
N a v a n e e t h15-Jan-09 19:04 
QuestionWhat is your preferred implementation for AJAX modal popups? Pin
Member 391904915-Jan-09 9:32
Member 391904915-Jan-09 9:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.