Monday, October 31, 2005

Passing complex object graphs through web services

The web method must be attributed as SoapRpcMethod and all the types that occur in the object graph must be defined by using BOTH XmlInclude AND SoapInclude attributes:
Public Function GetPersons() As Person()
    ' code to return person
End Function
The client proxy class must have SoapInclude attributes for all types in the object graph:

System.ComponentModel.DesignerCategoryAttribute("code"), _
System.Web.Services.WebServiceBindingAttribute(Name:="PersonServiceSoap", [Namespace]:=""), _ 
SoapInclude(GetType(Person)), _
SoapInclude(GetType(Nurse)), _ 
SoapInclude(GetType(Doctor))> _
Public Class PersonService    
Inherits System.Web.Services.Protocols.SoapHttpClientProtocol
    ' implementation
End Class
When you generate a proxy class using WSDL.exe (via Visual Studio too) it will generate dummy versions of all the classes described in the WSDL file. You need to delete these and make sure your proxy class has a reference to your domain objects so that it deserializes the soap message as the correct types. Passing object graphs through web services puts limitations on your object design. Rocky Lhotka discusses this here This is because of the way objects are serialized by web services. You have to have a default constructor and all properties have to be gettable and settable. This is unfortunate because it means you can’t do good object oriented design. An alternative is to use the binary serializer and then pass the resulting byte array using web services, but then you loose the interoperability that web services give you.

Tuesday, August 30, 2005

Automatically logging into windows

We have one Windows XP machine at home that is used by the whole family. When I first set it up I created an admin user and a low priviledged user 'mike' and gave both passwords. The default setup with XP is to automatically log you in as administrator (yes, I know, no wonder there are so many successfull exploits out there for windows), but after you create accounts and give them passwords you arrive at the logon screen after booting up. I wanted to keep both accounts with passwords but to automatically login to 'mike' when the machine booted up. type the following at the command prompt (while logged in as adminstrator): control userpasswords2 The 'user accounts' dialog opens. Uncheck 'users must enter a username and password to use this computer' and click 'apply'. A dialog pops up asking you to specify the user that will be automatically logged on. Enter the name and password, click OK and you're done.

Thursday, August 25, 2005

Programming Quotes

"Premature optimization is the root of all evil (or at least most of it) in programming." Donald Knuth "The first law of distributed object design: Don't distribute your objects!" Martin Fowler

Monday, August 08, 2005

Why you should never use the DataSet or XMLDom

OK, so that's quite controversial. I probably shouldn't say 'never', but I think it's usually a good indication of bad application design when the DataSet or XMLDom appear as central parts of the application architecture. So why shouldn't you use them? The simple answer is there is a much better way, the 'business object model' or 'domain model'. Pretty much all the enterprise application architecture gurus now favor centering an application around a central object oriented model of the business data. The DataSet and XMLDom are both ways of holding structured data in memory and they both suffer from two huge drawbacks compared with an OO approach: 1. They are not strongly typed. You can put any kind of data in a DataSet or XMLDom, you can dynamically change the 'schema' at runtime and you no way of ensuring that the structure you are expecting is the structure that is actually there until runtime. You are throwing away your first and best line of defense, the compiler, because the compliler can know nothing about your schema. 2. They break encapsulation. In the OO world the operations on data and the data itself are tightly coupled in the same class file allowing the class to only expose a very controlled interface to the outside world. That's the essence of encapsulation. Both the DataSet and the XMLDom are amorphous blobs of data that have to be operated on by code that has no instrinsic link to that data. You have no easy way of looking at all the code that operates on the data because it's spread throughout your application and you have no way controlling the access to that data because it's interface is not controlled. So what should I be doing? Firstly you should design your application around a 'domain' or 'business object' model. I strongly recommend Eric Evan's Domain Driven Design for a powerfull discussion on why's and hows of 'Domain modeling' and Rocky Lhotka's Expert C# Business Objects for a practical guide to building business object models with C#. He even provides a complete application framework, CLSA, that you can build your applications with. The next version of Visual Studio will come with Whitehorse, a fully intergrated class documentor/generator that will make designing and building domain models a joy. Now, instead of reading your data from SQL Server or XML into a DataSet or DOM, you write code to read the data into your domain objects. Reading relational data usually means cutting your own object-relational code although there are now some open source projects, such as NHibernate, that can supply an object-relational framework off the shelf. Microsoft also announced an object relational mapping tool, Object Spaces, but I understand that it's been dropped from .net V2.0. I'm still not quite persuaded how robust, secure or scalable these are, but I'm open minded about trying them out. With XML the .net framework makes it very easy if you have control over the XML Schema and your domain model simply to use XML serialization to stream XML to objects and objects to XML.

Development essentials

Here's a list of things that I currently think are essential for anything other than the most trivial .net project. Most of the tools I mention are either provided by Microsoft at no extra cost or are open source projects. There's no excuse not to use them! Dedicated build server You must have a dedicated build server that can build your entire software from source. At a minimum you must be able to run at least a daily build of your code from your source control system. It's best if it can automatically get the latest version from source control, build and run unit tests on demand, so that any developer can run the build after a check it. Breaking the build should be considered a serious offence. NAnt is a good open source build tool for .net. Build systems often overlook the database, this is understandable since the database if often the preserve of a separate team of DBAs, but it's no less essential that you can build your database from source. Maintaining SQL scripts in the right build order is a major headache, but there are some good tools available that can make database builds and updates much easier. I like DBGhost. I've worked on large projects which didn't have a build system in place. The pain is intense! Developers spend most of their time debugging deployment issues. No one really knows what version of the software is deployed on what servers. No one really knows what version of the source code is compiled into which components and no one really knows if the source code in the source control system actually compiles, let alone works! Automated Deployment Without automated deployment it's difficult and error prone to deploy your software and you are liable to be dedicating considerable resources to debugging deployment issues every time you need to spin a new rig. With automated deployment you can spin rigs easily which means that test teams get frequent, predictable, up to date test rigs and you can have confidence when you spin your production rig that it will perform without deployment issues. The Microsoft installer (msi) is a powerful scriptable tool that you can use for large multi server deployments. Source Control You must have source control. Most Microsoft shops use Source Safe which is just about OK for small projects but has major scalability issues. Microsoft will be shipping an enterprise source control system with VS2005. I've used Subversion with Tortoise which I was quite impressed with. You must only ever allow compilable unit test covered code to be checked in. Test Driven Development I would never write any software now without unit tests. NUnit is the the most popular .net unit testing framework. Microsoft will be releasing their own unit test tool with VS2005. It's also a good idea to use a tool to ensure that you've got full unit test coverage. NCover works well. If you're new to TDD read Kent Beck's book on the subject. Tool enforced coding standards You must have coding standards in place. The best way of making sure that programmers stick to them is to use a tool such as FXCop. Bug tracking database You need to be able to keep track of bugs. The best way of doing this is with a bug database like bugzilla. Bug databases can also be used to track features and are an essential piece of good software management. Once again, Microsoft are introducing a bug/feature tracking database with their VS2005 team system.

Friday, August 05, 2005

Developing with least privilege

I've always coded while logged in as Administrator, but after listening to a great discussion about developing with least privilege (DWLP) on dot net rocks I've been persuaded of the benefits and decided to give it a try. Developing, or doing anything for that matter, with least privilege is about making sure that for whatever task you're engaged in you only have the permissions necessary to carry it out. I guess the thing that persuaded me the most was thinking about the number of times I've worked on applications where everything worked fine on my machine (logged in as administrator), but then facing all kinds of problems at deployment. Not only that, but by developing as administrator you're hiding from yourself the permissions your application, or the tools you are using require since you're never forced to examine them. For example, I wasn't even aware of the VS Developer role until I started to do DWLP and the permissions used by ASP.NET were also somewhat misty in my mind. So what do you need to know to do .net development while not logged in as administrator? First your account must be a member of the following groups:
  • Users
  • Debugger Users
  • VS Developers
ASP.NET applications run under the 'ASPNET' account by default. You would have thought that being a member of Debugger Users would mean that you could debug ASP.NET applications even though they are running under a different account, but according to MSDN, you're only allowed to debug if you are logged in as an administrator. So in order to debug ASP.NET applications we need to run the ASP.NET worker process (aspnet_wp) under our own loggin. To do this change the machine.config process model: You also need to grant read/write access to the windows directory and the framework directory to your account. On my machine these are at: C:\WINDOWSC:\WINDOWS\Microsoft.NET\Framework\v1.1.4322 It's a shame that the ASP.NET development model requires these changes. It makes it apparent that the development team assumed that developers would be developing as Administrators against all security best practices. Having to give a restricted user write access to the windows directory and puting the user's password in plain text in the machine.config file kinda defeats the object of the exercise. Now if I inadvertently access the windows directory programmatically from my application I'll be breaking the application for deployment under a restricted user account, but I wont discover this until the application is first deployed. There are plenty of tools you are going to need to use as a developer that have to be run as administrator. The trick is to only run those tools as administrator. You can run any program with a shortcut as another user by right-clicking the icon and selecting 'run as', and then choosing the username you want to run under. You can run any command line program (including cmd.exe) under a different username with the 'runas' utility. E.g: runas /user:admin cmd.exe Check out developing as non admin for a really good overview.