I like C#. While I prefer languages like Perl and Python, I have to admit that C# is pretty cool. And, with Mono, I could even write nice, happy, FLOSS apps in it, if I like. But, I hate ASP.NET.
I am forced to use this abominable framework at work and today I was once again reminded of why I hate it so much. My biggest problem with it is that it seems to have been designed without any real thought put into what Web programming entails. I suppose it sounded like a great idea at the time to design a framework that mimicked desktop application development. But, the majority of the serious programming I have done in my life has in some way touched on the Web, either directly as a traditional Web application, or using Web-related protocols. I am a Web native and I don’t need my framework getting in my way all the time. Working within the Page model of ASP.NET feels like both my hands and feet have been shackled while I’m in the middle of a competitive sparing match. Today, I lost the fight.
On the plus side, I can dive into the HTTP Pipeline, which is nice. HTTPModules saved me when I was trying to create a big part of the next RMCP release. But, still, it wasn’t as easy as if I just used Python with Django or Ruby on Rails, or even, sometimes, straight up Perl CGI.pm! Today, I encountered a particularly nasty bug/feature of .NET 2.0 that has caused development of a simple implementation of an iTunes U login system grind to a screeching halt.
I have a form, lets call it Login.aspx, that iTunes U will redirect
users to when they try to access an iTunes U page that is not
public (i.e., requires you to be authenticated). So, their system
simply causes iTunes to launch the users browser and hands it a
URL with a simple query string like
http://mydomain.edu/Login.aspx?destination={$SomeITunesUrl}.
Simple, right? My Login.aspx page displays a Login form and in the
background will check LDAP to authenticate the user and then a custom
database to authorize the user and decide what specific iTunes U
credentials are assigned. Then, there is this whole iTunes U
authorization algorithm that I ported today from their Java example
that just builds a HTTP request with a special authorization token
that is sent to iTunes U and what I get back is a special HTML page
that I am supposed to forward back to the user’s browser, wherein the
user’s browser will open back up iTunes and, as if by magic, the user
will be logged into iTunes U.
The problem comes after I have the HTML page. How do I get
that page back to the user? You can’t do it from within a
regular ASPX page, as far as I can tell. Because of the way the
HTTP Pipeline processing works for ASPX pages, no matter what I
do, even if I directly mess with Application.Response within
the page, it will be overridden by the time the HTTP pipeline
event, OnEndRequest(), is called. So, what I want to do is just
redirect the request, after I have done the authentication and
authorization, to a custom HttpHandler that will do the actual
request to iTunes U and return the HTML to the user, since within
the handler, I can completely control the HTTP response sent
back to the client. Okay, still with me? Great.
The problem is that I need do the transfer to the handler while
passing it some context variables, specifically, information about
the user and the destination URL within iTunes U. So, I thought, hey,
that’s a perfect job for Server.Transfer()! WRONG! If you try
it, you get a nice error message that explains nothing.
Even though the documentation explicitly provides a method signature that would lead one to believe that you can transfer to a HttpHandler, you apparently, can’t. Well, at least not unless it is another Page handle. So, Microsoft says that this is by design, but then why have it in the documentation!
I wasted at least half of my day on this and now I am going to
need to figure out how to do this completely differently. I
think this Server.Transfer() “feature” should be considered a
bug. I could use Response.Redirect(), but that doesn’t help
me because I need to transfer context items and I can’t do that
with a redirect. I can’t pass the data as a query string because
then you’d be able to just see the query string params and
bypass the whole login form! I guess I could build some elaborate
system that encrypts my data as a string with a time stamp that is
decrypted by the handler, but I shouldn’t need to do something
like that for such a simple task.
Plain and simple: ASP.NET drives me crazy. There are just things that seem easy to do in other frameworks and languages, but force one to jump through incredible numbers of poorly documented hoops to do in ASP.NET. It is sucking the life out of me. Maybe v3.0/3.5 will help? I don’t even care. I’m so sick of ASP.NET and .NET in general, that I just want to dump the whole enterprise and I would, if only I could.
Oh well, maybe I’ll have better luck tomorrow. If anyone has
any ideas on a workaround to the Server.Transfer() with
HttpHandler problem, let me know. My frayed nerves would
appreciate it.
One Comment
I was looking for the answer to a different iTunes U problem I’m having when I found this post. I figured I would lend a helping hand.
In order to have ASP.NET display the response HTML that you get back from iTunes U directly to the user (browser), you have to change a few properties in the Page’s Response object. Here is an example.
public void Page_Load(object sender, EventArgs e) { string iTunesUHtml = InvokeITunesUAction(); // simplified function call
}
You can also setup a generic handler in ASP.NET 2.0 or later. I use this approach and have iTunes U refer to my iTunesU.ashx handler instead. With this approach, you verify if the user is already authenticated. If not, redirect them to a login page, which then redirects back to the handler after authenticating. Your handler can then lookup the necessary credentials and issue the request to iTunes U. Afterwards, you simply write out the HTML you get back from iTunes U. With a handler, you’ll just make sure to set context.Response.ContentType = “text/html”.
Either approach should work. If your Response.Write in the first example is not working with buffered output enabled, you may have some other HttpModule or HttpHandler installed that is messing with every single request (.aspx page).
Let me know if you need more info. and good luck!
-Matt
Post a Comment