2011-06-23 7 views
4

私が最も願っている機能の1つRazorEngine vNextはテンプレートアセンブリを別のAppDomainにロードするためのサポートです。必要なときにアセンブリをアンロードできます。素晴らしい機能要求ですが、テンプレートに挿入できるモデルタイプに制約を導入するというノックオン効果があります。AppDomain境界を越えた匿名オブジェクトのプロキシ

現在のv2.1リリースの優れた機能の1つは、モデルとして匿名タイプを使用できることです。テンプレートのモデルタイプが匿名型であると判断する作業を行い、基本テンプレートをTemplateBase<dynamic>と設定します。実行時バインダは、モデルメンバーの遅延呼び出しを注意して処理します。とても素敵です。

別のAppDomainでテンプレートを実行するサポートを導入した場合、モデルは[Serializable](継承によって暗示されているタイプ)のみであるという制約があります(MarshalByRefObjectを暗示しています)。匿名型はシリアル化されず、privateです。

私は、何らかの理由でモデルに呼び出しを送信するテンプレートベース(テンプレートが実行されているドメインではなく、呼び出し元のドメインにある)にプロキシモデル(dynamicと宣言)を作成することが考えられます。

テンプレート:本質的には

<h1>@Model.Name</h1> 

ような何かをするだろう@Model.Nameへの呼び出し:

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

は誰もが知っているか、プロキシコールにしようとする最善の方法と経験を持っています別のAppDomainの匿名(またはdynamicオブジェクト)に?

重要なことに、私は匿名オブジェクトをAppDomain境界に押し込もうとしているわけではありません。

+0

私はあなたに答えがありますが、ここに投稿できるより複雑です...私はそれを試して凝縮するだろうが、ソースは私のブログに行く...私はそれを説明する方法を見つけるとき。ちょっとしたものがいくつかあります...うわー...最初にそれらを試して修正しよう。 – Buildstarted

答えて

4

反射について知り、新しいAppDomainを作成すると仮定します。私はあなたのやり方を知っていると知っています... :)

匿名オブジェクトを渡すことができる2つのヘルパークラスを作成しました。 ProxyAnonymousObjectおよびProxyDynamicObject。最初のAppDomainにはProxyAnonymousObjectを作成し、もう1つのAppDomainにはProxyDynamicObjectを使用します。これはあなただけnew ProxyDynamicObject(model)に等しい目標dynamic objectを設定し、あなたのMarshalByRefObject継承したクラスで動作するように取得するには

[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; 
    } 
} 

を(これらのオブジェクトの両方が主AppDomainライブラリ内に存在します)。私が書いた例では、私はこのような呼び出しを行います。

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/それについてのブログ記事を書きました。 (これはあまりうまくいかないものですが)

この実装には間違いありません。ネストされた匿名タイプはサポートされていません。一般的に壊れることは間違いありません。しかし、それは間違いなくあなたを正しい軌道に乗せるためのものです。

関連する問題