Monday, September 6, 2010

Exposing DTO to javascript in ASP.NET...

This post is a continuity from my previous post related to Calling a webservice from javascript in ASP.NET 2.0. Fundamentally it's sharing the same concept. This time I've written the code in ASP.NET 3.5 (Visual Studio 2008). There's no prerequisite required compare to when I did it in ASP.NET 2.0 (Visual Studio 2005).

Once I knew how to call a webservice from javascript in ASP.NET (regardless of version). I've search google to check whether it's possible to pass an object as a parameter to webservice method. Indeed it is possible to do that, but I must make sure that the object should be simple enough without any business logic and with limited behaviour. The object known as Data Transfer Object or in short DTO. Now here's the step by step on how to do it.

1) Using Visual Studio 2008, create new web site. Select ASP.NET Web Site.

2) To create DTO object, add new class under App_Code folder. Lets name it as Student. Paste the code below.
    using System;

///
/// Summary description for Student
///

public class Student
{
public Student()
{
}

public string Id
{
get;
set;
}

public string Name
{
get;
set;
}
}
3) Create new webservice call MyWebService. Add System.Web.Script.Services namespace then add GenerateScriptType and ScriptService attribute to the webservice class. Notice that what I did here is almost the same as my previous post. The only extra code is at line 7 which is to expose Student class to javascript.
    ...
using System.Web.Script.Services;

///
/// Summary description for MyWebService
///

[GenerateScriptType(typeof(Student))]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class MyWebService : System.Web.Services.WebService
{
...
}
4) Add two methods call GetStudents and TestSubmit. GetStudents method will return a list of students to the caller. Since I want to return it as a JSON object, I've set the ResponseFormat to JSON.
    ...
[WebMethod]
[ScriptMethod(ResponseFormat=ResponseFormat.Json)]
public List<Student> GetStudents()
{
var students = new List<Student>();

for (int x = 0; x < 10; x++)
{
students.Add(new Student
{
Id = x.ToString(),
Name = "Name" + x.ToString()
});
}

return students;
}

[WebMethod]
public string TestSubmit(Student student)
{
return String.Format("You've submitted Student object with Id: {0} and Name: {1}", student.Id, student.Name);
}
5) Go to Default.aspx, add ScriptManager (again another same step as my previous post in ASP.NET 2.0).
    ...
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference InlineScript="true" Path="~/MyWebService.asmx" />
</Services>
</asp:ScriptManager>
...
6) Now add the html control
    ...
<div>
<input id="btnLoad" type="button" value="Get Students" onclick="javascript:btnLoad_Click();" />

<input id="txtId" type="text" /><input id="txtName" type="text" />
<input id="btnSubmit" type="button" value="Submit" onclick="javascript:btnSubmit_Click();" />

<table id="myTable" border="1" cellpadding="1" cellspacing="1"></table>
</div>
...
7) and the javascript
    ...
<script language="javascript" type="text/javascript">
function btnLoad_Click()
{
try
{
MyWebService.GetStudents(OnGetStudentsComplete);
}
catch(e)
{
alert("error " + e);
}
}

function OnGetStudentsComplete(result)
{
var htmlVal = "";

for(var x=0; x<result.length; x++)
{
htmlVal += "<tr><td>" + result[x].Id + "</td><td>" + result[x].Name + "</td></tr>";
}

$get("myTable").innerHTML = htmlVal;
}

function btnSubmit_Click()
{
try
{
var stu = new Student();
stu.Id = $get("txtId").value;
stu.Name = $get("txtName").value;

MyWebService.TestSubmit(stu, OnTestSubmitComplete);

var htmlVal = $get("myTable").innerHTML;
htmlVal += "<tr><td>" + stu.Id + "</td><td>" + stu.Name + "</td></tr>";
$get("myTable").innerHTML = htmlVal;
}
catch(e)
{
alert(e);
}
}

function OnTestSubmitComplete(result)
{
alert(result);
}
</script>
Now I have a web site that can call a webservice and passing an object as a parameter via javascript.

Sunday, September 5, 2010

Evolution of data query in C#...

One of the most common operation in programming is data query. In C# 1.2, normally I would use a custom collection class that derived from System.Collections. But for sake of example here, I'll show it with an ArrayList instead.

Here's a class that'll become an element of the collection (yes, I know Auto-Implemented Properties).
    public class Student
{
private int _id;
private string _name;
private string _gender;

public Student()
{
}

public int Id
{
get { return _id; }
set { _id = value; }
}

public string Name
{
get { return _name; }
set { _name = value; }
}

public string Gender
{
get { return _gender; }
set { _gender = value; }
}
}
This is how I normally code in C# 1.2 (.NET Framework 1.1) with an ArrayList.
    private ArrayList SomeFilterMethod(ArrayList myList)
{
ArrayList result = new ArrayList();

for (int x = 0; x < myList.Count; x++)
{
if (((Student)myList[x]).Gender == "Male")
{
result.Add(myList[x]);
}
}

return result;
}
Generic list with action and predicate was introduced in C# 2.0 (.NET Framework 2.0). This is how my code will look like.
    private List<Student> SomeFilterMethod(List<Student> myList)
{
return mylist.FindAll(GetMaleStudents);
}

private bool GetMaleStudents(Student item)
{
return item.Gender == "Male";
}
Not to forget an anonymous methods.
    private List<Student> SomeFilterMethod(List<Student> myList)
{
return mylist.FindAll( delegate(Student item) { return item.Gender == "Male"; } );
}
In C# 3.0 (.NET Framework 3.5), there's LINQ with 2 flavours.
1) Lambda Expression
    private List<Student> SomeFilterMethod(List<Student> myList)
{
return mylist.FindAll( item => item.Gender == "Male" );
}
2) Query Expression
    private List<Student> SomeFilterMethod(List<Student> myList)
{
return (from student in mylist
where student.Gender == "Male"
select student).ToList<Student>();
}
Between the two, personally I prefer the former.

Saturday, September 4, 2010

Huawei modem undetected on Ubuntu 10.04...

Scenario:
Plug-in modem, Ubuntu detect it as data storage only instead of modem. Only happen on Ubuntu 32bit, working as expected on 64-bit version.

Solution:
Install usb-modeswitch package.
    $ sudo apt-get install usb-modeswitch
Note:
Tested on Ubuntu 10.04 32-bit Desktop and Netbook Edition.

Wednesday, September 1, 2010

Calling a webservice from javascript in ASP.NET 2.0...

Prerequisite:
In Visual Studio 2005, to make a web project template available, you need to upgrade to SP1. The "other alternative" is to install VS80-KB915364-X86-ENU.exe and WebApplicationProjectSetup.msi. If you choose SP1 than ignore the "alternative" way.

1) For Ajax-Enabled Web Site, install ASP.NET Ajax 1.0.

2) Create new ASP.NET Ajax-Enabled Web Site.

3) Add reference System.Web.Extensions ver 1.0.61025.0.

4) On server side, create new WebService, add System.Web.Script.Services namespace and add ScripService attribute to your webservice class.
    ...
using System.Web.Script.Services;
...

[ScriptService]
public class MyWebService : WebService
{
public MyWebService()
{
//Uncomment the following line if using designed components
//InitializeComponent();
}

[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
5) On client side, create new web form and add ScriptManager to the aspx file that pointing to your webservice (MyWebService.asmx).
    ...
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference InlineScript="true" Path="~/MyWebService.asmx" />
</Services>
</asp:ScriptManager>
...
6) Add an html button and its eventhandler.
    ...
<input id="btnOk" type="button" value="Ok" onclick="javascript:btnOk_Click();" />
...

<script language="javascript" type="text/javascript">
function btnOk_Click()
{
try
{
MyWebService.HelloWorld(OnHelloWorldComplete);
}
catch(e)
{
alert("error " + e);
}
}

function OnHelloWorldComplete(result)
{
alert(result);
}
</script>
Done!!! Your first Ajax-Enabled Web Site.

Here's the full source code:
MyWebService.asmx.cs
    using System;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Script.Services;

///
/// Summary description for MyWebService
///

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class MyWebService : WebService
{
public MyWebService()
{
//Uncomment the following line if using designed components
//InitializeComponent();
}

[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
Default.aspx
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<!-- to include webservice proxy, set inlinescript=true, it's much more easier compare to adding script src=webservice.asmx/js -->
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference InlineScript="true" Path="~/MyWebService.asmx" />
</Services>
</asp:ScriptManager>

<div>
<input id="btnOk" type="button" value="Ok" onclick="javascript:btnOk_Click();" />
</div>
</form>
</body>
</html>

<script language="javascript" type="text/javascript">
function btnOk_Click()
{
try
{
MyWebService.HelloWorld(OnHelloWorldComplete);
}
catch(e)
{
alert("error " + e);
}
}

function OnHelloWorldComplete(result)
{
alert(result);
}
</script>

Monday, August 30, 2010

Stupid default setting in SQL Server 2008...

I've created a table in SQL server 2008, then decided to change one of the column size from varchar(10) to varchar(50). When I try to save the changes I'm getting the error below:

"Saving changes is not permitted. The changes you have made require the following tables to be dropped and re-created. You have either made changes to a table that can't be re-created or enabled the option Prevent saving changes that require the table to be re-created."

Solution:
In Management Studio, go to Tools -> Options then go to the Designer Page and uncheck "Prevent saving changes that require table re-creation".

Thursday, August 26, 2010

Installing VMware Player 3.1.1 on Ubuntu 10.04...


Screenshots...



1) Install build-essential and linux-headers (for my case I skip this step because I had these two packages installed before)
$ sudo apt-get install build-essential linux-headers-`uname -r`
2) Change the installer mode
$ chmod +x ./VMware-Player-3.1.1-282343.x86_64.bundle
3) Execute the installer
$ gksudo bash ./VMware-Player-3.1.1-282343.x86_64.bundle
When popup appear, click Install.

Note:
Tested on Ubuntu 10.04 Lucid Lynx and Linux Mint 10 64-bit.

Update (20/11/2010)
Command to uninstall.
sudo bash vmware-installer -u vmware-player
Update (01/03/2011)
Tested VMWare Player 3.1.3 on Linux Mint 10 64-bit

Connecting SQL Server 2008 from VS 2005 server explorer...

You need to install Service Pack 1 for Visual Studio 2005. The installer can be obtain from here.

Then install Visual Studio 2005 Update for SQL Server 2008 support.

Done.