Tuesday, December 20, 2005

Using CrystalReport to Export DataTable With Different Format

We can export data inside a DataTable to an Excel spreadsheet by defining the Response.ContentType:
Response.ContentType = "application/vnd.ms-excel";
string separator = "\t";
foreach (DataColumn dc in dataTable.Columns)
{
Response.Write(separator + dc.ColumnName );
}
Response.Write("\n");
foreach (DataRow dr in dataTable.Rows)
{
for (int i = 0; i < dataTable.Columns.Count; i++)
{
Response.Write(separator + dr[i].ToString());
}
Response.Write("\n");
}
What if we need more format such as PDF? You can export data to a few other popular formats by using Crystal's ReportDocument if you have Crystal Reports available:
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;
using System.IO;

private void ExportReport()
{
    MemoryStream oStream = new MemoryStream();
    string filename = string.Empty;
    try
    {
        ReportDocument crReport = new ReportDocument();
        string reportFile = "CrystalReport1.rpt";
        string reportPath = string.Format("{0}/{1}", Server.MapPath("."), reportFile);
        crReport.Load(reportPath);

        ReportDataSetTableAdapters.UtilityTableAdapter ad = new ReportDataSetTableAdapters.UtilityTableAdapter();
        ReportDataSet.UtilityDataTable ut = ad.GetAllData();
        crReport.SetDataSource((DataTable)ut);

        switch (SelectedType)
        {
         case "1": //Rich Text (RTF)
             oStream = (MemoryStream)crReport.ExportToStream(ExportFormatType.RichText);
             Response.ContentType = "application/rtf";
             filename = "data.rtf";
             break;
         case "2": //PDF 
             oStream = (MemoryStream)crReport.ExportToStream(ExportFormatType.PortableDocFormat);
             Response.ContentType = "application/pdf";
             filename = "data.pdf";
             //in case you want to export it as an attachment use the line below
             //crReport.ExportToHttpResponse(ExportFormatType.PortableDocFormat, Response, true, "Your Exported File Name"); 
             break;
         case "3": //MS Word (DOC)
             oStream = (MemoryStream)crReport.ExportToStream(ExportFormatType.WordForWindows);
             Response.ContentType = "application/doc";
             filename = "data.doc";
             break;
         case "4": //MS Excel (XLS)
             oStream = (MemoryStream)crReport.ExportToStream(ExportFormatType.Excel);
             Response.ContentType = "application/vnd.ms-excel";
             filename = "data.xls";
             break;
         default: //PDF 
             oStream = (MemoryStream)crReport.ExportToStream(ExportFormatType.PortableDocFormat);
             Response.ContentType = "application/pdf";
             filename = "data.pdf";
             break;
        }
        //write report to the Response stream
        byte[] dataByte = oStream.ToArray();
        Response.Charset = "";
        Response.AddHeader("content-disposition", "fileattachment;filename=" + filename);
        Response.ContentType = "application/octet-stream";
        Response.BinaryWrite(dataByte);
        Response.Flush();
        Response.Clear();
        Response.End();
    }
    catch (Exception ex)
    {
        ErrorLog.Write(ex);
    }
    finally
    {
        //clear stream
        oStream.Flush();
        oStream.Close();
        oStream.Dispose();
    }
}

Just a side note if you can not import Crystal merge module into your VS2003, then you need to register the dll again:
regsvr32 "C:\Program Files\Common Files\Microsoft Shared\MSI Tools\mergemod.dll"

Friday, December 09, 2005

Check Windows Group Users & Clean-up Network Logon

Often used commands inside Windows domain:

Show users in a local group:
>net localgroup administrators

Show users in a domain group:
>net group All_IT_Staff /domain

Delete credential for a network share
>net use \\shareServerName /del

Delete all credentials for all shares:
>net use * /del

Open Credential manager:
>control keymgr.dll
>rundll32.exe keymgr.dll, KRShowKeyMgr

Monday, November 28, 2005

.NET Volatile Field

The MSDN description for the volatile modifier:
"For non-volatile fields, optimization techniques that reorder instructions can lead to unexpected and unpredictable results in multi-threaded programs that access fields without synchronization such as that provided by the lock-statement."

What does it mean? In a multi-CPU and multi-threaded environment, a value could be temporarily stored in registers and multiple levels of cache, and the value change by a thread in one CPU may not be seen immediately by another thread run in another CPU. This could lead to some unpredictable issues.

We can guarantee to get a refresh value by declaring a volatile field:
using System;
using System.Threading;
class Test
{
public static bool finished = false;
private static object syncLock = new object();
static void Main()
{
new Thread(new ThreadStart(Thread1)).Start();
new Thread(new ThreadStart(Thread2)).Start();
Console.Read();
}
static void Thread1()
{
while (true)
{
if (finished)
{
Console.WriteLine("Finished.");
break;
}
}
}
static void Thread2()
{
lock (syncLock)
{
finished = true;
}
}
}
In above code snippet, Thread1 will immediately see the latest "finished" value updated by a Thread2, and guarantee to finish and break the infinite loop. Without volatile declared, Thread1 could (not always) never be ended in some systems.

One important note is that volatile field doesn't mean it's thread-safe. Locking mechanism is still required in some scenarios. With a locked field, the value of that field is guarantee to be the latest one, and volatile is unnecessary in such case.

(Updated 2006/9):
My original understanding may not be correct. Some people argue that volatile only means the sequence of accessing a volatile member won't reordered, it doesn't mean that a value assignment will be immediately visible to all processors. However I could not verify this without a real environment.

Wednesday, November 09, 2005

Visual Studio 2005 & SQL Server 2005 Launch Event in Toronto

Microsoft was launching VS2005, SQL Server 2005, BizTalk Sever 2006 Server as well as .NET 2.0 in Toronto Congress center yesterday. We attended the developer sessions and saw some really good stuff from the presenters. Even better, every attendee was given complimentary software. That includes full version of VS 2005 professional edition, SQL server 2005 standard edition and BizTalk Server 2006 standard edition. Microsoft is quite generous this time.

Tuesday, October 18, 2005

Web-based Real-time Information Tracking

I am working on a project required web-based real-time status tracking on a big automobile plant. Supervisors need to check if some events such as “incidents happen using a browser. The browser needs to update the information in a few seconds based on the setting. The status information such as “incidents” are stored in a database with information of “start time”, “end time”, “duration”, etc. We decided to use Dundas Charts to generate the information images, and use JavaScript to populate the real-time images. We thought about two approaches for dynamic loading Dundas images on the fly.

1. Image generated in the server
  • Advantage: browser friendly without any client side requirement
  • Disadvantage: increase the workload in server and more traffic in the network if images are big
2. Image generated in the client
  • Advantage: less overhead in server and network
  • Disadvantage: require ActiveX enabled in the browser and more overhead in the client
The first method uses JavaScript to update the images regularly. To avoid the page flicker, and the page only reloads the image instead of the whole page (change the image source inside JavaScript):

Consider the image generated in the server may take a bit time (retrieving data from database and building chart image), we could use image buffering in the server: the page image at client only loaded when it’s ready at server. We can buffer image in memory or in files:

The second method also uses JavaScript, but the JavaScript gets the real-time data from server instead of binary images. To do this, we create XMLDOM object inside JavaScript. The data is retrieved from server by XMLHTTP object, and filled into ActiveX object (Dundas chart), then we redraw the chart, as shown in following figure:

There is a sampling rate issue for plotting data in a chart when the unit of X-value in chart is different from that of the data from database. A simple solution for that is to plot the data when there is an incident inside that time slot. As depicted in below figure, three incidents are all plotted between the time shot 2 and shot 3:


(Nov. 2005 update) The first approach (generating images from the server) has been implemented with memory buffering mechanism. The client is quite satisfied what we delivered.

Friday, August 19, 2005

Autonomus System

We are working on a pilot project called BEAT (Best-Effect Autonomous Technology) that will be used in buildings' remote management. The project is quite challenging. We face so many concerns. The complexity of the application would grow significantly if every concern needs to be well addressed. It seems very hard to implement a practical and effective autonomous system in the real world. But hold on a second, is autonomous system well set in every automobile?:-)

Three of us in our team spent almost a whole day on discussing a module of our autonomous system, and the whiteboard pictures of our discussion:

Thursday, June 16, 2005

.NET Remoting vs Java RMI

I found .NET Remoting very close to Java RMI in terms of concept and usage. I did more research on .NET Remoting and happened to see a benchmark comparison between .NET Remoting and Java RMI. It shows .NET Remoting is much slower than Java RMI. Here's the conclusion from the article (http://www.cs.ru.nl/~marko/onderwijs/oss/RMI_and_Remoting.pdf):

"
The most obvious and expected result of these measurements is that the middleware for both Java and .Net causes a performance decrease compared to local system calls. This is still true when disregarding the networking
cost, because there is an extra layer of functionality within middleware.

RMI had the best performance in the 3 performed tests. It is up to 20
times faster than .Net Remoting on object invocation. This was more or less expected, as Microsoft warns for a bad performance in this specific test. The result was unexpected in the method invocation and data invocation tests. On method invocation RMI outperformed Remoting by a factor 7 and on data invocation by a factor 2.
"

The tests were conducted on .NET 1.1 and Java 1.4.2. I checked .NET 2.0 Beta documentation; new IPC channel and security enhancements are highlighted, and I couldn't see any information about Remoting's performance improvement in .NET 2.0.

Tuesday, May 03, 2005

.NET 2.0 Generics

I am testing out the new .NET 2.0 Generics feature, and found it's very cool.

Generics allow you to define type-safe classes without compromising type safety, performance, or productivity (From MSDN). That's really true especially on productivity. With Generics you are no longer need to do the type casting. Goodbye ArrayList because we have generic List!
using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
public interface ITimeable
{
DateTime GetTime();
}

public class MyEvent : ITimeable
{
private string _name;
private DateTime _time;
public MyEvent(string name, DateTime time)
{
_name = name;
_time = time;
}
public DateTime GetTime()
{
return _time;
}
public override string ToString()
{
return _name;
}
}

public class Helper
{
public static List<T> GenericSortByTime<T>(List<T> items) where T : ITimeable
{
items.Sort(delegate(T item1, T item2)
{
return item1.GetTime().CompareTo(item2.GetTime());
});
return items;
}

public static List<T> GenericSortByName<T>(List<T> items) where T : class
{
items.Sort(delegate(T item1, T item2)
{
return item1.ToString().CompareTo(item2.ToString());
});
return items;
}
}

class Program
{
static void Main(string[] args)
{
DateTime now = DateTime.Now;
List<MyEvent> events = new List<MyEvent>();
events.Add(new MyEvent("1", now.AddDays(1)));
events.Add(new MyEvent("3", now.AddDays(2)));
events.Add(new MyEvent("2", now.AddDays(3)));
events.Add(new MyEvent("a", now.AddDays(-1)));
events.Add(new MyEvent("b", now.AddDays(-2)));
Console.WriteLine("Original list:");
foreach (MyEvent myEvent in events)
Console.WriteLine(myEvent.ToString() + ":" + myEvent.GetTime().ToString());
events = Helper.GenericSortByTime(events);
Console.WriteLine("Sort by time:");
foreach (MyEvent myEvent in events)
Console.WriteLine(myEvent.ToString() + ":" + myEvent.GetTime().ToString());
events = Helper.GenericSortByName(events);
Console.WriteLine("Sort by name:");
foreach (MyEvent myEvent in events)
Console.WriteLine(myEvent.ToString() + ":" + myEvent.GetTime().ToString());
Console.Read();
}
}
}

Result:

Monday, April 18, 2005

.NET 2.0 Beta 2

.NET 2.0 Beta 2 and Visual Studio 2005 Beta 2 were just released last week. I tested it and did see a lot of improvements comparing previous version: full 64-bit support, enhanced intelli-sense, generics, partial class, typed data table, and a lot of new controls...

But one thing confused me is that VS2005 is still built by C++. Why not C#/VB.NET? It's more convincing to people that .NET is robust and mature enough for enterprise applications, if Microsoft is building their own tools using .NET.

Monday, March 07, 2005

Email Sending in .NET

First you need a SMTP server (relay server) available for your .NET application to send out emails. SMTP server can be a Linux Sendmail demon or IIS SMTP service.

To send an email in .NET 1.1, you need a reference to System.Web.dll and use the System.Web.Mail namespace:

MailMessage emailMsg = new MailMessage();
emailMsg.From =
"sender@mydomain.com";
emailMsg.To =
"receiver@mydomain.com";
emailMsg.Subject =
"Subject";
emailMsg.Body =
"Body";
SmtpMail
.SmtpServer = "mysmtpserver.com";
SmtpMail
.Send(emailMsg);

Be aware that under the hood .NET dispatches email message to a COM library CDO.Message included in cdosys.dll, which come with Windows 2003 server (in $Windows$/system32 folder). So .NET email function is just a wrapper function, and unmanaged (native) code is involved during the email sending.

If SMTP server requires authenitcation, you need to add following setting for MailMessage:

emailMsg.Fields["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"] = 1;
emailMsg.Fields[
"http://schemas.microsoft.com/cdo/configuration/sendusername"] = "myLogin";

emailMsg.Fields[
"http://schemas.microsoft.com/cdo/configuration/sendpassword"] = "myPassword";

If you want the a HTML format of email, and add an attachment to it:

emailMsg.BodyFormat = MailFormat.Html;
MailAttachment
emailAttchement = new MailAttachment(fileName);
emailMsg.Attachments.Add(emailAttchement);