在渲染液体模板时,我在特定情况下的应用程序中看到了一些奇怪的不一致结果。为了记录,我使用的是Ubuntu 12.10,Mono 3.2.3以及最新版本的Dotliquid(1.7)。我已经对Dotliquid做了几个小的改写,我将在下面概述它们的原因:
在DotLiquidViewEngine中,我插入了以下内容:
if (model is ResponseModel)
{
hashedModel = new Hash((model as ResponseModel).ToHash());
}
else
{
hashedModel = Hash.FromAnonymousObject(new
{
Model = new DynamicDrop(model),
ViewBag = new DynamicDrop(renderContext.Context.ViewBag)
});
}
这种轻微变化的意义在于我不必输入{{model.myobject.property}}而我可以使用{{myobject.property}}代替。
ResponseModel对象是一个Dictionary。开始偏离快乐路径的部分是我创建了一个继承自DotLiquid.Drop的对象,并且还实现了IDictionary。这样我就可以通过3种不同的方式访问对象列表:
{{ mylist.list_item_key.property }}
{{ mylist["list_item_key"].property }}
{% foreach list in mylist %}
{% if list.handle == 'list_item_key' %}
{{ list.property }}
{% endif %}
{% endfor %}
(我将在下面粘贴此通用收集代码。)
我看到的问题是这样的:我提供的代码在Windows环境中每次工作。在运行最新版Mono的Linux托管环境中,此代码有时会运行,有时则不运行。
我能找到的唯一模式是,一旦Apache重新启动,无论第一页请求发生什么(无论列表是否正确呈现),在每次后续页面请求中都会发生此行为,直到我再次重新启动Apache 。当它失败时,只有上面列出的前两种方法失败,第三种方法无论如何总是有效。当我看到失败时,这就是我看到的错误:
Liquid error: Array index is out of range.
无论运行Ubuntu还是CentOS,我都会在Mono中获得相同的不一致结果。我试过在debug vs release模式下执行代码。我甚至尝试通过Visual Studio和Xamarin进行编译,看看它是否会有所帮助。无论如何都是一样的结果。
唯一可能相关的其他信息是该解决方案在Nancy上运行,并且正在使用StructureMap进行IoC。这些都是Nuget的最新版本。
我宁愿坚持这一点,所以任何见解都非常感激。下面是实现Drop的通用集合中的代码:
public class GenericCollectionDrop : Drop, IDictionary<string, object>
{
private Dictionary<string, object> _collection = null;
public GenericCollectionDrop()
{
_collection = new Dictionary<string, object>();
}
public override object BeforeMethod(string method)
{
if (this.ContainsKey(method))
return this[method];
return base.BeforeMethod(method);
}
public void Add(string key, object value)
{
_collection.Add(key, value);
}
public bool ContainsKey(string key)
{
return _collection.ContainsKey(key);
}
public ICollection<string> Keys
{
get { return _collection.Keys; }
}
public bool Remove(string key)
{
return _collection.Remove(key);
}
public bool TryGetValue(string key, out object value)
{
return _collection.TryGetValue(key, out value);
}
public ICollection<object> Values
{
get { return _collection.Values; }
}
public object this[string key]
{
get
{
return _collection[key];
}
set
{
_collection[key] = value;
}
}
public void Add(KeyValuePair<string, object> item)
{
_collection.Add(item.Key, item.Value);
}
public void Clear()
{
_collection.Clear();
}
public bool Contains(KeyValuePair<string, object> item)
{
return _collection.Contains(item);
}
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public int Count
{
get { return _collection.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(KeyValuePair<string, object> item)
{
return _collection.Remove(item.Key);
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
return _collection.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _collection.Values.GetEnumerator();
}
}
我也尝试使用此帖中提供的解决方案替换上面的类,结果相同:Dictionaries and DotLiquid
答案 0 :(得分:1)
这是一个非常具体的问题,关于一些尚未广泛采用的开源组件,以及大多数人认为不适合生产环境的平台。我怀疑很多人会来寻找这种情况的答案,但我有一个解决方案以防任何人这样做:
我正在运行的DotLiquid版本是1.7。 1.8版本(仍处于测试版)的注释看起来很有希望,我想我可以使用另一种解决方案来实现安全接口模型的结果。但是,简单地将DotLiquid 1.7替换为1.8 beta似乎已经解决了这个问题,而不必在我的代码上进行任何代码更改。
就我个人而言,在我看来,唯一比不理解问题更糟糕的事情就是不理解为什么某个特定问题得到解决,所以也许将来我会深入挖掘源代码,看看下面发生了什么变化。目前,升级版本甚至测试版都完全消除了Linux / Apache / Mono中的问题,上述解决方案运行良好。