Speaking of using ASP.NET without ASPX files, I've been doing that for some time now.
About three years ago I started a web application, and quickly got overwhelmed trying to use the ASPX model.
It's just too much.
I don't think the 'code-behind' model is a good idea either.
Mind you, I'm not real proud of the solution that I've been using in its stead.
About a year or two ago I created a base class that implemented IHttpHandler with a bunch of template methods, and rendering methods, that would basically define the behaviour of any given web page. I did it one evening because a bloke who was working for me needed to start using it the next day.
The template methods were a great idea.
The rendering methods were a hack.
The system works, and I've got it in production, but it's a maintenance problem, and I have browser compatilbility issues that aren't easily solved, and extensibility issues. It's still way better than ASPX though (particularly from a comprehension/maintenance POV), in my opinion.
Over the past two weeks I've been focusing on the rendering engine for v.Next() of the same reporting tool.
I have a lot of work to do (new database schema, data import, data cleansing, administration utilities, HTML/CSS/JS UI hacking, not to mention all the SQL), and the rendering engine is something that I was hoping to avoid addressing.
But it's unescapably a core component of the entire architecture, and is a prime candidate for reuse in a data-entry aspect of the system (still under development, at least an order of magnitude more complicated) as well as simply in the reporting part that I'm working on now.
So that's what I've been doing for the last couple of weeks, fixing up my ASP.NET rendering engine.
I had a look at nvelocity, but that's not useful for me.
Let me explain how I'm thinking.
Basically a web page is a simple thing.
It is possible to sit down and designate a 'label' or a 'name' for every 'part' of a web page.
It is also possible to arrange those parts into a structure. That is, you will have a Page, a Page will contain a Title, a Page may contain a TopNavigationBar, etc.
Basically you can create a 'document object model'.
Not a HTML document object model mind you.
More of a Web Page document object model.
So that's what I've done (read: am doing).
The big reason for creating a Web Page document object model, is that you can seperate the 'view' from the 'model'.
The ASPX page architecture falls down there, because its 'model' is the 'view'. That is, a System.Web.UI.WebControls.TextBox will render itself. That's bad.
The way my system works is I create the Web Page model and then I designate a renderer.
The Web Page model is specified as a collection of interfaces. I have a 'generic' implementation of those interfaces, and I don't expect I'll need to customise them. My actual HTTP handlers get/create a Web Page Document, configure it with the content they want, nominate a renderer and then render it.
The model can easily render to any flavor of HTML (i.e. 3.2, 4.0, 4.01, X, etc.), to any form of XML schema I wish to support, to PDF, to plain text, to CSV, JPG, GIF, PNG, etc. (The reason for the images is that a component of my Web Page model is a charting engine (or 'charting model' I should say), thus I can give you a 'chart' as a JPG, or GIF, or PNG, or CSV, or XLS, or PDF, etc. because a Chart can be a part of the Content of a Web Page) (I'm drastically oversimplifying there, btw.)
Basically I'm planning to take the generic renderers and make them extensible by derivation. That's how I'll do skin/themes/branding. (Although I still obviously use CSS.)
I'm a big fan of factories, so the entire model can be configured with about two settings in the config file.
I think what I've been doing is a great idea. Unfortunately it's a lot of upfront work.
So far I have about half the model specified and generically implemented. I have a few test HttpHandlers that create the model.
I have two generic renderers, a HTML 4.01 renderer and a PDF renderer.
I'm tired.
I've said enough.
ASPX blows.
Put it this way:
this.IWebResource.Context.Response.ContentType = this.IWebPage.Renderer.ContentType;
this.IWebPage.Renderer.Render( this.IWebPage.Document, this.IWebResource.Context.Response.OutputStream );
I'm trying to build an XML based form thing, which I'll eventually have to build a (probably flash based) Desinger for. XML is a wonderful thing to use on .Net, the serialization makes it a breeze to migrate objects->XML->objects. Marvellous.
By using the renderer model, how can I make it extendable? By making each class responsible for its own rendering, I'm able to enable the model to be extended.
I suppose I could add an extra layer, so my form objects build a DOM, and then I have renderer(s) for that DOM, but really, I'm going to have to invent the wheel for that kind of thing, no?
Whilst we're on this tip, ASP.NET does implement renders - when a control "Renders" itself, it's actually putting things into a HTMLWriter, which is then responsible for writing the HTML to the response stream. That's why writer.BeginTag(HtmlTextWriterTag.Div) is better than writer.BeginTag("div") -> the former will render as a table on downgrade browsers (well, all apart from ie, but then this is MS we're talking about ;) I think you can config which HtmlTextWriter is used web.config, or machine.config.
But the whole Page Controler model is a bit poo. But then, if I do develop my own MVC framework, I'd have to develop an IDE for it, and I'm not up for that really.
Wow, perhaps I should get a blog too ;)
I'm not designing for 'extensibility'. At least not in the sense that you can add features to my DOM that I haven't already catered for or modelled. (Since I am the consumer of my DOM, if I want to 'extend' it, then I'll just add the feature to the model myself, and make it a capability. So if for example I wanted to add the capability of showing text in a paragraph, then I'd add that capability (naturally, I already have that capability))
(did I say capability too much? :)
So that answers some of your question about how I'll extend my model. I.e. with my compiler. Because the model is strong-typed/specific, as opposed to loose-typed/general. Extensibility is a non-goal. Specificity is a goal.
That said, the core of the model is the familiar IElement, IAttribute, IText. So the whole thing is just a hierarchical collection of elements, elements have attributes and a special type of element is a text element (that just represents plain text), and you can run over the entire model in the 'general case' like that, and adding a new type of element to the document is as simple as defining a new element type (i.e. an interface with a name and a set of capabilities that extend IElement). And while you can enumerate an IElement for sub-elements, IElement does not define a mechanism for adding sub-elements, so only a derived interface can support element addition, and it does so by providing a strong-typed mechanism for the types of sub-elements it allows.
HTML is actually a pretty decent 'general' document spec, I basically just cuts bits out that I won't need yet, and add bits to model stuff that HTML doesn't (like page breaks, charts, etc.) So my model, like HTML, contains notions like Reference (the <a> element) Paragraph (the <p> element) etc. It also models structural 'intent' (as opposed to dictating specific placement), so I have the concept of a Document, with a TopNavigationBar, a QuickLinkBar, a SideBar, Content, Block, Page, etc.
My renderers can pick and choose what parts of the model are relevant to the way they present their representation. So, a 'chart renderer' won't render navigational elements, for example, and a 'plain text renderer' may not support form elements, and a 'html renderer' may not support page breaks, etc.
But the entire data for everything that could be expressed in any 'web resource' is modelled in a general purpose document model. I (basically) understand how the HtmlTextWriter works, but that doesn't help me, given that I may not render to HTML, and I may want to model things that can not be defined in HTML.
...and this isn't quite like inventing the wheel. Because the wheel has already been invented. This is more like inventing the widget. The widget is a thing with a specific set of criteria that I haven't been able to find elsewhere. And although there are many 'widget like things' none that I've seen match up to my criteria. Chiefly, a model for expressing a document with a specific set of functional features that may be interactive or static, and a set of renderers for turning that document into a representation consumable by various software (such as a web browser, PDF reader, image viewer, spead sheet application or some other form of data consumer.)
I want to keep my scope as constrained as possible. I'm writing an application, not a general purpose tool.
In my case, I won't be using the XML serialization features of .NET, I'll write an XML renderer to serialize my model to a specific XML schema, and if necessary (which it is not initially) I'll write a Builder that will deserialize that schema using a specific document element factory.
I guess I should make the point that the 'extensibility' that I actually require, and the driving force for this particular architecture is that I want to be able to 'plug in' renderers. So that's where my extensibility is. I can render my model as ABC, or XYZ, all I need to do is create a new renderer. The problem with my current solution (and the ASPX solution) is that it can only render to HTML, and trying to extend that to say PDF, or GIF, would be 'unnatural', if not impossible.
It's not impossible that I could use the same Web Page DOM and create a 'windows forms renderer', although that is well out of scope.
I think I understand a bit more:
You're not restricting your DOM to describing HTML, it's describing a document, and it's up to the renderer how to represent that description.
I have a few questions:
Does your application handle user input? How? What does it do with it?
How would someone edit one of your documents? The benefit of the ASP.Net model, for me, is that anyone (esp team-members) using VS.Net, or even DreamWeaver, can edit my pages without having to understand a proprietry DOM. If I were to invent my own DOM, then I'd loose that.
For me, the benefit of using XML for storing the "templates" for my forms is that I can use it in anything. If I want, I can write an XSL-Transform to convert my form schema into plain old HTML, and, more importantly, I easily can pass it between Flash applications, delivered over HTTP and a Web-service.
As you said in your last comment: your requirement is that you can plug in different renderers. Mine is that I can plugin different elements. I suppose, in time, a solution might be developed that allows both, but I think that's beyond scope for both of us.
Basically I handle user input like this [1] (pseudo-code, atypical control flow removed).
Yep, if you're only using HTML then you can describe your DOM in HTML. If you're not..? I could write a 'document template designer' if I wanted, but I don't need one, my team consists of me. Further, I could (if I wanted) write a HTML renderer that knew how to read in HTML fragments from some sort of file (there's your code-behind right there!) and don't forget that I use a CSS file for most style stuff.)
I process POST data directly. I don't round trip it into my 'document model' to just to read it out again. Remember that the 'document model' is still a 'UI view'. So basically the entire Web Page DOM is just the 'view' for my application, the fact that 'inside' the Web Page DOM there is a split between the 'model of the application view' and the 'renderer for that model' is of no consequence to my application. Since it's a web application, it relies on the HTTP protocol, which is where it reads its data.
You could write a renderer that used XML and XSLT using my method too. (In fact, I'm considering doing exactly that, although it's not much drama to do it without XSL, and I'd guess and say that DOM->XML->XSL->HTML would be more expensive than DOM->HTML. But it's certainly possible.)
John.
[1]
protected IWebResource IWebResource { get { return this; } }
protected IWebPage IWebPage { get { return this; } }
protected abstract void InitializeResource();
protected abstract void ReadSession();
protected abstract void ValidateSession();
protected abstract void ReadQuery();
protected abstract void ValidateQuery();
protected abstract void ProcessQuery();
protected abstract void ReadSubmission();
protected abstract void ValidateSubmission();
protected abstract void ProcessSubmission();
protected abstract void FinaliseResource();
protected override void ProcessRequestCore() {
this.InitializeResource();
this.ReadSession();
this.ValidateSession();
this.ReadQuery();
this.ValidateQuery();
this.ProcessQuery();
if ( this.IWebResource.Context.Request.RequestType == "POST" ) {
this.ReadSubmission();
this.ValidateSubmission();
this.ProcessSubmission();
}
// render
this.IWebResource.Context.Response.ContentType = this.IWebPage.Renderer.ContentType;
this.IWebPage.Renderer.Render( this.IWebPage.Document, this.IWebResource.Context.Response.OutputStream );
this.IWebResource.Context.Response.End();
this.FinaliseResource();
}
asdad
"The ASPX page architecture falls down there, because its 'model' is the 'view'. That is, a System.Web.UI.WebControls.TextBox will render itself. That's bad."
Why is that bad? I've seen developers say this way or that way is bad but the reasons they have all given are preference or someone else wrote a book saying so or the developers of the language say so because the language doesn't operate that way. So what is your reason?
Because System.Web.UI.WebControls.TextBox doesn't render itself to PDF.