Подтвердить что ты не робот

Веб-API и HTTP-модуль

У нас есть HTTP-модуль, который декодирует все закодированные запросы. Он отлично работает со всеми запросами WCF, но НЕ в запросах Web Api - в Web Api запрос (как POST, так и GET) попадает на еще закодированную службу

Я вижу, что он попадает в HTTP-модуль, но, опять же, добирается до шифрования сервиса. Как я могу это исправить? или что я делаю неправильно? я знаю, что лучше работать с обработчиками сообщений в веб-Api, но HTTP-модули, вероятно, тоже работают?

Модуль 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])));
    }
}
4b9b3361

Ответ 1

Кажется, что веб-API не использует коллекцию QueryString в запросе, но сам анализирует URL-адрес.

См. метод GetQueryNameValuePairs в этот файл - они берут Uri и анализируют его свойство Query.

Итак, у вас есть два варианта:

  • Грязный должен изменить Uri запроса в вашем HTTP-модуле. Я не знаю, возможно ли это, но какое-то отражение может сделать трюк.
  • Лучше всего использовать обработчик сообщений Web API.

Ответ 2

Могу ли я предложить вам использовать Context.Items и предоставить QueryString кодированную версию.

Это не очень известный встроенный словарь ключей/значений, который длится всюду по запросу, где вы легко храните любой объект, а затем делитесь им между модулем, обработчиками и т.д.

Использование этого очень похоже на лучшую производительность, чем разблокировка объекта QueryString, но что более важно, вы обрабатываете значение в одном месте и повторно используете его во многих, а при необходимости вы просто добавляете второе значение, полный QueryString коллекцию или любое другое значение, которое вы хотите разделить на запрос.

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

Боковое примечание. Я вижу, что вы дважды вызываете HttpContext.Current.Server.UrlDecode. Я не думаю, что вам это нужно, если ваш метод Base64Decode не закодирует значение снова.

Ответ 3

Вы можете справиться с этим

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

Ответ 4

Добавляя к ответу @Tomáš Herceg, я бы использовал обработчик сообщения Web Api, а не модифицировал ваш HttpModule для размещения веб-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);
        }
    }

Ответ 5

Возможно, но вам понадобится размышление, что означает, что здесь существует риск. Пожалуйста, позвольте мне предложить вам то, что я считаю более чистым решением после решения.

Решение

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

Этот обновит следующие свойства запроса:

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

но не обновит:

Request.RawUrl

Чистое решение

Модуль перезаписи URL-адресов IIS
http://www.iis.net/learn/extensions/url-rewrite-module/developing-a-custom-rewrite-provider-for-url-rewrite-module