2010-12-02 10 views
3

ビジネスオブジェクトを返すメソッドを公開するWCFサービスがあります。そのフードの下では、このようなインターフェイスのメソッドを使用しています素敵なリポジトリ層を持っていますwcfで述語をシリアライズ

IEnumerable<User> GetUsers(Func<User, bool> predicate); 

私が欲しいのであれば、私が行うことができます与えられた役割内のすべてのユーザー:

var plebs = GetUsers(u => u.Roles.Contains(plebRole)); 

は今、私はこれを公開しますWCFインターフェイス上での任意のフィルタリングが可能な思考。私は(比較的)シンプルな型を使いたいので、WCF APIは.Net以外のクライアントからアクセスできる必要があります。

私はプロパティ名を保持しているFilterオブジェクトを持っており、その値:

[DataContract] public class Filter { 
    [DataMember] public string Property { get; set; } 
    [DataMember] public string Value { get; set; } 
} 

だから今私はこのようなWCFのメソッドを公開することができます

IEnumerable<User> GetUsers(IEnumerable<Filter> filters); 

その後、私は上のベースの述語を構築することができます何が入ってくるのか、クライアントのフィルタで。今では厄介な取得します。

private static Expression<Func<T, bool>> GetPredicate<T>(Filter filter) 
{ 
    var knownPredicates = GetKnownPredicates<T>(filter.Value); 
    var t = typeof(T); 
    return knownPredicates.ContainsKey(t) && knownPredicates[t].ContainsKey(filter.Property) 
      ? knownPredicates[t][filter.Property] 
      : True<T>(); 
} 

private static Dictionary<Type, Dictionary<string, Expression<Func<T, bool>>>> GetKnownPredicates<T>(string value) 
{ 
    // ReSharper disable PossibleNullReferenceException 
    return new Dictionary<Type, Dictionary<string, Expression<Func<T, bool>>>> 
    { 
    { 
     typeof (User), new Dictionary<string, Expression<Func<T, bool>>> 
     { 
     { "Forename", x => (x as User).Forename == value }, 
     { "IsAdult", x => (x as User).IsAdult.ToString() == value }, 
     ... 
     } 
    }, 
    { 
     typeof (Group), new Dictionary<string, Expression<Func<T, bool>>> 
     { 
     { "Name", x => (x as Group).Name == value }, 
     ... 
     } 
    }, 
    ... 
    }; 
    // ReSharper restore PossibleNullReferenceException 
} 

私はGetKnownPredicates方法を書き始めまでは、コードは本当に臭いませんでした。今それはあります。どうすれば修正できますか?

答えて

2

スーパーファンシーにしたい場合は、System.Linq.Expressions.Expressionクラスを使用して、渡されたフィルタに基づいて述語を動的に構築できます。検索するタイプを知っているので、Filter.Propertyを使用してcreate a property expressionを使用し、次にFilter.Valueを使用して定数式を使用するだけです。それらを使って等式を作成し、あなたはフィニッシュラインの近くにいます。

表現の作成に慣れていると苦労することがありますが、デバッガは本当に役立ち、あなたが作成するときに式のコードが表示されますので、ぜひ試してみてください!

+0

もちろん、エンドユーザーがクラスのプロパティを照会できるようにしたくないため、セキュリティを考慮する必要があります。フィルタを作成する前にチェックするカスタムの「OK to Filter」属性を持つ属性を属性に設定することがあります。 –

+0

クール、これは私が探索したいルートです。私は、要求オブジェクトに認証トークンを持っているので、セキュリティを心配していません。要求を処理するかどうかを決定するメカニズムがあります。 – grenade

1

絶対にがありませんあなたはFunc<User, bool>を配線することができます。 この式は保存されており、ジッタを受けてクライアント側の世界に存在します。

基本的には、u => u.Roles.Contains(plebRole)を使用して匿名のクライアント側の関数をコンパイルすることを忘れないでください。したがって、後でクライアント側でフィルタリングする一部のユーザーを取得することになります。

+1

それは本当ですが、多くの場合、猫をスキンするいくつかの方法があります。私は文字通り述語を連載することを意味しません。私はすでに 'IEnumerable 'でそれを行っています。フィルタにプロパティを追加して、演算子や比較タイプのようなものを指定することができました。本当の問題は、すべての可能なプロパティと比較タイプ( 'StartsWith() 'や' user.Roles'などのコレクションを扱う)を指定せずにフィルタを述語に変換する方法です。 – grenade