|
// ******************************************************************************
// ******************************************************************************
// 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.Web.Script.Serialization;
using System.Collections.Specialized;
namespace AspNetDaST.Web.Private
{
internal static class ScopeTreeTools
{
internal static class ClientBridge
{
public static string ConvertScopePath2ClientID(PathExact path)
{
StringBuilder sb = new StringBuilder("SCOPE");
for (int i = 0; i < path.Length; i++) sb.AppendFormat("${0}-{1}", path[i].Axis ?? 0, path[i].Name);
return sb.ToString();
}
public static PathExact ConvertClientID2ScopePath(string clientID)
{
PathExact path = new PathExact();
Regex rePath = new Regex("^SCOPE(\\$(\\d+)\\-([A-Za-z0-9]+))+$");
Match match = rePath.Match(clientID);
if (match.Success)
{
for (int i = 0; i < match.Groups[1].Captures.Count; i++)
{
int axis = int.Parse(match.Groups[2].Captures[i].Value);
string name = match.Groups[3].Captures[i].Value;
path = path.Append(axis, name);
}
}
else throw new DaSTException("Invalid client scope ID format");
return path;
}
public static string[] DecodeClientData(string data)
{
try
{
List<string> values = new List<string>();
int startIdx = 0, delimIdx;
while (startIdx < data.Length)
{
if ((delimIdx = data.IndexOf('|', startIdx)) == -1) throw new Exception("Expected delimiter");
int dataLen = int.Parse(data.Substring(startIdx, delimIdx - startIdx));
startIdx = delimIdx + 1;
string dataValue = data.Substring(startIdx, dataLen);
startIdx = startIdx + dataLen;
if (data[startIdx] != '|') throw new Exception("Expected delimiter");
startIdx++;
values.Add(dataValue);
}
return values.ToArray();
}
catch (Exception ex) { throw new Exception("Failed to decode client data"); }
}
}
internal static class DaSTState
{
private static JavaScriptSerializer _json = new JavaScriptSerializer();
public static string BuildDaSTState(ScopeTreeModel scopeTree)
{
// collect scope datas to store in state
var scopeDatas = from path in scopeTree.ScopeDataMap.Keys
let data = scopeTree.ScopeDataMap[path]
// select only needed datas according to some rules:
where data.Validated && // 1) data must be validated
data.RenderType != ScopeRenderType.None && // 2) must be visible
data.StoredParams.Count > 0 && // 3) must have storable params
!scopeTree.ScopeDataMap.Any(kv => // 4) must not be on a subtree of empty of invisible scope
kv.Key.IsSubpathOf(path) && kv.Key != path &&
(kv.Value.RenderType == ScopeRenderType.None ||
kv.Value.RenderType == ScopeRenderType.Empty))
select data;
// finally, serialize scopes and encode the result to put on the page
string serializedData = SerializeScopeDatas(scopeDatas);
return Convert.ToBase64String(Encoding.ASCII.GetBytes(serializedData));
}
public static void RestoreDaSTState(string state, ScopeTreeModel scopeTree)
{
string serializedData = Encoding.ASCII.GetString(Convert.FromBase64String(state));
var dataByClientID = ParseSerializedState(serializedData);
foreach (var kv in dataByClientID)
{
PathExact renderPath = ClientBridge.ConvertClientID2ScopePath(kv.Key);
var dict = _json.Deserialize<Dictionary<string, object>>(kv.Value);
ScopeDataBag scopeData = new ScopeDataBag(scopeTree, renderPath);
// populate stored params with values that we just deserialized
foreach (var pair in dict) scopeData.StoredParams.Add(pair.Key, pair.Value);
// set flag on restored scope to indicate that this scope is valid for following serialization
scopeData.Validated = true;
scopeTree.ScopeDataMap.Add(renderPath, scopeData);
}
}
private static string SerializeScopeDatas(IEnumerable<ScopeDataBag> scopeDatas)
{
StringBuilder sb = new StringBuilder();
foreach (var scopeData in scopeDatas)
{
string strParams = _json.Serialize(scopeData.StoredParams);
sb.AppendFormat("{0}|{1}|{2}|", strParams.Length, scopeData.ScopeClientID, strParams);
}
return sb.ToString();
}
private static List<KeyValuePair<string, string>> ParseSerializedState(string serializedData)
{
try
{
var results = new List<KeyValuePair<string, string>>();
int startIdx = 0, delimIdx;
while (startIdx < serializedData.Length)
{
if ((delimIdx = serializedData.IndexOf('|', startIdx)) == -1) throw new Exception("Expected delimiter");
int dataLen = int.Parse(serializedData.Substring(startIdx, delimIdx - startIdx));
startIdx = delimIdx + 1;
if ((delimIdx = serializedData.IndexOf('|', startIdx)) == -1) throw new Exception("Expected delimiter");
string clientID = serializedData.Substring(startIdx, delimIdx - startIdx);
startIdx = delimIdx + 1;
string data = serializedData.Substring(startIdx, dataLen);
startIdx += dataLen;
if (serializedData[startIdx] != '|') throw new Exception("Expected delimiter");
startIdx++;
results.Add(new KeyValuePair<string, string>(clientID, data));
}
return results;
}
catch (Exception ex) { throw new Exception("Failed to parse serialized state"); }
}
}
internal static class Model
{
internal static bool IsScopeAccessible(ScopeController controller, TreeNodeScope scopeNode)
{
// scope is accessible if corresponding node is within current controller
return object.Equals(controller, scopeNode.Controller) || // same controller
(scopeNode.ParentNode != null && object.Equals(controller, scopeNode.ParentNode.Controller)); // leaf node with assigned controller
}
}
}
}
|
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.
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.