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) :)

Tuesday, August 19, 2008

Using Linq for SQL with FOR XML procedures

The problem is

I have a stored procedure in MS SQL that ends with SELECT ... FOR XML, and formerly I used XmlReader to access the data from it (by calling SqlCommand.ExecuteXmlReader())

Now I'm trying to figure out how to access to this using LINQ
With VS constructor I drag and drop this procedure into Linq To SQL data class designer.

It creates something like that

[Function(Name="dbo.my_Procedure")]
public ISingleResult my_Procedure([Parameter(Name="param1", DbType="VarChar(50)")] string param1, ... all other params)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo) (MethodInfo.GetCurrentMethod())), param1, ... all other params);
return ((ISingleResult)(result.ReturnValue));
}


Strange thing that actually procedure returns not a sinlgle line but a collection of arbitrary broken XML source (I'm just wondering what parameter controls the size of each piece)

So to put all XML together you need to create a stream (memory stream) or file and an XmlTextWriter object, opened over the stream and a code like that to select all parts of the XML


System.Collections.Generic.IEnumerable rawXMLLines =
(new
my_ProcedureDataContext()).my_Procedure(param1, ....)
.Select(
my_Procedure => my_Procedure.XML_F52E2B61_18A1_11d1_B105_00805F49916B);

foreach (string rawXML in rawXMLLines)
{
writer.WriteRaw( rawXML );
}

Well, not so much development work but...

Seems, that we lost here the main advantage of the
SELECT ... FOR XML clause - an ability to write Xml to the output stream directly from XmlReader (that we get from
ExecuteXmlReader()) , which is the most effective way if you are working with large XML files.

In the example, shown above, the results of the procedure is extracted by LINQ engine to the collection of strings before we start writing these strings one by one into output stream with XmlWriter.


Thursday, August 14, 2008

Strange Oracle behaviour

In our project we have one very complicated query that involves 10 or more tables joined with left joins or inner joins

IN EACH TABLE there was a field DELETED.

Developer who writes a SQL query made a mistake forgetting to add an alias to the DELETED field in the following WHERE clause

select ...
from table1 t1 join table2 t2 on t1.table1_id = t2.table1_id etc...
WHERE DELETED = 0

and what was strange - there were no compilation errors, oracle executes that query but guess from what table it takes DELETED field? I don't know! But not from the first table :) This behaviour leads to the bug that was very hard to find, debug and correct.

Finally when developer corrected where condition, it starts work as expected

WHERE t1.DELETED = 0

It is not the first case that makes me furrious about Oracle!

Wednesday, May 28, 2008

Architecture of .NET projects with LINQ

LINQ promises a lot of advantages and simplify most things that usually should be implemented in Data acess layer

However, currently I can't find any suitable design patterns that can show how one can build a huge project (say 100+) tables avoiding copy-paste code.

Recently, I found a post Building Multi-Tier Web Application in .NET 3.5 Framework Using LINQ to SQL but there is no answer to how to avoid a lot of copy-paste code.

So, I think I should play more with that code, generic classes and new C# 3.0 language features...

Wednesday, March 19, 2008

Using Transactions with Strongly Typed datasets

Strongly typed datasets , generated by Visual Studio 2005 have a lot of disadvantages and developer of a real-world application usually have to write a lot of additional code in order to use them.

One of the issues - you cannot use SqlTransaction object with auto-generated datasets unless you write some additional code in partial classes of data adapters. Surprisingly, most .NET developers even don't care about that. But if you develop dataset composed of several tables that together mean one business entity, one may expect that if any exception during update of this entity happens, all changes should be rolled back, otherwise you may get inconsistent data.

In my example I created a Windows Console Application in VS 2005 C#. Then using database explorer connected to AdventureWorks database (that comes with MS SQL Server 2005 examples) created a dataset with the tables Customer (mapped to Sales.Customer), Address (mapped to Person.Customer) and CustomerAddress (mapped to Sales.CustomerAddress)

Supposing that I will have a form on UI where I want to edit customer's data and customer's addresses as well. It is not so unusual scenario, and I naturally will want to save all this in one transaction.

In order to do this I have to created a partial classes for all table adapters to make transaction property available to set from an external class, i.e.:

namespace TestDatasetTransaction.CustomerDataSetTableAdapters
{
partial class CustomerTableAdapter
{
public void SetTransaction(SqlTransaction tran)
{
this._adapter.UpdateCommand.Transaction = tran;
this._adapter.InsertCommand.Transaction = tran;
this._adapter.DeleteCommand.Transaction = tran;
}
}

partial class AddressTableAdapter
{
public void SetTransaction(SqlTransaction tran)
{
this._adapter.UpdateCommand.Transaction = tran;
this._adapter.InsertCommand.Transaction = tran;
this._adapter.DeleteCommand.Transaction = tran;
}
}

partial class CustomerAddressTableAdapter
{
public void SetTransaction(SqlTransaction tran)
{
this._adapter.UpdateCommand.Transaction = tran;
this._adapter.InsertCommand.Transaction = tran;
this._adapter.DeleteCommand.Transaction = tran;
}
}
}

in Visual Studio designer I created a

then I wrote the following code in the console's main class to prove that transactions really works.


using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;

namespace TestDatasetTransaction
{
class Program
{
static void Main(string[] args)
{
int customerID = 1;

CustomerDataSet customer = new CustomerDataSet();

//fill all records in CustomerDataSet with data for one customer
CustomerDataSetTableAdapters.CustomerTableAdapter customerTableAdapter = new CustomerDataSetTableAdapters.CustomerTableAdapter();
customerTableAdapter.FillByCustomerID(customer.Customer, customerID);

CustomerDataSetTableAdapters.AddressTableAdapter addressTableAdapter = new CustomerDataSetTableAdapters.AddressTableAdapter();
addressTableAdapter.FillByCustomerID(customer.Address, customerID);

CustomerDataSetTableAdapters.CustomerAddressTableAdapter customerAddressTableAdapter = new CustomerDataSetTableAdapters.CustomerAddressTableAdapter();
customerAddressTableAdapter.FillByCustomerID(customer.CustomerAddress, customerID);

Console.WriteLine("Current Customer's ModifiedDate is : {0:g}", customer.Customer[0].ModifiedDate);

//make some changes
//this change is valid
customer.Customer[0].ModifiedDate = DateTime.Now;
Console.WriteLine("Will change Customer's ModifiedDate to : {0:g}", customer.Customer[0].ModifiedDate);

//this change is not valid, sql server will not accept such date
customer.Address[0].ModifiedDate = DateTime.MinValue;
Console.WriteLine("Will change Address ModifiedDate to : {0:g}", customer.Address[0].ModifiedDate);



using (SqlConnection conn = new SqlConnection(
TestDatasetTransaction.Properties.Settings.Default.AdventureWorksConnectionString))
{
conn.Open();
SqlTransaction tran = null;
try
{
tran = conn.BeginTransaction();

customerTableAdapter.Connection = conn;
addressTableAdapter.Connection = conn;
customerAddressTableAdapter.Connection = conn;

customerTableAdapter.SetTransaction(tran);
addressTableAdapter.SetTransaction(tran);
customerAddressTableAdapter.SetTransaction(tran);

customerTableAdapter.Update(customer);
addressTableAdapter.Update(customer);
customerAddressTableAdapter.Update(customer);

tran.Commit();

}
catch (Exception ex)
{
if (tran != null) tran.Rollback();
Console.WriteLine(ex.Message);
}
tran.Dispose();

customerTableAdapter.FillByCustomerID(customer.Customer, customerID);


conn.Close();
}

Console.WriteLine("Finally Customer's ModifiedDate is : {0:g}", customer.Customer[0].ModifiedDate);
Console.WriteLine();
Console.WriteLine("Press a key");
Console.ReadKey();

}
}
}

-------------

The console output was respectivly


Current Customer's ModifiedDate is : 19.03.2008 17:16
Will change Customer's ModifiedDate to : 19.03.2008 17:33
Will change Address ModifiedDate to : 01.01.0001 0:00
Over SqlDateTime. Should be from 1/1/1753 12:00:00 AM to
12/31/9999 11:59:59 PM.
Finally Customer's ModifiedDate is : 19.03.2008 17:16
Press a key


------------

So, the transaction really works, and because of an exception happened during update of the 2nd table, all changes made to the first table was rolled back.

Of course the more simple solution is to use the TransactionScope() object from System.Transaction.dll, however this will not work on all platforms and databases. Also it seems, that an internal mechanism that exist in System.Transaction that is responsible for transparent (from developer's point of view) transaction enlisting from different resource managers should have affect on performance. If I will have some time, I will try to make a small performance test comparing TransactionScope() and SqlTransaction later...

Thursday, March 13, 2008

Applying Gamma correction to an Image

Recently, one of my tasks was to apply non-linear gamma correction to JPEG image. Using .NET Framework 2.0 System.Drawing.Imaging library one can reach this target quickly, however there is one big notice about working with JPEGs: Never do any transformations with JPEG images, first confert them to 32 bit Argb! If you pbey this, you may catch System.OutOfMemoryException. Also I was found in one post (can't find that link... :( ) that this format is also most efficient in terms of performance...


public static Bitmap CorrectGamma(Image source, decimal gamma)
{
Bitmap intermediate = new Bitmap(source.Width, source.Height, PixelFormat.Format32bppPArgb);

// Create an ImageAttributes object and set the gamma
ImageAttributes imageAttr = new ImageAttributes();
imageAttr.SetGamma(Convert.ToSingle(gamma));

Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
using (Graphics g = Graphics.FromImage(intermediate))
{
g.DrawImage(source, rect, 0, 0, source.Width, source.Height, GraphicsUnit.Pixel);
}

Bitmap corrected = new Bitmap(source.Width, source.Height, PixelFormat.Format32bppPArgb);
using (Graphics g = Graphics.FromImage(corrected))
{
g.DrawImage(intermediate, rect, 0, 0, intermediate.Width, intermediate.Height, GraphicsUnit.Pixel, imageAttr);
}

intermediate.Dispose();
return corrected;

}



It is essential that image is transformed once from JPEG to Format32bppPArgb (I described this in another post) and only after that it is transfomed second time, applying ImageAttributes. Doing both at one time will cause OutOfMemoryException, but of course you can try this out for yourself :)

Wednesday, March 12, 2008

Converting JPEG to BMP and other issues with Graphics

I was wondering why it is so difficult to find an easy solution using .NET Fremework 2.0 to convert JPEG image into BMP format (why there is a tone of examples to do BMP to JPEG convertion)

So here is my C# code, may be someone will find it helpfull


public static Image ConvertToBMP(Image source)
{
Bitmap result = new Bitmap(source.Width, source.Height, PixelFormat.Format32bppPArgb);

Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
using (Graphics g = Graphics.FromImage(result))
{
g.DrawImage(source, rect, 0, 0, source.Width, source.Height, GraphicsUnit.Pixel);
}

return result;

}

I didn't tested yet this for all image types, however for JPEG it works :)