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

ASP.NET DaST to wrestle with MVC and WebForms

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
26 Mar 2013CPOL82 min read 23.4K   152   11  
DaST is a new architectural pattern for building highly dynamic Web 2.0 applications. A web page is rendered as a set of randomly nested rectangles where each rectangle is controlled individually and every combination of rectangles can be partially updated via AJAX.
// ******************************************************************************
// ******************************************************************************
// ASP.NET DaST Rendering Engine
// Copyright (C) 2011 Roman Gubarenko
// Project Home: http://aspnetdast.sourceforge.net/
// ******************************************************************************
// ******************************************************************************
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// ******************************************************************************
// Primary Contact: rgubarenko@gmail.com
// Learn More: http://aspnetdast.sourceforge.net/
// Project Repository: http://sourceforge.net/projects/aspnetdast/
// ******************************************************************************




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace AspNetDaST.Web.Private
{
  internal class ScopeTreeModel
  {
    private TreeNodeScope RootScopeNode { get; set; }


    internal Dictionary<PathExact, ScopeDataBag> ScopeDataMap { get; private set; }
    internal List<PathExact> RefreshScopePaths { get; private set; }
    internal RenderState State { get; set; }


    internal ScopeTreeModel(ScopeController rootController)
    {
      ScopeDataMap = new Dictionary<PathExact, ScopeDataBag>();
      RefreshScopePaths = new List<PathExact>();
      State = RenderState.NotStarted;

      // initial setup for ROOT node
      RootScopeNode = new TreeNodeScope(this);
      RootScopeNode.Controller = rootController;
      RootScopeNode.IsControllerRoot = true;
      rootController.TreeNode = RootScopeNode;
    }


    #region Model Tree Building

    internal void RebuildControllerModel(ScopeController controller, PathExact renderPath)
    {
      // clear previously build model
      controller.TreeNode.ResetModel();

      // get controller template
      controller.SetNavigator(renderPath, renderPath);
      string template = controller.ProvideTemplate();
      if (template == null) throw new DaSTException("Template was not set properly");
      controller.SetNavigator(null, null);

      // parse template and build controller subtree
      TemplateTreeParser treeParser = new TemplateTreeParser();
      treeParser.ExtendTreeModelFromNode(controller.TreeNode, template);

      // set controller reference on all subtree nodes
      SetSubtreeControllerRec(controller.TreeNode, controller);

      // finally, do controller model initialization 
      controller.SetNavigator(renderPath, renderPath);
      controller.InitializeModel(new ControllerModelBuilder(controller));
      controller.SetNavigator(null, null);      
    }

    internal void RebuildControllerModelsOnPath(PathExact path)
    {
      TreeNodeScope nextNode = RootScopeNode;
      RebuildControllerModel(nextNode.Controller, PathExact.Empty);
      for (int segmIdx = 0; segmIdx < path.Length; segmIdx++)
      {
        nextNode = nextNode.ScopeNodes.Find(node => node.ScopeID == path[segmIdx].Name);
        if (nextNode == null) throw new DaSTException("Failed to rebuild controllers on path '{0}'", path);
        if (nextNode.IsControllerRoot) RebuildControllerModel(nextNode.Controller, path.Subpath(segmIdx + 1));
      }
    }

    private void SetSubtreeControllerRec(TreeNodeScope scopeNode, ScopeController controller)
    {
      foreach (var childNode in scopeNode.ScopeNodes)
      {
        childNode.Controller = controller;
        SetSubtreeControllerRec(childNode, controller);
      }
    }

    #endregion


    #region Model Tree Functions

    internal TreeNodeScope GetNode(PathBase path)
    {
      TreeNodeScope currNode = RootScopeNode;

      for (int i = 0; i < path.Length && currNode != null; i++)
      {
        currNode = currNode.ScopeNodes.Find(node => node.ScopeID == path[i].Name);
      }

      if (currNode == null) throw new DaSTException("Scope '{0}' not found", path);

      return currNode;    
    }

    #endregion

    #region Rendered Tree Functions

    internal ScopeDataBag GetScopeDataBag(PathExact renderPath)
    {
      if (!ScopeDataMap.ContainsKey(renderPath)) ScopeDataMap.Add(renderPath, new ScopeDataBag(this, renderPath));
      return ScopeDataMap[renderPath];
    }

    internal void InvokeDataBindingHandler(TreeNodeScope scopeNode, PathExact currentPath)
    {
      if (scopeNode.DataBindCallback != null)
      {
        // get path of the controller corresponding to the current node
        var controlPath = currentPath.Subpath(scopeNode.Controller.TreeNode.NodePath.Length);
      
        // set navigators to be used inside the handler to traverse model tree
        scopeNode.Controller.SetNavigator(controlPath, currentPath);
        // invoke databinding handler
        scopeNode.DataBindCallback();
        // unset navigators to prevent usage outside the handler
        scopeNode.Controller.SetNavigator(null, null);
      }
    }

    internal void InvokeScopeActionHandler(TreeNodeScope targetNode, PathExact actionPath, PathModel handlerPath, string actionName, object actionArg)
    {
      Debug.Assert(actionPath.Subpath(targetNode.NodePath.Length).IsSubpathOf(actionPath));
      Debug.Assert(!string.IsNullOrEmpty(actionName));

      // get action info using name and handler path
      ModelActionInfo actionInfo = targetNode.ActionHandlers.Find(ai =>
        ai.NodePath == handlerPath && ai.ActionName == actionName);

      if (actionInfo != null)
      {
        // get exact path of the controller corresponding to the action node
        var controlPath = actionPath.Subpath(targetNode.NodePath.Length);

        // set navigators to be used inside the handler to traverse model tree
        targetNode.Controller.SetNavigator(controlPath, actionPath);
        // invoke action handler
        actionInfo.Handler(actionArg);
        // unset navigators to prevent usage outside the handler
        targetNode.Controller.SetNavigator(null, null);
      }
    }

    #endregion


    #region Utility Classes

    internal enum RenderState
    {
      NotStarted,
      BuildingTree,
      HandlingActions,
      RenderingTree,
      WritingOutput
    }

    #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
Software Developer (Senior)
Canada Canada
Software Architect with over 15 years in IT field. Started with deep math and C++ Computer Vision software. Currently in .NET and PHP web development. Creator of DaST pattern, open-source frameworks, and plugins. Interested in cutting Edge IT, open-source, Web 2.0, .NET, MVC, C++, Java, jQuery, Mobile tech, and extreme sports.

Comments and Discussions