2016-02-25 12 views
12

Abbiamo un modulo HTTP che decodifica tutte le richieste codificate. È perfettamente compatibile con tutte le richieste WCF, ma NON in requests- Api Web nel Api Web la richiesta (sia POST e GET) ottiene al servizio ancora codificatoModulo Web API e HTTP

vedo che colpisce il modulo HTTP, ma, ancora una volta , arriva ancora al servizio codificato. Come posso risolvere il problema? o cosa sto sbagliando? so che è meglio lavorare con i gestori di messaggi in Web Api, ma i moduli HTTP suppongono di funzionare troppo no? Modulo

HTTP:

public void Init(HttpApplication context) 
    { 
     context.BeginRequest += new EventHandler(context_BeginRequest); 
     context.EndRequest += context_PreSendRequestContent; 
    } 

    void context_PreSendRequestContent(object sender, EventArgs e) 
    { 
     string encodedQuerystring = HttpContext.Current.Request.QueryString.ToString(); 
     if (!string.IsNullOrEmpty(encodedQuerystring)) 
     { 
      System.Collections.Specialized.NameValueCollection col = new System.Collections.Specialized.NameValueCollection(); 
      col.Add("q", encodedQuerystring); 
      WebFunction.CreateQuerystring(HttpContext.Current, col); 
     } 


    } 

    void context_BeginRequest(object sender, EventArgs e) 
    { 
     string encodedQueryString = String.Empty; 
     if (HttpContext.Current.Request.QueryString.Count > 0 && HttpContext.Current.Request.QueryString["q"] != null) 
     { 

      object _p = HttpContext.Current.Request.QueryString; 
      encodedQueryString = HttpContext.Current.Server.UrlDecode(HttpContext.Current.Request.QueryString["q"].ToString()); 

      string originalQueryString = HttpContext.Current.Server.UrlDecode(WebFunction.Base64Decode(encodedQueryString)); 

      if (!string.IsNullOrEmpty(originalQueryString)) 
      { 
       WebFunction.CreateQuerystring(HttpContext.Current, WebFunction.ConvertQueryToCollection(originalQueryString)); 

      } 
     } 
    } 

WebFunction:

public static void CreateQuerystring(HttpContext context, System.Collections.Specialized.NameValueCollection nameValueCollection) 
    { 
     // reflect to readonly property 
      PropertyInfo isreadonly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic); 
      // make collection editable 
      isreadonly.SetValue(context.Request.QueryString, false, null); 
      context.Request.QueryString.Clear(); 
      context.Request.QueryString.Add(nameValueCollection);   
      // make collection readonly again 
      isreadonly.SetValue(context.Request.QueryString, true, null);    
    } 

Web Api:

public class NamesController : ApiController 
{ 
    [HttpGet] 
    [ActionName("GET_NAMES")] 
    public Drugs_ResponseData Get(string q) 
    { 
//need to add the decode function to get it to work 
     string[] arrAmpersant = Commonnn.DecodeFrom64(q).Split('&'); 

     Names_obj = new Names(); 
     return _obj.GetResult(Convert.ToInt32(Commonnn.GetValFromEqual(arrAmpersant[0]))); 
    } 
} 
+0

dove hai registrato il modulo http? Se ti sei registrato all'interno di '', il tuo pool di applicazioni deve essere eseguito in modalità integrata. –

+0

@KhanhTO è in e viene eseguito in modalità integrata. arriva al modulo HTTP ma viene comunque codificato nella richiesta. – DasDas

+0

Posso chiedere in quanti posti viene utilizzata la QuerString codificata per richiesta e quanti visitatori colpiscono la pagina all'ora? – LGSon

risposta

2

Sembra che l'API Web non utilizzi la raccolta QueryString nella richiesta, ma analizza l'URL stesso.

Vedere il metodo GetQueryNameValuePairs in this file - prendono l'Uri e analizzano la relativa proprietà di Query.

modo da avere due opzioni per farlo:

  1. Quella sporca è di cambiare l'Uri della richiesta nel modulo HTTP. Non so se sia possibile, ma qualche riflessione potrebbe fare il trucco.
  2. Il modo migliore sarebbe utilizzare il gestore di messaggi API Web.
+0

Sapete se c'è qualcosa di strutturale nella pipeline di richieste predefinite di IIS che impedirebbe a un POST con un corpo codificato di essere recapitato tramite DelegatingHandlers dell'applicazione? –

2

Posso suggerire di utilizzare Context.Items e lasciare che QueryString abbia la versione codificata.

E 'una non molto conosciuta costruita nel dizionario chiave/valore che durano tutta una richiesta in cui è facilmente memorizzare qualsiasi oggetto e poi condividerlo tra il modulo, i gestori, ecc

Utilizzando questo sarebbe molto simile vi darà un prestazioni migliori rispetto allo sblocco dell'oggetto QueryString, ma ancora più importante, il valore viene elaborato in un'unica posizione e riutilizzato in molti e, quando necessario, è sufficiente aggiungere un secondo valore, la raccolta QueryString completa o qualsiasi altro valore che si desidera condividere in un richiesta.

void context_BeginRequest(object sender, EventArgs e) 
{ 
    string encodedQueryString = String.Empty; 
    if (HttpContext.Current.Request.QueryString.Count > 0 && HttpContext.Current.Request.QueryString["q"] != null) 
    { 

     string encodedQueryString = HttpContext.Current.Server.UrlDecode(HttpContext.Current.Request.QueryString["q"].ToString()); 

     HttpContext.Current.Items("qs_d") = HttpContext.Current.Server.UrlDecode(WebFunction.Base64Decode(encodedQueryString)); 

    } 
} 

Web Api:

public class NamesController : ApiController 
{ 
    [HttpGet] 
    [ActionName("GET_NAMES")] 
    public Drugs_ResponseData Get(string q) 
    { 
    string[] arrAmpersant = Commonnn.DecodeFrom64(HttpContext.Current.Items("qs_d").ToString()).Split('&'); 

    Names_obj = new Names(); 
    return _obj.GetResult(Convert.ToInt32(Commonnn.GetValFromEqual(arrAmpersant[0]))); 
    } 
} 

Nota a margine: Vedo che chiami HttpContext.Current.Server.UrlDecode due volte. Non penso che sia necessario, a meno che il tuo metodo Base64Decode non codifichi nuovamente il valore.

1

È possibile gestire in questo modo

protected void Application_BeginRequest(object sender, EventArgs e) 
     { 
      var app = (HttpApplication)sender; 
      string path = app.Context.Request.Url.PathAndQuery; 
      int pos = path.IndexOf("?"); 
      if (pos > -1) 
      { 
       string[] array = path.Split('?'); 
       app.Context.RewritePath(array[0]+"?"+ HttpContext.Current.Server.UrlDecode(array[1])); 
      } 
     } 
0

E 'possibile, ma avrete bisogno di riflessione, ciò significa che esiste un rischio qui. Per favore, lascia che ti suggerisca quello che considero una soluzione più pulita dopo la soluzione.

Soluzione

if (!string.IsNullOrEmpty(originalQueryString)) 
{ 
    var request = HttpContext.Current.Request; 
    request.GetType().InvokeMember("QueryStringText", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, request, new[] { "q=" + originalQueryString }); 
    //WebFunction.CreateQuerystring(HttpContext.Current, WebFunction.ConvertQueryToCollection(originalQueryString)); 
} 

Questa aggiornerà le seguenti proprietà della Richiesta:

Request.Param 
Request.QueryString 
Request.ServerVariables 
Request.Url 

ma non aggiornerà il:

Request.RawUrl 

Cleaner Soluzione

URL Rewrite Module di IIS
http://www.iis.net/learn/extensions/url-rewrite-module/developing-a-custom-rewrite-provider-for-url-rewrite-module

+0

Questo sembrava un approccio interessante, anche se quando ho provato, la nuova stringa di query è ancora codificata? ... Suppongo o mi è mancato qualcosa qui, perché l'OP sta cercando una stringa di query decodificata. – LGSon

+0

I miei passaggi sono: 1 - Creata una soluzione WebAPI; 2 - Creato un modulo che ottiene que queryString "q", lo decodifica ed esegue il codice che ho postato qui. 3 - Modificato il ValuesController creato per ricevere un parametro stringa q e restituirlo. Prima di registrare il modulo, l'API restituisce la stringa codificata, dopo di che la stringa restituita viene decodificata. –

1

Aggiunta a @ risposta Tomáš Herceg s', vorrei implementare un gestore di messaggi Web Api, piuttosto che modificare il modulo Http per accogliere Api Web.

public class DecodeQueryStringMessageHandler : DelegatingHandler 
    { 
     protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, 
      CancellationToken cancellationToken) 
     { 
      if (request.Method == HttpMethod.Get) 
      { 
       var originalQueryString = request.RequestUri.Query; 
       if (!string.IsNullOrEmpty(originalQueryString)) 
       { 
        var ub = new UriBuilder(request.RequestUri) { Query = HttpUtility.UrlDecode(originalQueryString) }; 
        request.RequestUri = ub.Uri; 
       } 
      } 

      return base.SendAsync(request, cancellationToken); 
     } 
    }