Monday, October 19, 2009

Localizing images

It is a common practice these days to localize applications. Well there are are number of options to localize the static text labels in an application. But how many times you have wanted to have some texts in your images and load them based on the current-thread's locale? One option is you can programatically set the ImageUrl to the asp.net image controls based on the current locale. But how many lines of code you would have to write to get this done? With .Net 2.0 Implicit Localization you can achieve this with zero code lines. Here is how we would do it.


step 1 : have your images placed on different directories based on the locale. i.e images/en/image1.jpg , images/es/image1.jpg and so on.

step 2 : have a resource key in the respective resource files pointing to the above images.
i.e in Page.es.resx file we might have a key BannerImage.ImageUrl with the value "~/images/es/image1.jpg"

step 3 : make the implicit localization do the rest of the job by properly formatting it.



Now when ever the BannerImage is rendered in the page life cycle, the ImageUrl will be picked from the resource files and based on the value for the current locale.

Hope that helps.

/BB

Friday, March 20, 2009

Steps to setup CRM 3.0

I tried to setup CMR 3.0 once and it was the craziest installation that I have ever done. I did it in my Win Server 2003 box and what I initially had was a crack; in the middle of the installation it asks to upgrade SP2 after which it doesn't allow to login to the OS without registration. So my advice is , don't try this unless you have Win Server 2003 genuine or crack with SP2.

CRM Server can only be setup on server operating systems as it requires certain server only features like Active Directory and DNS.

Step 1 : Setup Active Directory

Authorization for CRM happens via the AD so it is required to have AD setup before the installation.This documents a comprehensive steps to setup the active directory for Server 2003.

Step 2: Install SQL Server 2005 as the default instance.

It is important to setup SQL Server 2005 as the default instance since named instances are not working for CRM and it is difficult to change a named instance to a default instance after the setup. In theory CRM 3.0 should work with SQL 2000 but i was never able to get it to work even after doing all the patches that is said are required. So best option is to start with 2005.

Step 3: Install SQL Server 2000 and 2K Reporting Services

Sounds crazy to install two versions of DBMS to work with single product but that the way it worked for me :). It doesn't work with 2005 reporting services so you have to have a 2000 instance to install reporting servieces. This can be a named instance. After installing the Database engine there it should be patched with SP3 for SQL. The database engine would be a named instance as we already have a Default 2005 engine.

Step 4. Install CRM 3.

Sunday, December 28, 2008

Damaged cable in Mediterranean sea


It was reported that both SEA-ME-WE4 and SEA-ME-WE3 (primary optical cables that connect Asia-Middle East and Europe) were damaged and hence internet connections between Asia and Europe will be disrupted most probably till end of 2008. These two cables are the primary links between Asia, Middle East and Europe and obviously are carrying a significant amount of load. SEA-ME-WE3 is the longest optical cable link in the world and since it was not sufficient enough to bear the heavy load SEA-ME-WE4 was added to complement it. 

From the way it looks, seems both the cables are heavily damaged this time probably by a trawler net or a anchor of a ship. Whatever it is the French company who has undertaken the repair work claims that the cables are dragged long distance apart and the cables need to be taken to the ship in order to do the reconnection which is a complex process that may take days. 

This incident took me interested to see what are the cables that connect Sri Lanka and the rest of the world. 

contains the map as of end 2008. 



Following are the names of the cables incase the map is not so clear :) . 

Bharat Lanka Cable System
Maldives-Sri Lanka
SEA-ME-WE 4 
SEA-ME-WE 3 
SEA-ME-WE 2 




Wednesday, July 9, 2008

Intellisense for custom XML files with VS 2008

Its pretty simplistic than you would think. I was searching my options to have intellisence in NHibernate mapping files so that i could edit them with convenience. All you have to do is to copy the schema files (.xsd) that has a definitions for intellisense and paste them in to the %ProgramFiles%\Microsoft Visual Studio 8\XML\Schemas folder. In the case of Hibernate, you have to copy the following files {nhibernate-configuration.xsd, nhibernate-generic.xsd, nhibernate-mapping.xsd} from the \src\NHibernate to %ProgramFiles%\Microsoft Visual Studio 8\XML\Schemas.

references :

http://blogs.msdn.com/astebner/archive/2005/12/07/501466.aspx




Friday, June 27, 2008

Crystal reports with Excel

Lets have a look at how we can export a crystal report document to a excel sheet.

The steps i have explained here are specific to one of the project requirements that i have worked on.

Summary

Following is a rough summary of what i have done below
  • Create a crystal report
  • Determine the data retrieval mechanism
  • Create a schema that has two tables, one to carry report headers other to carry report data.
  • Create the report layout based on the two tables added above.
  • Databind the report from the data returned by the data retrieval mechanism.
  • Set the report headers.
  • Generate a report object out of the data bound report.
  • Export the report document to a memory stream with the export format type excel (pdf, doc or anything).
  • Write the stream to the response.

Requirements :

  • It should allow the data binding of the report data from the form code-behind.
  • The report headers should be able to be localized to the user locale.
  • Users should be able to specify the report title.
The Approach:

To be able to edit report column headers and the title dynamically, we are using a dataset which contain two tables. The first table contains the actual data that is to be databinded with the report. The second table contains the report headers and title. Obviously there will be only one row in the second table.


















Preconditions :

You need to have a report file in place and have its layout defined using two tables that we've discussed above.

I've used LINQ data contract called GetCatalogItemsForReportResult to get the results from the persistent storage. Basically this is a contract for a stored procedure that i have written to retrieve the dataset.

/// Export to excel event handler
protected void ExportToExcel_OnClick(object sender, EventArgs e)
{
//populate the report document.
ReportDocument rptDocCatalogPriceList = getPopulatedReportDocument();

MemoryStream oStream; // using System.IO
oStream = (MemoryStream)rptDocCatalogPriceList.ExportToStream(CrystalDecisions.Shared.ExportFormatType.Excel);

Response.Clear();
Response.Buffer = true;
Response.AddHeader("Content-Disposition", "attachment; filename=" + ddlSupplier.SelectedValue + "_" + ddlCatalogs.SelectedValue + ".xls");
Response.ContentType = "application/xls";
Response.BinaryWrite(oStream.ToArray());
Response.End();
}



///
/// 1. get a report document
/// 2. load it with the report
/// 3. populate the report with data
/// 4. retur the populated report doc
///
/// A populated
private ReportDocument getPopulatedReportDocument(string reportSourcePath)
{
//the report document path
string reportPath = Server.MapPath(reportSourcePath);
ReportDocument rptDocCatalogPriceList = new ReportDocument();

//load the report from the report path
rptDocCatalogPriceList.Load(reportPath);

//assign the report with the data source
rptDocCatalogPriceList.SetDataSource(getPopulatedDataSet());
return rptDocCatalogPriceList;
}

private DataSet getPopulatedDataSet()
{
DataSet ds = new DataSet();
populateDTCatalogItemReportCaptions(ds);
populateDTCatalogItems(ds);

return ds;
}



///
/// assign the dataset with a datatable that is carrying the table headers and report header
/// we can assign any new field to the table that needs to be displayed in the report
/// but make sure not to change the order of the table fields which could cause incorrect display of
/// columns.
///
///
private void populateDTCatalogItemReportCaptions(DataSet dsCarrier)
{
TranslationService ts = getTranslationSvc();

//the table that carries report data
ReportCaptions.DTCatalogItemReportCaptionsDataTable dtCatItemCaptions = new ReportCaptions.DTCatalogItemReportCaptionsDataTable();

DataRow dr = dtCatItemCaptions.NewRow();

int noOfColumns = dr.Table.Columns.Count;

//the very first row is to carry the report header so we eliminate that and start from the second column
for (int i = 1; i in the translation table
//get the appropriate value and set it for the column header
//what i have done here is retrieving the column headers from a seperate service that is focused //on getting translations for ui fields
dr[i] = ts.GetTranslation(string.Concat("ColumnHeader", "." , dr.Table.Columns[i].ColumnName ));
}

//set the report title
dr["ReportHeader"] = txtHeading.Text;

//add the row to the table
dtCatItemCaptions.Rows.Add(dr);

//add the table to the containing DataSet
dsCarrier.Tables.Add(dtCatItemCaptions);
}



///
/// populates the passed in data set with the table DTCatalogItems.
/// this table is carrying data that is to be displayed in the report
/// ...ps: there is another table to carry the table headers in the report
///
/// the dataset that carries report info
private void populateDTCatalogItems(DataSet dsCarrier)
{
//the table that carries report data
ReportCaptions.DTCatalogItemsDataTable dtCatItem = new ReportCaptions.DTCatalogItemsDataTable();

//the list of catalog items that need to be shown in the report
//this is the place where it refers to the LINQ contract to get the data from the database. You can do this step the way you want it to be. It is as simple as filling a generic list from some table from the database.
List itemList = getCatalogService().GetItemsByCatalogIdForReporting(ddlCatalogs.SelectedValue.ToInt64());

//iterate through the loop and populate the table with from the list
foreach (GetCatalogItemsForReportResult item in itemList)
{
DataRow dr = dtCatItem.NewRow();

dr["ArticleNo"] = item.ArticleNo;
dr["ItemName"] = item.ItemName;

//the price could be adjusted appropriately
dr["Price"] = getAdjustedPrice(item.Price);
dr["Currency"] = item.Currency;
dr["UnitOfSale"] = item.UnitOfSale;
.
.
.

dtCatItem.Rows.Add(dr);
}

//assign the table to the data set
dsCarrier.Tables.Add(dtCatItem);
}

Monday, June 9, 2008

Essential Dev tool that can help to build high quality software products

Requirement Analysis tools : Automated Requirements Measurement tool from NASA

Standard Blueprint Generator tools : ???

Automated Unite Testing Techniques : nUnit, MSTest (.Net) ; JUnit (Java)

Complexity measurement tools : McCabe’s Cyclomatic complexity metric , CRAP metric (Change Risk Analyzer and Predictor)

Configuration Management tools : VSS, P4, TeamSystem, SourceForge,

Continuous Integration : Cruise Control,

Build Tools : nAnt, MSBuild.

Code Analysis Tools : FxCop (.Net) , CheckStyle, Findbugs (JAVA)

Documentation tools : nDoc, Ghost doc

Code Formatting tools : Resharper (.Net)

Automatic Code Generation tools : CodeSmith

* MSDN provides some in depth analysis on some of these tools in here

Sunday, June 8, 2008

Seperating the static content to a light-weight server?

Every time a request comes to a web server it goes though a stack of libraries to process the request. e.g. in IIS when a request to a .aspx comes it goes through the aspnet_isapi.dll to process the request. Simillerly if a request to a static content like .css files or image files comes, then also it has to go through the costly isapi processing. An alternative for this is to have static content served in a lightweight web server and have a url-rewriter in place at the main server (to redirect the requests to static content to the light weight server) which could result in a large performance gain.

In Here it is given details of this