Web Forms are killing me
I would preface by saying that I am using Web Forms at my current project because the client insisted. They are paying, they get to make the decisions, end of story.
This is a rant, plain and simple. I don't do those often, but I have too much annoyances lately to not do it.
I have several years of working with Web Forms, in projects of various sizes, I have committed my Sins Against the GridView, and have memorized the page lifecycle, I have walked the path of Page.ProcessRequest, and learnt at a distant monastery about the mysteries of the ViewState, I have studied the intricate play of control's events and the secrets of Data Binding.
I get Web Forms. I know how they work.
I have detailed elsewhere what I don't like about WebForms (trying to be stateful, complex, lying, etc). Today it had gotten to the point when I have given up on trying anymore. This was after we have been hitting, repeatedly, obstacle after obstacle with using Web Forms.
Today we had no less than three such incidents, all of them related to various intricate ways that the whole messy pipeline is working together to create a results that is more complex than the sum of all its parts and the legacy systems on the next door. Today was far from being an exception.
We didn't even try to do anything complex. Take a bunch of objects, bind them to a GridView, rinse-repeat. There was a set of pages that were almost literally forms over data, exactly the use case for WebForms, or so I have thought. In a set of about a dozen pages, with really minor differences between one another, we had at least one serious problem at each page. Invariably it was related to some weird way WebForms expected me to work.
In order to get the data from the request, I need to bind the data again in page load, and in a later event, I need to process it, after the Web Forms engine had magically filled the values from the request. And woe upon you if you dare to mix a data source with a call to this.DataBind(); for you are heretic and deserve to lose the user's input without warning, and only by the grace of the good lord will you be saved.
At one point today I resorted to an http handler and a set of calls to Response.Writer(), because that was easier than trying to get the functionality from the WebForms engine.
At this point, I feel like I am trying to build on top of a house of cards, with the slightest movement will send everything crumbling down. I found a bug that was totally my fault today, and we had about five minutes of hilarity about finally finding something that we could easily fix. While this is a very instructive in terms of knowing how the internals of the WebForms engine works, it is a complete waste of time otherwise. When I need to be absolutely aware, at all times, about all the implications of what is going on all around me, I can't really do anything at all.
I have learned my lessons from past projects, thou shall not try to be smart with the WebForms framework, it will be smart right back at you and bit you in the ass. I am not trying to do anything smart here. I am literally scaling down everything that I do on the UI layer to the set of what is wholly approved and blessed by Microsoft. I am not even trying to workaround technical limitation, I am just trying to build working software.
At this point, I am more willing to debug Dynamic Proxy's IL generation engine than my pages, because at least with Dynamic Proxy, I have some control over what is going on, hard as it may be. The WebForms engine gives the illusion of control, but it does things in completely arbitrary ways, contrary to the principal of least surprised and common sense.
I am sick of it.
Comments
"thou shall not try to be smart with the WebForms framework"
Will be quoted on my blog.
Ayende,
I agree with your opinion on some things, disagree on others, but what you have said:
"I get Web Forms. I know how they work."
I think it isn't true. When I read this post from you a couple of months ago:
http://www.ayende.com/Blog/archive/2007/03/20/WebForms-and-lies.aspx
It was clear to me that you haven't mastered Web Forms. Paul Wilson's comments were incredibly right and to the point.
Some things of the Web Forms model can be complex and hard to get on the first time you found some errors or quirks, but after you overcome them, it is easy to work with web forms. Maybe you'll need to take a couple of hours using Reflector to understand the most obscure problems, but that is knowledge you gain to avoide future problems.
I don't know if it is because that is a Microsoft idea, or because you can't debug through the source code while using it, or because you don't have the control to change the code but I think you don't put enough effort on your side to work with web forms. If you like monorail more, good for you. Work with it.
As a developer, it is really easy to say: This doesn't work. A lot of times, the real reason is because of lack of knowledge rather than a real problem with the framework. This happens a lot in web forms.
Ayende,
I feel your pain and I think I know how to help avoid further pain. First it sounds like you are setting the DataSource on your GridViews and calling DataBind programatically. This is done commonly but does introduce many of your headaches. Instead you can set the GridView to use an ObjectDataSource which you simply point to a class and method which returns a collection of your objects. It could be a DataSet or a List<MyObject>. You can then declare the bindings.
<asp:TextBox ID="TextBox1" runat="server"
Notice the use of single quotes on the attribute while the Bind call references the name of a property on your object (or DataTable column name) with double quotes. If you have a custom business object you can define this property for any field, even a calculated field.
From here things should be much easier. When the GridView wants data it will use the ObjectDataSource to go get it. To support paging and sorting you need to implement a method signature for all scenarios. At the end of this comment I will paste in a code snippet to get a subset of users. The maximumRows and startRowIndex parameters are the important ones. You may find more details on MSDN.
You can also set the input parameters to the method defined by the ObjectDataSource. Fritz Onion has a useful post on the topic.
http://pluralsight.com/blogs/fritz/archive/2006/01/16/18054.aspx
Drop me an email and I can send you the full source code for the example below which is a part of a set of user controls used to manage users with the Membership Provider.
public MembershipUserCollection GetAllUsers(
{
}
@Manuel,
I feel differently, the post you quoted is not a cry for help, it a cry about the violation of the principal of least surprise.
I have a good understanding on how the WebForms machinery works, if after several years of working with it, it still manages to surprise me on the common path, requiring me to sit back and figure out what is going on that is a problem.
I can do that, but it shouldn't be the case.
@Brennan,
Thanks, I am already using the ODS for some things, it is cumbersome to use, and there are cases where I need to have control over what/ when I do databinding, in which case it caused me to tread really carefully.
First, let me preface my comment by saying that I'm a junior developer. I've been working in "The Real World" for two years.
My first year was a job with web development in PHP, and slowly I made my way from spaghetti PHP to using an MVC framework. I realized that it was perfectly possible to write clean, well-separated code in PHP with some discipline, and it was still straight forward to explain: the file is processed from top to bottom, and what's got an 'echo' or outside of <?php ?> marks is output to the browser. Input is in the $_GET and $_POST arrays. Combined with my own simple ActiveRecord implementation for PHP, Web development was just easy peasy.
In my spare time, I played with Ruby on Rails and tinkered (but never seriously developed with) Helma (server-side Javascript, IIRC) and Seaside (used continuations; really neat stuff). These are all vastly different approaches to Web development than naked PHP -- but I could still grok them after a few weeks of reading online documentation.
Then I spent a year leaving Web development, instead hacking on a large Windows Forms application. I was introduced to n-tier architectures, GDI+, and all sorts of fun things about Windows development on the .NET framework. I played with Enterprise Library. I explored CAB and its SmartParts and EventBrokers and learned a lot, and saw first hand the problems that it solves. I don't think any of these things were especially simple, but they are not impossibly complex. It was a nice diversion.
Then it came time to return Web development. I started working for a client who was managing an application built on ASP.NET using WebForms. "WebDev wasn't so bad," I thought. "I could get back into that." So I did the first thing I do when learning a new technology; I find a book on it and read it.
The first discomforting itch was that the book I purchased was a 1,500 page tome. "Really, 1,500 pages?!" I thought. "For a Web framework?" Then I read about the Page Controller pattern, and I began thinking about how that threw a wrench into my tried-and-true front controller development pattern. Then I started looking into databinding, the awkward magic between aspx pages and their code-behind files, the viewstate, and then dealing with horribly bad, non-semantic markup that half of the built in controls produce. Then I asked myself why am I using a static language to build a front end for a paradigm that deals with strings? I discovered how databinding makes formatting simple things annoying -- logic like "print A if the value is between 1-3 or B if the value is anything else". Databinding seemed to work well in the silly stupid examples, but my objects never seem to have my data exactly right for formatting. Do I really have to pollute the page controller with all of this formatting crap?
Then I started to play with Monorail, and it was like walking out of a drunken hangover fog. It was like a throwback to my days of clean PHP--after all, the Web is GET, POST, and outputting strings to a browser. How complicated could we possibly make this? It is not a difficult problem.
WebForms, a framework that doesn't even give you explicit control over the exact HTML to the browser (unless you want to rewrite a lot of stuff and have a LOT of discipline), seems completely insane to me. Completely and utterly insane. I can see its values for corporate intranets where you just want to hack a form together, but if you're moving beyond forms -- no.
I don't know if it's because of my incompetence or immaturity as a developer, I don't know if it's because I started with Web development before Windows development and not the other way round, but with WebForms I find that "grokking" the framework and all of its moving parts is just ... just ...
... a waste of time.
Just my two cents. Thanks for listening. =)
Ayende,
Stop wasting time on blog and get back to work! :P
The point is there are people who likes WebForms, Tapestry, etc. I geniuely think MR/RoR approach is better, ASP.NET/Tapestry OOed way have some good favour for people who love extreme encapsulation (with trade of flexibility), to me ASP/PHP are bad due to lack of real OO supports (PHP latest implementation might have put some light there, but again I am not sure on this one)
So, maybe its just your favour, not that you don't know them enough, but its too troublesome to get around if you always try to do things not designed in ASP.NET ways. I found that you have to somehow give up the way you want to do it and instead try to adopt a more Windows Form alike model to make it work easier.
And finally, yes, Object Data Source sucks. I tried working with it and always wonder why people ever imagine to use such approach. It's a very sick way to add up necessary middleware, especially if you try to do a stateless web page.
Ayende,
Stop wasting time on blog and get back to work! :P
The point is there are people who likes WebForms, Tapestry, etc. I geniuely think MR/RoR approach is better, ASP.NET/Tapestry OOed way have some good favour for people who love extreme encapsulation (with trade of flexibility), to me ASP/PHP are bad due to lack of real OO supports (PHP latest implementation might have put some light there, but again I am not sure on this one)
So, maybe its just your favour, not that you don't know them enough, but its too troublesome to get around if you always try to do things not designed in ASP.NET ways. I found that you have to somehow give up the way you want to do it and instead try to adopt a more Windows Form alike model to make it work easier.
And finally, yes, Object Data Source sucks. I tried working with it and always wonder why people ever imagine to use such approach. It's a very sick way to add up necessary middleware, especially if you try to do a stateless web page.
I CC'ed my manager to this post, this comment had me checking twice who is the sender.
Although some things within ASP.NET are pretty relaxed. Especially the automated serialization of objects. But this is also a pain in the ass. It really takes lot of practice to get used to the event model of ASP.NET.
The thing I hate in ASP.NET is that it is based on ONE form per page. This brings lots of problems when you are developing and all need to be worked around. ASP.NET 2.0 made life somewhat easier but still.. Why must it be so difficult to POST to another page without loosing viewstate data? Why must it post all form data when I only want to submit my search string?
ASP.NET is useful for simple screens but when you are at the point to having master pages loaded with different controls that all have their own lifecycle so that you cannot rely on IsPostback for example then it really is becoming a challenge to keep all things working.
But also the non asynchronous handling of page request within ASP.NET. But that has more to do with the way .NET handles. WHY must it be so hard to this with http handlers and such.
I don't say all is bad. I really like the code behind idea to seperate UI logic (UI logic, not application logic) from UI presentation layout.
Ayende,
You told that you disable ViewState in all your projects at the web.config level. The ViewState has it good things and bad things. I have it enabled in some controls and disabled in others. Using it judiciously works for me and make my life easier.
For most non trivial asp.net applications, working without viewstate may be asking for trouble. IMHO you are not using the framework as it is supposed to be used. Your way of working in the web doesn't fit very well in the web forms model (it is somehow, nonstandard), so I'm not surprised you're enjoying more other models like monorail.
For me, wokring with web forms is not that painful, but I'm with you when you criticize other thinks like SSIS, for example.
Oren,
WebForms is one of those places where rolling your own is faster than trying to work around all of it's black magic. The page lifecycle, I believe is full of hacks, I remeber the first time I saw that "Load PostData Second Try Message" WTF?
The basic idea behind the page lifecycle is sound, however this is one of those areas where somthing was released with inherint flaws because it was only tested for the simplest of scenarios. A couple of my opinions.
You should be able to:
Have multiple forms on a page.
Change the control tree and not break the page.
Easily inject onload script and script blocks.
Have Viewstate that can be accessed from the page via JS.
Yes, client is King, in the future I would recommend that you constrain yourself to not working with System.Web.UI and the world will be a better place.
Caught you :P
@Manuel, if you haven't encountered the problems Ayende is describing, then you haven't used ASP.NET web forms in anger. They are tricky, they are painful, they make some things beautifully elegant, but make others complicated beyond belief. The almost random nature of the execution path is just one aspect, there are many others.
The framework certainly has problems, and the work-arounds are not elegant to say the least. ASP.NET was revolutionary when released, it is certainly creaking now.
I'm just about to start a real 'enterprise' applciation, and the thought of using WebForms yet again is filling me with dread. I know what problems I will get, I know how my team will work around the problems, and I know I am going to spend ages fixing it afterwards, and I know I will leave a whole bucket load of hacks in place to make it work. That's just the way it is.
hello.
I've been reading your blog for quite some time now. most times, i agree with you. this time, I think that Manuel is right. i'm not saying that web forms model is great. I'm just saying that if you want to use it, you should play by its rules.
I'm still not sure on what's the problem you're facing (i mean, it looks like you're pissed with databinding and you're calling the databind method somewhere, but I still don't understand what you're getting and what you expected to get).
to me, it seems like you're trying to make ASP.NET behave the what you think it's the correct way. Even though you're really smart, I believe that you should consider that you're not always right about something.
And this time, i do believe that you're wrong...at least, about the way databinding is supposed to work in ASP.NET 2.0...
Luis,
It wasn't about a specific example, it was about how the whole framework continuesly violate the principal of least suprise.
Hello again.
As i've said, i'm not defending the web forms approach. I'm just saying that if you're always surprised with the way it behaves then maybe you're not seeing the whole picture yet.
can you at least give a specific example that is responsible for your outrage?
Casey,
The most complex asp.net project I've done was an ERP for a customer that have 5 companies and sold about 5 millions of dollars per year. The database is replicated and has more than 60 tables, so I think that wasn't a small project.
Of course I've found in the situation of asking myself: why this event isn't firing or why no data is showing if I'm calling DataBind. But after realizing what the problem was the fix was easy. Is everything great with web forms? I haven't said so. There are problems and things to improve but I think it is usable to make web applications.
The execution path is not almost random as you say. It has a lot of steps and it is a bit complex. Some things are done under the hood and probably it is easier to make mistakes when you use it (i.e. automatic databinding) but it can be mastered after some time if you really put interest.
Mike D says: "Load PostData Second Try Message" WTF? That could be a good question to see if somebody knows the lifecycle.
I think that Luis makes a good argument too.
Yes, that is the problem.
After your find out what the problem is, the fix is obvious. The problem is that it happens very frequently, and you really have no way of understanding what is going on
Manuel,
I agree with your project size justification- but I need to know one thing, did you ever tried to use RoR/MR? If you haven't, its not fair trying to justify what Ayende said. Its just like we could be keep screaming here all day saying Java sxxks, but that doesn't make any sense unless we have been playing Java and .Net in reasonable scale and then compare (I think Jamie from testdriven.net would be the right person to answer this question due to his background on Java consultant :) )
So, try it out first. The problem really won't look as a problem unless you do have a more elegant solution. We were not saying Windows 3.1 is a problem until we all being moved to Windows 2000. Now we feel Windows 3.1 is a crap. If you compare your ASP old days with ASP.NET, I could hardly think you will feel any issue with ASP.NET- instead you keep saying ASP have issues on architecture and flexibility. Now its the same- try MonoRail first, then you will know what Ayende has said.
The point is- ASP.NET isn't necessary wrong, but there is a better way. Once you found that way you will always wonder how come you did waste time to even understand what happened on ASP.NET when something better exist.
Manuel,
I agree with your project size justification- but I need to know one thing, did you ever tried to use RoR/MR? If you haven't, its not fair trying to justify what Ayende said. Its just like we could be keep screaming here all day saying Java sxxks, but that doesn't make any sense unless we have been playing Java and .Net in reasonable scale and then compare (I think Jamie from testdriven.net would be the right person to answer this question due to his background on Java consultant :) )
So, try it out first. The problem really won't look as a problem unless you do have a more elegant solution. We were not saying Windows 3.1 is a problem until we all being moved to Windows 2000. Now we feel Windows 3.1 is a crap. If you compare your ASP old days with ASP.NET, I could hardly think you will feel any issue with ASP.NET- instead you keep saying ASP have issues on architecture and flexibility. Now its the same- try MonoRail first, then you will know what Ayende has said.
The point is- ASP.NET isn't necessary wrong, but there is a better way. Once you found that way you will always wonder how come you did waste time to even understand what happened on ASP.NET when something better exist.
goodwill,
I really see your opinion as a very good point, as I have experimented that myself with other things. You work in a way and you like it, then you get into another way of working and you love it. So getting back the the previous way of working makes you feel that you are wasting your time.
I haven't used RoR/MR and even if I can try it, I won't be able to use it in a real world project any time soon, so I won't be able to compare both. However, you post has given me the extra information I was missing to better understand web forms haters.
In your screencast (hibernating rhinos #2) you dragged a customers table to the web form designer. Then you claimed that there isn't a way to filter the customers returned based on something like a permission (for example).
In reality this is simple. All you have to do is hook the RowDataBound event and hide the row. Surely you know this, I'm not sure why you made that argument since it only strengthens the other side when there is such an easy response.
That is a UI centric view of the world, and VERY painful to work with in any non trivial scenario.
Now if I want to change the permission model I need to go visit every page, right?
Worse, even if I refactored it out to a common class that handles permissions, it is now having to dealt with the GridView idea of what is allowed and what it not. Now I want to do it for the Customers DropDown, time to write a new class, etc.
Ayende,
I have been a reader of your site for a long time and have much respect for your perspective. I was wondering if you have seen/used:
http://www.codeproject.com/useritems/NHibernateDataSource.asp
Might this help in this situation? I am very curious to hear your thoughts on this particular matter since I am considering using it for my client.
ps - Great job being the voice of reason on DotNet Rocks!
El ,
Now thats a big deal. You are saying to add business logic on the Page Controller, which in any case I classify that as a UI layer rather than the BI layer. That doesn't sound right at all. All too often there are people from MS demonstrating such approach, and this is not right- if its right then back to VB6 we should have been using data binding. The reality is even since VB6 I never saw big scale app use any kind of binding at all, and the binding approach in many cases encourage UI layer business logic.
K Jones,
I know of it, but didn't really use it.
I need to do things with the data, not just display it.
Also from a performance standpoint retrieving all the rows, then throwing an event and testing each one is really not what you want the application to be doing. This is exactly the sort of thing databases were made for and you want to handle that on the SQL/Database level.
What I understood as the point of that part of the webcast was that using Webforms the easy and obvious way to do things is many times in the long run the wrong way to do them while in MR you do things once and do them right.
If you do Web Forms you have to accept its rules. No discussion about this.
Web Forms aren't easy, if you look with Reflector at the GridView... wow... GridView is great for doing fast table administration pages, but for a real project it should be forbidden together with ObjectDataSource.
One control to manage the CRUD operations, the caching, the paging, the presentation, the validation, the... wow, it's a bomb for any project.
Anyway, asp.net is very flexible so I don't understand why to use this controls when you can avoid them. If people know how to write naked WinForms apps without an extra layer of indirection that makes databinding, state management and other atrocities, why people can't write asp.net apps without using the System.Web.UI namespace ?
Probably because they fear HTML and HTTP, so they prefer an over-enginereed object-oriented technology.
Dan, i guess you've said it all. but, if you're into the web forms model, then you got to play by its rules.
Comment preview