Friday, January 27, 2006

Don't use SQL Server 2000 Table Variables

SQL 2k's table variable is handy in some ways -- less locking required during transactions, fewer sproc recompiles than temp tables. However, I don't recommend using table variables because:
  • Table variables cannot be defined using User Defined Types. We use UDTs frequently to enforce consistency in even the smallest dbs. Table variables force you to break this best practice and reverse its benefits.
  • Unclear that the variable is a table. The # (or ##) prefix of temp tables gives immediate indication that it is a table. Although good naming conventions could be used to reduce this, naming conventions aren't validated by the compiler.

Friday, January 06, 2006

Power Blogger?

Am I a power blogger or what? It's only been 6 MONTHS since my last entry. Oh yeah -- all over this bloggin' thing.

MS Enterprise Library for GAC

Since I need to use E/L for several apps on a current project, I want to GAC the whole thing. I also want to make it easy for all the devs (of course). Easy solution, right? Just create an installer to gac the E/L assemblies. Well, I had more trouble than one would expect. One of the major hurdles was fairly obscure, so I want to record it here.

Update App Config After GAC'ing Enterprise Library


The biggest gotcha I ran into is that using the E/L config tool for an application sets PublicKeyToken=null in the reference info. This will cause exceptions similar to "Logging.Configuration.ConfigurationException" to occur. To correct this problem, add the PublicKeyToken from the GAC for each E/L assembly to the appropriate location in the app's config files.

Wednesday, June 22, 2005

ASP.NET Apps within SharePoint

While designing a digital asset management system for one of my clients, I considered running the ASP.NET app within SharePoint by simply instructing SharePoint to exclude the path. This is a pretty good idea, if the app can live within the confines SharePoint imposes. Authentication & Session, for example, can't be controlled at the this level.

If your app needs to impersonate, the capabilities are limited. Setting impersonation in the identity element causes the Windows Identity to be IUSR_. Leaving impersonation off causes the Windows Identity to be that of the App Pool (NETWORK SERVICE in my case). In either case, the Page and Thread Principals are empty since the Directory Security setting in IIS allows anonymous. Changing the Dir Sec setting does as you'd expect -- the Page and Thread Principals are set appropriately, impersonation is set, etc. But, now the entire top-level SharePoint site requires authorization (no anonymous access).

ASP.NET Impersonation and Principals

Every now and then I write a simple app to remind myself of what the principals are for the various impersonate config options. Maybe in the future I'll remember to look here.

Assumptions:
  • VRoot requires authentication (anonymous disabled)
  • VRoot's App Pool identity using NETWORK SERVICE
  • "IEUser" is the end user
  • "ImpersonatedUser" is the user config'd in the identity element
















ScenarioPage
User
Thread
CurrentPrincipal
WindowsIdentity
impersonate=falseIEUserIEUserNETWORK SERVICE
impersonate=true;
userName not set
IEUserIEUserIEUser
impersonate=true;
userName set
IEUserIEUserImpersonatedUser

So, the identity of System.Security.Principal.WindowsIdentity is the only one that changes. Page.User should typically be used for IsInRole checks.

Tuesday, March 08, 2005

SharePoint & WSS_Medium

As I mentioned in an earlier post, I've been trying to determine the overhead involved with updating data via SharePoint WebParts vs. ASP.NET WebForms. To get started, I created a simple WebPart to render the request's query params to a HTML table. So, the first problem I ran into is that a WebParts do not have access to the params collection due to CAS. When I exec'd the page, an error regarding "LinkDemand for AspNetHostingPermission failed" (or similar). So, my WebPart didn't have this permission. I added it to GAC, but elevating it to Full trust probably isn't a good idea. Thanks to several blog posts (Debugging Web Parts - a full explanation of the requirements in particular) I changed the system.web/trust config from level='WSS_Minimal' to 'WSS_Medium' This brought my WebPart back to life, and I believe I'm operating in a least required security mode now.

Applications in SharePoint

I'm architecting a solution for a customer which would benefit from several features in SharePoint 2003 (Tasks, Alerts, doc repository, etc.) The solution will need several of these concepts, and I hope SharePoint's features will be a good match. However, I'm concerned that data entry pages will be complicated by the fact that SharePoint uses WebParts in zones on the page. This is similar to other frameworks I've used, yet so far I have not been able to determine the amount of additional overhead required to do data entry in SP.

WebParts are very similar to Server Controls in ASP.NET -- code in an assembly writes HTML to the output stream. No big deal from the output standpoint, but you don't get as much of the input benefits from ASP.NET controls (DataGrid is a good example).

Big Gaps

Wow! It's amazing how long the "dry spells" are between my blogging activities. Too busy!

Thursday, October 14, 2004

XSLT, XPath and GUID's

Ahh, GUIDs. We love 'em; we hate 'em. Actually I usually love them, but querying for GUIDs in XML is fraught with peril. Consider a simple case of seaching for a Person node by the value of an attribute:

<xsl:template match="//Person[@PersonID='3'] >
...
</xsl:template>

But what if the unique identifier for Person nodes is a GUID?

<xsl:template match="//Person[@PersonID='
{4C22F4FA-0C4A-4FCF-85DF-F9B7A902244E}'] >
...
</xsl:template>

  • What GUID format is used in the XML?
    • Bracket notation?
    • Hyphenated?
    • Mixtures?
  • With which casing are the alphabetic portion of the hex values stored in the XML?
    • Upper case?
    • Lower case?
    • Mixture?

As you can see from just these two items, the matrix of problems expands rapidly. In the particular case I am dealing with, I am able to control format (bracketed, hyphenated), but not case. I have had to assume that case will be either upper or lower, but that mixed case will not occur (a fairly reasonable assumption since the GUIDs are not manually edited; for code to render mixed case it has to do extra work). So, my XSLT file finds the appropriate node by this method:

<xsl:param name='FindThisGuid'>
<xsl:variable name='UCaseGuid' select='translate($FindThisGuid, "abcdef", "ABCDEF")'>
<xsl:variable name='LCaseGuid' select='translate($FindThisGuid, "ABCDEF", "abcdef")'>
<xsl:template match='Person[@PersonID = $UCaseGuid) Person[@PersonID = ($LCaseGuid)]>
...
</xsl:template>

Now the Good News: XSLT 2.0 will hopefully resolve this issue by promoting GUID to a first class citizen (actual type).


Thursday, September 16, 2004

IE Gotcha! Do Not Use Self-Closing Script Tag

I recently had the (ahem) pleasure of helping a colleague debug a JavaScript problem. The issue was the he had multiple JavaScript blocks on a page like this:

<script type='text/JavaScript' src='uitools.js' />
<script type='text/JavaScript'>
function DoSomething() {
//...
}
</script>

Seems harmless enough, right? For the longest time we could not determine why DoSomething was not accessible to page elements. We tried all kinds of things until we stumbled upon a surprising resolution. We began to drill in on the issue when I moved the DoSomething function into the upper script block (which required breaking open the self-closing script tag). Suddenly, page elements could use the function successfully. After we moved the function back to its rightful home, everything still worked. Then I realized that the only difference was that the upper script block was no longer self-closing. When I converted it back to self-closing, sure enough the page stopped working again.

For some reason IE (and possibly other browsers) does not handle self-closing script tags in an XML compliant manner. Go figure!

BP: 15 Minutes Isn't Enough

One of the pitfalls of the internet era is that we easily forget that communication takes time. Today's case in point has to do with product build announcements. On my current project, the dev team's "practice" is to send email announcing, "We're going to sync & build in X minutes. Don't check in anything until we send email announcing a successful build." (Formerly X was 5 minutes; recently it has trebled to a whopping 15. The fact that the dev team builds on a random schedule is poor practice in the first place.)

The person who does these builds seems to think that everyone receives the email instantaneously and that they will act on the information immediately. As is predictable, however, the builder frequently sends email along these lines, "Everybody stop checking in! I haven't been able to build." or "We will not have a build today because too many checkins occurred after the cut-off."

The problem is that people are not immediately in tune with email in some Borg-like fashion. We need consistent, dependable builds; but we're trying to deliver randomly.

Monday, September 13, 2004

How much will break?

I don't claim to be an expert in javascript, but I continue to find myself working with it. As I was working on a separate issue, I saw that the language attribute of <script> has been depricated as of HTML 4.01. Ok. I can switch to type='text/javascript' easily enough. The issue that got my attention however, is that XHTML 1.0 does not support the language attrib. So, tons of existing javascript in HTML pages will be rejected in the XHMTL world. That will create a significant barrier to adoption for XHTML.


Wednesday, September 08, 2004

Best Practices

My current project is very random and undisciplined. There are no good Product or Program Managers, the dev team is almost out of control. The situation has driven me to think about several BPs that would help.


.NET Related

Ensure all XSDs (XML Schemas) are DataSet compatible.

This doesn't mean that XSDs should be generated by a DataSet (DS) nor is msdata:IsDataSet='true' attribution required. The intent of this practice is to make XML data readily available to .NET UI components (e.g., DataGrid). If the schema is compatible, then you can create a DataSet, initialize it with the XSD, and then load a conformant XML data. Viola! Now just hook the DataSet up to the DataGrid (or other UI control) and bind.

Note also that you can create a typed DataSet from the XSD and load XML directly into it. The typed DataSet gives you a bit more capability (e.g., dataSet.People["Name"] where People is a DataTable and Name is a column in the DT)

Source Control

Even very small teams (2 people) should use a good source control mechanism. The cost of source control systems (on a per seat basis) pales in comparison to the risk of devs losing code to oversight (accidental deletion or overwrite), disk failure, time loss due to out-of-sync code, etc. It amazes me that so many teams try to "survive" without source control.

Check In Frequently

Once source control is in place, all developers should check in frequently -- at least daily. Code should be checked in after some levels of validation (it compiles, generally works, etc.), but it also needs to be acceptable to check in code that is distinctly work-in-progress. A good rule of thumb I use is: The greater the upstream dependencies, the higher the check in standard. Checking in changes to a thread pool, for example, must always compile and work very well (unless it is early enough in the project that there are no dependencies yet).

Branch Code

Branching code involves penalties, but it is your friend. My current project is losing time and is risking code losses because they don't want to branch. A major demo is coming up, so most developers are coding for days on end without checking in. Creating a dead-end branch and taking targeted changes would allow devs to continue unhindered in the mainline. Another mechanism is to have a dedicated build machine for a specific purpose. In our current case, for example, just using the demo machine to build the code for itself frees the restrictions on the mainline. Of course you reduce opportunities to refine deployment procedures, but everything has its cons.


Monday, June 21, 2004

Crystal Reports' -- Auto-gen'd code files

After designing a Crystal report file (.rpt), a corresponding code file (.cs in my case) will be generated. Typically, if your report is "Inventory.rpt" then the code file will be "Inventory.cs" Sometimes, however, you will get code file pollution (due to VSS issues, copying between machines, etc.) Crystal's engine will auto-gen another file ("Inventory1.cs" in this case) and the original code file will simply be abandoned. Here's the best way I've found to remedy this problem and reset all the code files to the original names:
  • Delete all code files associated with report files (in this case, delete Inventory*.cs)
  • In Visual Studio, R-click each report file and select the "Run Custom Tool" context menu item
  • Rebuild your solution
Pretty simple.