1

The classes in my data model implement an interface:

public class SomeType : ISomeInterface

public interface ISomeInterface

In my WCF query interceptors, I want to use a common Expression so that I can use the same filtering logic on multiple types:

[QueryInterceptor("SomeType")]
public Expression<Func<SomeType, bool>> SomeTypeInterceptor()
{
    // Return CommonFilter() or extend it with logic unique to SomeType
}

private Expression<Func<ISomeInterface, bool>> CommonFilter()
{
    // Use ISomeInterface methods and properties to build expression
    // ...
}

The problem is getting the Expression<Func<SomeType, bool>> to get along with the Expression<Func<ISomeInterface, bool>>.

Attempt #1

Just returning the common expression does not compile:

[QueryInterceptor("SomeType")]
public Expression<Func<SomeType, bool>> SomeTypeInterceptor()
{
    return CommonFilter();
}

with the error:

Cannot implicitly convert type System.Linq.Expressions.Expression<System.Func<ISomeInterface, bool>> to System.Linq.Expressions.Expression<System.Func<SomeType, bool>>

Attempt #2

Using the interface in the query interceptor definition:

[QueryInterceptor("SomeType")]
public Expression<Func<ISomeInterface, bool>> SomeTypeInterceptor()

compiles, but WCF does not like this, returning an error to the client:

Return type of method 'SomeTypeInterceptor' on type 'DataService' is of type System.Linq.Expressions.Expression<System.Func<ISomeInterface, System.Boolean>> but a type assignable to System.Linq.Expressions.Expression<System.Func<SomeType, System.Boolean>> is required for a query interceptor.

Attempt #3

Looking at the questions How can I cast an expression from type interface, to an specific type and C# How to convert an Expression<Func<SomeType>> to an Expression<Func<OtherType>>, I tried implementing this answer:

[QueryInterceptor("SomeType")]
public Expression<Func<SomeType, bool>> SomeTypeInterceptor()
{
    Expression<Func<SomeType, bool>> someTypeExpression =
        someType => CommonFilter().Compile().Invoke(someType);

    return someTypeExpression;
}

but now LINQ to Entities does not like this, returning an error:

LINQ to Entities does not recognize the method 'Boolean Invoke(ISomeInterface)' method, and this method cannot be translated into a store expression.


Is there a way to use common logic in WCF query interceptors?

Community
  • 1
  • 1
Aaroninus
  • 1,062
  • 2
  • 17
  • 35

1 Answers1

2

Make the CommonFilter method generic with required interface constraint on the generic type argument plus class constraint (needed by LINQ to Entities):

private Expression<Func<T, bool>> CommonFilter<T>()
    where T : class, ISomeInterface
{
    // Use ISomeInterface methods and properties to build expression
    // ...
}

Then use a slightly modified version of your Attempt #1 (which does compile):

[QueryInterceptor("SomeType")]
public Expression<Func<SomeType, bool>> SomeTypeInterceptor()
{
    return CommonFilter<SomeType>();
}
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343