我正在努力为RazorEngine vNext提供的一个最需要的功能是支持在单独的AppDomain
中加载模板程序集,以便我们可以在需要时卸载程序集。很棒的功能请求,但它具有对可以注入模板的可能模型类型引入约束的连锁效应。
当前v2.1版本的一个很好的功能是能够使用匿名类型作为模型。我们确定模板中的模型类型是匿名类型,并将基本模板设置为TemplateBase<dynamic>
。运行时绑定程序为我们处理模型成员的后期绑定调用。一切都很好。
当我们在单独的AppDomain
中引入对运行模板的支持时,我们现在有一个约束,即模型只能是[Serializable]
的类型(通过继承MarshalByRefObject
隐含) 。匿名类型不可序列化,也是private
。
我的想法是以某种方式在模板库中创建一个代理模型(声明为dynamic
),该模型基于调用模型的调用(它将在调用域中,而不是模板运行的域) 。实质上:
模板:
<h1>@Model.Name</h1>
对@Model.Name
的调用会执行以下操作:
Template.Model (ModelProxy) -> GetMember(Name) -> |BOUNDARY| -> Model.Name
是否有人知道或有过尝试代理对另一个dynamic
中的匿名(或AppDomain
对象)的调用的最佳方法的经验?
重要的是,我不是试图通过AppDomain
边界推送匿名对象,这是无法做到的。
答案 0 :(得分:4)
确定。假设您了解反射并创建新的AppDomain
。我知道你知道怎么做...... :)
我创建了两个帮助程序类,允许您传递匿名对象。 ProxyAnonymousObject
和ProxyDynamicObject
。您可以在第一个ProxyAnonymousObject
中创建AppDomain
,并在另一个ProxyDynamicObject
中使用AppDomain
。 (这两个对象都存在于主AppDomain
库中)
[Serializable]
public class ProxyAnonymousObject : ISerializable {
static Dictionary<string, Type> cached = new Dictionary<string, Type>();
object model;
public Dictionary<string, object> ModelProperties = new Dictionary<string, object>();
public ProxyAnonymousObject(object model) { this.model = model; }
public ProxyAnonymousObject(SerializationInfo info, StreamingContext ctx) {
try {
string fieldName = string.Empty;
object fieldValue = null;
foreach (var field in info) {
fieldName = field.Name;
fieldValue = field.Value;
if (string.IsNullOrWhiteSpace(fieldName))
continue;
if (fieldValue == null)
continue;
ModelProperties.Add(fieldName, fieldValue);
}
} catch (Exception e) {
var x = e;
}
}
public void GetObjectData(SerializationInfo info, StreamingContext context) {
foreach (var pi in model.GetType().GetProperties()) {
info.AddValue(pi.Name, pi.GetValue(model, null), pi.PropertyType);
}
}
}
public class ProxyDynamicObject : DynamicObject{
internal ProxyAnonymousObject Proxy { get; set; }
public ProxyDynamicObject(ProxyAnonymousObject model) {
this.Proxy = model;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
result = Proxy.ModelProperties[binder.Name];
return true;
}
}
要让您在MarshalByRefObject
继承的课程中发挥作用,您只需将目标dynamic object
设置为new ProxyDynamicObject(model)
即可。在我写的例子中,我打这样的电话。
instance = Activator.CreateInstance(type);
var setModel = type.GetMethod("SetModel", BindingFlags.Public | BindingFlags.Instance);
var render = type.GetMethod("Render", BindingFlags.Public | BindingFlags.Instance);
setModel.Invoke(instance, new object[] { new ProxyDynamicObject(model) });
render.Invoke(instance, null);
我写了一篇关于它的博客文章http://buildstarted.com/2011/06/28/getting-anonymous-types-to-cross-the-appdomain-boundary/,以便更详细地解释一下。 (虽然这是我不太擅长的东西)
这种实现肯定存在问题。它不支持嵌套的匿名类型,我相当肯定它会破坏。但这绝对能让你走上正轨。