Sử dụng webservice như một datasource

Bạn muốn sử dụng web service như một datasource cho ứng dụng của mình!

Giải pháp: Tạo một web service trả về một dataset và gọi phương thức đó ở client

Cách thực hiện (step by step)

Bước 1: Tạo 1 webservice đặt tên tùy ý, ở đây mình đặt là DemoWebservice

Capture

Bước 2: Trong App_Code/Service.cs bạn gõ vào đoạn code sau


[WebMethod]
public DataSet GetDataSet(string sql) {
SqlConnection con = new SqlConnection("Data Source=nguyenvanthanh;Initial Catalog=Demo;Integrated Security=True");
SqlDataAdapter ad=new SqlDataAdapter(sql,con);
DataSet ds=new DataSet();
ad.Fill(ds, "table1");
ad.Dispose();
return ds;
}

Chạy chương trình và bạn được như hình sau:

Capture

Bạn cứ để đó và tiếp tục làm nhé.

Bước 3: Mở thêm 1 cửa sổ Visual Studio mới vào tạo một ứng dụng Windows Form Application

- Kéo vào form 1 DataGridview

Bước 4: Tham chiếu tới web service, bạn làm từng bước 1 theo các hình sau:

Kích phải vào project ở solution explorer và chọn Add Service Reference…1

Copy địa chỉ của web service ở project trước vào ô Address rồi ấn go, ta được như hình sau:

2

Ta thấy có phương thức GetDataSet ở bên ô Operations. Ấn OK.

Bước 5: Tạo đối tượng vào sử dụng

Mình làm đơn giản như sau. Tại sự kiện formload bạn gõ vào đoạn code sau:


ServiceReference1.ServiceSoapClient sv=new ServiceSoapClient();
dataGridView1.DataSource = sv.GetDataSet("Select * from sinhvien").Tables[0];

Chạy chương trình và bạn sẽ thấy kết quả được hiển thị trên datagridview là danh sách tất cả sinh viên có trong bảng sinh viên.

Để thêm, xóa, sửa, bạn cũng viết thêm các web method trong webservice để thực hiện điều này. đó chình là phương thức Executenonquery(string sql) mà mình hay làm đó. Sau đó các bạn cũng gọi tương tự là được.

Khi bạn public web service này lên IIS của máy thì mỗi khi cần dùng chỉ cần gọi đường dẫn http://localhost/DemoWebservice/Service.asmx là có thể sử dụng được cho ứng dụng của mình.

Chúc các bạn thành công!

Cách gắn hình ảnh vào file dll và sử dụng

Khi lập trình ứng dụng, hình ảnh là một thứ không thể thiếu để làm đẹp thêm ứng dụng. Nhưng nếu bạn add thẳng vào resource của ứng dụng thì khi build ra file exe sẽ rất nặng và làm chậm ứng dụng khi khởi động. Nếu tạo 1 thư mục và chứa hình ảnh rồi tham chiếu đến thì cũng được nhưng không hay, nó có cảm giác không chuyên nghiệp và lỡ ai đó xóa mất thì ứng dụng sẽ bị khuyết hình ảnh chỗ đó. Vậy giải pháp là tạo 1 file dll chứa các hình ảnh rồi tham chiếu đến dll đó để lấy hình ảnh ra hiển thị. Làm như vậy ta sẽ có cảm giác ứng dụng sẽ chuyên nghiệp hơn (đó là cảm giác của mình) và mọi người thấy file dll cũng ko dám xóa linh tinh (theo cảm nghĩ của mình là như vậy Open-mouthed smile)

Thôi không nói dài dòng nữa, tóm lại là đây chỉ là một cách để sử dụng hình ảnh trong ứng dụng, các bạn có thể không làm theo cũng chả sao vì nó có vài cách, ứng dụng nhỏ thì cứ add thẳng vào resource cho nó đơn giản. Bắt đầu nhé.

Bước 1: Tạo 1 project Windows Form Application đặt tên tùy ý

1

Bước 2: Add thêm 1 class library vào ứng dụng để tạo 1 file dll chứa hình ảnh

Bước 3: Add 1 resource file vào class library trên.

2

Bước 4: Add 1 vài hình ảnh vào resource file đó

3

Bước 5: Mở class1.cs ra và gõ vào đoạn code như hình sau

4

Bước 6: Build Class Library này => ta được 1 file dll.

Bước 7: Add file dll vào ứng dụng Windows Form Application

5

Bước 8: Sử dụng

6

Kết quả sau khi chạy chương trình

7

Vậy là xong rồi đó. Chúc các bạn thành công!

Cách cấu hình kết nối SqlServer khi mang ứng dụng sang máy khác

Hôm nay, mình sẽ hướng dẫn các bạn cách tạo kết nối Sql Server cho ứng dụng của mình khi mang sang máy khác sử dụng mà mất thông số kết nối.

- Đầu tiên, bạn tạo 1 file text chứa thông tin kết nối, file text đó có nội dung như sau:

Server:
Database:
UserName:
Password:

Các giá trị ban đầu để trống. Mình đặt tên file là ConnectString.con

- Tiếp theo, bạn tạo 1 class tên là Helper.cs với nội dung như sau:


using System.Data.SqlClient;
using System.IO;

namespace iloveit1208_ConnectSQLServer
{
class Helper
{
public string Server{ get; set; }
public string Database { get; set; }
public string UserName { get; set; }
public string Password { get; set; }

public Helper()
{
StreamReader reader=new StreamReader("ConnectString.con");
this.Server = reader.ReadLine().Split(':')[1];
this.Database = reader.ReadLine().Split(':')[1];
this.UserName = reader.ReadLine().Split(':')[1];
this.Password = reader.ReadLine().Split(':')[1];
reader.Close();
}
public SqlConnection GetConnect()
{
if (this.UserName!="")
return new SqlConnection("Data Source=" + this.Server + ";Initial Catalog=" + this.Database + ";User Id=" + this.UserName + ";Password=" + this.Password + ";");
else
return new SqlConnection("Data Source=" + this.Server + ";Initial Catalog=" + this.Database + ";Integrated Security=True");
}
public static void WriteFile(string server,string data,string uid,string pass)
{
StreamWriter writer = new StreamWriter("ConnectString.con");
writer.WriteLine("Server:"+server);
writer.WriteLine("Database:"+data);
writer.WriteLine("UserName:" + uid);
writer.WriteLine("PassWord:" + pass);
writer.Close();
}
}
}

Chức năng của class này là cung cấp các phương thức đọc và ghi vào file ConnectString.con

- Tiếp theo bạn tạo 1 form kết nối như hình sau:

1

Form này sẽ tự động hiện lên cho bạn cấu hình kết nối SqlServer khi mất kết nối (trường hợp chuyển sang máy khác).

Code cho từng nút bạn có thể xem ở Project đính kèm.

- Tạo 1 form chính cho chương trình, mình làm đơn giản chỉ có một nút kiểm tra kết nối.

2

Trong sự kiện formload, bạn phải kiểm tra xem kết nối tới máy chủ có thành công hay không, nếu thất bại thì formconnection sẽ được hiện lên để cấu hình lại kết nối.


private void Form1_Load(object sender, EventArgs e)
{
try
{
Helper h = new Helper();
SqlConnection con = h.GetConnect();
con.Open();
con.Close();
}
catch (Exception)
{
frmConnection f=new frmConnection();
f.ShowDialog();
}
}

Nguyên lý chỉ đơn giản vậy thôi, mình sẽ đính kèm project ở dưới nếu bạn không hiểu đoạn code này thì reply lại mình sẽ giải thích kĩ càng.

Link download Project: Download

Chúc các bạn thành công.

Cách lưu hình ảnh vào csdl Sql Server

Đầu tiên, các bạn tạo csdl có 1 table như hình dưới:


Tiếp theo, các bạn tạo 1 form có giao diện như hình dưới (Ở giữa là 1 picture box và bên cạnh là các nút điều khiển.



Tiếp theo, các bạn tạo 1 class có tên AccessData.cs. Nội dung class đó như sau:

using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Data.SqlClient;

namespace ImageInSQL
{
class AccessData
{
public SqlConnection conn;

public string connectionString =
"Data Source=.\\SQLEXPRESS;AttachDbFilename='E:\\My Code\\C#\\ImageInSQL\\ImageInSQL\\ImageData.mdf';Integrated Security=True;User Instance=True";
public AccessData()
{
conn = new SqlConnection(connectionString);
}
public void StorePicture(string filename)
{
byte[] imageData = null;
// Read the file into a byte array
using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
imageData = new Byte[fs.Length];
fs.Read(imageData, 0, (int) fs.Length);
}
string shortFileName = filename.Split('\\').Last();
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("InsertImage", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@filename", shortFileName);
cmd.Parameters["@filename"].Direction = ParameterDirection.Input;
cmd.Parameters.Add("@Image",SqlDbType.Image);
cmd.Parameters["@Image"].Direction = ParameterDirection.Input;
// Store the byte array within the image field
cmd.Parameters["@Image"].Value = imageData;
conn.Open();
cmd.ExecuteNonQuery();
}
}

public byte[] RetrieveImage(int id)
{
byte[] imageData = null;
conn.Open();
SqlCommand cmd = new SqlCommand("select Image from tbl_Image where ID="+id+"",conn);
// Assume previously established command and connection
// The command SELECTs the IMAGE column from the table

using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
reader.Read();
// Get size of image data – pass null as the byte array parameter
long bytesize = reader.GetBytes(0, 0, null, 0, 0);
// Allocate byte array to hold image data
imageData = new byte[bytesize];
long bytesread = 0;
int curpos = 0;
int chunkSize = 1;
while (bytesread < bytesize)
{
// chunkSize is an arbitrary application defined value
bytesread += reader.GetBytes(0, curpos, imageData, curpos, chunkSize);
curpos += chunkSize;
}
}
conn.Close();
// byte array ‘imageData’ now contains BLOB from database
return imageData;
}
public int NumberImageInDB()
{
conn.Open();
SqlCommand cmd=new SqlCommand("select Max(ID) from tbl_Image",conn);
int kq = int.Parse(cmd.ExecuteScalar().ToString());
cmd.Dispose();
conn.Close();
return kq;
}
public string FileNameOfImage(int id)
{
conn.Open();
SqlCommand cmd = new SqlCommand("select FileName from tbl_Image where ID="+id+"", conn);
string kq = cmd.ExecuteScalar().ToString();
cmd.Dispose();
conn.Close();
return kq;
}
}
}

Các bạn cần chỉnh lại connectionString cho đúng với máy mình.
vào phần code của form khai báo đối tượng AccessData và 2 biến private để lưu tên file và chỉ số ảnh

AccessData ac=new AccessData();
private string filename;
private int i=1;

Tiếp theo sẽ là code cho từng nút:
Nút select picture

OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter ="All File (*.*)|*.*|JPG Files(*.JPG)|*.JPG | GIF Files(*.GIF)|*.GIF";
if (dlg.ShowDialog(this) == DialogResult.OK)
{
pictureBox1.Image = Image.FromFile(dlg.FileName);
filename = dlg.FileName;
blFileName.Text = filename.Split('\\').Last();
}

Nút save to DB

try
{
ac.StorePicture(filename);
MessageBox.Show("Successful!", "Infomation", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message.ToString(), "Infomation", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Nút picture first

byte[] img = ac.RetrieveImage(1);
MemoryStream str = new MemoryStream(img);
pictureBox1.Image = Image.FromStream(str);
i = 1;
button5.Enabled = false;
button3.Enabled = true;
blFileName.Text = ac.FileNameOfImage(1);

Nút next

button5.Enabled = true;
if (i < ac.NumberImageInDB()) i++;
else button3.Enabled = false;
byte[] img = ac.RetrieveImage(i);
MemoryStream str = new MemoryStream(img);
pictureBox1.Image = Image.FromStream(str);
blFileName.Text = ac.FileNameOfImage(i);

Nút preview

button3.Enabled = true;
if (i >1) i--;
else button5.Enabled = false;
byte[] img = ac.RetrieveImage(i);
MemoryStream str = new MemoryStream(img);
pictureBox1.Image = Image.FromStream(str);
blFileName.Text = ac.FileNameOfImage(i);

Nút picture last

byte[] img = ac.RetrieveImage(ac.NumberImageInDB());
MemoryStream str = new MemoryStream(img);
pictureBox1.Image = Image.FromStream(str);
i = ac.NumberImageInDB();
button3.Enabled = false;
button5.Enabled = true;
blFileName.Text = ac.FileNameOfImage(ac.NumberImageInDB());

Vậy là xong, các bạn có thể test thử và xem kết quả.
Download code full

Chúc các bạn thành công!

5. Sử dụng SqlDataAdapter, DataSet, DataTable

Ở bài trước bạn đã biết cách xử lý và hiện kết quả ra màn hình dùng Data Reader. Chú ý rằng : nếu chỉ muốn xem thông tin thì dùng Data Reader. Bài này hướng dẫn sử dụng DataSet để xử lý kết quả kết hợp với DataAdapter. Không giống với DataReader, tạo ra các đối tượng dùng interface System.DataIDataReader, thì DataSet là một thành phần đặc trưng của ADO.NET được sử dụng bởi tất cả các nhà cung cấp dữ liệu (data provider). Dataset có thể hoàn toàn độc lập và sử dụng khi kết nối hoặc ngắt kết nối khỏi nguồn. Mục đích cơ bản của DataSet là cung cấp xử lý xem xét dữ liệu lưu trữ trong một ‘memory cache’. Nếu như một DataSet không kết nối tới cơ sở dữ liệu thì làm sao mà xử lý dữ liệu và save lại vào database ? Đây là lí do mà DataAdapter ra đời. Hãy nghĩ DataAdapter chính là một chiếc cầu nối giữa DataSet và Data Source. Nếu không có một DataAdapter nào thì DataSet không thể truy cập bất cứ DataSource nào. DataAdapter đảm bào việc kết nối và truyền thông tin cho DataSet.

Tìm hiểu về ObjectModel

Đầu tiên thì mình đưa ra một số so sánh giữa DataSet và DataReader nhé, để các bạn tránh hay hỏi nhiều về việc : Lúc nào thì xài DataSet và lúc nào thì xài DataReader, giống và khác nhau như thế nào ?

So sánh DataSet và DataReader

Nếu bạn đơn giản chi muốn lấy dữ liệu và trình bày nó ra thôi thì dùng DataReader. Đặc biệt trường hợp mà bạn đọc với một số lượng lớn dữ liệu, ví như là vòng lặp tới hàng triệu dòng kết quả dữ liệu, bạn muốn tốc độ đọc nhanh và trình bày nhanh thì DataReader được sử dụng cho mục đích này, NHANH và TIỆN LỢI, cho việc ĐỌC dữ liệu.

Nếu bạn muốn chỉnh sử dữ liệu rồi update thông tin dữ liệu lại database thì bạn sử dụng DataSet. DataAdapter lấp đầy (fill) dữ liệu vào DataSet bằng cách sử dụng một DataReader, thêm vào đó resource cần được lưu trữ vào để sử dụng khi ngắt kết nối. Vì vậy việc sử dụng DataSet tốn nhiều tài nguyên hơn DataReader rất nhiều, bạn cần cân nhắc ở đây lúc nào sử dụng thành phần nào thì tốt, tránh lạm dụng quá. Nếu như bạn muốn đọc dữ liệu và viết ra dưới dạng XML, hoặc export database schema, viết lại db dưới dạng XML,…. thì nên sử dụng DataReader.

Giới thiệu sơ qua về DataSet

DataSet trong ADO.NET là một bước phát triển lớn trong việc phát triển ứng dụng cơ sở dữ liệu đa hệ. Khi lấy và chỉnh sửa dữ liệu, duy trì liên tục kết nối tới Data Source trong khi chờ user yêu cầu thì rõ ràng là tốn tài nguyên máy rất nhiều.

DataSet giúp ích ở đây rất lớn. Vì DataSet cho phép lưu trữ dữ liệu và chỉnh sửa tại ‘local cache’, hay gọi là offline mode. Có thể xem xét và xử lý thông tin trong khi ngắt kết nối. Sau khi chỉnh sửa và xem xong thì tạo một kết nối và update dữ liệu từ local vào Data Source.

Dữ liệu trong DataSet được lưu trữ dưới dạng một Collection các Tables và bạn cần phải xử lý thông qua các lớp DataTable -> DataRow và DataColumn.

Bảng dưới đây là kiến trúc DataSet.

Bạn chỉ cần tưởng tượng rằng : bạn có một cái bể nước (DataSource) , một cái máy bơm (DataAdapter) và một cái thùng đựng nước (DataSet). Thì khi lấy nước dùng cái bơm lấy nước từ bể, kiểm tra và lọc nước sau đó lại dùng cái bơm hút lại về cái bể nước. Đó chính là vai trò của cái bơm và DataAdapter tương tự như vậy.

Tương quan 3 lớp như thế này :

Có 4 cách tạo DataAdapter :


// Cách 1 : Đơn giản chỉ khai báo tạo đối tượng Adapter
SqlDataAdapter da = new SqlDataAdapter();
// Cách 2 : Thiết lập đối tượng SqlCommand
SqlDataAdapter da = new SqlDataAdapter(cmd);
// Cách 3 : Thiết lập query và đối tượng SqlConnection
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
// Cách 4 : Thiết lập query và mệnh lệnh thực thi
SqlDataAdapter da = new SqlDataAdapter(sql, connString);

Giới thiệu về DataTable và thành phần kèm

Nằm trong lớp : System.Data.DataTable. Có cấu trúc theo cấu trúc của bảng trong cơ sở dữ liệu gồm các hàng và cột nên có 2 thành phần kèm theo là : DataRow và DataColumn

DataRow sẽ là tập hợp các cột (record-set)

DataColumn là tập hợp các hàng cùng một đặc tính. (Field)


DataTable dt = new DataTable();
DataColumn col = dt.Columns[“Contact”]; // Cột Contact
DataColumn col = dt.Columns[2];
DataRow row = dt.Rows[2];

Làm việc với DataSet và DataAdapter

Tạo một dataset :


DataSet ds = new DataSet();
DataSet ds = new DataSet(“DataSet Name”);

Nếu bạn dùng cách 1 thì theo mặc định DataSet sẽ có tên là “NewDataSet”, cách thứ 2 là bạn đặt tên luôn cho DataSet bên trong constructor. Hoặc bạn có thẻ thay đổi tên của DataSet bằng thuộc tính ‘DataSetName’

Có nhiều cách xử lý với DataSet như:

· + Sử dụng thông qua Adapter

· + Đọc từ một tài liệu XML

Thử xử lý dữ liệu bằng một ví dụ :


using System;
using System.Data;
using System.Data.SqlClient;

namespace MSSQL_Server
{
class Database
{
static void Main(string[] args)
{
// Tạo connection strin
string connString = @"Server = NguyenVanThanh
Integrated Security = True;
Database = Demo
// Tạo SQL query
string sql = @"SELECT MaSV,TenSV FROM SinhVien";
// Tạo connection
SqlConnection conn = new SqlConnection(connString);
try
{
// Mỏ kết nối
conn.Open();
// Tạo Adapter
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
// Tạo DataSet
DataSet ds = new DataSet();
// Lấp đầy kết quả vào DataSet
da.Fill(ds, "sinhvien");
// Tạo DataTable thu kết quả từ bảng
DataTable dt = ds.Tables["sinhvien"];
// In kết quả ra Console
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn col in dt.Columns)
Console.WriteLine(row[col]);
Console.WriteLine("".PadLeft(20, '='));
}
}
catch (Exception e)
{
// Bắt lỗi
Console.WriteLine(e.Message);
}
finally
{
// Đóng kết nối
conn.Close();
}
}
}
}


Phân tích bài đơn giản ở trên nha.

Sau khi đã mở kết nối thì ta tạo một Adapter. Adapter này chứa thông tin về SQL query cần thực thi và một đối tượng kết nối conn, sau đó tạo một DataSet. Lúc này thì DataSet chưa có gì. Sau đó lấp đầy kết quả vào DataSet bằng method ‘Fill’ của Adapter. Từ đó hiểu thêm rằng : Adapter tự động thực thi câu lệnh SQL , thu lấy kết quả và gán hết vào DataSet. Khác với DataReader cần có một đối tượng SqlComnmand đễ xử lý. Nếu khi lấp đầy kết quả vào DataSet mà không gán tên bảng nào thì tự động trong DataSet tên lần lượt từng bảng là ‘TableN’ với bảng đầu tiên là Table, Table1,Table2…TableN.

Nếu một query được thực thi lại nhiều lần thì DataSet sẽ cập nhật thông tin từng đó bảng vào trong .

Chú ý trong Adapter ở trên nếu thay bằng cách tạo Adapter dưới đây :


SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = new SqlCommand(sql, conn);

Thì kết quả thu được giống hệt nhau, không có gì thay đổi.

DataSet có thể chứa nhiều table vì thế khi xử lý Table nào cần phải gán vào DataTable một tên table cụ thể. Và cuối cùng dùng DataColumn và DataRow để xử lý DataTable đó. Đó là cách extract dữ liệu từ DataSet.

Các bạn có thể xem video sau để hiểu rõ hơn: download