May 29, 2012

doPostBack() saves the day

In its recent versions of ASP.NET Microsoft advises shift to MVC application model.
It is currently its flagship. 
Old classic webforms event driven model obviously want be given to much consideration in future.

But for us regular guys there will still be plenty of legacy code out there written in that old event driven model.
One of often obstacles for anyone starting to use ASP.NET webforms model it is concept of POSTBACK.
People coming from different web background like PHP, JAVA etc. are astounded with this term because it has nothing to do with standard HTTP model.

Anyway, many of us working with complex event driven controls like Telerik gridview and etc. sooner or later stumbled on this event system when we did not had legit ways to "talk" to backend and just POST it simple data.

Ok, one should always put effort to find legit way through given control event model or props to pass certain value(s) to backend.
But, I guess you've been there when you are pushing deadlines and you have to deliver.
Well sometimes you have to cross the line and start writing dirty. 

After 5 years I'm still learning so recently I've discovered doPostBack().

You need to push something using full page reload and tell the backend that it came from specific control which on top of it sends some value and you don't have faintness idea how to do it with given set of asp.net controls

Here is what you could consider as workaround: 


__doPostBack(postbackcontrolid,id)



;This will result in full page reload and then in PageLoad event you can handle action to be taken like this:

VB.NET


If Request.Params("__EVENTTARGET") = "imgDeleteWeitere" Then

            Dim id As Long

            If Long.TryParse(Request.Params("__EVENTARGUMENT"), id) = True Then


Watch it !  Compiler can't save you from typos in postbackcontrolid. Some articles also point out that it is not certain that in every scenario doPostBack will fill these params.

So if you use it thoroughly test and soon as possible replace with proper control driven solution...



May 16, 2012

Making HTTPS POST using webrequest with cookie handling

A bit intro in beginning...
My credit card company is a bit lazy. In this age of IT revolution its normal to receive info and not to ask for it. In order to get my credit card account balance I need to access my online account.
This sucks.
I wanted to receive my credit card balance in email on a regular timely base. But credit card company does not allow for this. It's not like they want me to be aware of it :)

Challenge was how to do POST from windows service on HTTPS url.
Simple sniffing of POST from browser got me details for POST data.
After a bit of google-ing I came up with this.
You know that stupid feeling when you write a bit complex stuff and it works on a first try.

One must admire guys from Microsoft in doing good job.
Observe what complexity is hidden in just few lines - negotiating HTTPS protocol, handling in and out of cookies.

Cool...

Here is the code that makes actual HTTPS POST:


   var postData = "j_username=xxxxxx&j_password=xxxxxx&Submit=continue";
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] postByteArray = encoding.GetBytes(postData);

            var response = new List();
            Uri myuri = new Uri(MYURL);
   
   var cookieContainer = new CookieContainer();

   //.NET client to accept all certificates
            ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);
        
            HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(myuri);
            webRequest.CookieContainer = cookieContainer;
            webRequest.Method = "POST";
            webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.ContentLength = postByteArray.Length;
            var requestStream = webRequest.GetRequestStream();
            requestStream.Write(postByteArray, 0, postByteArray.Length);
            requestStream.Close();
            
            HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
            
            using (Stream resStream = webResponse.GetResponseStream())
            {
                StreamReader reader = new StreamReader(resStream);
                string resline = "";
                while (resline != null)
                {
                    resline = reader.ReadLine();
                    response.Add(resline);
                }
                reader.Close();
                resStream.Close();
            }
            return response.ToArray();

May 8, 2012

ASP.NET web api - multiple get does not work ?

So you've read and seen all there is on asp.net/webapi and your webapi service is running smoothly.
You follow rest and design guidelines of WEBAPI and place one GET, POST and all HTTP verbs.
Everything works, great cool.
For example in your CustomersController you have simple and single GET action which works just fine:
public string Get()  { 
return "Coolest customer controller";
 ; on url:   http://localhost/api/customers/get
and then you casually add another GET action:

public string Get(string what){
return "I'll be back";
}
And you run into problems:

404 - File or directory not found.



What a hack ?!

Ok, so you comment second Get and it works again. Aha!
But if you comment first Get and leave second it still works?
Actually if you step way back to your scenario with one GET and change action name like this:

public string GetDummy() {
thing still works on same url !

http://localhost/api/customers/get

What a  ... ?
You fervently start playing with different action names and it always works ?!
Now wait a sec... If you haven't played too much with MVC concept and you come from clean ASP.NET webforms arena you are by now probably in major piss of  state :)

Solution to your problem is tweaking routing engine. WEB API as HTTP skeleton of WCF is build on top of ASP.NET MVC and it uses its routing engine.

Catch is that guys from WEB API did not mean that average dude should have this basic routing setup out of the box in your WEB API template.

So go ahead and do it your self.
In your Global.asax.cs observe this part:


routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );


; and tweak route so it accepts your action name like this:


routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );


Now everything should work fine ...