Removing the leaky abstractions from WebForms
My preferred approach to develop on the web is using MonoRail, but since I am doing a lot of work for clients, they sometimes get to choose the technology. My current project is using Web Forms and Atlas. I already mentioned that I am using Igloo to provide a truer MVC support for WebForms, it is not as good as what MonoRail can provide, but it is nice. (The only problem is that I keep feeling that my controllers are getting too big and complex, I have finally finished doing a stint on the UI that left me little time for refactoring, but it is getting past time to do it).
I believe that I have already mentioned in the past that I am not particulary fond of Web Forms, it is a leaky abstraction, trying to bring a semblence of statefulness to something that is stateless by nature. I did some big projects with WebForms, and I was bitten really bad by some of the stuff that went under the hood.
At any rate, here is the stuff that we came up with for the project:
- Disable viewstate. That means that I disable it at the web.config level, and never enable it. Like most ASP.Net developers, I have been fighting with ViewState for a long time. It means that controls "forget" their state, and that sometimes I need to maintain state on my own, but it means that I get a lot more control on what is going on in the application. For some annoying reason, I still get a _VIEWSTATE variable in the pages, I assume that it is the ControlState, but so far I haven't dug far enough to find yet. I got some worrying responses from team mates, about what the implications of this can be. I had to sit and show them with Fiddler what is going on the wire to make sure that they understand what is happening.
- Understand how Update Panels work. They are really cool technology. I am usually critical of Microsoft, but I have to say that I like UpdatePanels, they are a good solution for a problem that most WebForms developers need to deal with.
- Do not get the data from the controls, get it from the request. There are two reasons for this, the first reason for it is simple, it is possible to access the request object from everywhere, it is much harder (and not wise) to pass the controls references. The second reason is that the controls will lie to you about their state. I just run into a situation where a DropDown reported SelectedValue = "" when the selected item was the one defined on the aspx (with append data bound items set to true), while on the request it was "0", the value given in the aspx.
- Do no processing the the code behind files. When my controllers do not get the data directly from the request object, they expose methods such as:
public ICollection<Policy> GetPoliciesForCustomer(string maybeId); - Don't bother with the designer.
- Consider using the AjaxToolkit where appropriate, but be aware that it is not mature yet. If it gives you the least bit of trouble, drop it and go to Google.
- Watin is really cool.
- Would you write the tests already?
It is not comprehensive list by any mean, but this is just a few things that were brought up.
Comments
You feel Igloo is ready for prime time production?
Is there any good documentation on it?
I'm interested in learning more.
I want to keep my Atlas, but get a MVC - sounds alot like what you have done
Code Craft Why great coders get paid far too little [Via: shanselman ] Tip/Trick: Integrating ASP.NET...
@Steve
I believe that Igloo can certainly give you quite a bit.
Take into account that I have fiddled with it to the point that I have the automatic injection of controllers into the views/user controls, and easy access to the user input.
Do Igloo controllers have a reference to an IView? Or is everything done through the property bag?
Actually, I'm setting up an application at the moment with Castle and ASP.Net and currently I can't inject Presenters (MVP pattern) because they need a reference to the view interface. So I have to call resolve in the presenters to get their dependencies. Do you know if there's a way I can do that Ayende?
At the moment I have this:
partial class View : Page, IView
{
Presenter _presenter;
void PageLoad()
{
}
}
public class Presenter
{
IView _view;
IDependency _dep;
public Presenter(IView view)
{
}
public Dependency
{
}
public Presenter(IView view)
{
}
}
In my tests I can set Dependency to my mock, and in live it will get resolved on first use, but I'm sure there's a better way to do it!
This is probably the longest comment i've written....
No, there is no reference to the view from the controller, I pass the data either via strongly type wrapper on the property bag, or via return values from the controller methods.
Ayende has a post on "Removing the leaky abstractions from webforms", webforms do leak abstractions
Asp.Net and Atlas sucks!! They are so heavy and slow!
Why did you abandoned Monorail? Your articles about Monorail are very nice, but lalely you only speak on webforms.
cheers
Samir
@Samir,
Much as I would like to work solely on the Castle stack, in the end, it is the client that gets to make (some) of the decisions.
If they really want web forms, I will work with web forms.
The file extension would be aspx, the convention would be as close as to MonoRail as web forms would allow.
ASP.NET sucks? Why don't you use assembly code, it must be faster than Monorial, LOL!
I am sure you already got this, but ControlState IS in the _VIEWSTATE field.
I use Fritz Onion's ViewState decoder and it splits up between ViewState and ControlState to see exactly what is in there.
@AA,
I didn't say that ASP.Net sucked, I said that the WebForms model is not a good fit for the web.
And if I could be convinced that a piece of code really really needed to be done in assembly, I would write it in assembly.
I find it hard to think about a scenario that would call for this.
When I choose what to work with, I take into account not just the code performance, but developer performance as well, assembly is really bad for developers performance.
@Mike,
I thought that this may be the case.
And no way to get rid of that.
Thanks for clarifying that.
You could have used and IHttpHandler object.
All you get with that is session state (if enabled) and http context.
Also, you know that viewstate is not an all or nothing proposition - right? You can selectively turn control state on or off as needed. But, viewstate can get out of hand - but that is not an asp.net problem is much is it as a tuning problem or design problem.
Heck, you can even compress it or move the storage else where if it fits your needs.
You could have used an .aspx and avoided the use of web controls entirely.
In asp.net you are not STUCK with using the technolgy in a particular way.
This depends on where you call it in the page cycle. If you call it before the "Init" cycle is completed for the control then may will appear to lie to you becaue state fo the control has not yet been updated. Since asp.net pages use an event driven pipeline, where you call an object for it's state maters.
You give up validtion plus plus OO for design. Plus, who said you have to pass the controls around. They are global to the instance so you can handle the data from any method.
I would that this is a design problem or a design mismatch, not an asp.net problem.
Yes. This is control state.
If you want to superimpose your deisgn practices on the webforms model and then gripe that it falls apart then whose problem is that?
Yes. But this is for webforms.
No, you mean the WebForms model doesn't fit well with your design pattern.
Stop blaming the tool!
Ayende,
Oops you really seems started fire on this one. :)
Guys before you say ASP.NET is good or not, I kindly invite you to try monorail first. You will not be in a good position to debate unless you know both reasonable well enough.
ASP.NET might not be sucks, but there are lots of hiccups which lots of developers already trained themselve to get use to it. A lot of time a website is really just html and js, a huge abstraction model might not be necessary, or might even hinder a lot of your work. Try to get your ajax do a per html table row update(insert/update/delete), I think in most case you are binded to update entire gridview. And how about a highlight for your new added row? not there unless you take the really big hassle to write the entire ajax enabled web control (I never saw one before). Have a look to scriptaculous sort list and try to implement yourself in asp.net, then I think you have some good idea on what are the difference too.
I have been writing ASP.NET since 1.0, and now I move to monorail and never want to look back due to the clean MVC design provided. If Ruby on Rails makes a miracle, it must have a reason, thats what I tend to believe.
@ mysterious.e,
Selectively working with the view state means that I need to manage it, and I don't like the idea at the first place, better to turn it off completely and work like the web is meant to work.
I am aware of the options of compressing / removing it, again, I feel that this is me needing to manage something that should have never been there in the first place.
And yes, if I am using WebForms, I am stuck with using the technology in a particular way.
No, it happens in the Page_Load event, and it would not show the value if it was defined in the aspx page and then databinding (with append data bound items = true) was performed).
And here is the crux of the matter, I am not handling it in the aspx page. That class is dedicated to presentation logic only.
I want to handle it from my controllers, not my views.
Yes, I feel the same way, WebForms is not designed to allow good separation of business logic and presentation logic, leading to a lot more work on my part.
WebForms. If it tries to be a web framework, it should enable working with the best practices for the web, period.
Otherwise, there is a big fault in it.
Yes, indeed. Unfortunately, I feel that my design pattern is a best practice for working on the web, and I am not going to work in worst practices just because WebForms thinks that I should
You say to get data from the request and not from controls; does this mean you know exactly what name attribute will be generated for every control (is it always the same as the client_id?)? I assume you're not using string literals here? (I believe you linked to this post, titled "We Hate String Literals": http://blog.eleutian.com/PermaLink,guid,088e158b-cd3c-4920-8df5-a3628013cc1d.aspx .)
I am using the something like:
string policyName = Scope.Input[Constants.Policy.Name];
Where Constants.Policy.Name is "Name", which is also the id of the control on the page. I am handling the ASP.Net name mangling by searching not on the full key, but on the last part of it only.
I wholeheartedly agree! ASP.Net tries to do too much and forgets the basics.
The abstractions ultimately must be leaky because inevitably you find yourself having to inspect HTTP responses or dissect the raw HTML produced by some fancy control so that you can apply CSS or DHTML effects to it. Not good.
I almost never get any mileage out of a designer unless it's written as a true direct-manipulation interface like SmallTalk. Almost all of the interesting stuff in a UI is dynamically generated so it does me no good at all to produce a static mock-up of a form. Even less so if the mock-up is incorrect because it is produced in some way other than running the actual code. A designer's mock-ups do not provide high fidelity with the real app and they never will. I believe this is true to all designers whose implementation requires providing a distinct representation of the view from that actually used by the system.
I've also frequently encountered issues due to ASP.Net's closed-world implementation. There are many things that the framework is allowed to do via internal APIs that apps cannot reproduce or change. One of my favourite examples is the fact that SQLDependency auto-enlistment works because SQLCommand knows to look for an undocumented CallContext variable value that ASP.Net has set just prior to page processing. I think there's something seriously wrongheaded about coupling your Data and Web frameworks together like this.
I respect the work that many brilliant and talented people have put into ASP.Net but it's not for me.
Nope... I'll be using MonoRail for my next app.
Can someone explain why rails/mvc is better than a view presenter approach?
I have looked over the getting started examples and docs for MonoRail and can clearly see the clean separation of the view and the controller. I can also see that it is using raw html and a scripting language, all of which as far as I can tell is reverting almost back to classic ASP.
Also, what about server controls? IMHO, they are a huge time saver. Not to mention custom 3rd party controls I can use that contains a lot of functionality so I don't have to write it in. I have never once had a control lie to me about its state, if something was wrong about its state, it was because I did something wrong, not the control.
I understand the issues with ViewState and the event model behind ASP.NET, but I think with proper abstraction like view / presenter the and judicious use of viewstate, most if not all problems can be dealt with.
Joe,
check here for an example of the controls lying to me:
http://ayende.com/Blog/archive/2007/03/20/WebForms-and-lies.aspx
I will post about the rest of your issues in a short while
Comment preview