Friday, May 22, 2009

How to publish a ClickOnce Application without Visual Studio

When i search a solution for the question “How to change .exe.config.deploy”, i cannot have a good answer. So, i try to create my solution and it is successful.

In this solution, you can deploy a ClickOnce Application to customer’s server, it execute with requests:

  • Modify config in app.config, example: Connection String, Web Reference URL,…
  • Change start location of a signed ClickOnce Application.
  • Change Version of product.
  • Publish application without VS and .NET Framework SDK.
1. Create necessary files for ClickOnce Server

        To publish the ClickOnce Application to a server, you must have necessary files includes: MyApp.application (my application sample is MyApp), index.html and setup.exe.

        Open the source code in Visual Studio and publish ClickOnce Application to local IIS . Next, open  publish folder (C:\Inetpub\wwwroot\MyApp) and copy only files MyApp.application, index.html and setup.exe to the deployment folder (MyAppClickOnce). This folder will be provided the customer who will publish application to his server.

  2. Copy the contents of the application to the deployment folder

       Copy the contents of the application from the build output folder (bin\Release) to folder’s name [ApplicationName_Version(a_b_c_d)] to the deployment folder (MyAppClickOnce\MyApp_1_0_0_0).

       Copy the publisher certificate that was generated by Visual Studio when you first published to the deployment folder.

       Open folder [Microsoft Visual Studio 8]\SDK\v2.0\Bin and copy file mageui.exe  to the deployment folder.

       Now, you can compress the deployment folder to your customer with install guide and he should be install a ClickOnce Application without Visual Studio and .NET Framework SDK 2.0.

3. Publish application
  • Open mageui.exe, on menu File –> New –> Application Manifest.
  • In the tab “app1.exe.manifest”, select “Name” from list in the left, input name of application into Name textbox  (MyApp) and Version textbox (1.0.0.0).
  • In the tab “app1.exe.manifest”, select “Files” from list in the left,
    • At “Application directory:”, select folder containing the application files (MyApp_1_0_0_0) .
    • Click check on checkbox “When populating add the .deploy extension to any files that does not have it”.
    • Click button “Populate”.
  • On menu of mageui, select File –> Save.
    • In the screen “Signing Options”, select option “Sign with certificate file”, click button […] to select publisher certificate. Click OK to next.
    • In the screen “Save As”, save with default file name to folder containing application files (MyApp_1_0_0_0).
  • On menu of mageui, select File –> Open.
  • Select file MyApp.application in the deployment folder.
  • In the tab “MyApp.application”, select “Name” from list in the left, change Version to 1.0.0.0
  • In the tab “MyApp.application”, select “Deployment Options”, modify “Start Location” to new path or url of the current server.
  • In the tab “MyApp.application”, select “Application Reference”, click button “Select Manifest…” to select file manifest that is created above.
  • On menu of mageui, select File –> Save.
  • In the screen “Signing Options”, select option “Sign with certificate file”, click button […] to select publisher certificate. Click OK to save.

Now, you can install ClickOnce Application from new location.

P.S: I am sorry about my English. :)

Wednesday, May 6, 2009

Test-Driven Development (TDD) trong .NET bằng ví dụ – Phần 3

Phần này sẽ cài đặt các Test 3 và Test 4 trong loại bài về Test-Driven Development trong .NET qua ví dụ. Các phần trước bao gồm:

Test-Driven Development (TDD) trong .NET bằng ví dụ

Test-Driven Development (TDD) trong .NET bằng ví dụ – Phần 2

Test 3: Push một đối tượng đơn, Pop đối tượng đó và xác nhận IsEmpty là true.

Trong Test case này, ta thêm một phương thức mới cho lớp Stack có nhiệm vụ lấy ra phần tử trên đỉnh của Stack. Nhưng trước tiên, ta cần tiến thành cài đặt unit test cho test case này, đoạn code như sau:

    [Test]
    public void Pop()
    {
        stack.Push("first element");
        stack.Pop();
        Assert.IsTrue(stack.IsEmpty,
            "Sau khi Push - Pop. IsEmpty phải bằng true.");
    }

Và tất nhiên, ta phải cài đặt một phương thức Pop trong lớp Stack.

    public void Pop()
    {
    }

Tuy nhiên, nếu bây giờ bạn tiến hành complite và chạy test, thì sẽ trả về kết quả fail. Do đó, ta bổ sung thêm m_IsEmpty = true để hoàn thành test case này.

    public void Pop()
    {
        m_IsEmpty = true;
    }

Kết quả là chúng ta đã hoàn thành unit test cho Test case 3. Tiếp theo, ta sẽ cài đặt test case 4.

Test 4: Push một đối tượng đơn, ghi nhớ đối tượng đó; Pop đối tượng, và xác nhận hai đối tượng này là giống nhau.

Trong unit test của test case này, chúng ta sẽ thực hiện so sánh nội dung của 2 phần tử, đó là phần từ đưa vào Stack với phần tử lấy ra từ Stack ngay sau khi đưa vào. Do đó, ta sẽ đặt tên là PushPopContentCheck:

    [Test]
    public void PushPopContentCheck()
    {
        int expected = 1234;
        stack.Push(expected);   
        int actual = (int) stack.Pop();
        Assert.AreEqual(expected, actual);
    }

Tiếp theo, ta cần phải thay đổi lại phương thức Pop của lớp Stack.

    public object Pop()
    {
        m_IsEmpty = true;
        return null;
    }

Sau khi build thành công và chạy test, thì kết quả test trả về sẽ error vì lúc này ta chưa trả về giá trị trên đỉnh của Stack. Do đó, để pass cho unit test này, chúng ta lưu lại giá trị nhận được từ Push và trả lại giá trị trong Pop. Đoạn code sau khi thay đổi sẽ như sau:

using System;

public class Stack
{
    private bool m_IsEmpty = true;
    private object m_Element;

    public bool IsEmpty
    {
        get {
            return m_IsEmpty;
        }
    }

    public void Push(object element)
    {
        m_IsEmpty = false;
        m_Element = element;
    }

    public object Pop()
    {
        m_IsEmpty = true;
        object top = m_Element;
        m_Element = null;
        return top;
    }
}

Lúc này, ta thấy phương thức IsEmpty chỉ cần kiểm tra xem phần tử đang được lưu có bằng null hay không. Do đó, ta sẽ thay đổi ở phương thức IsEmpty như sau:

using System;

public class Stack
{
    private object m_Element = null;

    public bool IsEmpty
    {
        get {
            return (m_Element == null);
        }
    }

    public void Push(object element)
    {
        m_Element = element;
    }

    public object Pop()
    {
        object top = m_Element;
        m_Element = null;
        return top;
    }
}

Lúc này đã tốt hơn với code của Stack vì ta thấy rằng lúc này chỉ cần cập nhập lại một biến thay vì hai như trước đây.  Đến lúc này, khi thực hiện đưa vào 1 phần tử thì nó vẫn nằm trên đỉnh của Stack vì lúc lấy ra ta lấy đúng phần tử đã đưa vào. Tuy nhiên, sẽ có vấn đề lúc đưa nhiều hơn 1 phần từ vào Stack, ta sẽ được thấy điều này qua các test case tiếp theo.

Test-Driven Development (TDD) trong .NET bằng ví dụ – Phần 2

Trong Phần 1 chúng ta đã hoàn thành Test 1, bây giờ tiếp theo phần này chúng ta sẽ hoàn thành Test số 2.

Test 2:  Push một đối tượng đơn vào Stack và xác nhận IsEmpty là false

Bây giờ chúng ta sẽ viết code để test yêu cầu này.

    [Test]
    public void PushOne()
    {
        Stack stack = new Stack();
        stack.Push("first element");
        Assert.IsFalse(stack.IsEmpty,
            "Sau khi Push. IsEmpty phải bằng false.");
    }

Và tất nhiên, ta sẽ viết phương thức Push cho lớp Stack.

    public void Push(object obj)
    {
    }

Bây giờ, ta thực hiện chạy NUnit Test với PushOne và cho kết quả sau:

Passed: 1 Failed: 1 Errors: 0 Inconclusive: 0 Invalid: 0 Skipped: 0 Time: 0.078125

StackFixture.PushOne:  Sau khi Push. IsEmpty phải bằng false.
  Expected: False
  But was:  True

Kết quả test fail bởi vì sau khi Push thì m_IsEmpty = false, nhưng ở đây vẫn đặt là true. Do đó, ta thực hiện thay đổi phương thức Push như sau:

    public void Push(object obj)
    {
        m_IsEmpty = false;
    }

Trước khi cài đặt Test Case tiếp theo, chúng ta cần hiệu chỉnh code test để tránh trùng lặp code. Do đó, ta sẽ tạo thêm các phương thức Init để làm việc này với thuộc tính được khai báo là [Setup], nó sẽ tự động khởi tạo các dữ liệu cần thiết trước khi chạy mỗi Test Case. Đây là mã nguồn sau khi hiệu chỉnh:

using System;
using NUnit.Framework;

[TestFixture]
public class StackFixture
{
    private Stack stack;

    [SetUp]
    public void Init()
    {
        stack = new Stack();
    }

    [Test]
    public void Empty()
    {
        Assert.IsTrue(stack.IsEmpty);
    }

    [Test]
    public void PushOne()
    {
        stack.Push("first element");
        Assert.IsFalse(stack.IsEmpty,
            "Sau khi Push. IsEmpty phải bằng false.");
    }
}

Trên đây là một ví dụ tuyệt vời cho nguyên tắc thứ 2 của TDD: Loại trừ trùng lặp.

Bây giờ, kết quả chạy của các test case đã được cài đặt đều pass. Do đó, ta sẽ chuyển qua Test Case tiếp theo.

Test-Driven Development (TDD) trong .NET bằng ví dụ

Test-Driven Development (TDD) như được định nghĩa trong Wiki, là một kỹ thuật phát triển phần mềm chia nhỏ một chức năng thành các pha phát triển nhỏ dựa trên việc định nghĩa các test case. Mỗi pha tạo ra các đoạn code cần thiết để có thể đạt được các pha test. Cuối cùng, người lập trình hiệu chỉnh (refactor) code cho khớp với các thay đổi. Một khái niệm quan trọng của TDD là phải chuẩn bị các bản test trước khi lập trình để thuận tiện cho việc nhanh chóng đáp ứng các thay đổi. Chú ý rằng test-driven development là một phương pháp thiết kế phần mềm, không chỉ là một phương pháp của việc kiểm thử.

Trong bài viết này, chúng tôi sẽ sử dụng một ví dụ là xây dựng một Stack sử dụng Test-Driven Development (TDD) theo từng bước một.

Nhim v

Stack là một cấu trúc dữ liệu mà được truy cập theo kiểu tuần tự vào sau ra trước. Các hoạt động bao gồm: Push, Pop, Top IsEmpty. Push thêm một phần từ vào đỉnh của Stack, Pop lấy một phần tử trên đỉnh của Stack, Top trả lại phần tử trên đỉnh của Stack. IsEmpty trả về true khi Stack rỗng, ngược lại là false.

Như vậy, danh sách test gồm:

  • Tạo một Stack và xác nhận IsEmpty là true.
  • Push một đối tượng đơn vào Stack và xác nhận IsEmpty là false.
  • Push một đối tượng đơn, Pop đối tượng đó và xác nhận IsEmpty là true.
  • Push một đối tượng đơn, ghi nhớ đối tượng đó; Pop đối tượng, và xác nhận hai đối tượng này là giống nhau.
  • Push ba đối tượng, ghi nhớ chúng; Pop từng đối tượng một, và xác nhận chúng được xóa theo đúng thứ tự.
  • Pop một Stack không có thành phần nào.
  • Push một đối tượng đơn và sau đó gọi Top. Xác nhận IsEmpty là false.
  • Push một đối tượng đơn, nhớ nó; sau đó gọi Top. Xác nhận đối tượng trả lại là giống với đối tượng đã được đưa vào.
  • Gọi Top trên một Stack rỗng.

Ở đây, chúng ta sẽ chọn test case đơn giản nhất để thực hiện đầu tiên, đó chính là test case đầu tiên trên danh sách ở trên.

Cài đặt

Tiếp theo, chúng ta sẽ cài đặt từng test case trong danh sách ở trên.

Test 1: Tạo một Stack và xác nhận IsEmpty là true.

Chúng ta sẽ tạo 1 file source code test gọi là StackFixture.cs, trong đó sẽ chứa các test case được cài đặt.

Đầu tiên, chúng ta khai báo

  using System; 
  using NUnit.Framework; 

  [TestFixture] 
  public class StackFixture 
  { /*...*/ }	
  

Tiếp theo, chúng ta viết phương thức test cho test case này, tên là Empty.

    [Test]
    public void Empty()
    {
        Stack stack = new Stack();
        Assert.IsTrue(stack.IsEmpty);
    }

Với bản test ở trên, chúng ta sẽ thực hiện cài đặt code cho Property là IsEmpty của lớp Stack mà ta đang cài đặt.

using System;

public class Stack
{
    private bool m_IsEmpty;

    public bool IsEmpty
    {
        get {
            return m_IsEmpty;
        }
    }
}

Như vậy, việc cài đặt cho test case đầu tiên đã hoàn thành. Khi bắt đầu, bạn nên tập trung vào test case mà bạn đang viết và không nghĩ đến các test case khác. Điều đó sẽ giúp bạn kiểm soát được tốt hơn khi mà lượng test case lớn hơn.