Web API and HTTP Module

本文关键字:Module HTTP and API Web | 更新日期: 2023-09-27 18:36:05

我们有一个HTTP模块来解码所有编码的请求。它适用于所有WCF请求,但在Web Api请求中则不然 - 在Web Api中,请求(POST和GET)到达仍然编码的服务

我看到它命中 HTTP 模块,但仍然到达编码的服务。我该如何解决它?或者我做错了什么?我知道最好在 Web 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));
            }
        }
    }

网络功能:

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

网页接口:

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

Web API and HTTP Module

Web API 似乎没有在请求中使用 QueryString 集合,但它会分析 URL 本身。

请参阅此文件中的GetQueryNameValuePairs方法 - 它们获取 Uri 并分析其 Query 属性。

因此,您有两种选择:

  1. 肮脏的是在HTTP模块中更改请求的Uri。我不知道这是否可能,但一些反思可以解决问题。
  2. 更好的方法是使用 Web API 消息处理程序。

我建议你使用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));
    }
}

网页接口:

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方法再次对值进行编码。

你可以这样处理

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

除了@Tomáš Herceg的答案之外,我将实现一个Web Api消息处理程序,而不是修改HttpModule以适应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);
        }
    }

这是可能的,但你需要反思,这意味着这里存在风险。请让我向您建议我认为在解决方案之后更干净的解决方案。

溶液

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

更清洁的解决方案

IIS 网址重写模块
http://www.iis.net/learn/extensions/url-rewrite-module/developing-a-custom-rewrite-provider-for-url-rewrite-module