Friday, September 4, 2009

Using Sandcastle as a documentation tool

Recently, we evaluated several documentation tools, like ndoc, doxygen etc. We found that SandCastle (together with SandCastle Help File Builder GUI app - http://shfb.codeplex.com/) is the most appropriate tool for generation of rich documentation to .NET libraries.

It can create HTML DOC 1.1, 2.0 and pure HTML output, and here is an example of our work.

http://corp-web.b2bits.com/fixanet/doc/html/

What bugs we has found
1) When we add a picture to the headers of help content files, some fonts will be smaller then it was supposed. Perhaps the tool adds additional div and corrupts styles somehow
2) Sync topics button doesnt work in FireFox (but it is OK in other browsers)

In generally, it is the best free tool for .NET, I believe, while there are also several commercial tools one may consider - a list of them can be found there http://stackoverflow.com/questions/546053/anyone-using-ndoc-or-a-similar-tool-to-help-with-system-documentation/1200561#1200561

Thursday, June 4, 2009

Avoid verbose log formatting in .NET TraceListeners

The problem is:

when you use any of default TraceListeners (for example, I need ConsoleTraceListener), and when you call Trace.LogInfo , Trace.LogError or Trace.LogWarning, you wil have something like

Your application name: Information : : And here is a text of your message
Your application name: Warning : : And here is a text of your warning
....

Well, I don't need application name and I want to exactly control how the log is formatted. Setting traceOutputOptions in app.config will not change the situation, because with traceOutputOptions you can add date, timestamp or even full stack to the log, but there is no way to remove something out from there. Damn, now I understand why we have been used Log4Net for logging instead of System.Diagnostics.Trace! But in the current project I can't use Log4Net

Ok, to solve the problem I try to understand how the MS code works, when going from the point where you call LogInfo (message) to the point where it outputs to the stream.
I noticed that

When I call Trace.LogInfo(message), the following happens

1) TraceListener.Write is called with parameter like "application_name: message_type: 0 "
2) TraceListener.WriteLine is called with my message

So actually they write a log message in 2 turns, OK, sound great for me, as far as we can handle it now in the following way:

1) I created a simple class LaconicTraceListener, and the code you will find below. You need to override just one function there
2) And I added new cutom listener to the app.config file to the section.



And it works!


///
/// Class overrides one function of standard ConsoleTraceListener
/// to make output less verbose
///

public class LaconicConsoleTraceListener: System.Diagnostics.ConsoleTraceListener
{

public LaconicConsoleTraceListener(): base()

{
}

public LaconicConsoleTraceListener(bool useErrorStream)
: base(useErrorStream)
{
}

public override void Write(string message)
{
/*
A trick to avoid verbose logging.
LogInformation function works in following way -
For each call of LogInformation(Message) it actually calls:
1) Write("AssemblyName: MessageType: MessageIndent");
2) WriteLine(message)

We don't want to have an assembly name in each trace line, so we will exclude it
*/
if (!message.StartsWith(this.GetType().Assembly.GetName().Name,
StringComparison.InvariantCultureIgnoreCase))

{
base.Write(message);
}
}
}


Thursday, May 14, 2009

Using SET ROWCOUNT to limit number of deleted records

I was given MS SQL database with no normalization, no primary keys in tables and lot of duplicates.
How can you delete a duplicate rows from the table, if you have 2 rows where no unique key exists, all fields are equal, so there is no way to distinguish one row from another?

In Oracle you always have row_id so 2 between 2 rows you can delete a row with max(row_id)

In MS SQL you can use SET ROWCOUNT to limit the number of deleted records.

Run the following example, and you wil get and idea.

create table t
(
id int,
name varchar(100)
)
GO

insert t values(1, 'Number One')
insert t values(2, 'Number Two')
insert t values(3, 'Number Three')
insert t values(1, 'Number One')

GO


SELECT count(*) FROM t /* will return 4 */

GO

SET ROWCOUNT 1
DELETE from t where ID = 1 /* will delete only one record from 2 records with ID = 1 */

GO

SELECT count(*) FROM t /* will return 3 */

GO

Friday, May 8, 2009

The cheapest option to deploy Windows SharePoint Service solution for external users

Recently, we were estimating a solution for our customers. They want a Sharepoint (WSS 3.0) solution to be installed on a dedicated server and then used by their 100+ employees (they do not want to install a box in their own domain because don't want to bear additional administrative expenses, and don't want to pay too much for hardware, while renting a dedicated server will let them safely starts with small monthly payments for the hardware.

We were to find the cheapest solution with as less licensing costs as possible

The licensing politics of the Microsoft is very tricky. :) First of all, they recommend Windows Server Web Edition for front end servers. It has no limits in number of users. It costs only approx. 500$. However it is not suited for WSS deployment well, because you cannot install any database except MS SQL Express there. And SQL Express is limited with 4G, but our customer expects to have more then 100 Gb of documents in WSS document libraries.

Well so we though we will have to use SQL Workgroup Edition (to store more then 4Gb) and that means that we need to use Windows Server Standard Edition. We have 100 users, so per-user licensing model of SQL Server is not good for us, but per processor license is also not very cheap. And what if we have 2 processors...

Hopefully, I find the solution that post . It tells that Windows Internal Database, that is automatically installed when you install WSS in basic mode, is actually a special version of MS SQL Express with no memory limitation !

So, we proceed with installing Windows Server Standard Edition (costs approx. 1000$) and that should be enough to deploy WSS solution on one box, using Basic setup option.

Tuesday, April 7, 2009

Multi-dimensional arrays vs arrays of arrays in F#

Recently, I had to write a module with some array-manipulation functionality, and I decided to write it on F#

I had an array initialization function, something like this

let size = 100
let create_empty_array() = Array.create size (Array.create size 0)

Actually I meant to create an array of arrays initialized with zero. :)
But then I found that I have a lot of bugs with the functions that use that array. What an idiot I was when I was writing this!
Of course it will not work, because this code doesn't create 100 arrays of arrays, it actually initializes 1 array int[100] and then creates 100 references to the same array.

So I have to change it for the following

let create_empty_array() = Array.init size (fun i -> Array.create size 0)

The difference is that init function is evaluated value (using lambda expression) for each row, so it will really initialize 100 arrays of 100 integers

If you will use multidimensional arrays (instead of arrays of arrays) you will find that it will more convenient to use Array2 class (for 2-dimensional arrays) or Array3 (for 3-dimentional)...

let create_empty_array() = Array2.create size size 0

So what will you prefer - multidimensional arrays or arrays of arrays?

In my case I use arrays of arrays only to simplify multithreading processing if the need of it will arise in the future. I have a function that takes one row of array for some long-running processing, and I can run several threads to process rows in parallel (currently my function is not working that long, so it is only an imaginary scenario :) )

For those who is interested in some intorduction to arrays in F#, I will recommend the following post http://mariusbancila.ro/blog/?p=109

Thursday, March 26, 2009

Is there a really free full-functional blog in Kentico CMS (free edition)?

Really, if one will look at the http://www.kentico.com/cms-asp-net-features/Feature-Matrix.aspx to evaluate if Kentico CMS free edition is something that you can use for building a personal web site for your small non-profit organization, it will be clear that free edition contains only one blog. ok 1 blog will be enough for me, who cares, if our organization has only 10 people so let them use 1 common blog, that's all.

But, the truth is that Blog for the free edition comes without front-end editors for Blog. To post a blog message, you have to log in to CMSDesk (it is a content administration console) and add a new blog there.

I played with the blog page design trying to add a Edit Blog web part, but I got an error message saying that your license doesn't allow this.

Actual reason for this license limitation is that blog editing is implemented with the User contributions module (see Kentico developer's guide, Blog Module, On-site management via User contributions).

And, guess what, User contribution is not included neither in a Free edition nor in a profeccional one. So if you want to be your Blog a real blog, you will have to prepare 2K $ for an enterprise edition of Kentico. Or find another free blog engine for you .NET site (for example, subtext) :)