2016-12-16 4 views
1

J'ai un projet dans lequel je souhaite utiliser les attributs d'itinéraire avec un type personnalisé. Le code suivant dans lequel le type personnalisé est défini en tant que paramètre de requête fonctionne correctement et la page d'aide affiche le type personnalisé.ApiExplorer ne reconnaît pas les attributs d'itinéraire avec le type personnalisé

// GET api/values?5,6 
[Route("api/values")] 
public string Get(IntegerListParameter ids) 
{ 
    return "value"; 
} 

WebApi.HelpPage donne les documents suivants Help:Page

Si je change le code pour utiliser des attributs de route, le résultat est que je reçois une page d'aide vide.

// GET api/values/5,6 
[Route("api/values/{ids}")] 
public string Get(IntegerListParameter ids) 
{ 
    return "value"; 
} 

Quand j'inspecte le code que je constate dans HelpController.cs que ApiExplorer.ApiDescriptions retourne une collection vide de ApiDescriptions

public ActionResult Index() 
{ 
    ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider(); 
    Collection<ApiDescription> apiDescriptions = Configuration.Services.GetApiExplorer().ApiDescriptions; 

    return View(apiDescriptions); 
} 

Est-il possible d'obtenir ApiExplorer reconnaître ma IntegerListParameter de classe personnalisée comme attribut routage?

Répondre

0

Vous ne savez pas exactement quelle est la structure de données IntegerListParameter mais si vous devez envoyer une liste d'entiers délimités par des virgules dans la requête (par exemple ~api/products?ids=1,2,3,4), vous pouvez utiliser les attributs de filtre. Un exemple d'implémentation de ce qui peut être trouvé ici: Convert custom action filter for Web API use?

+0

J'ai implémenté séparés par des virgules liste des nombres entiers. Cela fonctionne bien comme paramètres de requête et comme routage d'attributs. –

+0

Mon problème est que l'helppage ne montre pas d'actions où la liste est un routage d'attribut. Le problème est que ApiExplorer.ApiDescriptions ne reconnaît pas l'action lorsque la liste est implémentée en tant que routage d'attribut. –

0

Vous devez:

  1. ajouter HttpParameterBinding pour votre marque IntegerListParameter Type
  2. la liaison comme IValueProviderParameterBinding et mettre en œuvre ValueProviderFactories
  3. ajouter un convertisseur pour IntegerListParameter et remplacer la méthode CanConvertFrom pour typeof(string) paramètre

Après ces actions, route avec le type personnalisé IntegerListParameter doit être reconnue dans ApiExplorer.

Voir mon exemple pour le type ObjectId:

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     //... 
     config.ParameterBindingRules.Insert(0, GetCustomParameterBinding); 
     TypeDescriptor.AddAttributes(typeof(ObjectId), new TypeConverterAttribute(typeof(ObjectIdConverter))); 
     //... 
    } 

    public static HttpParameterBinding GetCustomParameterBinding(HttpParameterDescriptor descriptor) 
    { 
     if (descriptor.ParameterType == typeof(ObjectId)) 
     { 
      return new ObjectIdParameterBinding(descriptor); 
     } 
     // any other types, let the default parameter binding handle 
     return null; 
    } 
} 

public class ObjectIdParameterBinding : HttpParameterBinding, IValueProviderParameterBinding 
{ 
    public ObjectIdParameterBinding(HttpParameterDescriptor desc) 
     : base(desc) 
    { 
    } 

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) 
    { 
     try 
     { 
      SetValue(actionContext, new ObjectId(actionContext.ControllerContext.RouteData.Values[Descriptor.ParameterName] as string)); 
      return Task.CompletedTask; 
     } 
     catch (FormatException) 
     { 
      throw new BadRequestException("Invalid id format"); 
     } 
    } 

    public IEnumerable<ValueProviderFactory> ValueProviderFactories { get; } = new[] { new QueryStringValueProviderFactory() }; 
} 

public class ObjectIdConverter : TypeConverter 
{ 
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
    { 
     if (sourceType == typeof(string)) 
      return true; 
     return base.CanConvertFrom(context, sourceType); 
    } 
}