L'ho implementato per un'API che restituisce solo JSON.
Per prima cosa ho creato due struct per (de) serializzare e interpretare il "campi" argomento Sintassi di query ricorsive:
FieldSelector
, che specifica un campo e, eventualmente, i suoi figli FieldSelection
racchiuso tra parentesi;
FieldsSelection
, che è un elenco separato da virgola di FieldSelector
.
Ho usato le strutture anziché le classi perché, AFAIK, non è possibile sovrascrivere la serializzazione (de) di classe da/per gli URL in ServiceStack. Con struct puoi farlo ignorando ToString
(serializzatore) e fornendo un costruttore che accetta una stringa come parametro (deserializzatore).
Poi si include questo su ogni DTO richiesta, che restituisce JSON:
FieldsSelection Fields { get; set; }
Su un costume ServiceRunner<T>.OnAfterExecute
si serializzare la risposta DTO a JSON, analizzarlo con ServiceStack.Text di JsonObject
e applicare la selezione campi in modo ricorsivo con un metodo come questo:
private static JsonObject Apply(this JsonObject json, FieldsSelection fieldMask)
{
IEnumerable<string> keysToRemove = json.Keys.ToList().Except(fieldMask.Keys);
foreach (var key in keysToRemove)
json.Remove(key);
foreach (var selector in fieldMask.Selectors.Values.Where(s => s.HasSubFieldsSelection))
{
var field = json[selector.Field];
if (field == null)
continue;
switch (field[0])
{
case '{':
json[selector.Field] = Apply(json.Object(selector.Field), selector.SubFieldsSelection).ToJson();
break;
case '[':
var itensArray = json.ArrayObjects(selector.Field);
for (int i = 0; i < itensArray.Count; i++)
itensArray[i] = Apply(itensArray[i], selector.SubFieldsSelection);
json[selector.Field] = itensArray.ToJson();
break;
default:
throw new ArgumentException("Selection incompatible with object structure");
}
}
return json;
}
Quindi si restituisce il risultato come risposta DTO. Ho anche implementato selettori di campi negativi (fields=-foo
seleziona tutti i campi DTO tranne foo), ma hai un'idea.
Ho preso in considerazione questo metodo e potrebbe essere l'unico modo possibile per farlo.Sembra che la doppia gestione cammini nell'albero delle proprietà impostando i campi che non si desidera tornare a null, perché il serializzatore sta nuovamente camminando nell'albero delle proprietà per generare la risposta json. – jmc
Esiste una proprietà di configurazione per controllare se i valori null vengono restituiti o meno. 'JsConfig.IncludeNullValues' – jmc
Sfortunatamente questo non funzionerà con i membri DTO con tipicità. – starteleport