4 pagine in totale: <<Indietro 1 2 [3] 4 Avanti >>
Query context ed expression tree parsing
Siamo giunti al punto cruciale. Nel metodo Execute del query context, i parametri della query LINQ sono estratti e convertiti in parametri per la chiamata al web service.
Per fare questo, occorre prima di tutto identificare la clausola where più interna non ancora valutata (nel caso ci si trovi ad avere delle query LINQ annidate). Successivamente, si deve passare la lambda expression, che rappresenta il predicato passato in questa clausola where, ad un partial evaluator, in modo che tutte le variabili locali siano sostituite da valori.
InnermostWhereFinder whereFinder = new InnermostWhereFinder();
MethodCallExpression whereExpression = whereFinder.GetInnermostWhere(expression);
LambdaExpression lambdaExpression = (LambdaExpression)((UnaryExpression)(whereExpression.Arguments[1])).Operand;Nonostante questa operazione possa sembrare estremamente complicata, è in realtà piuttosto semplice se si usano le classi di helper class dall'Expression Visitor (che si può trovare qui). L'InnermostWhereFinder non fa altro che fare l'override del visit del metodo where in modo ricorsivo, ritornando quindi il più interno.
internal class InnermostWhereFinder : ExpressionVisitor
{
private MethodCallExpression innermostWhereExpression;
public MethodCallExpression GetInnermostWhere(Expression expression)
{
Visit(expression);
return innermostWhereExpression;
}
protected override Expression VisitMethodCall(MethodCallExpression expression)
{
if (expression.Method.Name == "Where")
innermostWhereExpression = expression;
Visit(expression.Arguments[0]);
return expression;
}
}A questo punto passeremo la lambda expression ad una funzione che estrarrà i parametri necessari a chiamare il nostro web service attraverso un altro ExpressionVisitor personalizzato. In questo caso, dobbiamo estrarre dalla clausola where i predicati per CultureInfo, SourceType e QueryTerms. Per fare questo, basta fare l'override del metodo che fa il parsing di espressioni binarie e agire sulle espressioni del tipo SourceType=A && QueryTerms=B && CultureInfo=it-it:
struct QueryCriteria
{
public string queryTerm;
public string sourceSearch;
public string cultureInfo;
}
internal class SearchCriteriaFinder : ExpressionVisitor
{
private Expression expression;
private List<QueryCriteria> queryConditions;
public List<QueryCriteria> QueryCriterias
{
get
{
if (queryConditions == null)
{
queryConditions = new List<QueryCriteria>();
this.Visit(this.expression);
}
return this.queryConditions;
}
}
protected override Expression VisitBinary(BinaryExpression be)
{
if (be.NodeType == ExpressionType.Equal)
{
if (ExpressionTreeHelpers.IsMemberEqualsValueExpression(be,
typeof(LinqSearchObject), "QueryTerm"))
{
string value =
ExpressionTreeHelpers.GetValueFromEqualsExpression(be,
typeof(LinqSearchObject), "QueryTerm");
QueryCriteria criteria = new QueryCriteria();
criteria.queryTerm = value;
criteria.sourceSearch = "web";
queryConditions.Add(criteria);
return be;
}
else
return base.VisitBinary(be);
}
if (be.NodeType == ExpressionType.AndAlso)
{
if (ExpressionTreeHelpers.IsMemberEqualsAndAlsoExpression(be,
typeof(LinqSearchObject)))
{
QueryCriteria criteria =
ExpressionTreeHelpers.GetValueFromAndAlsoExpression(be,
typeof(LinqSearchObject), "QueryTerm", "SourceSearch",
"CultureInfo");
queryConditions.Add(criteria);
return be;
}
else
return base.VisitBinary(be);
}
else
return base.VisitBinary(be);
}
}Fatto questo, chiameremo il web service attraverso una helper class che incapsula completamente l'operazione (la analizzeremo in un attimo).
L'IEnumerable ottenuto sarà ora convertito in un IQueryable con una chiamata a AsQueriable<LiveSearchResult>. Questa chiamata avrà come risultato il popolamento dell'expression tree con i risulatati della query più interna (necessario nel caso di query annidate).
Se siete sopravvissuti fino a qui, avete conquistato LINQ. Da qui in poi definiremo i dettagli di questa implementazione particolare, ma la parte più ostica è passata.
Chiamare Live Search
A questo punto il codice che effettua la chiamata al web service è banale. Una volta creata la web service reference all'oggetto MSNSearchPortTypeClient, si può creare il proxy del servizio.
MSNSearchPortTypeClient client = new MSNSearchPortTypeClient();
client.Open();
SearchResponse searchResponse = null;Una volta popolate le proprietà dell'oggetto SearchRequest con i valori estratti dall'expression tree, si deve chiamare il servizio con client.Search(searchRequest).
searchResponse = client.Search(searchRequest);La logica rimanente non deve fare altro che estrarre dall'oggetto searchResponse i valori da ritornare nell'IEnumerable di LiveSearchResult che rappresenta il valore di ritorno da passare al query context.
4 pagine in totale: <<Indietro 1 2 [3] 4 Avanti >>
Contenuti dell'articolo
- Pagina 1
- Pagina 2
- Pagina 3
- Pagina 4
Aggiungi un nuovo commento »»»
Per inserire un commento, devi registrarti alla nostra community.





Difficoltà

Stampa
Download 



