PDA

View Full Version : نحوه پاس دادن خطا در برنامه نویسی لایه ای



saeed zarei
پنج شنبه 15 فروردین 1392, 20:37 عصر
با سلام
من تو پروژه ام از برنامه نویسی لایه ای استفاده کردم . حالا میخام بدونم چطوری میشه اگه خطایی تو sql اتفاق افتاد رو به کاربر نشون بدم . با Try Catch فقط این کارو انجام دادم " تشخیص اینکه ایا خطایی رخ داده یا نه " . ولی اینکه اون چه خطایی بوده و متن اون خطا چیه و چطور به کاربر نشون بدم رو دیگه نمیدونم . ممنون میشم از دوستان کمک کنن.
با تشکر

veniz2008
پنج شنبه 15 فروردین 1392, 20:56 عصر
سلام.
میتونید اینطور بنویسید:

try
{
// کدهای اصلی برنامه
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
خطاهایی که در sql رخ میدن :

try
{
// کدهای اصلی برنامه
}
catch(SqlException ex)
{
MessageBox.Show(ex.Message);
}
موفق باشید.

plus
پنج شنبه 15 فروردین 1392, 20:56 عصر
ببینید متن خطای Sql بدرد کاربر نمیخوره، شما میتونی، با همون try-catch، خطای نوع SqlException رو catch کنید، و با بررسی مشخصات شئ Exception، متن خطایی که برای کاربر قابل فهم باشه رو بهش نشون بدی، علاوه بر اون امکانی بگذاری، که مشخصات این SqlException رو یا جایی ذخیره کنید، یا e-mail بشه بهتون.و البته میتونید برای دم دست بودن به کاربر هم نشون بدین (با گذاشتن مثلا قابلیت کپی) ولی برای نمایش به کاربر به متن انگلیسی خطا اکتفا نکنید.

saeed zarei
پنج شنبه 15 فروردین 1392, 21:48 عصر
ممنون از جوابتون . حالا سوال من اینه که چطور خود Exception رو از لایه Dal به Bll و در نهایت به Ui ارسال کنم . منظورم اینه که باید متد جداگونه ای بنویسم که اگه خطا داشتیم کنترل اجرا به اون واگزار بشه یا .... ؟
یه چیزی در مورد EventLog دیدم ولی نمیدونم درسته یا نه و اصلا چطور باید باهاش کار کرد .
ممنون

linux
پنج شنبه 15 فروردین 1392, 22:37 عصر
ممنون از جوابتون . حالا سوال من اینه که چطور خود Exception رو از لایه Dal به Bll و در نهایت به Ui ارسال کنم . منظورم اینه که باید متد جداگونه ای بنویسم که اگه خطا داشتیم کنترل اجرا به اون واگزار بشه یا .... ؟
یه چیزی در مورد EventLog دیدم ولی نمیدونم درسته یا نه و اصلا چطور باید باهاش کار کرد .
ممنون
بله شما در لایه‌های پایین‌تر باید خطا را تولید کنید و در آخرین لایه یعنی لایه UI در صورت بروز خطا پیغام مناسب بدهید
با دستور throw new exption

plus
پنج شنبه 15 فروردین 1392, 22:44 عصر
هندل کردن Exception ها باید تو سطح کل نرم افزار یه فکری براش بشه، نه فقط لایه DAL و ... . بسته به نیاز، کارهای مختلفی میشه کرد.
میتونین همونطور که گفتم متن مناسب فارسی و متن خطا و... رو در بیارین و در قالب یک شئ مثلا DALException:Exception در پایین ترین لایه throw کنید.این expcetion رو میتونید توی UI با گذاشتن یک try catch هندل کنید و یا در رویداد Application.ThreadException .
.ٍEvent logs هم روشی هست که برای ثبت خطاها، رویدادها و ...در ویندوز پیاده شده. پیشنهاد میکنم از اون استفاده نکید و روشی داشه باشید که مجزا اطلاعات خطا رو روی فایل یا جای دیگه ذخیره کنه.

linux
پنج شنبه 15 فروردین 1392, 23:04 عصر
برای log کردن از log4net استفاده کنید...

saeed zarei
پنج شنبه 15 فروردین 1392, 23:17 عصر
میشه خواهش کنم بیشتر توضیح بدید

linux
جمعه 16 فروردین 1392, 00:12 صبح
میشه خواهش کنم بیشتر توضیح بدید
از کدهایی که نوشتی برای مثال از هر لایه یک کلاس بگذار تا روی آنها توضیج بدهم

saeed zarei
جمعه 16 فروردین 1392, 17:22 عصر
منون میشم تا انتها کمکم کنید .
این قطعه کد مربوط به لایبراری DAL و کلاس Base هست :

public SqlDataReader ExecuteReaderWitParameters(out SByte result, CommandType commandType, string commandText, SqlParameter[] commandParameters)
{
SqlConnection con = new SqlConnection(ConnectionString);

SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = commandType;
cmd.CommandText = commandText;
cmd.Parameters.AddRange(commandParameters);

bool mustCloseConnection = false;
try
{
if (con.State != ConnectionState.Open)
{
mustCloseConnection = true;
con.Open();
}
else
{
mustCloseConnection = false;
}


dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection) ;
result = 100;

return dataReader;
}
catch
{
if (mustCloseConnection)
con.Close();
dataReader = null;
result = -100;
return dataReader;
}


}

این هم مربوط به لایبراری DAL و کلاس Total:

public SqlDataReader GetAllPrivateTotal(out sbyte result, string start)
{
return ExecuteReaderWitParameters(out result, CommandType.StoredProcedure, "S_All_Private_Total", new SqlParameter[] {
new SqlParameter ("@start" , start)});
}


اینم کد مربوط به لایبراری BLL و کلاس Total :

public static List<Total> GetAllPrivatTotal(out sbyte result, string start)
{
DAL_Acc_Fakke.Total dalTotal = new DAL_Acc_Fakke.Total();
IDataReader idrTotal = dalTotal.GetAllPrivateTotal(out result,start);

if (result == 100)
{
List<Total> totalList = new List<Total>();
while (idrTotal.Read())
{
Total tempTotal = new Total();
tempTotal.Text = idrTotal["Text"].ToString();
totalList.Add(tempTotal);
}
return totalList;
}
return null;
}


من چون نمیدونستم باید چطور این کار رو انجام بدم اومدم از یک آرگومان به نام Result استفاده کردم و اگه اون برابر با -100 بود یعنی کدم خطا داشته . حالا باید چی کار کنم . بی زحمت یه کم کامل توضیح بدید .
ممنون و تشکر از وقتی که گذاشتید

linux
شنبه 17 فروردین 1392, 02:20 صبح
کلا کد نویسی تون عجیب و غریب هست. شما لایه dal را بی جهت تا bll گسترش دادید.
به هر حال
در bll اگر result==-100 باشد فکر کنم باید می نوشتید.
در try قسمت catch این جور بنویسید
catch (exception ex)
throw new exception("خطا در واکشی داده ها",ex)

در bll هم همین طورهمین کد را تکرار کنید و در انتها در لایه نمایش
در try در قسمت catch مثلا از یک messagebox استفاده کنید تا خطا را به کاربر نمایش دهید.

saeed zarei
شنبه 17 فروردین 1392, 14:49 عصر
سلام . ممنون از راهنماییتون . من کد رو به صورتی که گفتید درست کردم و جواب هم گرفتم . حالا نکته دیگه ای در این مورد هست که بگید ؟
و دیگه اینکه من چطور میتونم بفهمم چه خطایی اتفاق افتاده که پیغام فارسی معادل اونو به کاربر نشون بدم ؟(لطفا تو این زمینه به صورت کامل کمکم کنید . ممنون)
در اخر شما گفتید که

کلا کد نویسی تون عجیب و غریب هست. شما لایه dal را بی جهت تا bll گسترش دادید.
میشه در این مورد هم یه کم توضیح بدید . چون من همه پروژه هامو دارم به همین صورت مینویسم .
خدا خیرتون بده .

linux
شنبه 17 فروردین 1392, 17:13 عصر
سلام . ممنون از راهنماییتون . من کد رو به صورتی که گفتید درست کردم و جواب هم گرفتم . حالا نکته دیگه ای در این مورد هست که بگید ؟
و دیگه اینکه من چطور میتونم بفهمم چه خطایی اتفاق افتاده که پیغام فارسی معادل اونو به کاربر نشون بدم ؟(لطفا تو این زمینه به صورت کامل کمکم کنید . ممنون)
در اخر شما گفتید که

میشه در این مورد هم یه کم توضیح بدید . چون من همه پروژه هامو دارم به همین صورت مینویسم .
خدا خیرتون بده .
خوب یک exception خودتان بسازید با ارث بری از کلاس exception یک کمی پر و بالش بدهید مثلا براش errorCode را بصورت پروپرتی تعریف کنید. یک چیزی شبیه این (http://www.c-sharpcorner.com/uploadfile/puranindia/creating-your-own-exception-classes-in-C-Sharp/) اونجایی که throw می‌کنید اطلاعات بشتر به پروپرتیهای بدهید.
بعد در لایه UI یک فرم طراحی کنید که برای نمایش این خطا ها باشه بجای msgbox از این فرم استفاده کنید. شما شروع کنید من کمکتون می‌کنم.
در مورد کدهاتون
شرایط ایده‌ال این هست که از or mapper استفاده کنید که فعلا بهترین ها Entity Framework , NHibernate هست. یک کمی باید مطالعه کنید در موردشون مخصوصا انتیتی فریمورک.
در حالتی که شما مستقیم با ADO.net کار می‌کنید. شما همین Total را باید در لایه DAL برگردانید. ولی نوع توتال باید در همان بیزینس تعریف شود در بیزینس نباید کدهای مربوط به واکشی داده‌ها وجود داشته باشد اصطلاحا نباید ارجایی به System.data داشته باشید.
دوست داشتید می‌توانید سر فرصت کدهای شما را بررسی کنیم

saeed zarei
یک شنبه 18 فروردین 1392, 00:01 صبح
ممنون از اینکه دارید وقت میزارید .
راستش تازه دارم با EF کار میکنم ، و خیلی بلد نیستم و دیگه اینکه تقریبا نیمی از پروژه ای که دارم مینویسم رو با برنامه نویسی لایه ای انجام دادم . من کدهام رو به این صورت که شما گفتید نوشتم ولی خطایی مبنی بر اینکه باید لایبراری Dal رو هم به پروژه ارجاع بدید بهم داد :
این مربوط به لایبراری DAL و کلاس Base
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using System.Text;

namespace dal
{
public class BaseDal
{

public SqlDataReader ExecuteReaderNoParameters(CommandType commandType, string commandText)
{
SqlConnection con = new SqlConnection(ConnectionString);

SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = commandType;
cmd.CommandText = commandText;

bool mustCloseConnection = false;
try
{
if (con.State != ConnectionState.Open)
{
mustCloseConnection = true;
con.Open();
}
else
mustCloseConnection = false;
SqlDataReader dr;
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection) ;
return dr;
}
catch (Exception ex)
{
if (mustCloseConnection)
con.Close();
dataReader = null;
throw new Exception("Can Not Connect.", ex);
}

}


}
}


این چندتا هم مربوط به لایبراری DAL و کلاس Total
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using System.Text;

namespace dal
{
public class Total : BaseDal
{
public string Text { get; set; }


private SqlDataReader GetAllTotal()
{
try
{
return ExecuteReaderNoParameters(CommandType.StoredProced ure, "S_All_Total");
}
catch (Exception ex)
{
throw new Exception("Can Not Connect.", ex);
}
}


public SqlDataReader GetAllPrivateTotal(out sbyte result, string start)
{

return ExecuteReaderWitParameters(out result, CommandType.StoredProcedure, "S_All_Private_Total", new SqlParameter[] {
new SqlParameter ("@start" , start)});
}


public List<Total> GetListAllTotal()
{

try
{
Total dalTotal = new Total();
IDataReader idrTotal = GetAllTotal();


List<Total> totalList = new List<Total>();
while (idrTotal.Read())
{
Total tempTotal = new Total();
tempTotal.Text = idrTotal.GetValue(1).ToString();
totalList.Add(tempTotal);
}
return totalList;

}
catch (Exception ex)
{
throw new Exception("Can Not ... ", ex);

}
}

}
}

و در نهایت :
private void btnShow(object sender, EventArgs e)
{
dgv.DataSource = BTotal.GetAllTotal();

}

مگه در برنامه نویسی لایه ای هر لایه فقط به لایه بالاتر از خودش سرویس نمیده ؟
یعنی Dal --> Bll -->UI
پس در bll یه ارجاع به Dal ، و در UI هم فقط باید یه ارجاع به Bll داشته باشیم .

برای کلاس Exception هم که گفتید ، چشم من شروع میکنم و خواهشم اینه که کمک کنید .
با تشکر

saeed zarei
دوشنبه 19 فروردین 1392, 18:47 عصر
اقای بابک بخشایش (Linux) چی شد ؟

linux
سه شنبه 20 فروردین 1392, 00:08 صبح
ممنون از اینکه دارید وقت میزارید .
راستش تازه دارم با EF کار میکنم ، و خیلی بلد نیستم و دیگه اینکه تقریبا نیمی از پروژه ای که دارم مینویسم رو با برنامه نویسی لایه ای انجام دادم . من کدهام رو به این صورت که شما گفتید نوشتم ولی خطایی مبنی بر اینکه باید لایبراری Dal رو هم به پروژه ارجاع بدید بهم داد :
این مربوط به لایبراری DAL و کلاس Base
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using System.Text;

namespace dal
{
public class BaseDal
{

public SqlDataReader ExecuteReaderNoParameters(CommandType commandType, string commandText)
{
SqlConnection con = new SqlConnection(ConnectionString);

SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = commandType;
cmd.CommandText = commandText;

bool mustCloseConnection = false;
try
{
if (con.State != ConnectionState.Open)
{
mustCloseConnection = true;
con.Open();
}
else
mustCloseConnection = false;
SqlDataReader dr;
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection) ;
return dr;
}
catch (Exception ex)
{
if (mustCloseConnection)
con.Close();
dataReader = null;
throw new Exception("Can Not Connect.", ex);
}

}


}
}


این چندتا هم مربوط به لایبراری DAL و کلاس Total
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using System.Text;

namespace dal
{
public class Total : BaseDal
{
public string Text { get; set; }


private SqlDataReader GetAllTotal()
{
try
{
return ExecuteReaderNoParameters(CommandType.StoredProced ure, "S_All_Total");
}
catch (Exception ex)
{
throw new Exception("Can Not Connect.", ex);
}
}


public SqlDataReader GetAllPrivateTotal(out sbyte result, string start)
{

return ExecuteReaderWitParameters(out result, CommandType.StoredProcedure, "S_All_Private_Total", new SqlParameter[] {
new SqlParameter ("@start" , start)});
}


public List<Total> GetListAllTotal()
{

try
{
Total dalTotal = new Total();
IDataReader idrTotal = GetAllTotal();


List<Total> totalList = new List<Total>();
while (idrTotal.Read())
{
Total tempTotal = new Total();
tempTotal.Text = idrTotal.GetValue(1).ToString();
totalList.Add(tempTotal);
}
return totalList;

}
catch (Exception ex)
{
throw new Exception("Can Not ... ", ex);

}
}

}
}

و در نهایت :
private void btnShow(object sender, EventArgs e)
{
dgv.DataSource = BTotal.GetAllTotal();

}

مگه در برنامه نویسی لایه ای هر لایه فقط به لایه بالاتر از خودش سرویس نمیده ؟
یعنی Dal --> Bll -->UI
پس در bll یه ارجاع به Dal ، و در UI هم فقط باید یه ارجاع به Bll داشته باشیم .

برای کلاس Exception هم که گفتید ، چشم من شروع میکنم و خواهشم اینه که کمک کنید .
با تشکر

حرفتون درست هست این وسط اصطلاحی به اسم بیزینس آبجکتها داریم که بین همه لایه ها مشترک هستند. مثل همین آبجکت توتال. شما یک آبجکتی به اسم توتال دارید حالا اینجا فقط یک استرینگ هست ممکن مثلا اطلاعات مربوط به یک شخص باشه یک کلاس تعریف کنید که فقط پروپرتی داشته باشه .