Monday, November 14, 2005

Old Dog, New Trick

Want to implement "Created By" fields for your custom tables in your SharePoint environment?

Fairly easy to do, once you know how to ;)

The trick is to use a not-so-well-kown SQL Server method called "SYSTEM_USER", this will automatically be filled with the SQL Server authenticated user, whether thats a SQL User or a Windows User.

So, first make a CreatedBy field on your table.
Then create an insert trigger, and use the SYSTEM_USER method to fill the field.

CREATE TRIGGER MyTable_FillCreatedBy
ON dbo.MyTable
FOR INSERT
AS
UPDATE MyTable SET CreatedBy = SYSTEM_USER WHERE ID = (SELECT ID FROM INSERTED)


Then of course, you need to correctly configure your authentication towards your custom database.
In case of SQL Authentication, just set the correct user and config in your application configuration file (such as web.config).
In case of Windows Authentication, its somewhat more complicated.
First, you need to change your connection string to Integrated Windows Authentication.

Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=MyDb;Data Source=127.0.0.1

Make sure the 'Identitity Impersonate' tag is also set to true!

Then you need to add the necessary user accounts as logins to your SQL Server. Its generally speaking a good idea to work with a *group*, give that group access to your database and add all users that need access to your group.

The nice thing is that SYSTEM_USER is still going to fill in the individual logged-in user even though only the group has access to the SQL Server.

One big gotcha with Windows Authentication is that it won't work when your SQL Server is on a different server than your Sharepoint (or more in general, IIS) server, at least not when your network is configured with NT Authentication as opposed to Kerberos. There are a few basic fixes for this:
1) Use SQL Authentication ;)
2) Setup Sharepoint to use Kerberos authentication (not so trivial)
3) Setup a 'trust' relationship between the two servers (fiddly)

Friday, October 14, 2005

Need a plumber?

Sometimes with all the glittering IDE's and the Autocomplete features in our development tools, its easy to forget that those too, are just (or have been) someone else's software project and are as such subject to the same deadlines, feature creeps and illogical decisions that our own projects sometimes experience.

Therefore, no matter how shiny a tool may be, always remember that it may have its own logic and ideosyncracies underneath. Because you don't know (and you probably don't *want* to know) what happened in the development lifecycle. Also, most products are really a hodge-podge of various other technologies, some of which were written by 3rd parties, and I'm sure had questionable documentation ;)

Self-proclaimed software guru Joel Spolsky called it the "Law of Leaky Abstractions" in one of his essays and that a pretty good analogy.

We recently met one of those leaky abstractions, in the follow-up of a BizTalk project in which a client had some encoding troubles consuming a .NET webservice from his PHP webserver. In the course of investigating the problem, we traced it all the way from a File Pickup port through an Orchestration schedule, to the Send Port and finally up to the (generated) webservice itself. Having determined that all of the previous steps didn't help in resolving the problem, we then went about the process to change the encoding in the webservice itself (even though its a less-than-optimal solution, because Biztalk regenerates that webservice when you deploy).

So we edited the Web.Config of the webservice, and changed the following line:
<globalization requestEncoding="utf-8" responseEncoding="utf-8"/>
to
<globalization requestEncoding="utf-16" responseEncoding="utf-16"/>

Save web.config, refresh the webservice client, look at the results.
And absolutely nothing changed...

When even a IISReset didn't help the problem (programmer's superstition...), we did some more research and suddenly found this:
http://weblogs.asp.net/tmarman/archive/2004/02/02/66476.aspx

So change that globalization tag all you want, change the encoding by other means, pin needles in a voodoo doll, its just not going to work, because apparently ASMX's are hardcoded to UTF-8...

Make sure you also read the first comment on this blogentry, as its apparently from some Microsoft employee who was involved in the process. ;)

So remember this when next time you wonder why a piece of software doesn't what you wanted. There's probably a leak somewhere ;)

Friday, October 07, 2005

Design vs Deadline

One of the most controversial topics between programmers is the discussion of "design vs getting things done". It takes place on many different levels, from the low-level data-access strategy (DataSets vs Typed Objects), to the higher-level architectural descisions of reusability, extensibility, etc.

The good thing about Microsoft .NET is (IMO) that for the first time - using Microsoft technologies - you can now sort of combine both. .NET allows you to create fully-fledged object-oriented, event-based, strongly-typed applications, which - from a design point of view - are infinitely much better constructed than most VB6 applications. Make no mistakes though, even in .NET its completely possible to write crappy applications, and unfortunately it gets done a lot.

The situation gets even more complicated when you add a product to the mix, lets take - as an example - SharePoint? ;)Sharepoint allows you to extend its out-of-the-box functionality with Webparts, which are really just a specific kind of Asp.Net user controls. Problem is, Sharepoint has its own logic, which makes a number of 'normal' sound design principles more problematic (client-side validation using Validators being one).

Again though, with a little effort, it is possible to create a well-structured application even in Sharepoint. As an example, in a recent project, we needed to create a webpart, which would, when the user put the page in Design Mode, automatically display a fairly complex user administration part. This admin part would then manipulate those values and have to pesist them as properties in the WebPart.

Now, speaking in design terms, two obvious choices presented itself.

1. Implement the functionality in the WebPart itself, resulting in a flat less-complex structure, but also quite quickly leading to spaghetti code, especially if the desired functionality is moderately complex. Plus, from a design POV, the level of abstraction is practically zero, which will not encourage reuse and/or extensions of the webpart.

2. Create a series of ASP.NET user controls, and use LoadControl on the top-level user control to add him to the control collection of the webpart. Its elegant, its sound design-wise, but it does raise the problem, how do we communicate between the 'layers'. Its the classic circular reference problem, webpart needs to know about user control to create it, and user control needs to know about webpart to give some information back to it. Circular references are solveable usually, but even if it was solved it would still leave you with a user control who somehow knows he'll be included in a webpart, which is again Bad Design.

So whats the solution then? Any experienced control builder in .NET will now be screaming it. *Events* of course. That wonderful mechanism, IMO one of the better features of .NET alltogether, that allows us to decouple layers from one another and create true plug-and-play usercontrols.

So, you set up the following situation:

- Webpart creates UserControl through LoadControl
MyCustomControl myControl = (MyCustomControl) Page.LoadControl("MyCustomControl.ascx");

- Webpart subscribes to the OnDataChanged event from the UserControl
myControl.OnDataChanged += new MyDataEventHandler( myControl_OnDataChanged );

- Webpart adds control to his own control collection
pnl = new Panel();
pnl.Controls.Add(myControl);
Controls.Add(pnl);

- Something happens in the control, and it raises the OnDataChanged event. Thats all the control needs to do, no 'upper references' needed.
private void changeButton_Click(object sender, System.EventArgs e)
{
if ( OnDataChanged != null )
{
OnDataChanged (sender, new MyDataEventArgs(e));
}
}
- The webpart receives notification of the event and does whatever it needs to do with it.
private void myControl_OnDataChanged(object sender, MyDataEventArgs args)
{
// do something useful
}

Thats all there is to it, the beauty of it is that you now have a user control which can be easily re-used in another webpart, or in another usercontrol or even directly in an aspx page.
Of course, there are a few SharePoint gotchas that even good design can't solve, but we'll leave those for another time ;)

Sunday, September 25, 2005

To fill the void

Welcome to (yet another) technology blog.

In here, I'll mostly be talking about my (mis) adventures in the land of technologies such as BizTalk, ASP.NET and SharePoint 2003. If the mood strikes me, I might even get a bit philosophical now and then, feel free to skip those parts.

What am I doing right now? I'm a Technical Analyst/Projectleader at Dolmen, a belgian software company. For the last few years, I've primarily focused on such areas as ASP.Net, Design Patterns, UML and BizTalk 2002 and 2004. Recently, Sharepoint 2003 has entered that list, and thats what I'm currently using the most.

I consider myself a generalist, meaning that I don't blindly focus on one technology, which - in my opinion - is not really possible anymore, since (for example) to know SharePoint you need at least a solid base of ASP.NET and Web UserControls knowledge (try making a Web Part without it...). Of course, its completely impossible to know everything about all products from the Microsoft family, so a little bit of specialization automatically occurs.

In the end, being a software guy is not about how good you are in certain technologies, what is important is your ability to adapt to new environments and products. With the current rate of new products/platforms/frameworks/whatever, by the time you 'dig' something completely, the RC1 of the next version usually rolls around the horizon anyway ;) So adaptability and flexibility are key. All of this is of course IMHO, allthough you can probably drop the 'H' :D

Anyhow, that was rambling number 1.

Sam