4/13/09

Building Saas application in .NET


Take advantage of ASP.NET single sign-on

If your application is going to be comparmentalized into multiple sections, consider using third domain (sub-domain) such that you have

http://foo.myapp.com
http://bar.myapp.com

then make sure to enable cross-sub-domain SSO by writing the ASP.NET forms authentication cookie against "myapp.com" domain (as against a specific sub-domain such as "foo.myapp.com" or "bar.myapp.com"). This provides extension points for additional ASP.NET web applications while using the same login sessions.

Consider using third-party single sign-on integrations
Try not to build your own identify server. That is: do not implement your own "login" page that takes password that you manage. You want to stay away from that. Instead, use external identity servers including Windows Live!, Yahoo BBAuth, OpenID, etc. This is a win-win for developers as well as users.

Use XML schema-driven business objects
After many tries with different approaches, I am convinced that using XML Schema (XSD) with tool generated C# wrapper is the best way to capture business objects. For any new web application, I create a folder called "Entities", and I create three files:

mybusinessobjects.xsd
mybusinessobjects.cs
generate.bat

mybusinessobjects.xsd will contain all of the data type definitions of the application's business objects. For example, if your application is about student enrollment process, then you will define Studen, Course, Semester, etc. in this XML schema.

mybusinessobjects.cs is not manually created but created by running XSD.exe tool, that takes XML schema file and produces a C# class definitions. generate.bat is for running XSD.exe and it looks like this

xsd.exe mybusinessobjects.xsd /n:MyApp.Entities

By executing this line, you will easily get C# object representations of all of the things you defined in mybusinessobjects.xsd, placed in the namespace, "MyApp.Entities"

These tool-generated C# classes are in-memory "storage" for your business objects, and they can be serialized to XML (and deserialized from XML) very easily.

This serializability between XML and C# is very convenient and flexible. For example, you can write UI that takes C# object model and set it to DataSource of ASP.NET Repeater control. Or, you can deserialize it to XML and pass it through XSLT to produce another XML, which can be consumed by an existing code. It opens up possibilities to working with your business objects.

Use XML to communicate with Database
After many attempts to use DataSet in ADO.NET, I am settled with this approach. The idea is to use very stable stored procedure interface, and use XML as input and output parameters, and all variations are captured in XML input/output. For example, many of the stored procedures have the same signature of:

sp_foo(userId, languageId, xml)

which returns string (which is xml output)

Note: there will be some stored procedures that must deviate from this pattern

With this interface, you can easily build Data Access layer that can be used by Business Logic layer to update data and retrive data to/from database.

The stored procedure has to be written such that it can take incoming XML and parse it to obtain necessary inputs for the procedure, and be able to form XML output. (Luckly, DBA I work with is very good at this that I don't need to know how its done exactly...)

Use SQL Data Services
This is another approach for solving data storage needs for a SaaS application. Instead of your maintaining database for your self, completely offload that task to cloud computing. Though I have not used it for commercial development project, I am convinced that SQL Data Services provides sufficient data storage capabilities to web-based application. The benefit is clear: you do not need to maintain your own database tier in your data center (and if you use Azure, where you host your ASP.NET application, then you don't need data center all together!); you pay as much as you use so it is cost-effective.

Use YUI (Yahoo! UI) for your page development
I have used YUI for both work and hobby and works great. It gives you browser neutrality right from the beginning. Let these experts at Yahoo! to solve browser compatibility issues and just focus on solving your own problem. YUI can be a bit tricky to use in ASP.NET, but many of the components in YUI can be used easily in simpler cases.

Use HttpHandler for AJAX server
It is possible, and often done, to use regular ASP.NET pages (.aspx) to implement server-side logic that returns XML (or JSON) output to a client-side script. Howerver, it makes more sense to implement such server-side logic using HttpHandler, which is more efficient than ASP.NET pages, and fits well with the model of "client script (UI) - server logic (BLL)". Essentially, client script is acting as user interface, and if you follow strict sepration of UI and Logic, then your server-side logic should not have anything to do with UI, such as page controls. HttpHandler is nothing but an end-point responding to an Http request, where returned output may not necessarily HTML but XML, JSAN, image, document, etc.

Enable Google Analytics right away
No further discussion on this. Just do it.

Pay attentions to security from the beginning
With web application, you want to start with "locked" down application instead of you lock it down as you go by. Read up "cross-side scripting" and "SQL injection" first and make sure we have no holes for that. Compile a list of Query string being passed around, Cookies saved to the user's machines, input fields that user can type in, and make sure each item is being evaluated to ensure that these cannot be exploited.

Build exception and error handling infrastructure
First thing you have to do is to define "application exceptions" at your Business Logic layer. Any Business Logic has an error condition that is created because of "user". For example, with Student Enrollment application, if one of the business rules states that "You cannot sign up for a class unless pre-requisites are completed", then you have an exception. Yes, UI can try to make sure that it will never be in such condidtion, but who knows? Business logic layer should NOT rely on UI does good job and never create such situation. Instead, Business Logic should throw "application error".

This is one of the most important use of Exception handling. You will define your own "application exception" that can be presented to the user and "user" can modify his/her behavior to fix the issue. This is in contrast to "system exception" where it is due to system error and not user. For example, if disk space run out and causes IO exception, user can do absolutely nothing to remedy that.

So, you deal with two large groups of exceptions: Application Exception and System Exception. Now, how do you handle them and where? The answer is: at each page, look at method that make call to Business Logic layer and wrap it around with try block, then create one catch block to handle application exception, and anthor one for system exception. The way you handle two kinds of exception is different: for application exception, tell user why and what user should to do avoid receiving the same exception (example: show message like "You are not allowed to enroll this course because you have not completed HIS101"). In contrast, for system exceptions you want to show something like "A system error encountered. The error has been reported to system administrator. If this problem continues, please contact xxx-xxxx. Error Code: 2231".

When handling system exception, your catch code must log the error to somewhere (such as text log file or event log). Ideally, you generate a unique Error Code value, and write it to the event log with the detailed error information, and also show it to the end user. This way, when user calls for a help, technical person at our end can locate the related error event log.

Use WF and WCF right from the beginning
There are features in Workflow Foundation and Communication Foundations that let you implement your application features easily and effectively. WF comes with sequential workflow and state machine workflow that models many real-world workflow. For example, "student enrollment" is a perfect example for sequential workflow that takes multiple input values to produce a result (student has sign up, system accept it, schedule bill, etc.)

WCF opens up possibilities to "extentions" such as web-service, REST based API, working with additional back-end engines, etc. The boilerplate code for hand-shaking, security, throttling and bufferin, are all taken care of for you.

Engage users as soon as possible
In another word, engage in Agile software development model. I strongly recommend using User Stories methodology to drive the whole development process. Good applications solve real user problems, and to do so developers need to know what the problems users are facing. Sometimes users don't know how to describe the problems, and/or they may not understand the best way to solve it. The chances are, the application you built today will be ineffective tomorrow and you will have to make constant changes to the application. So, stay small and address core issues first, then present it to the users to see if it is indeed solveing the users problem. Do not waste time working on bells & whistle since users can go without them for a while.

Integrate with Facebook and other social media as much as possible
Consider creating a Facebook application that provides an interface to your web application. At minimum, Facebook app has iFrame mode where you can show your web application interface embedded in Facebook. Of course, if you can integrate more, that would be nice. Facebook is an organic solution delivery mechanism where solical graph drives the distribution of solutions. If your application solves a problem for one Facebook user, then chances are, it will be useful to other Facebook users, and the initial "case" of one user solving his/her problem can proliferate to other users with similar problems. Forget the classic "you come to our website and sign up to get good stuff" model.

That's it for now...