7

Ho il seguente:Come dovrebbe funzionare un fornitore di raccoglitori modello API Web C#?

  • richiesta url: 'endpoint/1,2,3 q = foo?'
  • azione per cui la richiesta è legato: oggetto pubblico Bar ([ModelBinder] Lista < T> ids, [FromUri] stringa q)

voglio mappare il "1,2,3" frammento ai "id" parametro, così ho creato un ModelBinderProvider secondo il this link, che dovrebbe chiamare il corretto modello legante.

public class MyModelBinderProvider: ModelBinderProvider 
{ 
    public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType) 
    { 
     IModelBinder modelBinder = null; 

     if (modelType.IsGenericType && (modelType.GetGenericTypeDefinition() == typeof(List<>))) 
     { 
      modelBinder = new ListModelBinder(); 
     } 

     return modelBinder; 
    } 
} 

ho registrato il fornitore in Global.asax come questo:

GlobalConfiguration.Configuration.Services.Insert(typeof(ModelBinderProvider), 0, new MyModelBinderProvider()); 

Il motivo: Ho creato questo fornitore perché voglio, non importa quale T è ('1,2,3 'o' uno, due, tre '), il legame per lavorare.

Il problema: Diciamo che T è "int"; ogni volta che viene inviata una richiesta, il parametro 'modelType' è sempre 'int' e non quello che mi aspetto - 'List < int>', quindi la richiesta non è gestita correttamente.

La strana cosa: fare qualcosa di simile funziona, ma T è specializzata e per questo non quello che voglio:

var simpleProvider = new SimpleModelBinderProvider(typeof(List<int>), new ListModelBinder()); 
GlobalConfiguration.Configuration.Services.Insert(typeof(ModelBinderProvider), 0, simpleProvider); 

non riesco a vedere quello che sto facendo di sbagliato, perché è il parametro 'modelType' non il valore atteso?

+0

Si prega di elaborare perché si vuole fare questo? Qual è lo scenario attuale che ritieni utile? Come tale sembra davvero un trucco per qualcosa che potrebbe avere una soluzione più elaborata con un URI diverso del tutto. –

risposta

0

È una domanda molto vecchia ma ho riscontrato un problema simile qui con un codice legacy.

virgole sono riservati e dovrebbe essere evitato pur lavorando in alcuni casi, ma se si vuole veramente usarli ...

Credo che questo sia più un problema di percorso di un modello di legante una volta che il "1, 2,3 "è parte del percorso dell'URL. Assumendo questo ho scritto una piccola RouteHandler che fa il trucco (per favore perdona il semplicissimo traduttore "word to integer").

CsvRouteHandler ottiene l'array id dall'URL e lo inserisce in RouteData come una matrice di numeri interi. Se l'array originale ha parole come uno, due o tre, traduce ciascun valore in int.

MvcRouteHandler configurazione

protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext) 
{ 
    var idArrayParameter = requestContext.RouteData.Values["idArray"] != null ? requestContext.RouteData.Values["idArray"].ToString() : null; 
    if (string.IsNullOrEmpty(idArrayParameter)) 
    { 
     return base.GetHttpHandler(requestContext); 
    } 

    requestContext.RouteData.Values.Remove("idArray"); // remove the old array from routedata 

    // Note: it is horrible and bugged but and you probably have your own translation method :) 
    string[] idArray = idArrayParameter.Split(','); 
    int[] ids = new int[idArray.Length]; 

    for(int i = 0; i < idArray.Length; i++) 
    { 
     if (!int.TryParse(idArray[i], out ids[i])) 
     { 
      switch (idArray[i]) 
      { 
       case "one": 
        ids[i] = 1; 
        break; 
       case "two": 
        ids[i] = 2; 
        break; 
       case "three": 
        ids[i] = 3; 
        break; 
      } 
     } 
    } 

    requestContext.RouteData.Values.Add("Id", ids); 

    return base.GetHttpHandler(requestContext); 

} 
} 

Percorso:

routes.Add(
     name: "Id Array Route", 
     item: new Route(
      url: "endpoint/{idArray}", 
      defaults: new RouteValueDictionary(new { controller = "Test", action = "Index" }), 
      routeHandler: new CsvRouteHandler()) 
    );