Ok, I'm not sure if there's a better way (because this seems like a lot of work for what seems like it would be a common use case), but here's how I solved this.
I inherited from the QueryHelper
class to modify the PostExecuteQuery
method to execute a delegate.
public class ExtendedQueryHelper : QueryHelper
{
public ExtendedQueryHelperOptions Options { get; set; }
public ExtendedQueryHelper(ODataQuerySettings querySettings) : base(querySettings)
{}
public override IEnumerable PostExecuteQuery(IEnumerable queryResult)
{
if (Options != null && Options.PostExecuteQueryHandler != null)
{
return Options.PostExecuteQueryHandler(queryResult);
}
return base.PostExecuteQuery(queryResult);
}
}
The delegate is defined in a class called ExtendedQueryHelperOptions
public class ExtendedQueryHelperOptions
{
private const string EXTENDED_QUERY_HELPER_OPTIONS_KEY = "EXTENDED_QUERY_HELPER_OPTIONS_KEY";
public delegate IEnumerable PostExecuteQueryDelegate(IEnumerable queryResult);
public PostExecuteQueryDelegate PostExecuteQueryHandler { get; set; }
public void InjectIntoRequest(HttpRequestMessage request)
{
request.Properties.Add(EXTENDED_QUERY_HELPER_OPTIONS_KEY, this);
}
public static ExtendedQueryHelperOptions GetFromRequest(HttpRequestMessage request)
{
object options;
request.Properties.TryGetValue(EXTENDED_QUERY_HELPER_OPTIONS_KEY, out options);
return (ExtendedQueryHelperOptions)options;
}
}
In order to set these options, I had to inherit from BreezeQueryableAttribute
and inject these options when the QueryHelper
is being created:
public class ExtendedBreezeQueryableAttribute : BreezeQueryableAttribute
{
protected HttpRequestMessage Request { get; set; }
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
Request = actionContext.Request;
base.OnActionExecuting(actionContext);
}
protected override QueryHelper NewQueryHelper()
{
var queryHelper = new ExtendedQueryHelper(GetODataQuerySettings());
queryHelper.Options = ExtendedQueryHelperOptions.GetFromRequest(Request);
return queryHelper;
}
}
Now I can inject code to be run on the filtered results like this:
[BreezeController]
public class BreezeController : BaseController
{
//...
[HttpGet]
[ExtendedBreezeQueryable]
public IQueryable<Foo> Foos()
{
var options = new ExtendedQueryHelperOptions
{
PostExecuteQueryHandler = delegate(IEnumerable results) {
// This code will be run after the querying has been
// applied by Breeze
var foos = results.Cast<Foo>().ToList();
foreach (var foo in foos)
{
foo.ComputedProperty = ComputeSomething();
}
return foos;
}
};
// Inject these options into the Request, so the ExtendedBreezeQueryableAttribute
// can get to them later
options.InjectIntoRequest(Request);
return Db.Foos;
}
}