PDA

View Full Version : سوال: Unhandled Exception



Saeed_m_Farid
دوشنبه 31 خرداد 1389, 17:24 عصر
با سلام
بنده تو کدم با اینکه همه Exception ها رو (برای از بین بردن هرگونه شکی) هندل میکنم بازم برنامه با وضع فجیعی Object reference میده و میترکه.
خلاصه کار هم اینه که من از وب سرویس یه دیتاست میگیرم که اون رو در dsTotal می ریزم (قبل تابع تعریف شده)، و بالفرض اگه وب سرویس نتونه جوابی برگردونه اصولاً باید dsTotal مقداردهی نشه (یا null بمونه)؛ که این امر صورت نمی گیره و میام که چک کنم ببینم dsTotal.Tables مقدارش null هست یا نه، یا مثلاً dsTotal.Tables.Count == 0 و یا dsTotal.Tables[0] != null به هرصورت اینجا برنامه منفجر میشه و با وجود اینکه لاگ درون catch رو مینویسه ولی Exception هندل نمیشه و برنامه به دار فانی مراجعت میکنه! چرا نباید Exception هندل بشه اونهم از هر نوعی catch (Exception ex) : میدونم این کار اشتباهه ولی برای نبودن بهانه این کد رو نوشتم و بازم فرقی نکرد؛ این هم کد کامل تابع من :

private void GenTotalNational(DataRow dr, DataRow infoRow, string time)
{

string trce = "StartGetCallList";
try
{
dsTotal = faxService.CallList_GetTotalList(dr["TEL_NO"].ToString(),
false,
int.Parse(dr["DORE_NO"].ToString()),
Properties.Settings.Default.PulsePrice.ToString(),
Properties.Settings.Default.CityCode.ToString());
trce = "CheckResultDataSource";
if ((dsTotal == null) || (dsTotal.Tables.Count > 0))
{
trce = "CheckResultTable";
if (dsTotal.Tables != null)
{
trce = "CheckRecordCount";
if (dsTotal.Tables[0].Rows.Count > 0)
{
trce = "CreateRepTitle";
infoRow["MAIN_TITLE"] = Properties.Settings.Default.ReportTitle;
infoRow["TEL_NO"] = dr["TEL_NO"].ToString();
infoRow["DATE"] = PersianDate();
infoRow["TIME"] = time.Remove(8);
infoRow["DORE"] = dr["DORE_NO"].ToString();
infoRow["TYPE_TITLE"] = Properties.Resources.TotalNational.ToString();
}
else
{
infoRow["NO_RECORDS"] = Properties.Resources.NoRecords.ToString();
}
}
else
{
infoRow["NO_RECORDS"] = Properties.Resources.NoRecords.ToString();
}

trce = "Check&DeleteExtra";
if (dsDetail.Tables[0].Rows.Count > Properties.Settings.Default.MaxRecords)
DeleteExtraRecords(false);

trce = "AddRepRows";
dsTitleInfo.Tables["Info"].Rows.Add(infoRow);
trce = "Reg-dsTitleInfo-Data";
srFaxDetail.RegData(dsTitleInfo);
trce = "Reg-dsTotal-Data";
srFaxDetail.RegData(dsTotal);
trce = "Load-Total.mrt";
srFaxDetail.Load(Application.StartupPath + "\\Reports\\Total.mrt");
trce = "Render";
srFaxDetail.Render(false);
trce = "CreateReportFile";
CreateReportFile(dr, infoRow["DATE"].ToString(), time, "National Total");
trce = "Succeed";
}
else
{
trce = "NoData-1";
AddLog("No data for [National Total] report request for Tel Number: " + dr["TEL_NO"].ToString(), LogType.Warning);
faxService.CallList_SetState(int.Parse(dr["REQ_ID"].ToString()), -3, true);
trce = "NoData-2";
}
}
catch (Exception ex)
{
AddLog("GenTotalNational[" + trce + "]: " + ex.Message, LogType.Error);
}
}


http://sys-developer.persiangig.com/image/UnhandledException.PNG

جزئیات و عکس خطا رو هم با اینکه فکر نمی کنم بدرد بخوره آوردم؛ دوستان و اساتید گرامی اگه نظری دارند محبت کنند دریغ نفرمایند:خجالت:

See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.

************** Exception Text **************
System.NullReferenceException: Object reference not set to an instance of an object.
at FaxGenerator.frmMain.GenerateReport(DataRow dr, String Duplicate)
at FaxGenerator.frmMain.OperateFaxRequests(DataTable faxesTable)
at FaxGenerator.frmMain.timerFetch_Tick(Object sender, EventArgs e)
at System.Windows.Forms.Timer.OnTick(EventArgs e)
at System.Windows.Forms.Timer.TimerNativeWindow.WndPr oc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)


************** Loaded Assemblies **************
mscorlib
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/mscorlib.dll
----------------------------------------
FaxGenerator
Assembly Version: 1.1.3824.31236
Win32 Version: 1.1.3824.31236
CodeBase: file:///C:/Program%20Files/Elka-pt/Fax%20Generator/FaxGenerator.exe
----------------------------------------
System.Windows.Forms
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Windows.Forms/2.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System/2.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Drawing
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Drawing/2.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
System.Data
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_32/System.Data/2.0.0.0__b77a5c561934e089/System.Data.dll
----------------------------------------
Stimulsoft.Report
Assembly Version: 2008.1.129.0
Win32 Version: 2008.1.129.0
CodeBase: file:///C:/Program%20Files/Elka-pt/Fax%20Generator/Stimulsoft.Report.DLL
----------------------------------------
System.Xml
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Xml/2.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------
Stimulsoft.Base
Assembly Version: 2008.1.129.0
Win32 Version: 2008.1.129.0
CodeBase: file:///C:/Program%20Files/Elka-pt/Fax%20Generator/Stimulsoft.Base.DLL
----------------------------------------
System.Web
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_32/System.Web/2.0.0.0__b03f5f7f11d50a3a/System.Web.dll
----------------------------------------
Stimulsoft.Controls
Assembly Version: 2008.1.129.0
Win32 Version: 2008.1.129.0
CodeBase: file:///C:/Program%20Files/Elka-pt/Fax%20Generator/Stimulsoft.Controls.DLL
----------------------------------------
System.Design
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Design/2.0.0.0__b03f5f7f11d50a3a/System.Design.dll
----------------------------------------
Stimulsoft.Compression
Assembly Version: 2008.1.129.0
Win32 Version: 2008.1.129.0
CodeBase: file:///C:/Program%20Files/Elka-pt/Fax%20Generator/Stimulsoft.Compression.DLL
----------------------------------------
System.Configuration
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Configuration/2.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Web.Services
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Web.Services/2.0.0.0__b03f5f7f11d50a3a/System.Web.Services.dll
----------------------------------------
g_em1gma
Assembly Version: 1.1.3824.31236
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System/2.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Transactions
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_32/System.Transactions/2.0.0.0__b77a5c561934e089/System.Transactions.dll
----------------------------------------
System.EnterpriseServices
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///C:/WINDOWS/assembly/GAC_32/System.EnterpriseServices/2.0.0.0__b03f5f7f11d50a3a/System.EnterpriseServices.dll
----------------------------------------

************** JIT Debugging **************
To enable just-in-time (JIT) debugging, the .config file for this
application or computer (machine.config) must have the
jitDebugging value set in the system.windows.forms section.
The application must also be compiled with debugging
enabled.

For example:

<configuration>
<system.windows.forms jitDebugging="true" />
</configuration>

When JIT debugging is enabled, any unhandled exception
will be sent to the JIT debugger registered on the computer
rather than be handled by this dialog box.

mehdi.mousavi
دوشنبه 31 خرداد 1389, 20:29 عصر
سلام.
خط 13 از کدتون رو نگاه کنید.

if ((dsTotal == null) || (dsTotal.Tables.Count > 0))

خوب، اگر dsTotal شما null باشه، اونوقت یکی دو خط پایینتر جاییکه نوشته اید:

dsTotal.Tables

معلومه که برنامه میترکه. :قهقهه: (به قول خودتون!)

فکر میکنم شرط اول رو خسته بودید نوشتید...

موفق باشید.

Saeed_m_Farid
سه شنبه 01 تیر 1389, 08:58 صبح
معلومه که برنامه میترکه. :قهقهه: (به قول خودتون!)
فکر میکنم شرط اول رو خسته بودید نوشتید...

خیلی ممنون آقای موسوی، آره درسته اونقدر انگولک کردم که آخرش کد غلط رو اینجا paste کردم؛ اولش dsTotal != null بود، ولی سوال من یه چیز دیگه است :
"با وجود اینکه لاگ درون catch رو مینویسه ولی Exception هندل نمیشه و برنامه به دار فانی مراجعت میکنه! چرا نباید Exception هندل بشه اونهم از هر نوعی (catch (Exception ex "
اصلاً شما فرض کنید من عمداً این کار رو کردم؛ امکان داره که یه کدی هم تو catch هندل بشه و هم از طریق JIT و برنامه اونجوری :اشتباه: بشه (درستش چیه؟ یعنی میگن برنامه چی شد؟)؛ یا من برم جاهای دیگه رو چک کنم؟ شاید جایی Exception رو هندل نکرده باشم و اونجا این اتفاق میافته؟
در ضمن اگه محبت کنید و بفرمایید تو این تابع شما بجای من بودید جای (catch (Exception ex چی میذاشتید خیلی ممنون میشم، ببخشید سوالهام زیاد شد :خجالت:

FastCode
سه شنبه 01 تیر 1389, 09:11 صبح
Ctrl+D
E
همه‌ی چک ها رو بردار.

mehdi.mousavi
سه شنبه 01 تیر 1389, 10:29 صبح
خیلی ممنون آقای موسوی، آره درسته اونقدر انگولک کردم که آخرش کد غلط رو اینجا paste کردم؛ اولش dsTotal != null بود، ولی سوال من یه چیز دیگه است :
"با وجود اینکه لاگ درون catch رو مینویسه ولی Exception هندل نمیشه و برنامه به دار فانی مراجعت میکنه! چرا نباید Exception هندل بشه اونهم از هر نوعی (catch (Exception ex "
اصلاً شما فرض کنید من عمداً این کار رو کردم؛ امکان داره که یه کدی هم تو catch هندل بشه و هم از طریق JIT و برنامه اونجوری :اشتباه: بشه (درستش چیه؟ یعنی میگن برنامه چی شد؟)؛ یا من برم جاهای دیگه رو چک کنم؟ شاید جایی Exception رو هندل نکرده باشم و اونجا این اتفاق میافته؟
در ضمن اگه محبت کنید و بفرمایید تو این تابع شما بجای من بودید جای (catch (Exception ex چی میذاشتید خیلی ممنون میشم، ببخشید سوالهام زیاد شد :خجالت:

سلام.
سوال خوبی پرسیدید. اگر من بودم چیکار میکردم. اول از همه من از Typed DataSet ها استفاده میکردم و قوانین مورد نظرم رو با Schema ای که می ساختم به دیتاست Enforce میکردم. اینطوری دیگه مجبور نبودم برای هر دسترسی جزیی، یکبار چک کنم ببینم null هستش یا نه، اگر نبود، تعدادش بزرگتر از صفر هست یا نه و ... ضمن اینکه کدی که می نوشتم دیگه Type Safe بودش و اگر به هر دلیلی فردا روزی، نام ستونم رو از MAIN_TITLE به چیز دیگه ای تغییر میدادم، برنامه کامپایل نمیشد تا کلیه Reference های نادرستم رو تصحیح کنم. اما الان شما اگر چنین تغییری در DataSet اتون رخ بده، باید کلیه توابعی که از اون DataSet خاص استفاده کردن رو چشمی دنبال کنید (یا دنبال string مربوطه بگردید) و دستی اونها رو تغییر بدید. (البته همه اینها هنگامی رخ میداد که من میخواستم Web Service ام DataSet بر گردونه، و الا در حالت اولیه، من خیلی به ندرت از DataSet ها استفاده میکنم و ترجیح میدم از Custom Object های خودم برای این منظور استفاده کنم).

به نظرم در مورد Exception دارید اشتباه میکنید، چه اشتباهی نمیدونم، اما این غیر ممکنه که Log بشه (یعنی بیفته تو Catch Block) اما اونجا Break نخوره. (منظورتون همین بود؟)

در نهایت، if مورد نظر شما قاعدتا باید این باشه:

if (dsTotal != null && dsTotal.Tables != null && dsTotal.Tables.Count > 0))

ضمنا، من Call Stack رو نگاه کردم، به نظر میرسه شما در timer tick خاصی دارید این تابع رو Call میکنید. خود همین مساله نیز میتونه شرایطی رو پیش بیاره که کد شما انتظارش رو نداره. من بدون دیدن کد نمیتونم نظر دقیقی بدم، اما از راه دور، میتونم این توصیه رو کنم که کل کدهای درون GenTotalNational رو Comment کنید. بعد تکه تکه کدها رو از حالت Comment خارج کنید و هر بار برنامه رو اجرا و آزمایش کنید تا به خطای مورد نظر پی ببرید.

موفق باشید.

Saeed_m_Farid
سه شنبه 01 تیر 1389, 15:52 عصر
البته همه اینها هنگامی رخ میداد که من میخواستم Web Service ام DataSet بر گردونه، و الا در حالت اولیه، من خیلی به ندرت از DataSet ها استفاده میکنم و ترجیح میدم از Custom Object های خودم برای این منظور استفاده کنم.
به نظرم در مورد Exception دارید اشتباه میکنید، چه اشتباهی نمیدونم
اما این غیر ممکنه که Log بشه (یعنی بیفته تو Catch Block) اما اونجا Break نخوره.
منظورتون همین بود؟
در نهایت، if مورد نظر شما قاعدتا باید این باشه:

if (dsTotal != null && dsTotal.Tables != null && dsTotal.Tables.Count > 0))

ممنون از پیگیری شما :

2 و 3 ) دقیقاً درست فرمودید، همون کار رو کردم و دیدم وقتی در یک تابع دیگه به نام GenerateReport که تو تایمر اجرا میشه ;()dsTotal.Clear میکنم، Object Reference میده، چرا باید اینطوری باشه؟ dsTotal یک DataSet هست که تو Designer گذاشتم، یعنی اینها یکبار مصرف هستند؟ ببخشید من زیاد C#‎‎‎‎‎‎ کار نیستم و این مشکلات واسم پیش میاد، Reset گذاشتم بدتر هم شد! اصلاً لازم نیست احتمالاً همچین کاری نه؟ یعنی وقتی از طریق وب سرور انتصاب داده میشه خودش تغییر میکنه و احتمال اشتباه نیست؟ می بخشید ولی مجبورم اون قسمت رو هم بذارم تا ببینید بازم مشکلی دارم یا نه؟ میدونم یکم زیادی بودار هست ولی مخم بیشتر از این خوشبو کار نکرد! یکم اگه ممکنه ادکلن بزنید به کدم ممنون میشم :

private void GenerateReport(DataRow dr)
{
string trce = "Start";
try
{
DataRow infoRow = dsTitleInfo.Tables["Info"].NewRow();
trce = "ClearTitleInfo";
dsTitleInfo.Clear();
trce = "ClearDetail";
dsDetail.Clear();
trce = "ClearTotal";
dsTotal.Clear();
string time = GetTime(true);
trce = "CheckReport";
switch (dr[2].ToString()) //Report Type
{

case "1"://Detailed National
AddLog("[National Detailed] request for Tel Number: " + dr["TEL_NO"].ToString(), LogType.Information);
GenDetailedNational(dr, infoRow, time);
break;

case "2"://Detailed International
AddLog("[International Detailed] request for Tel Number: " + dr["TEL_NO"].ToString(), LogType.Information);
GenDetailedInternational(dr, infoRow, time);
break;

case "3"://Total National
AddLog("[National Total] request for Tel Number: " + dr["TEL_NO"].ToString(), LogType.Information);
GenTotalNational(dr, infoRow, time);
break;

case "4"://Total International
AddLog("[International Total] request for Tel Number: " + dr["TEL_NO"].ToString(), LogType.Information);
GenTotalInternational(dr, infoRow, time);
break;

case "5"://Bill
AddLog("[Bill] request for Tel Number: " + dr["TEL_NO"].ToString(), LogType.Information);
GenBillReport(dr, infoRow, time);
break;

case "6"://Payment Receipt
AddLog("[Payment Receipt] request for Tel Number: " + dr["TEL_NO"].ToString(), LogType.Information);
GenPaymentReceipt(dr, infoRow, time);
break;

case "7"://Detailed National & International
AddLog("[All Detailed] request for Tel Number: " + dr["TEL_NO"].ToString(), LogType.Information);
GenAllDetailed(dr, infoRow, time);
break;

case "8"://Total National & International
AddLog("[All Total] request for Tel Number: " + dr["TEL_NO"].ToString(), LogType.Information);
GenAllTotal(dr, infoRow, time);
break;

default:
GenUnknownState(dr);
break;
}
AddLog("End GenerateReport: " + dr["TEL_NO"].ToString(), LogType.Information);
}
catch (Exception exp)
{
AddLog("GenerateReport[" + trce + "] Error: " + exp.Message, LogType.Error);
}
}

توضیح :


()dr[2].ToString بخاطر اینه که ممکنه وب سرویس Exception برگردونه.
AddLog وقتی LogType اش Information هست، همیشه لاگ رو تو صفحه نمی نویسه و بستگی به فلگ ای داره که میگه شرایط وخیم هست مثل الان یا نه! الان مثلاً اول ماه هست و وب سرویس null برمی گردونه و پته ها و باگ های برنامه من رو میشه!

****************************
1) خودتون سر شوخی رو باز کردید :لبخند: : من مدت هاست دنبال یه راه حل مناسب برای اینکار میگردم، این Custom Object های خودتون هم یه جورایی باید XML Based باشند و طوری که تمام برنامه هایی که قراره از وب سرویس من سرویس می گیرن ازش بتونن استفاده کنند. مثلاً جاوا کارها، دلفی کاران، انجمن PHP کارها و ... قادر باشند با WSDL من کار کنند؛ خوب الان من DataSet دات نت رو هرجا بهشون میدم میگم این Schema و این هم Body دیتاهای شماست و تو هر زبانی یه راه حلی براش هست که می تونن ازش استفاده کنند (بعنوان نمونه تو دلفی از XML Mapper استفاده میشه)؛ ولی بنظر شما راه حلی برای ایجاد یک Custom Object استاندارد واسه اینکار هست؟ طوری که واسه حداقل صدهزار رکورد به بالا هم جوابگو باشه و ما رو از شر دردسرهای Dataset دات نت خلاص کنه؟ یه ابزاری واسه اینکار هست یا باید بشینم دستی XML Schema درست کنم و ... ؟ یا بنظرتون بهتره برم سراغ WCF و مشتقات اون که هیچ پیش زمینه ای در موردش ندارم! کلاً یکم در این زمینه دست امثال بنده رو بگیرید، منون میشم یا حداقل سرنخی برای ادامه کار درست و صحیح ...

4 ) آره منظورم همین بود ولی اگه روی سوال شما به این سوال بنده بود : "درستش چیه؟ یعنی میگن برنامه چی شد؟" دقیقاً منظورم اینه که وقتی یک برنامه اونطوری "Break نخوره" و از سرویس دهی متوقف بشه، میگن برنامه چی شد؟ ما می گیم : ترکید، منفجر شد، به باد فنا رفت، به لقاا... پیوست، ... Go To شد، وغیره شد و ...؛ اصطلاح فنی/علمی اش چیه؟

5) با این شرط مشکلی پیش نمیاد؟ یعنی شرایط به ترتیب اعمال میشن؟ نیاد ببینه مثلآً dsTotal مقدارش null هست ولی دوباره dsTotal.Tables چک کنه یا Count اش رو؟ اگه این درسته که خیلی خوب میشه، تو دلفی این کد میترکه (یا همون که شما درستش رو خواهید گفت میشه، ببخشید درستش رو هم یاد بگیرم اون رو میگم).

بازم ممنون ...

mehdi.mousavi
سه شنبه 01 تیر 1389, 17:38 عصر
ممنون از پیگیری شما :
خواهش میکنم قربان.


2 و 3 ) دقیقاً درست فرمودید، همون کار رو کردم و دیدم وقتی در یک تابع دیگه به نام GenerateReport که تو تایمر اجرا میشه ;()dsTotal.Clear میکنم، Object Reference میده، چرا باید اینطوری باشه؟

دلائل زیادی میتونه داشته باشه، اما خوب، بدون دیدن کد نمیشه در موردش سخن گفت. برای حل چنین مشکلاتی باید حتما کد جلوم باشه تا سناریوی استفاده از DataSet رو ببینم. اما میتونم بازهم سوالی مطرح کنم که شاید پاسخ رو بهمون بده و اون سوال اینه: "آیا متود Clear داره این Exception رو throw میکنه، یا dsTotal بگونه ای null شده؟" اگر حالت دوم باشه، میتونید با Trace کردن برنامه پاسخ رو پیدا کنید. اما اگر Clear داره این Exception رو throw میکنه، اونوقت یعنی درد سر و پیدا کردن این مشکل دشوارتره (و البته، در حال حاضر هیچ Hint ای برای حل چنین مشکلی به ذهنم نمیرسه که عنوان کنم).


dsTotal یک DataSet هست که تو Designer گذاشتم، یعنی اینها یکبار مصرف هستند؟

خیر. یکبار مصرف نیستن، اما باید به دقت ازش استفاده بشه. بخصوص هنگام Clone کردن، Merge کردن و ...


ببخشید من زیاد C#‎‎‎‎‎‎‎ کار نیستم و این مشکلات واسم پیش میاد، Reset گذاشتم بدتر هم شد! اصلاً لازم نیست احتمالاً همچین کاری نه؟ یعنی وقتی از طریق وب سرور انتصاب داده میشه خودش تغییر میکنه و احتمال اشتباه نیست؟

ببینید. قاعدتا شما متودی از سرویس رو فراخوانی میکنید و ازش در پاسخ یک DataSet میگیرید. درسته؟ در چنین حالتی، وب سرویس هستش که DataSet رو new کرده، اونو با Data پر کرده و به سمت شما ارسال میکنه. شما هر کاری مایلید سمت Client با اون DS انجام میدید، و در نهایت، اونو Dispose میکنید. کلاس DataSet از MarshalByValueComponent مشتق شده و MarshalByValueComponent نیز IDisposable رو Implement کرده. پس شما باید حتما در انتهای کار، اون Instance خاصی رو که از وب سرویس گرفته اید Dispose کنید. (یا با فراخوانی مستقیم متود Dispose یا با استفاده از Using Block).

منظورتون از "خودش تغییر کنه و احتمال اشتباه نیست" چیه؟ این وظیفه Web Service هستش که داده مورد نظر شما رو بر اساس Schema ی توافق شده، به دست سرویس گیرنده برسونه...


می بخشید ولی مجبورم اون قسمت رو هم بذارم تا ببینید بازم مشکلی دارم یا نه؟ میدونم یکم زیادی بودار هست ولی مخم بیشتر از این خوشبو کار نکرد! یکم اگه ممکنه ادکلن بزنید به کدم ممنون میشم.


توضیح :


()dr[2].ToString بخاطر اینه که ممکنه وب سرویس Exception برگردونه.
AddLog وقتی LogType اش Information هست، همیشه لاگ رو تو صفحه نمی نویسه و بستگی به فلگ ای داره که میگه شرایط وخیم هست مثل الان یا نه! الان مثلاً اول ماه هست و وب سرویس null برمی گردونه و پته ها و باگ های برنامه من رو میشه!



ظاهرا این گفتگوی فنی رو خیلی ها تاثیر گذاشته و خیلی ها از اون روز از کلمه بو دار، بد بو، خوش بو و ادکلن و ... استفاده می کنن. :قهقهه: بسیار خوب. با توجه به توضیحاتی که دادید، شما باید هزینه زیادی برای خوشبو کردن این کد بپردازید...

اول از همه، وب سرویس اجازه نداره Exception رو بصورت string به شما برگردونه! WS* ها برای همین جور مسائل بوجود اومدن. بطور نمونه، در پروتکل SOAP، وقتی متود وب سرویسی رو فراخوانی میکنید، Exception تولید شده سمت سرور، میتونه در بخش Failure پیام SOAP قرار بگیره و به دست Client برسه. بهتون اکیدا توصیه میکنم در مورد استفاده و نوشتن Web Service مطالعه بیشتری کنید. میدونم سخته، اما اگر الان نتونید رییس بزرگ رو برای این وقفه قانع کنید، بعدا خودتون به شخصه به درد سر میفتید، وقتی که سرویس شما گسترش پیدا میکنه و به مرور زمان نیازهای جدید بوجود میاد.

WSE یا Web Services Extension (نسخه 3) (http://www.microsoft.com/downloads/details.aspx?FamilyID=018a09fd-3a74-43c5-8ec1-8d789091255d&displaylang=en) به WS* ها و استانداردهایی که مایکروسافت در ASP.NET Web Services به اونها نپرداخت، میپردازه. انتقال Exception روی Wire تنها بخش کوچکی از سرویس های مربوطه رو تشکیل میده. به مرور زمان، رییس از شما میخواد که فکری به حال امنیت داده های دریافتی از وب سرویس کنید. یا فلان اطلاعات رو به شکل Inbound به سرویس ارسال یا از اون دریافت کنید و ... به تمام این نیازها در WSE 3.0 پاسخ داده شده.

این اعداد 1-8 که شما در سوئیچ قرار داده اید، بیشتر به enum شباهت دارن. شما نباید اینطور از این اعداد استفاده کنید... بعدش هر کسی بخواد از وب سرویس شما استفاده کنه، علاوه بر Schema ی مزبور، یه خروار هم Document میخواد تا بدونه 1 یعنی Detailed National و ...

من راستش از این بخش از کدهای شما هم سر در نمیارم:


trce = "ClearTitleInfo";
dsTitleInfo.Clear();
trce = "ClearDetail";
dsDetail.Clear();
trce = "ClearTotal";

چرا اینها رو دونه به دونه Clear میکنید؟ trce رو برای چی set میکنید؟ (اگر اینکارو برای Trace کردن انجام داده اید و موقته،نیازی به پاسخ دادن نبست). اما راستش متوجه Clear کردن DataSet ها نمیشم. دلیل اینکار چیه؟

(حیف که هنوز در Aspect Oriented Programming به پیشرفت چندانی نرسیده ایم، و الا این کد شما دقیقا با AOP سازگاره و بخوبی میشه اونو حل کرد (منظورم بخش Log کردنه)).


ولی بنظر شما راه حلی برای ایجاد یک Custom Object استاندارد واسه اینکار هست؟ طوری که واسه حداقل صدهزار رکورد به بالا هم جوابگو باشه و ما رو از شر دردسرهای Dataset دات نت خلاص کنه؟

ببینید. من دو سال تمام (حداقل) با DataSet ها انواع و اقسام کارها رو انجام دادم. وقتی میدونید چیکار دارید میکنید و به محدودیت میرسید، این سوال معنای دیگه ای میده و نشون میده شما دنبال Solution بهتری برای دوری از محدودیت های DataSet هستید. اما تو شرایط دیگه، وقتی این سوال مطرح میشه، من این برداشت رو میکنم که شما در مقابل DataSet جا زدید و کم آوردید، در نتیجه هرگز بهتون توصیه نمیکنم دنبال Custom Object ها برید.

احتمالا یکی از اشتباهاتتون در وب سرویس، طراحی DataSet های بزرگی هستش که حاوی چندین Table هستش که باعث میشه اطلاعات فربهی رو روی Wire رد و بدل کنید. از اونجاییکه DataSet هاتون رو در وب سرویس، Typed تعریف نکرده اید، این مساله دیگه واقعا یه کابوس محسوب میشه. تبدیل Untyped DataSet اتتون به Typed DS باعث ایجاد یک کلاس Proxy بشه که بشدت در خوانایی کد شما تاثیر داره و شما رو از ارتباط مستقیم با جداول به شکل Tables[0] و ... نجات میده.

من بحث رو به سمت استفاده از Plain Object ها نمیبرم، تا بیشتر از این آب رو گل آلود نکنم.


یه ابزاری واسه اینکار هست یا باید بشینم دستی XML Schema درست کنم و ...؟

اگر منظورتون ساخت WSDL هستش، کافیه تا در انتهای URL مربوط به فایل ASMX خودتون، ?wsdl رو اضافه کنید تا XML مورد نظر رو دریافت کنید.


یا بنظرتون بهتره برم سراغ WCF و مشتقات اون که هیچ پیش زمینه ای در موردش ندارم!

حقیقتش من هنوز فرصت نکردم خودم اینکارو کنم، در نتیجه نمیتونم توصیه ای در این مورد کنم. WSE 3.0 هر آن چیزی که من تو این زمنینه نیاز داشتم رو بهم میده.


4 ) اصطلاح فنی/علمی اش چیه؟
حقیقتا نمیدونم... Lost in the middle of nowhere شاید عبارت مناسبی باشه :چشمک:



5) با این شرط مشکلی پیش نمیاد؟ یعنی شرایط به ترتیب اعمال میشن؟ نیاد ببینه مثلآً dsTotal مقدارش null هست ولی دوباره dsTotal.Tables چک کنه یا Count اش رو؟ اگه این درسته که خیلی خوب میشه، تو دلفی این کد میترکه (یا همون که شما درستش رو خواهید گفت میشه، ببخشید درستش رو هم یاد بگیرم اون رو میگم).

منظورتون چیه؟ چون بین اون سه شرط از && استفاده کردم، اگر هر کدوم از شرطها برقرار نباشن، دیگه شرط بعدی چک نخواهد شد. درنتیجه اگر اولی null باشه، دیگه برنامه نیازی به چک کردن دو شرط دیگه نداره... و if مزبور کاملا معتبره. (یعنی تو دلفی نمیتونید چنین if ای بنویسید؟؟؟)

موفق باشید.