Customizing WebPublisher Edit Feedback
I was recently asked to develop an alternative to the WPP edit feedback page. The complaint was that it showed all the fields, could not be customized to suit the intranet template, and looked the same for all textbases. What would be nice, they said, is a different feedback page for each database, that didn't show all the fields, and that could have a completely customizable look.
The file that all edits submit to, which performs all database interactivity and which acts as the feedback page, is /dbtw-wpd/asp/iwpp-edit.asp. It is a bad idea to mess with any file in the WebPublisher install directory which will be overwritten with each WPP upgrade, so I didn't want to touch it. I created a copy of it instead and moved it to an application subfolder, beneath the search page/new record page location: [application root]\EditHelper\iwpp-edit.asp. This makes it simple to keep track of and I don't disturb the original.
I changed nothing in my new copy of iwpp-edit.asp except for the addition of a script block at the very end which redirects after database interaction, based on the name of the textbase being edited, and passes on any error message from the edit. For example, a textbase called "sales" would be redirected to [application root]\EditHelper\sales\EditSuccess.htm on a successful edit action. EditFailure.htm is similar but has some script that picks up the error msg from the query string and displays it on the page.
The only addition to the edit forms was adding script to change the form action on page load. Instead of /dbtw-wpd/asp/iwpp-edit.asp, the edit form posts to EditHelper/iwpp-edit.asp. Since the dynamic edit form does not expose its body tag onload event, I attached an event listener from the script.
The addition of a new textbase to this scheme is easy because redirection is based on textbase name. I just need to add a new folder under EditHelper which matches the name of the textbase, e.g. [application root]\EditHelper\catalog, and put a "catalog" version of EditSuccess.htm and EditFailure.htm in there.
Easy peasy.
Run query on page load
To run a canned query when a web page is loaded, instead of a user having to manually begin the query by clicking a link:
<head>
<script type="text/javascript">
window.location.replace("http://localhost/dbtw-wpd/exec/dbtwpub.dll
?AC=QBE_QUERY&TN=cars&RF=Full+information&QY=Findall");
</script>
</head>
Obviously the query itself will change depending on your needs, but the key is to set the window.location to the canned query url.
WebPublisher security and our WPDK
We have many times discussed amongst ourselves the best way to deal with the following security issue: the WebPublisher dll must either be open to anonymous access or locked down, but not both, at least through the same IIS alias. Even though an anonymous user has access to the dll, they should not be able to retrieve results from every database.
What we have done up until now is create a .NET control (the Andornot Results Control) that takes a query, whether a form POST or a canned query string GET, and handles communication with the WebPublisher dll. The active account being used is therefore the ASP.NET worker process account (NETWORK SERVICE on Win 2003) and not IUSR_machinename.
We give NETWORK SERVICE the permissions on the WebPublisher install directory it needs (same as IUSR has). We then strip IUSR permissions from the "internal" databases. Even if an anonymous user knows an internal database name and constructs a canned query to target it, NTFS permissions deny them.
Now, the funky thing is that the WebPublisher dll does not behave the way you think it would. If directory security on the dbtw-wpd alias is set to both anonymous access and integrated Windows authentication, as is the default case, then these two things should happen in IIS:
1) Anonymous requests to any database with permissions allowing anonymous read requests should return results without further ado. This happens.
2) Anonymous requests to any database that DOES NOT allow anonymous read requests should return a HTTP 401 Access Denied and a message that says integrated Windows authentication is acceptable. A bit of back and forth occurs, but essentially if the requestor has Windows credentials, they should be accepted and the request carried out. In the case of our .NET control, what should happen is that the initial request should bounce, but that the passed-in credentials (proof that it is operating as NETWORK SERVICE) should be accepted and the request fulfilled. This does not happen. The WebPublisher dll sends back a 401 for the initial anonymous request for a database with no IUSR read permissions, but then is unable to accept valid credentials and thus does not fulfill the request.
So, we must set up two dbtw-wpd directories, one with anonymous access allowed and one without, until we come up with something better. We recently brainstormed about this, and we'll see what we come up with.
You can get more information about IIS authentication here: MSDN Authentication and Security for Internet Developers
More information about the Results Control and the WPDK (WebPublisher Developer Kit) here: http://www.andornot.com/Products/Addons/WPDK.aspx.
Peter Blum's spidey senses detect a Cry For Help
Peter Blum himself comments on my naive, whiny and complaining post. I am so impressed! It's like making a disparaging remark about Brad Pitt in a DVD you rented, and having him, surprise!, drop by later to personally explain.
The Validation and More package is incredible. I just didn't expect it to cover so much ground. And that's a good thing, regardless of my mewling over how much I have to learn.
Okay, so, wow! Thanks, Mr. Blum - my personal estimation of you just rose about 1000%.
Validation and More. And More and More.
We bought Peter Blum's validators and more package just recently. Everyone says it's better than sex for ASP.NET edit pages. Then again, that's the kind of thing your average .NET developer WOULD say. Unremediated social misfits, the lot.
But I got more than I bargained for when I started working with them today. The validation controls, not the misfit developers. First clue was opening the user's guide, and seeing it was 235 pages. And, oh wait, that was only one of the user guides. There were a couple more, plus a tutorials PDF. I think it all added up to about 500 pages. Of instructions. Gawd. I slumped into instant depression.
It's an in-depth package. It's going to do everything, and I'm going to be able to retire early with Peter Blum's Validation and More running the whole show for me.
And now it's the end of the day, and I can say I have implemented exactly one (1) validation control that makes Title a mandatory field. I don't know whether to shoot myself or have a party.
Fetch record after ODBC INSERT the Guid way
I remembered today, with Ted's help, a technique which I really dig for retrieving the just-created textbase record when using ODBC Insert. 'Cause you don't get back any textbase-produced stuff like an autonumber RecordID or DateTimeEntered or anything, when using Inmagic ODBC to insert a record. There's just this kinda whistly sound the little integer-that-could makes as it tumbles its tumbleweedy way back from the database. "1" for "ayuh, I reckon we got ourselves a new record", and "not 1" for "they saw us comin' and Li'l Joe's been shot!"
Or. Yeah. And that is the lamest wordplay ever in a title.
Okay so, I have used things like SELECT MAX(ID) FROM [tb] WHERE Title = ? to fetch what I just inserted, not yet knowing the ID, since it's produced in the BLACK BOX down there where the database is. And that's worked because it's unlikely that a field like Title, even when not unique, is going to repeat often, and since each new ID is an integer based on last-produced-integer +1, it's very very likely I'm going to get the record back that I just inserted. Ted and Nathan have used unique fields or field combinations that have a statistically high unlikelihood of repeating.
But still, it's bothered me that the method is not airtight. And today I remembered something Nathan had come up with: produce a GUID, stick it into the textbase along with the rest of the record, fetch record by GUID. So simple and effective. One needs to add a new field for it, but so what? And creating a string GUID in VB.NET is dead-easy: System.Guid.NewGuid.ToString().
Ahhh. Relax... the Andornot Way.
Blog splits in two
Due only to my own sense of decorum [ggggmmmffff-harf harf harf] I have elected to continue personal blogging on my personal site at peaeater.com, and stick to andornot-related topics here. No one made me do this, it just seems right.
|