2011-06-23 115 views
4

我试图为RazorEngine vNext调用最多的功能之一是支持在单独的AppDomain中加载模板程序集,以便我们可以在需要时卸载程序集。强大的功能请求,但它具有在可以注入模板的可能模型类型中引入约束的连锁效果。跨AppDomain边界代理匿名对象

当前v2.1版本的一个很好的功能是能够使用匿名类型作为模型。我们确定模板中的模型类型是匿名类型,并将基本模板设置为TemplateBase<dynamic>。运行时绑定器为我们处理模型成员的迟到调用。一切都很好。

当我们在单独的0123'中引入对运行模板的支持时,我们现在有一个约束,即模型只能是[Serializable](通过继承MarshalByRefObject暗示)的类型。匿名类型不可串行化,也是private

我的想法是以某种方式在派发模型调用的模板库(在调用域中,而不是模板运行的域)中创建代理模型(声明为dynamic)。从本质上说:

模板

<h1>@Model.Name</h1> 

@Model.Name的调用会做这样的事情:

Template.Model (ModelProxy) -> GetMember(Name) -> |BOUNDARY| -> Model.Name 

有谁知道或有企图代理呼叫的最佳方法体验到另一个AppDomain中的匿名(或dynamic对象)?

重要的是,我不是试图通过AppDomain边界推动匿名对象,那是无法完成的。

+0

我有一个答案,但它比这里可以发布更复杂...我会试着压缩它,但是当我找出如何解释它的时候,源代码将会发布到我的博客上。有一些小事情是有点... won ... ...会尝试先解决这些问题。 – Buildstarted

回答

4

好的。假设你知道反射并创建一个新的AppDomain。我知道你知道该怎么做...... :)

我已经创建了两个帮助类,允许你传递匿名对象。 ProxyAnonymousObjectProxyDynamicObject。您在第一个AppDomain中创建ProxyAnonymousObject,并在其他AppDomain中使用ProxyDynamicObject。 (这两个对象在主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/来解释它更详细一点。 (尽管这是我不擅长的)

这个实现肯定有问题。它不支持嵌套的匿名类型,我相当肯定它会打破一般。但这绝对是让你走上正轨的一些东西。