Saturday 14 July 2007

SSW Code Auditor - a review

A quick search for code standards review tools for C# lead me to SSW Code Auditor. Among others (FxCop, Standards Master 2005,FMS Total..), this tool appeared to be something easy for an average developer to use from the first day.

Details

Once the trial version is downloaded, the first thing which would strike you are the pictures of all kinds of fruits (yes! apple, the sign of health to start with). The GUI tries to be very straightforward using a wizard kind of interface but is not effective. It would take atleast another 10mins before you realise that the 'database' is effectively a kind of project where you add each subsections to be tested, as 'jobs'. Not sure why this isnt just a project file and a list of jobs within it such that I can create multiple projects using File->New?

Anyways, once you add your list of folders, files which needs to be audited, you get to select the rules you want to be tested. The trial version appears to have 147 rules of all kinds enabled. Perhaps new standard rules would be added periodically by SSW as a rule-update file?

Could not add a new rule or edit a rule in this trial version. But would have been good if the trial version let you create one custom rule - just to check out things. A fully functional version which works for particular time period is recommended for bringing out trial versions of utils.

Within a normal wizard layout, the usual tendency is to click next next next.. finish. One non-standard UI design was the start/skip button within one of the wizard page. These buttons are the ones which check the selected files against the selected rules. What would have been a better UI design would be to bring down the start/stop/skip buttons instead of the back/next/cancel buttons.

The browser rendered result page tells if the application is healthy or not (images varying from apple to burger to denote these!) and the detailed list of issues it located. Thankfully, the results can be arranged by file names such that I can see all the issues my particular class has.

What strikes you while you use this application is the language of the messages contained in the forms and the reports. Its just simple and communicates good to the developer. The report tells you what is wrong in plain simple English with a quick tip. Great, when you think about the rather complex messages from FxCop.

The other nifty functions included emailing the results, scheduling the tests (again not available in trial version), creating a batch file which you could execute from the command line and also performing a test of the just checked-in file ( with Team Foundation Server). This feature would be really good - the developer would get the list of issues with his file as soon as its checked in - great.

In addition to the standalone application, the VS.NET plugin is what you would use on a daily basis. The plugin makes the distinction between FxCop and Code Auditor obvious when it lets you select assemblies with FxCop and source code with itself. Sadly, I could not get this to test just my active source file. It had to perform the test on the whole project each time.

The VS.NET plugin also appears to add two files (one for fxcop another for itself) into an individual solution item folder for each of the project in the solution. This definitely appears to clutter up the solution explorer. What would have been a lot better is a single solution item with all the files for all the project within the active solution.

To summarise, once you get a kick of this no-nonsense tool, it should be a pretty good companion during your daily development activity. Perhaps the next versions might also fix the obvious errors automatically.

All those fruits; from apples, bananas to strawberry has definitely made me hungry! I think am off to the kitchen.

Sunday 24 June 2007

SQL Server + CLR -> Stuff noted

There appears to be many limitations and rules to be followed while using the CLR to write an SQL object:

. While using the context connection object via SqlConnection("context connection=true"), make sure only one connection object with this context is open at any point in time. 'Using' should be your friend here.

. If you want to initialize application data which needs to be re-used each time the function/trigger is called, you would want to use static variables. SQL Server would let you define readonly static variables only. (This effectively means, that all initialization has to happen at the constructor).

. Want to access a different database from within a function/any other CLR object ? Make sure the assembly has EXTERNAL_ACCESS granted.

. When your code starts to use locking/objects which use locking (most trace listeners do) , SQL Server complains like mad. At this point, you have no way out other than make sure that the login you created with the asymmetric key on the master DB has got the UNSAFE access.

. To make sure that debugging works OK, make sure that the symbols file (.pdb) is added to the assembly with an alter assembly add file statement.

. If you are accessing a different DB, the transaction for the current context would not be use full there since CLR would not let you. You would need to force a new transactionscope in this case.

As can be seen, there requires lots of hacks to make the stuff working in the CLR environment. The first draft of the code you wrote is guaranteed to not work with SQL CLR :)

May the CLR be with you.


Monday 28 May 2007

SQL Server 2005 & A Global Trigger

With the introduction of CLR into SQL Server 2005, the programmer can now write functionalities exploiting the C# language and the vast .NET library. A closer look at integrating CLR trigger handlers reveals many interesting stuff:

Classes of concern
Namespace Microsoft.SqlServer.Server contains all of the classes we would use in a SQL CLR object. While writing triggers, we would be exposed to:

SqlContext - gives you back the execution context to get more information;In the case of triggers, we would use the SqlTriggerContext to get the TriggerAction - delete/insert/update, columns updated etc.

SqlPipe - This acts as the channel/pipe to send back stuff to SQL Server, ranging from debug messages to recordsets; using the Send method.

SqlTrigger Attribute - These attributes appear to be used only by the Visual Studio environment while deploying the CLR object (I think!), since most of these parameters (Target, Event) can also be specified using DDL statements.

Writing Trigger in CLR & Integrating
Once you create a DB project in SQL Server 2005, writing a trigger is quite simple. Create a new class, create a new public method with the SqlTrigger Attribute applied to it. Within the procedure you would want to use the SqlTriggerContext and perhaps the SqlPipe object (as described above)

Once everything is compiled right, go to your T-SQL editor and perform the following [you could also deploy the assembly directly from within VS.NET; but then, where is the fun? :)]

a.) create an assembly within SQL Server, pointing to our .NET dll file. You would need to specify EXTERNAL ACCESS if you are looking at cross database updations from within the trigger, which would also need special permissions.

b.) create the trigger against your table using the CREATE TRIGGER with EXTERNAL name pointing to the assembly.namespace.class.function.

c.) Thats it!

Global Trigger
Its interesting to note that if you havent specified a Target in the SqlTriggerAttribute, you could reuse the same assembly object for any number of tables. You just have to create a trigger against the table in concern using our assembly object. This way, you effectively have a single trigger codebase running against all of the tables. Easy to maintain :)

Accessing the Table Name from within Trigger
Unless you are writing trigger for a single table, you might want to know the table name for which the trigger is executing. There appears to be no straight property/method to do this (Why couldnt the context object just return this?) and what could be figured :
SELECT object_name(resource_associated_entity_id) FROM sys.dm_tran_locks WHERE request_session_id = @@spid and resource_type = 'OBJECT'

This basically gets the object name which is locked in this session. (a very dirty hack ,unless someone figured out a better way?)


Saturday 19 May 2007

The Jukebox Issue

Problem at hand
What we had in place was a jukebox system wherein the client application on user machines would request songs from the main play list on the server. The server would pick up the next song in this queue and play it using media player on the server machine. The sound output is directed to the music system such that everyone around could listen to the many songs requested by others.

Everything appeared to go well until the non-jukie fellows started complaining - they did not want to hear to these songs, usually a different language/dialect. The music system had to go :(

Requirement
Now how do we fix this problem ? Music enthusiasts needed to be able to listen songs requested by others from their individual machines, perhaps using the headphones such that the non-jukies are not bothered.

Solution
Instead of directing the output from mediaplayer to the music system, use windows media encoder 9 series on the juke box server machine. Windows media encoder could encode music coming out from the soundcard into a live stream.

We needed a Win2003 box with Windows Media Services 9 series installed (comes with SP2) which can broadcast streams. Once we have this, setup the windows media services to feed from the media encoder stream off the jukebox server. What is remaining is simple. Ask all our dear enthusiasts to use Windows media player to listen to the live stream off the 2003 box. This way, the enthusiasts listen to the songs requested by other enthusiasts without disturbing the non-jukies.

Peace reigns once again.

Thursday 19 April 2007

WWF - Persisting WorkFlow

Why Persist?
The workflow host, which could be anything from a console application to a full fledged service application like MOSS, is not expected to maintain the state of the workflow instance in memory all the time. This is simply to save server resources and make them available. This considers the fact that workflows could be running for days.

Persisting - The common path
To save/persist/dehydrate/stream/serialize (yes, all denote the same idea conceptually) workflows, you usually use a workflow persistence service object such as the SqlWorkflowPersistenceService. This object could either be consumed directly within your own hosting application codebase or set up via a config file.In either of the case, you could ask for an automatic save when the workflow is 'idle' using the UnloadOnIdle entry.

What needs to be noted here is that all objects used by our workflow should be serializable in order for the host to persist the workflow (and the related objects) OK. An exception is guaranteed otherwise.

When does the save happen?
The workflow runtime appears to persist the workflow on these scenarios ('persist points') :
Against an activity, when it gets completed. (Check out the PersistOnCloseAttribute declared against Activities.)
When the workflow is completed or idle (delays, event waits)
When the workflow is forcefully unloaded.

Writing Custom Persistence Layer

Overriding a few functions by descending from the WorkflowPersistenceService class makes it easy to write a custom persistence class. Further, this new class could be made active against the workflow via the config file. But, most of us should be happy with the out of box SqlWorkflowPersistenceService which does seem to do the job good.

Persistence under MOSS
MOSS as a host has its own persisting service which uses the SPWinOePersistenceService object by default. [haven't tried forcing a different persistence object via the config though]. Waiting for external actions which include delays, waiting for events to fire etc causes the workflow to be persisted/saved to DB. The workflow appears to be serialized to the WorkFlow table (check out the InstanceData column) in the Content DB for the site.

Wednesday 18 April 2007

Sharepoint - Integrating MOSS+WWF+ASPX - Part 3

Exposing our WWF workflow to MOSS
There are two more bits we need to do in the WWF workflow application to make it available to MOSS. We need to declare the feature and the workflow xml.

feature.xml
MOSS introduced features for the developers to create site items/functionality which can later be linked with sharepoint collectons/sites. Within this XML file, you would also tell which XML would contain the feature specific details - in our case workflow.xml.

workflow.xml
Describes stuff about our workflow to sharepoint, including name, description , id etc. This also defines the pages which would be used for workflow Instantiation, association and modification. We shall have a look at an example of Instantiation later in a different blog entry. Modification of workflow (say you would to add more reviewers) at runtime needs a few extra steps and this is when the modification page comes into effect.

Defining Custom Pages for Task Initiation
For ease, all of these three pages needs to derive from Microsoft.Sharepoint.WebControls.LayoutsPageBase with sharepoint master pages (~/_layouts/application.master) being used in the ASPX definition. MOSS provides a lot many master pages which give the consistent look and feel of standard MOSS pages. The content placeholders within the masterpages would need to be filled in by us to define the various entries for the page. Since the master pages would not be usually available at the developer machine, designing these pages is not the easiest of task. Did try copying the pages locally to my machine, but VS.NET does not want to pick these, no matter what.

What we would want to do within the initialisation page is to serialize all the user entered stuff and call a Web.Site.WorkflowManager.StartWorkflow with the serialized data. Its this data which the OnWorkFlowActivated event in the WWF workflow would contain (refer to part 2 of this series)

The important points to note here would be the layouts page, the master page , calls to sharepoint functions and the way the page data transfer data to WWF via MOSS.

We have on more VS.NET task remaining, which is creating the task updating page. This page would be used by users to approve/reject tasks. This works a bit different from the three pages listed above; exploits ContentTypes. Next Blog.

Thursday 5 April 2007

Sharepoint - Integrating MOSS+WWF+ASPX - Part 2

Starting with SharePoint Workflow Project
Once you have the sharepoint extension installed, the default project based on these templates would have the OnWorkFlowActivated activity placed as the first activity in the workflow. When Sharepoint initiates our workflow, its this activity it calls as the first step - acting as the entry point into our workflow.

Data Sharing
Sharepoint shares data with the workflow using one of the following ways:
1.) Instance of SPWorkflowActivationProperties would anytime contain the workflow properties, the most important of which is the initiation data. Initiation data could basically be any custom string passed in while you start the workflow from sharepoint. If you happen to have a custom initiation page (we shall discuss later) which explicitly initiates the workflow within sharepoint, it could perhaps serialise a data class instance based on the form data which we could use via this activation property.

2.) Events - Each of the OnXX events against an activity have event properties passed applicable to the context.

3.) Activity Properties - Each activity have certain properties which map to a workflow property/variable, which you usually setup during design time.
eg:- CreateTask activity has got two properties TaskID, TaskProperty. If you refer to the same variable in a different activity property, (say CompleteTask.TaskID), you are effectively refering to the same task. Also, any data you set to these variables are also passed back to Sharepoint. What you acheive here is sharing/relating data items between activities and between workflow & sharepoint.

Correlation-Token
Nearly all activities have a correlation token which is an identifier for the workflow context. This is for sharepoint to understand the context in which the activity is working. Eg:- you would use the same correlation-token for the createtask, ontaskchanged, completetask activities to specify that all these are of the same workflow context.

Does sharepoint persist the workflow?
Ofcourse it does. There is no way sharepoint can remember workflows running for days (say the task may not have been looked yet by the user). In these special cases when sharepoint is explicitly waiting for an event (
during a while activity, during a delay activity etc), sharepoint automatically serializes the workflow. When the related event happens , sharepoint deserializes the workflow and returns control back to the workflow. At this point, its the correlation token which is used to relate the item in concern with the workflow context [eg:- identify the task context]

Example
So to try out some basic stuff, add the basic activities - CreateTaskActivity and within a WhileActivity put the OnTaskChangedActivity and finally a CompletetaskActivity. If your property links and the correlation token is right, there is nothing more to be defined at the workflow definition designer.
To define what happens at each activity (some code finally):
At the CreateTask activity, setup values for the task property like who is the recipient, description, taskid etc.
At the whileactivity, check if the task has been completed - perhaps using a public variable which was inturn set at the OnTaskChanged activity.
And at the completetask, setup the task status to 'complete'.

Guess we are done defining the Workflow.

Next lets define the custom pages which we would use for initiation of the task and also relate these pages to the workflow. Please await for part 3 :)