Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web API and HTTP Module

We have an HTTP Module that decodes all encoded requests. It works great with all WCF requests, but NOT in Web Api requests- in Web Api the request (both POST and GET) gets to the service still encoded

I see that it Hits the HTTP Module but,again,still gets to the service encoded. How can i fix it? or what am i doing wrong? i know that its better to work with Message Handlers in Web Api, but HTTP Modules suppose to work too- no?

HTTP Module:

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])));
    }
}
like image 476
DasDas Avatar asked Feb 25 '16 10:02

DasDas


People also ask

What is HTTP module in Web API?

An HTTP module is an assembly that is called on every request to an application. It's a part of the HTTP request and response pipeline. Even the ASP.NET engine uses HttpModule to perform certain operations (which are outside our interests here).

What is HTTP handler and HTTP module in MVC?

To explain HTTP Modules and HTTP Handlers, HTTP module and HTTP handler are used by MVC to inject pre-processing logic in the request chain. HTTP Handlers are extension based pre-processor whereas HTTP Module are event based preprocessor.

Is HTTP a custom module?

This walkthrough illustrates the basic functionality of a custom HTTP module. An HTTP module is called on every request in response to the BeginRequest and EndRequest events. As a result, the module runs before and after a request is processed.

What is HTTP handler HTTP modules and middle ware?

HttpModules helps you to attach code specific to a application events. HttpModules are tied to System. web. Middleware are configured in Startup.cs code rather than web.config file (entry point for application) Unlike HttpModules, there is full control of what get's executed and in what order.


2 Answers

It seems that the Web API doesn't use the QueryString collection in the request, but it parses the URL itself.

See the GetQueryNameValuePairs method in this file - they take the Uri and parse its Query property.

So you have two options to do that:

  1. The dirty one is to change the Uri of the request in your the HTTP module. I don't know whether it's possible, but some reflection could do the trick.
  2. The nicer way would be to use the Web API message handler.
like image 174
Tomáš Herceg Avatar answered Sep 21 '22 18:09

Tomáš Herceg


May I suggest you use Context.Items and let the QueryString have the encoded version.

It's a not very well known built in key/value dictionary which last throughout a request where you easily store any object and then share it between module, handlers, etc.

Using this would very like give you a better performance than unlocking the QueryString object, but more importantly, you process the value in one place and reuse it in many, and when needed, you just add a second value, the complete QueryString collection or any other value you want to share across a request.

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

Side note: I see you call HttpContext.Current.Server.UrlDecode twice. I don't think you need that unless your Base64Decode method encode the value again.

like image 25
Asons Avatar answered Sep 19 '22 18:09

Asons