简体   繁体   English

跨AppDomain边界代理匿名对象

[英]Proxying Anonymous Objects across AppDomain boundaries

One of the most requested features I'm trying to iron out for RazorEngine vNext is support for loading template assemblies in a separate AppDomain so we can unload the assemblies when we need to. 我正在努力为RazorEngine vNext提供的最需要的功能之一是支持在单独的AppDomain加载模板程序集,因此我们可以在需要时卸载程序集。 Great feature request, but it has the knock-on effect of introducing constraints on the possible model types that can be injected into templates. 很棒的功能请求,但它具有对可以注入模板的可能模型类型引入约束的连锁效应。

One of the nice features of the current v2.1 release is the ability to use anonymous types as models. 当前v2.1版本的一个很好的功能是能够使用匿名类型作为模型。 We do the work of determining that the model type in the template is an anonymous type, and we set the base template as TemplateBase<dynamic> . 我们确定模板中的模型类型是匿名类型,并将基本模板设置为TemplateBase<dynamic> The runtime binder takes care late-bound calls for the model members for us. 运行时绑定程序为我们处理模型成员的后期绑定调用。 All very nice. 一切都很好。

When we introduce support for running templates in a separate AppDomain we now have a constraint that models can only be of types that are [Serializable] (which is implied through inheritance of MarshalByRefObject ). 当我们在单独的AppDomain引入对运行模板的支持时,我们现在有一个约束,即模型只能是[Serializable]的类型(通过继承MarshalByRefObject来暗示)。 Anonymous types are not serialisable, and are also private . 匿名类型不是可序列化的,也是private

My thinking would be to somehow make a proxy model (declared as dynamic ) in the template base which despatches calls to the model (which would be in the calling domain, not the domain the template is running in). 我的想法是以某种方式在模板库中创建一个代理模型(声明为dynamic ),它调用模型的调用(它将在调用域中,而不是模板运行的域)。 In essence: 在本质上:

Template : 模板

<h1>@Model.Name</h1>

The call to @Model.Name would do something like: @Model.Name的调用将执行以下操作:

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

Does anyone know or have experience with the best method of attempting to proxy a call to an anonymous (or dynamic object) in another AppDomain ? 有没有人知道或者有尝试代理对另一个AppDomain的匿名(或dynamic对象)的调用的最佳方法的经验?

Importantly, I'm not trying to push the anonymous object through AppDomain boundary, that can't be done. 重要的是,我不是试图通过AppDomain边界推送匿名对象,这是无法做到的。

Ok. 好。 Assuming you know about reflection and creating a new AppDomain . 假设您了解反射并创建新的AppDomain Which I know you know how to do... :) 我知道你知道怎么办... :)

I've created two helper classes that will allow you to pass anonymous objects. 我创建了两个辅助类,允许您传递匿名对象。 ProxyAnonymousObject and ProxyDynamicObject . ProxyAnonymousObjectProxyDynamicObject You create the ProxyAnonymousObject in the first AppDomain and use the ProxyDynamicObject in the other AppDomain . 您在第一个AppDomain创建ProxyAnonymousObject ,并在其他AppDomain使用ProxyDynamicObject (both of these objects exist in the primary AppDomain library) (这两个对象都存在于主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;
    }
}

To get this to work in your MarshalByRefObject inherited class you just set the target dynamic object equal to a new ProxyDynamicObject(model) . 要使其在MarshalByRefObject继承的类中起作用,您只需将目标dynamic object设置为等于new ProxyDynamicObject(model) In the example I've written up I make a call like this. 在我写的例子中,我打这样的电话。

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);

I've written a blog post about it http://buildstarted.com/2011/06/28/getting-anonymous-types-to-cross-the-appdomain-boundary/ to explain it in a bit more detail. 我已经写了一篇关于它的博客文章http://buildstarted.com/2011/06/28/getting-anonymous-types-to-cross-the-appdomain-boundary/来更详细地解释它。 (though it's something I'm not very good at) (虽然这是我不太擅长的东西)

There are definitely problems with this implementation. 这个实现肯定存在问题。 It doesn't support nested Anonymous Types and I'm fairly certain it will break in general. 它不支持嵌套的匿名类型,我相当肯定它会破坏。 But it's definitely something to get you on the right track. 但这绝对能让你走上正轨。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM