Feeds:
Posts
Comments

This should be a simple matter, but it troubled me so much.

Simply, you need to the followings, but be warned that there are slight incorrect version of command on internet, at least which didnt’ work for me on Lion.

defaults write com.apple.finder AppleShowAllFiles -bool true

Then

killall Finder

For me, if you did “YES” instead of true, it didn’t work.

from ehow (http://www.ehow.com/how_2274100_hidden-files-mac-os-x.html)

Snowy, our beloved cat

This is a reminder for myself not to forget snowy’s details

  • Flea medicine: Frontline Combo Spot-On Cat
  • Worming: Drontal

It is so good that all those videos are published after conference. If you are not a speaker at the conference, not sponsored by your company, or not have a free ticket, often you can’t simply afford to attend it. This is the first of “My learnings from NDC Conference Videos” series.

The benefits of simple, automated performance testing by Kristoffer Dyrkorn

1. Crawl the site every night! Log the response times for each page.

2. Visualise the result with graph.

 

3. Are we slower now than 3 months ago

4. Estimate environment differences. HOw are DEV servers performing, compared to TEST and QA?

5. Tools: NCrawler + Log Parser + IIS with time-taken

What is “Sandwich Code”? I found it in Ruby Koans.

Often, you have to do something at the beginning and at the end, even though your main lock is in the middle. Let’s say, you want to retrieve data from database. You have to create a connection, open it, use it to load data, and close it. You are interested in loading data, but you have to do some chores like opening a connection and closing it.

_connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Db"].ConnectionString);
_connection.open()var sql =
    @"SELECT     DATEPART(YEAR, PDate) AS [Year],
                 DATEPART(MONTH, PDate) AS [Month],
                 DATEPART(DAY, PDate) AS [Day],
                 COUNT(*) AS [Count]
        FROM     JobPostingPeriod
       WHERE     PublishToDate >= GETDATE() AND PDate <= GETDATE()
       GROUP BY  DATEPART(YEAR, PDate), DATEPART(MONTH, PDate), DATEPART(DAY, PDate)
       ORDER BY  [Year], [Month], [Day]";

var result = _connection.Query(sql));return result;_connection.close()



Those “bread-in-the-sandwich” code is repeated whenever you write any code that load data, and it can be quite annoying as you go on. In ruby, you can write a method that handles the opening and closing with block. In C#, you can use lamda delegate and Func.

I wrote a simple method, “ManageConnection”, with the help of Dan, my Totaljobs colleague, as he happened to be with me.
It accepts an anonymous method that has SqlConnection as input, and return T.
And now I can re-write the data loading method like this.

private T ManageConnection(Func func)
{
    _connection.Open();
    var result = func(_connection);
    _connection.Close();
    return result;
}

The excution flow is
1. GetJobCountByDate is called
2. It calls ManageConnection and pass conn.Query(sql) as anonymous method
3. In ManageConnection, _connection is opened.
4. In ManageConnection, func(_connection) is called. func is conn.Querysql at this point.
5. ManageConnection returns the result.
6. GetJobCountByDate receives the result from ManageConnection, and now returns the result.
I think this is nice and clean, once you understand how it works.
There are loads of sandwich code. If you write file, access database, write to http stream, …

	ection.open()
var sql =
    @”SELECT    DATEPART(YEAR, PostedDate) AS [Year],
                DATEPART(MONTH, PostedDate) AS [Month],
                DATEPART(DAY, PostedDate) AS [Day],
                COUNT(*) AS [Count]
       FROM     JobPostingPeriod
      WHERE     PublishToDate >= GETDATE() AND PostedDate <= GETDATE()
      GROUP BY  DATEPART(YEAR, PostedDate), DATEPART(MONTH, PostedDate), DATEPART(DAY, PostedDate)
      ORDER BY  [Year], [Month], [Day]“;
var result = _connection.Query(sql));
return result;
_connection.close()_connection = new SqlConnection(ConfigurationManager.ConnectionStrings["JobSeekerReadOnly"].ConnectionString);
_connection.open()
var sql =
    @”SELECT    DATEPART(YEAR, PostedDate) AS [Year],
                DATEPART(MONTH, PostedDate) AS [Month],
                DATEPART(DAY, PostedDate) AS [Day],
                COUNT(*) AS [Count]
       FROM     JobPostingPeriod
      WHERE     PublishToDate >= GETDATE() AND PostedDate <= GETDATE()
      GROUP BY  DATEPART(YEAR, PostedDate), DATEPART(MONTH, PostedDate), DATEPART(DAY, PostedDate)
      ORDER BY  [Year], [Month], [Day]“;
var result = _connection.Query(sql));
return result;
_connection.close()
_connection = new SqlConnection(ConfigurationManager.ConnectionStrings["JobSeekerReadOnly"].ConnectionString);
_connection.open()
var sql =
    @”SELECT    DATEPART(YEAR, PostedDate) AS [Year],
                DATEPART(MONTH, PostedDate) AS [Month],
                DATEPART(DAY, PostedDate) AS [Day],
                COUNT(*) AS [Count]
       FROM     JobPostingPeriod
      WHERE     PublishToDate >= GETDATE() AND PostedDate <= GETDATE()
      GROUP BY  DATEPART(YEAR, PostedDate), DATEPART(MONTH, PostedDate), DATEPART(DAY, PostedDate)
      ORDER BY  [Year], [Month], [Day]“;
var result = _connection.Query(sql));
return result;
_connection.close()

This is purely for me and to remind myself of the frequently used jQuery expressions. Forgetfulness is a curse as well as a bliss!

$("#target option:first").attr('selected','selected');

  • populate select list dynamically. This simply replace html. If there is a better way, please let me know. I used an extension method, Html.ClientIdFor.

function(result) {
    var options = '';
    for(var i=0; i<result.length; i++) {
        options += '<option value="' + result[i].Id + '">' + result[i].Name + '</option>';
    }
    $('#<%= Html.ClientIdFor(m => m.Input.ProductCategoryId) %>').find('option').remove().end().html(options);
    $('#<%= Html.ClientIdFor(m => m.Input.ProductCategoryId) %> option:first').attr('selected', 'selected');
}

  • table and click on a link on table row

$('#result').delegate('a[name="lnkDescription"]', 'click', function(e) {
    e.preventDefault();

    var link = $(this).closest('tr').find('a[name="lnkDescription"]');

    ...
    });

})

mongodb and norm

People use ORM like Entity Framework and NHibernate a lot and I am one of them. When I use ORM, often I ma haunted by two inner thoughts. One is “This can be done in sql so easily” and the other is “What would it be like to use object database or document database? It might be fantastic.” So I tried mongodb.

Installing mongodb was unexpectedly easy. You just download it and double click it. You can install it as windows service very easily like below. (from http://www.mongodb.org/display/DOCS/Windows+Service)

mongod --bind_ip 127.0.0.1 --logpath d:\mongo\logs --logappend --dbpath d:\mongo\data --directoryperdb --install

I user NoRM, which is mongodb driver for .NET. There are three C# drivers for .NET.

  • mongodb-csharp
  • simple-mongodb
  • NoRM
(to be continued)

As you use ASP.NET MVC on and on, you start building and using handy html helpers. Rob Conery posted a few of his helpers on his blog. You can find some more in his ASP.NET MVC source code. Inspired by his helpers, here I post mine.

1. Html.Image

Depending on the environment, the absolute url of an image can change. For example, on the dev machine, it is http://localhost:3107/content/images/cancel.gif. On Integration server, if the server host multiple applications under root with the same port numer, 80, the image path can be like http://intserver/app1/content/images/cancel.gif. In this case, the image would not be rendered. SiteRoot is Rob Conery’s helper.

To avoid the situation like the above, I reference image suing SiteRoot functionality.

public static string Image(this HtmlHelper helper, string imageName, string altText)
{
    var builder = new TagBuilder("img");
    builder.MergeAttribute("src",
        UrlHelpers.SiteRoot(helper.ViewContext.HttpContext) + "/content/images/" + imageName);
    builder.MergeAttribute("alt", altText);

    return builder.ToString(TagRenderMode.SelfClosing);
}

2. Html.ClientIdFor

In MVC, you pass viewmodel to View. I often refactor the viewmodel and the change involve property name. When you change a property name of a viewmodel, all server side code like Html.TextBoxFor(m => m.Input.Firstname” change accordingly, but you have to manually change javascript code.

For example,

$('#Input_Firstname').change(resetRate);

You would have to change the id manually. I thought it would be nice to specify clientId with server-side code, and I was not alone. There were guys with the same idea. The following is the code for ClientIdFor and I got the code from John Landheer‘s answer on stackoverflow.

public static MvcHtmlString ClientIdFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
{
    return
        MvcHtmlString.Create(
            helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(
                ExpressionHelper.GetExpressionText(expression)));
}

3. Script

This writes javascript include statement.

public static string Script(this HtmlHelper helper, string fileName)
{
    if (!fileName.EndsWith(".js"))
        fileName += ".js";

    return string.Format("<script src='{0}/{1}/{2}/{3}' type='text/javascript' ></script>\n",
        helper.SiteRoot(), PUBDIR, SCRIPTDIR, helper.AttributeEncode(fileName));
}

public static string ScriptIe(this HtmlHelper helper, string fileName)
{
    if (!fileName.EndsWith(".js"))
        fileName += ".js";

    return string.Format("<!--[if lt IE 7]>\n<script src='{0}/{1}/{2}/{3}' defer type='text/javascript' ></script>\n<![endif]-->",
        helper.SiteRoot(), PUBDIR, SCRIPTDIR, helper.AttributeEncode(fileName));
}

– To be continued –

Ideally, it is not recommended to test private methods, as complex internals should be kept hidden and only interface be tested. Well, in real world, sometimes, you need to test your private methods, as it performs very important operation.

In my case, the method was public and later I changed it to private, since it is better to be hidden. Yet, I still wanted to test it, as it does lots of things – calling several other private methods and sum up the result.

You can use .Net reflection and easily do it. One nice article I found by googling was http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx. Simple and straight-forward.

I created a static helper method. I changed variable names in the above example, as it follows old C++ style. These days, C# guys prefer longer variable name without type prefix.

public class TestHelper
{
    public static object RunStaticMethod(Type type, string method, object[] parameters)
    {
        return RunMethod(type, method, null, parameters, BindingFlags.Static | BindingFlags.NonPublic);
    }

    public static object RunInstanceMethod(Type type, string method, object instance, object[] parameters)
    {
        return RunMethod(type, method, instance, parameters, BindingFlags.Instance | BindingFlags.NonPublic);
    }

    private static object RunMethod(Type type, string method, object instance, object[] parameters, BindingFlags flags)
    {
        try
        {
            MethodInfo info = type.GetMethod(method, flags);
            return info.Invoke(instance, parameters);
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
}

Dropbox is getting more and more popular. I use it on my desktop, laptop, iphone, and ipad. Once I went to a post office to post a document, and realised that I don’t know the address. I had my iphone with me, so used Dropbox to get the address. It was so useful, and ever since, I became a fan of Dropbox.

Anyway, Dropbox has nice Flash-based upload functionality, and I wanted to mimic the feature in my asp.net application. SlickUpload is a very good component, but commercial. I googled and came across uploadify.

The site has good example code and a link to asp.net example too. If you want to make your file upload testable, read Scott hanselman’s fantastic post about it.

The below is my code. One thing to note in the code are

  • Url.SiteRoot() is a custom extension method that finds root of the web application. I use it as this application goes under another application. So the url of images is not /public/images/, but /[unknown]/public/images. You would not need Url.SiteRoot() if your application root is the top level directory in iis.

public ActionResult UploadFiles()
{
    foreach (string file in Request.Files)
    {
        var postedFileBase = Request.Files[file];
        if (postedFileBase.ContentLength == 0)
            continue;

        string savedFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
                                            Path.GetFileName(postedFileBase.FileName));
        postedFileBase.SaveAs(savedFilename);
    }

    return View();
}

$(function(){
    $("#file").uploadify({
        'uploader': '<%= Url.SiteRoot() %>/public/images/uploadify.swf',
        'script': 'Home/UploadFiles',
        'cancelImg': '<%= Url.SiteRoot() %>/public/images/cancel.png',
        'auto': false,
        'multi': false
    });
})

<h2>Simple file upload.</h2>
<p>
    
    <form action="<%= Url.Action("UploadFiles", "Home") %>" method="post" enctype="multipart/form-data">
        
        <p>
        <input type="file" name="file" id="file" />
        <a href="javascript:$('#file').uploadifyUpload();">Upload Files</a>
        </p>
        
    </form>
</p>

Recently, I moved to Barclays. My job is still development, though. Totaljobs is a good company, and I enjoyed its casual, IT geek culture. It’s the thing I miss in my new job, as I work with quants.

The web application here has generally more complex UI. On public web page, you would not normally demand user to put in more than 20 textboxes or dropdowns. On financial application, it seems to be common. Nice graphs are often mandatory.

Anyway, one of my recent task was to let user download a report in pdf format. A colleague in the team told me we already used iTextSharp. I haven’t used it before, but it seems to be popular in java community, and ported to .Net as well. It looks like great component, but has poor documentation. It’s not easy to find good code examples.

One good working code is http://ozzieperez.net/blog/?p=255. I was lucky to find a code dealing with multi-columns and fixed column table. (http://www.mikesdotnetting.com/Article/89/iTextSharp-Page-Layout-with-Columns) This article greatly helped me.

I want to share my code too, to help other guys who may feel frustrated without any code sample. I changed variable names and also removed most part of the code, but it shouldn’t matter.


public class ExportService
{
    private const int LEFT = 0;
    private const int CENTER = 1;

    private pcService _pSvc;
    private BaseFont _verdanaBase;
    private Font _verdanaNormal, _verdanaHeading, _verdanaTitle;
    private BaseColor _textColor, _lineColor, _backgroundColor;

    public ExportService()
    {
        _pSvc = new pcService();

        _textColor = new BaseColor(ColorTranslator.FromHtml("#003366"));
        _lineColor = new BaseColor(ColorTranslator.FromHtml("#00a4e8"));
        _backgroundColor = new BaseColor(ColorTranslator.FromHtml("#eeeeee"));
        
        _verdanaBase = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.EMBEDDED);
        _verdanaNormal = new Font(_verdanaBase, 10, Font.NORMAL, _textColor);
        _verdanaHeading = new Font(_verdanaBase, 12, Font.NORMAL, _textColor);
        _verdanaTitle = new Font(_verdanaBase, 24, Font.ITALIC, _textColor);
    }

    public MemoryStream GetPdfStream(int pcId, string logoPath)
    {
        var memoryStream = new MemoryStream();

        var pageSize = new Rectangle(PageSize.A4);
        var document = new Document(pageSize, 36, 36, 50, 50);

        SetMetadata(document);
        EncryptPdf(document, memoryStream);

        document.Open();
        
        document.Add(GetLogo(document, logoPath));

        var title = new Paragraph("Report", _verdanaTitle);
        title.SetAlignment("Center");

        document.Add(title);
        document.Add(new Paragraph("\n"));
        document.Add(new Paragraph("\n"));

        var table = GetTable(_pSvc.Get(pcId));
        document.Add(table);
        document.Close();

        return memoryStream;
    }

    private PdfPTable GetTable(Pc pc)
    {
        var table = new PdfPTable(4);
        var widths = new[] { 110f, 120f, 110f, 120f };
        table.TotalWidth = 460f;
        table.LockedWidth = true;
        table.SetWidths(widths);


        AddHeading(table, "Global Settings");
        AddCell(table, "Country: ", pc.OCountry, "Country: ", pc.OperatingAssetsCountry);
        AddCell(table, "Currency: ", pc.Currency, "Date: ", pc.ValuationDateString);

        AddHeading(table, "Customer");
        AddCell(table, "Customer Name: ", pc.Customer.Name, "Customer ID: ", pc.Customer.Id.ToString());
        AddCell(table, "Bc: ", pc.Customer.Bc.ToString(), "Sales Turnover (m): ", pc.Customer.Sales.TwoDpText());

        ...

        AddHeading(table, "Valuation Identification Number: " + pc.Id);
        return table;
    }

    private void AddHeading(PdfPTable table, string heading)
    {
        PdfPCell cell = new PdfPCell(new Phrase(heading, _verdanaHeading));
        cell.Colspan = 4;
        cell.BackgroundColor = _backgroundColor;
        cell.HorizontalAlignment = CENTER;
        cell.Border = iTextSharp.text.Rectangle.BOX;
        cell.BorderColor = _lineColor;
        cell.MinimumHeight = 22;
        cell.VerticalAlignment = 1;
        table.AddCell(cell);
    }

    private void AddCell(PdfPTable table, string label1, string text1, string label2, string text2)
    {
        var labelCell = GetLabelCell();
        var textCell = GetTextCell();

        labelCell.Phrase = new Phrase(label1, _verdanaNormal);
        table.AddCell(labelCell);

        textCell.Phrase = new Phrase(text1, _verdanaNormal);
        table.AddCell(textCell);

        labelCell.Phrase = new Phrase(label2, _verdanaNormal);
        table.AddCell(labelCell);

        textCell.Phrase = new Phrase(text2, _verdanaNormal);
        table.AddCell(textCell);
    }

    private void AddCell(PdfPTable table, string label, string text)
    {
        var labelCell = GetLabelCell();
        var textCell = GetTextCell();

        labelCell.Phrase = new Phrase(label, _verdanaNormal);
        table.AddCell(labelCell);

        textCell.Phrase = new Phrase(text, _verdanaNormal);
        table.AddCell(textCell);

        labelCell.Phrase = new Phrase(string.Empty, _verdanaNormal);
        table.AddCell(labelCell);

        textCell.Phrase = new Phrase(string.Empty, _verdanaNormal);
        table.AddCell(textCell);
    }

    private PdfPCell GetTextCell()
    {
        return new PdfPCell
                   {
                       Border = Rectangle.RIGHT_BORDER | Rectangle.BOTTOM_BORDER | Rectangle.TOP_BORDER,
                       BorderColor = _lineColor,
                       MinimumHeight = 20,
                       HorizontalAlignment = LEFT,
                   };
    }

    private PdfPCell GetLabelCell()
    {
        return new PdfPCell
                   {
                       Border = Rectangle.LEFT_BORDER | Rectangle.BOTTOM_BORDER | Rectangle.TOP_BORDER,
                       BorderColor = _lineColor,
                       MinimumHeight = 20,
                       HorizontalAlignment = LEFT,
                       PaddingLeft = 3
                   };
    }

    private Image GetLogo(Document document, string logoPath)
    {
        var logo = Image.GetInstance(logoPath);
        logo.ScalePercent(48f);
        logo.SetAbsolutePosition(document.PageSize.Width - 36f - 130f, document.PageSize.Height - 36f - 15.36f);
        return logo;
    }

    private void SetMetadata(Document document)
    {
        document.AddAuthor("Wordpress");
        document.AddSubject("Report");
        document.AddKeywords("Report;Wordpress");
    }

    private void EncryptPdf(Document document, MemoryStream memoryStream)
    {
        var writer = PdfWriter.GetInstance(document, memoryStream);
        writer.SetEncryption(PdfWriter.STRENGTH128BITS, null, null, PdfWriter.AllowCopy | PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_SCREENREADERS);
    }

}

Older Posts »

Follow

Get every new post delivered to your Inbox.

Join 89 other followers