2012-08-31 15 views
5

Ho il seguente controller API:MVC Api Action e System.Web.Http.AuthorizeAttribute - Come ottenere i parametri del post?

public class TestController : ApiController 
{ 
    [HttpPost] 
    [APIAuthorizeAttribute] 
    public IQueryable<Computers> ListOfComputersInFolder(Guid folderId) 
    { 
     return GetListOfComputersForFolder(folderId); 
    } // End of ListOfComputersInFolder 
} // End of TestController 

E la seguente è la mia base APIAuthorizeAttribute.

public class APIAuthorizeAttribute : System.Web.Http.AuthorizeAttribute 
{ 
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext) 
    { 
     var Request = System.Web.HttpContext.Current.Request; 
     var folderId = Request.RequestContext.RouteData.Values["folderId"] ?? Request.Params["folderId] as string; 
     if(null == folderId) 
     { 
      folderId = actionContext.ControllerContext.RouteData.Values["folderId"]; 
     } 

     base.OnAuthorization(actionContext); 
    } 
} 

Il problema che sto avendo è che folderId è venuta fuori nulla nel metodo onAuthorize. (Ho basato il fetcher sul codice this).

Mi sembra che questo dovrebbe essere di lavoro, ma io non riesco a farlo. Qualche idea su cosa sto facendo male e come dovrei fare per ottenere il parametro postato?

Edit: Ho provato a leggere i dati di post direttamente con il seguente:

using (StreamReader inputStream = new StreamReader(request.InputStream)) 
{ 
    output = inputStream.ReadToEnd(); 
} 
request.InputStream.Position = 0; 

Il che mi ottiene i dati post in formato JSON, che ho potuto quindi analizzare, ma poi la mia chiamata non rende però. Ottengo la seguente eccezione nella risposta:

<h2>500 - Internal server error.</h2> 
    <h3>There is a problem with the resource you are looking for, and it cannot be displayed. 

at System.Json.JXmlToJsonValueConverter.JXMLToJsonValue(Stream jsonStream, Byte[] jsonBytes)\u000d\u000a at System.Net.Http.Formatting.JsonMediaTypeFormatter.<>c__DisplayClass7.<OnReadFromStreamAsync>b__6()\u000d\u000a at System.Net.Http.Internal.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)"} 

EDIT: Alla fine, sembra che questo potrebbe essere un bug con la combinazione di ApiController, System.Web.Http.AuthorizeAttribute e HttpPost (funziona quando si utilizza HttpGet). È stata presentata una segnalazione di errore.

risposta

7

Il AuthorizeAttribute dovrebbe avere un parametro di AuthorizationContext piuttosto che un HttpActionContext uno, dal che si dovrebbe essere in grado di accedere al RouteData esempio

public override void OnAuthorization(AuthorizationContext filterContext) 
{ 
    var folderId = filterContext.RouteData.Values["folderId"]; 
    ... 
} 

Aggiornamento

notato che utilizza ApiController e come tale utilizzando Http.AuthorizeAttribute (spiega perché non si dispone di un AuthorizationContext). In tal caso, è possibile ottenere il RouteData tramite il contesto dell'azione, ad es.

var folderId = actionContext.Request.GetRouteData().Values["folderId"]; 
+3

noti che perché questo è un [APIController] (http://msdn.microsoft.com/en-us/library/system.web.http.apicontroller(v=vs.108).aspx) e non un [controller] (http://msdn.microsoft.com /en-us/library/system.web.mvc.controller(v=vs.108) Aspx), io uso il 'System.Web.Http.AuthorizeAttribute' e non il' System.Web.Mvc.AuthorizeAttribute'. Ho provato ad accedere a 'ControllerContext.RouteData.Values ​​[" folderId "] e ancora restituito null. – Kyle

+0

@Zenox vedere la mia risposta aggiornata. – James

+0

grazie Ho dato un'occhiata anche a questo, ma ancora senza fortuna. La classe 'actionContext.Request' è un [HttpRequestMessage] (http://msdn.microsoft.com/en-us/library/system.net.http.httprequestmessage_methods) e non contiene un metodo' GetRouteData'. Inoltre se guardo: actionContext.ControllerContext.RouteData.Values ​​contiene solo due chiavi: controller e azione. Penso che la mia migliore scelta di azione sarebbe quella di leggere i dati dei post da inputStream. Ho fatto una prova e ho confermato che posso vedere i miei dati postati, ma sembra un po 'hacky, quindi continuerò a cercare ora. – Kyle

0

È possibile dare a questo metodo di estensione una prova: (questo è un estratto di codice funzionante)

public static string GetParameter(this RequestContext requestContext, string key) 
{ 
    if (key == null) throw new ArgumentNullException("key"); 

    var lowKey = key.ToLower(); 

    return requestContext.RouteData.Values.ContainsKey(lowKey) && 
      requestContext.RouteData.Values[lowKey] != null 
       ? requestContext.RouteData.Values[lowKey].ToString() 
       : requestContext.HttpContext.Request.Params[lowKey]; 
} 

Sono d'accordo con la risposta di James', è necessario accedere al contesto di richiesta tramite l'actionContext in questo scenario.

1

Ho anche riscontrato questo problema.

Per ovviare a ciò ho scritto il seguente metodo che io chiamo dall'interno del metodo OnAuthorization:

private static object GetValueFromActionContext(HttpActionContext actionContext, string key) 
{ 
    var queryNameValuePairs = actionContext.Request.GetQueryNameValuePairs(); 

    var value = queryNameValuePairs 
     .Where(pair => pair.Key.Equals(key, StringComparison.OrdinalIgnoreCase)) 
     .Select(pair => pair.Value) 
     .FirstOrDefault(); 

    var methodInfo = ((ReflectedHttpActionDescriptor) (actionContext.ActionDescriptor)).MethodInfo; 
    var parameters = methodInfo.GetParameters(); 
    var parameterType = 
     parameters.Single(p => p.Name.Equals(key, StringComparison.OrdinalIgnoreCase)).ParameterType; 

    var converter = TypeDescriptor.GetConverter(parameterType); 

    return converter.ConvertFromString(value); 
} 

Questo codice rende le seguenti ipotesi:

  • La chiave si estraggono corrisponde a un nome dell'argomento sul metodo di azione.

  • Il tipo di parametro che si sta ottenendo avrà un convertitore valido per il tipo.

  • Non utilizza qualsiasi associazione personalizzata o la formattazione sul parametro.

Nello scenario che sto usando il codice che sto solo aspettando tipi semplici come Guid, Boolean, String ecc e hanno potuto essere adattati secondo le vostre esigenze.

Il metodo GetQueryNameValuePairs estensione è parte della classe System.Net.Http.HttpRequestMessageExtensions e leggerà dati querystring/modulo.

uso Esempio:

object folderId = GetValueFromActionContext(actionContext, "folderId"); 
0

Se contenttype della richiesta è application/json;charset=utf-8

L'azione API in grado di recuperare i dati POST come segue:

Stream stream = actionContext.Request.Content.ReadAsStreamAsync().Result; 
Encoding encoding = Encoding.UTF8; 
stream.Position = 0; 
string responseData = ""; 

using (StreamReader reader = new StreamReader(stream, encoding)) 
{ 
    responseData = reader.ReadToEnd().ToString(); 
} 

var dic = JsonConvert.DeserializeObject<IDictionary<string, string>>(responseData); 
Problemi correlati