2016-02-25 21 views
12

Mamy moduł HTTP, który dekoduje wszystkie zakodowane żądania. Działa świetnie z wszystkich żądań WCF, ale NIE w Web API requests- w Web API żądanie (zarówno POST i GET) dostaje się do służby nadal zakodowanyWeb API i moduł HTTP

widzę, że Odsłon modułu HTTP, ale znowu , nadal dostaje się do usługi zakodowanej. Jak mogę to naprawić? albo co robię źle? Wiem, że lepiej współpracować z Message Handlerami w Web Api, ale moduły HTTP również działają - nie? Moduł

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

gdzie zarejestrowałeś swój moduł http? Jeśli zarejestrowałeś się w '', twoja pula aplikacji musi działać w trybie zintegrowanym. –

+0

@KhanhTO jest w i działa w trybie zintegrowanym. trafia do modułu HTTP, ale nadal jest kodowany do żądania. – DasDas

+0

Czy mogę zapytać, w ilu miejscach jest używany zakodowany kwerenda na żądanie i ilu użytkowników trafia na stronę na godzinę? – LGSon

Odpowiedz

2

Wygląda na to, że interfejs Web API nie korzysta z kolekcji QueryString w żądaniu, ale analizuje sam adres URL.

Zobacz metodę GetQueryNameValuePairs w this file - pobierają one Uri i parsują właściwość Query.

Więc masz dwie opcje, aby to zrobić:

  1. Brudna jeden jest zmiana URI żądania w moduł HTTP. Nie wiem, czy to możliwe, ale niektóre refleksje mogą załatwić sprawę.
  2. Najprzyjemniejszym sposobem byłoby użycie funkcji obsługi komunikatów Web API.
+0

Czy wiesz, czy istnieje coś strukturalnego do domyślnego potoku żądania IIS, który uniemożliwiłby wysłanie POST z encodowanym ciałem za pośrednictwem aplikacji DelegatingHandlers mojej aplikacji? –

2

Może proponuję użyć Context.Items i pozwolić wersji QueryString na kodowanie.

To niezbyt dobrze znany zbudowany w słowniku klucz/wartość, która trwała przez cały wniosek, w którym łatwo przechowywać dowolny obiekt, a następnie podzielić ją między modułem, koparki itp

Stosując ten będzie bardzo podoba dać ci lepsza wydajność niż odblokowywanie obiektu QueryString, ale co ważniejsze, przetwarzasz wartość w jednym miejscu i ponownie ją używasz w wielu, a gdy zajdzie taka potrzeba, dodajesz tylko drugą wartość, kompletną kolekcję QueryString lub dowolną inną wartość, którą chcesz udostępnić żądanie.

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]))); 
    } 
} 

marginesie: Widzę zadzwonić HttpContext.Current.Server.UrlDecode dwukrotnie. Nie wydaje mi się, że tego potrzebujesz, chyba że twoja metoda Base64Decode ponownie zakoduje tę wartość.

1

można obsługiwać jak to

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

Jest to możliwe, ale trzeba będzie odbicie, co oznacza, że ​​istnieje ryzyko tutaj. Pozwolę sobie zaproponować to, co uważam za bardziej czyste rozwiązanie po rozwiązaniu.

Rozwiązanie

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)); 
} 

Ten zaktualizuje następujące właściwości żądanie:

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

ale nie zaktualizuje z:

Request.RawUrl 

Cleaner Rozwiązanie

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

+0

To wyglądało na interesujące podejście, ale kiedy próbowałem, nowy ciąg zapytania jest nadal zakodowany? ... Czy to jest coś takiego, czy też coś mi tu brakowało, ponieważ OP szuka rozszyfrowanego ciągu zapytań. – LGSon

+0

Moje kroki: 1 - Utworzono rozwiązanie WebAPI; 2 - Stworzono moduł, który pobiera que queryString "q", dekoduje go i uruchamia kod, który tu zamieściłem. 3 - Zmodyfikowano ValuesController, aby otrzymać parametr ciągu q i go zwrócić. Przed rejestracją modułu api zwraca kodowany ciąg, po czym zwracany łańcuch jest dekodowany. –

1

Dodawanie do @ odpowiedź Tomáš Herceg „s, chciałbym wdrożyć wiadomość obsługi Web API zamiast modyfikowania HttpModule pomieścić Web API.

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); 
     } 
    }