نظرات مطالب
ثبت استثناهای مدیریت شده توسط ELMAH
- بله؛ منتقل نمی‌شود به روال‌های رویدادگردان یاد شده. سطر یاد شده در متن فوق، صرفا خطای مدنظر را به لیست لاگ‌های قابل گزارشگیری ELMAH اضافه می‌کند.
- Elmah یک فایل DLL دارد به نام Elmah.dll. به این فایل‌های DLL در دات نت، اصطلاحا اسمبلی گفته می‌شود. افزودن ارجاعی به اسمبلی، یعنی مراجعه به منوی پروژه در VS.NET و سپس انتخاب گزینه‌ی Add reference در آنجا و انتخاب DLL یاد شده.
- در قسمت «مطالب مرتبط » ذیل هر بحث، یا حتی مقدمه‌ی بحث جاری، مثال‌های بیشتری ارائه شده‌اند.
مطالب
بهینه سازی فایلهای js و css در برنامه‌های ASP.NET با استفاده از Combres - قسمت اول
 یکی از مواردی که در توسعه وب نقش مهمی دارد، بهینه سازی فایلهای js  و css است که با فشرده سازی و کش کردن آنها می‌توان سرعت بارگذاری را تا حد چشمگیری افزایش داد. برای درک بهتر، به مثال زیر توجه کنید.
یک پروژه ساده را ایجاد می‌کنیم و فایل‌های CSS و js  را مانند شکل زیر، به آن اضافه می‌کنیم:


طبق تصویر فایل‌ها را به صفحه‌ای که ساختیم اضافه می‌کنیم:


پروژه را اجرا کرده و توسط افزونه‌ی firebug درخواست‌هایی را که از سرور شده‌است، بررسی می‌کنیم. مشاهده خواهید کرد که به ازای هر فایل، یک درخواست به سرور ارسال شده و هیچکدام از فایل‌ها توسط  وب سرور فشرده سازی نشده‌اند و اطلاعاتی در مورد کش، به هدر آنها اضافه نشده است.

برای رفع این موارد، روشهای گوناگونی وجود دارد که امروز قصد داریم این کار را توسط  کتابخانه Combress انجام دهیم !
نصب کتابخانه Combres
شما می‌توانید با استفاده از nuget این کتابخانه را به پروژه خود اضافه کنید. 
ایجاد فایل تنظیمات
پس از نصب کتابخانه، فایلی با نام combres.xml در فولدر app_data ساخته می‌شود که تمامی فعالیت‌های کتابخانه براساس آن انجام می‌شود و ساختار آن بصورت زیر است:
<?xml version="1.0" encoding="utf-8" ?>
<combres xmlns='urn:combres'>
  <filters>
    <filter type="Combres.Filters.FixUrlsInCssFilter, Combres" />
  </filters>
  <resourceSets url="~/combres.axd"
                defaultDuration="30"
                defaultVersion="auto"
                defaultDebugEnabled="false"
                defaultIgnorePipelineWhenDebug="true"
                localChangeMonitorInterval="30"
                remoteChangeMonitorInterval="60">
    <resourceSet name="siteCss" type="css">
      <resource path="~/content/Site.css" />
      <resource path="~/content/anotherCss.css" />
      <resource path="~/scripts/yetAnotherCss.css" />
    </resourceSet>
    <resourceSet name="siteJs" type="js">
      <resource path="~/scripts/jquery-1.4.4.js" />
      <resource path="~/scripts/anotherJs.js" />
      <resource path="~/scripts/yetAnotherJs.js" />
    </resourceSet>
  </resourceSets>
</combres>
ResourceSet: با استفاده از هر ResourceSet می‌توانید آن مجموعه فایل را در یک درخواست از سرور دریافت کنید.
پارامتر url : برای تولید لینک فایل‌ها از آن استفاده میکند.
پارامتر defaultDuration : این عدد به تعداد روزهای پیشفرض برای کش کردن فایلها اشاره میکند.
پارامتر defaultVersion :در صورتی که مقدار آن auto باشد به ازای هر تغییر، آدرس جدیدی برای فایل موردنظر ایجاد میشود.
پارامتر defaultDebugEnabled :با استفاده از آن میتوانید debug mode را مشخص کنید. در صورتیکه مقدار آن auto باشد، این مقدار مستقیما از وب‌کانفیگ خوانده میشود.
مقادیر پیش فرض برای تمامی ResourceSet‌ها استفاده می‌شود و در صورت نیاز میتوان این مقادیر را برای هر ResourceSet بازنویسی کرد. فیلترها برای اعمال تغییراتی در فایل js و CSS استفاده می‌شوند که باید به این شکل معرفی شوند. در قسمت بعد با فیلترها بیشتر آشنا میشویم.
فایل cobmres.xml  را به منظور استفاده در پروژه به صورت زیر تغییر می‌دهیم.
<?xml version="1.0" encoding="utf-8" ?>

<combres xmlns='urn:combres'>
  <filters>
    <filter type="Combres.Filters.FixUrlsInCssFilter, Combres" />
  </filters>
  <resourceSets url="~/combres.axd"
                defaultDuration="30"
                defaultVersion="auto"
                defaultDebugEnabled="false"
                defaultIgnorePipelineWhenDebug="true"
                localChangeMonitorInterval="30"
                remoteChangeMonitorInterval="60">
    <resourceSet name="siteCss" type="css">
      <resource path="~/Styles/Site.css" />
    </resourceSet>
    <resourceSet name="siteJs" type="js">
      <resource path="~/Scripts/jquery-1.10.2.js" />
      <resource path="~/Scripts/jquery-1.10.2.min.js" />
    </resourceSet>
  </resourceSets>
</combres>
اگر از نیوگت برای نصب کتابخانه استفاده کرده باشید تغییرات مورد نیاز در فایل وب کانفیگ به صورت خودکار اعمال می‌شود؛ در غیر اینصورت باید قسمتهای زیر را به آن اضافه کنید.
<configuration>
  <configSections>
    <section name="combres" type="Combres.ConfigSectionSetting, Combres, Version=2.2, Culture=neutral, PublicKeyToken=1ca6b37997dd7536" />
  </configSections>
  <system.web>
    <pages>
      <namespaces>
        <add namespace="Combres" />
      </namespaces>
    </pages>
  </system.web>
  <combres definitionUrl="~/App_Data/combres.xml" />
  <appSettings>
    <add key="CombresSectionName" value="combres" />
  </appSettings>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="AjaxMin" publicKeyToken="21ef50ce11b5d80f" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.84.4790.14405" newVersion="4.84.4790.14405" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>
حال باید Route  مربوط به Combres را به RouteTable اضافه کنیم. در صورتیکه از نیوگت استفاده کرده باشید، کلاسی به فولدر app_start  اضافه شده است که با استفاده از WebActivator اینکار را در Application_Start انجام میدهد؛ در غیر اینصورت باید به صورت زیر این کار را انجام دهیم.
protected void Application_Start(object sender, EventArgs e)
        {
            RouteTable.Routes.AddCombresRoute("Combres Route");
        }
بعد از انجام مراحل قبل، نوبت به آن رسیده است که از لینکهای combres در صفحات خود استفاده کنیم. شیوه استفاده از آن در وب فرم به این صورت است:
<%@ Import Namespace="Combres" %>
<head runat="server">
    <%= WebExtensions.CombresLink("siteCss") %>
    <%= WebExtensions.CombresLink("siteJs") %>
</head>
و در MVC به صورت زیر می‌باشد:
<%= Url.CombresLink("siteCss") %>
<%= Url.CombresLink("siteJs") %>
در هر دو مورد نام ResourceSet برای تولید لینک به متد CombresLink ارسال میشود. پس از اجرای مجدد برنامه و با استفاده از firebug خواهیم دید که به ازای هر ResourceSet، یک درخواست به سرور ارسال شده است و حجم فایلها به صورت چشمگیری کاهش یافته است و اطلاعات مربوط به کش هم به آن اضافه شده است.

در ادامه می‌توانید فایل site.css قبلی و فعلی را مقایسه کنید!

در قسمت بعد با سازوکار combres و روش استفاده از فیلترها، بیشتر آشنا میشویم.

CombresProject-67bd3b7299f24c5484edc35537fa990b.zip 

نظرات مطالب
شروع به کار با بوت استرپ 4
یک نکته‌ی تکمیلی: چگونه کلاس‌های CSS استفاده نشده را تشخیص دهیم؟

اگر قصد ارتقاء از نگارش قبلی، به جدید را داشته باشید، پس از اصلاح مداخل جدید بوت استرپ، به هم ریختگی‌هایی را در صفحات مختلف، مشاهده خواهید کرد. بنابراین اولین سؤالی که در اینجا مطرح می‌شود این است: «کدامیک از کلاس‌هایی که هم اکنون در صفحه‌ی جاری تعریف شده‌اند، دیگر در بوت استرپ جدید وجود خارجی ندارند و حذف شده‌اند؟» برای پاسخ به این سؤال، در مرورگر کروم، این مراحل را طی کنید:


در developer tools آن، برگه‌ی Sources و سپس در اینجا، قسمت Snippets را انتخاب کنید. در همین ناحیه کلیک راست کرده و گزینه‌ی new را انتخاب نمائید. سپس قطعه کد «List all undefined CSS classes» را در باکس خالی جلوی آن paste کنید و ctrl+s را بفشارید.

اکنون بر روی این مدخل جدید کلیک راست کرده و گزینه‌ی Run را انتخاب کنید:


بلافاصله در برگه‌ی Console، چنین خروجی را مشاهده خواهید کرد:


این‌ها کلاس‌هایی هستند که در صفحه‌ی جاری استفاده شده‌اند، اما از بوت استرپ 4 (جمع تمام CSSهایی که به صفحه الحاق شده‌اند) حذف شده‌اند و دیگر حضور ندارند.
مطالب
حل مشکل ویژوال استودیو در سیستمهایی که از رزولوشن (DPI) بالا و مانیتور های 4K استفاده می کنند
مدتی بود بر روی یک پروژه‌ی اتوماسیون اداری در VB.NET کار می‌کردیم. پروژه‌ی ما بر روی سیستمی با رزولوشن بالا  2160 * 3840 و مانیتور 4K قرار داشت. بعد از اینکه لایه بندی و کد‌های نرم افزار نوشته شد، نوبت به طراحی اینترفیس پروژه رسید. با مشکلی عجیب روبرو شدیم، به این صورت که در قسمت طراحی ویژوال استودیو، منوها، دکمه‌ها و ... بیش از حد معمول کوچک و به هم ریخته بود. ولی زمانیکه پروژه اجرا می‌شد، نسبت به طراحی که در سمت وِیژوال استودیو انجام داده بودیم، دکمه‌ها  بزرگتر و منوها بزرگتر و شکسته شده بودند. در حقیقت، سمت طراحی و سمت اجرای پروژه، هم خوانی نداشتند. در حالیکه ما قبلا بر روی مانیتور‌های HD و رزولوشن‌ها HD، هیچ مشکلی در طراحی و اجرای پروژه نداشتیم و هم خوانی لازم را باهم داشتند. بعد از جستجوهای متعدد، به این مطلب پی بردیم که این مشکل بیشتر برنامه نویسانی هست که از سیستم‌هایی با رزولوشن بالا و مانیتور‌های 4K استفاده می‌کنند و پاسخ مناسبی به کاربران داده نشده است. با تست راه‌های متعدد و جستجوهای پی در پی، به پاسخ قطعی رسیدیم و خواستم این مطلب  را به صورت مقاله‌ای کوتاه، با شما به اشتراک بگذارم.
مشخصات سیستمی که مشکل زیر را دارد : ویندوز 10  نسخه  Enterprise  x64 و ویژوال استودیو 2015 نسخه  Enterprise 
نمونه اسکرین شات گرفته شده که مشکل یکی از کاربران ایرانی بود و برای حل مشکل خود، اسکرین شات صفحه نمایش خود را قرار داده بود و به پاسخ قطعی نرسیده بود:

  اگر ملاحظه کنید، تصویر سمت راست، از پروژه‌ای بر روی VirtualBox با رزولوشن و DPI پایین در دیزاین ویژوال استودیو و تصویر سمت چپ از همان پروژه در دیزاین ویژوال استودیو با رزولوشن بالا و مانیتور 4K تهیه شده‌است و ملاحظه می‌کنید که پروژه به هم ریخته است و این مشکل در خیلی از برنامه‌های دیگر نیز موجود می‌باشد؛ مانند SQL SERVER و ...
 نمونه اسکرین شات گرفته شده از بعضی پنجره‌های SQL server 

حال برای رفع این مشکل چه باید کرد؟ به صورت زیر عمل می‌کنیم  

  1. به مسیر زیر در رجیستری مراجعه می‌کنیم :    
HKEY_LOCAL_MACHINE > SOFTWARE > Microsoft > Windows > CurrentVersion > SideBySide
 و رایت کلیک کرده  NEW > DWORD (32 bit) Value  انتخاب کرده و نام را PreferExternalManifest وارد کرده و Value را بر روی 1 قرار می‌دهیم .

     

2. نرم افزار Resourcehacke را دانلود کرده و آن‌را اجرا کرده و از قسمت File، بر روی Open کلیک کرده و مسیر ویژوال استودیو را به نرم افزار داده و  Ok را انتخاب می‌کنیم . 
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE


بعد از بارگذاری اطلاعات ویژوال استودیو در نرم افزار  Resourcehacke، از سمت چپ بر روی Manifest و 1:1033 کلیک کرده و dpiAware را بر روی False قرار می‌دهیم .
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
  <application xmlns="urn:schemas-microsoft-com:asm.v3"> 
    <windowsSettings> 
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">False</dpiAware> 
    </windowsSettings> 
  </application> 
</assembly>

ودر آخر سیستم را ریستارت کرده و با همان رزولوشن بالا و مانیتور 4K، ویژوال استودیو را اجرا می‌کنیم و ملاحظه میکنیم که مشکل خاصی وجود ندارد و سمت دیزاین با سمت اجرای پروژه همخوانی دارد و همسان می‌باشد.

مطالب
ساخت گزارش Code coverage مربوط به تست‌ها
اگر برای پروژه‌های خود تست نویسی انجام می‌دهید، یکی از موارد مهم، Code coverage مربوط به تست‌ها می‌باشد که نشان می‌دهد چند درصد از کدهای شما تست شده، کدام قسمت از کد، تست نشده‌است و ... .
در این مطلب نحوه‌ی استفاده از ReportGenerator را برای ایجاد گزارش مربوط به Code coverage، ارائه می‌دهیم. ReportGenerator دیتاهای تولید شده‌ی توسط coverlet, OpenCover, dotCover, Visual Studio, NCover, Cobertura, JaCoCo, Clover و ... را به یک گزارش قابل درک در فرمت‌های Html, Coberura و CSV تبدیل می‌کند. در  این مطلب چند موردتست نویسی با xUnit در Asp.Net Core  را نوشته‌ام و اکنون می‌خواهیم برای تست‌های نوشته شده، Code coverage آنها را بدست آوریم.
در کد زیر، سه تست برای متد AverageUsersAge نوشته شده است:
[Fact]
public async Task AverageUsersAge_When_Repository_Return_Null_Then_Zero_Should_Be_Returned()
{
    _userRepository.Setup(a => a.GetAllUsers())
        .ReturnsAsync((List<User>)null);
    var result = await _userService.AverageUsersAge();
    result.Should().Be(0);
}
[Fact]
public async Task AverageUsersAge_When_Repository_Return_Empty_Then_Zero_Should_Be_Returned()
{
    _userRepository.Setup(a => a.GetAllUsers())
        .ReturnsAsync(new List<User>());
    var result = await _userService.AverageUsersAge();
    result.Should().Be(0);
}
[Fact]
public async Task AverageUsersAge_When_Repository_Return_List_Of_Users_Then_Average_Of_Age_Should_Be_Retunred()
{

    _userRepository.Setup(a => a.GetAllUsers())
        .ReturnsAsync(UserMockData.People);
    var result = await _userService.AverageUsersAge();
    var expected = (UserMockData.AdultUser.Age + UserMockData.ChildUser.Age + UserMockData.InfantUser.Age) / 3;
    result.Should().Be(expected);
}
اکنون اگر بخواهیم Code coverage مربوط به این تست‌ها را مشاهده کنیم، ابتدا باید پکیج coverlet.collector  را در پروژه‌ی تست نصب کنیم. سپس باید دستور زیر را برای نصب ReportGenerator اجرا کنید؛ درون powershell:
dotnet tool install -g dotnet-reportgenerator-globaltool
اکنون میتوانیم Code coverage تست‌ها را تولید کنیم و با استفاده از ReportGenerator، آن‌را به قالب HTML تبدیل کنیم. اگر به مسیر پروژه تست خود بروید و دستور زیر را وارد کنید:
dotnet test --collect:"XPlat Code Coverage"
در پروژه‌ی تست شما، یک پوشه به نام TestResults ایجاد می‌شود و همچنین یک فایل xml با عنوان coverage.cobertura ایجاد شده‌است که نتیجه‌ی Code coverage مربوط به تست‌های شما در آن قرار دارد. 
اکنون می‌توانید با استفاده از ReportGenerator گزارش تست‌های خود را از فایل ایجاد شده، تهیه کنید. برای این کار باید دستور زیر را در مسیر پروژه تست، در powershell  وارد کنید:
reportgenerator -reports:"C:\Users\Farhad\source\repos\xUnitExample\xUnitExample.Tests\TestResults\*\coverage.cobertura.xml" -targetdir:"coveragereport" -reporttypes:Html
در پارامتر reports باید مسیر فایل xml ایجاد شده مربوط به Code coverage را قرار دهید (با هر بار اجرای دستور "dotnet test --collect:"XPlat Code Coverage یک فایل xml جدید ایجاد می‌شود و ممکن است در سیستم شما مقدار GUID ایجاد شده، تفاوت داشته باشد). 
درون پوشه TestResults یک پوشه دیگر قرار دارد که نام آن پوشه، یک GUID می‎‌باشد و به همین دلیل به جای استفاده از GUID از * استفاده کرده‌ایم.
 اگر دستور بالا را اجرا کنید باید خروجی زیر را مشاهده کنید:
2021-11-18T14:05:02: Arguments
2021-11-18T14:05:02:  -reports:C:\Users\Farhad\source\repos\xUnitExample\xUnitExample.Tests\TestResults\*\coverage.cobertura.xml
2021-11-18T14:05:02:  -targetdir:coveragereport
2021-11-18T14:05:02:  -reporttypes:Html
2021-11-18T14:05:02: Writing report file 'coveragereport\index.html'
2021-11-18T14:05:02: Report generation took 0.3 seconds
اکنون اگر در مسیری که دستور بالا را اجرا کردید بروید، یک پوشه به نام coveragereport مشاهده می‌کنید که یک فایل index.html دارد و اگر آنرا در مرورگر مشاهده کنید، Code coverage مربوط به تست‌های نوشته شده را مشاهده میکنید:


در عکس ارسال شده، تست‌های نوشته شده برای تمامی لایه‌ها به صورت جدا ایجاد شده‌است.
تست مربوط به UserService:

در عکس بالا قسمت‌هایی که تست شده‌اند، با رنگ سبز مشخص می‌شود و اگر قسمتی از کد تست نشده باشد، با رنگ قرمز مشخص می‌شود. 

برای مثال در عکس زیر مشخص شده‌است که برای فایل ApplicationConfiguration هیچ تستی نوشته نشده‌است.


اگر از CICD استفاده میکنید، می‌توانید در قسمت CI پروژه، هربار دستورات بالا را اجرا کنید و Code coverage مربوط به هر Build را به صورت جداگانه در کنار فایل‌های آپلود شده داشته باشد.
نکته: برای اجرای دستورات بالا و ساخت گزارش باید ورژن SDK نصب شده بر روی سیستم شما برابر 2.2.401 یا بیشتر باشد و ورژن Microsoft.NET.Test.Sdk برابر 16.5.0 یا بیشتر باشد.

نظرات مطالب
Blazor 5x - قسمت 18 - کار با فرم‌ها - بخش 6 - حذف اطلاعات
با تشکر؛ من Review کردم و متاسفانه مشکل رو پیدا نکردم. امکان داره که از تغییر ورژن به ورژن 6 باشه؟ چون الان تست کردم نمونه کد شما هم این مشکل رو داشت. من حدسم روی تغییر ورژن دات نت هست.
پاسخ به بازخورد‌های پروژه‌ها
AspNetIdentityRegistery
1_ راه حل مشکل اول (برای عدم دسترسی به System.Web.Http):
Install-Package Microsoft.AspNet.WebApi.Core 
2_ ورژن Microsoft.AspNet.Identity.Owin، در لایه Services (ورژن 2) و IocConfig (ورژن 3) متفاوت بود.
مطالب
پیدا کردن وابستگی‌های اشیاء در SQL Server

با بالا رفتن تعداد اشیاء تعریف شده در SQL server ، نگهداری آنها نیز مشکل‌تر می‌شود. در این حالت تغییر کوچکی در یکی از اشیاء ممکن است باعث از کار افتادن قسمتی از سیستم شود. بنابراین قبل از هر گونه تغییری در یک شیء، ابتدا باید سایر اشیاء وابسته به آن‌ را یافت و در نظر داشت ( dependencies ). برای این منظور ( impact analysis ) راه‌کارهای مختلفی در SQL server وجود دارد که در ادامه به آن‌ها خواهیم پرداخت:

الف) استفاده از امکانات management studio (اس کیوال سرور 2005 به بعد)

ساده‌ترین راه ممکن که گزارش مفصلی را نیز ارائه می‌دهد، کلیک بر روی یک شیء در management studio و انتخاب گزینه view dependencies است (شکل زیر).


در صفحه ظاهر شده می‌توان اشیایی را که شیء مورد نظر به آنها وابسته است، مشاهده نمود یا برعکس (اشیایی که عملکرد آنها وابسته به شیء انتخابی است را نیز می‌توان ملاحظه کرد).

ب) کوئری گرفتن از جداول سیستمی

امکانات قسمت قبل را با استفاده از اطلاعات جدول syscomments نیز می‌توان شبیه سازی کرد. در این جدول اطلاعات تعاریف کلیه view ، trigger ، رویه‌های ذخیره شده و غیره نگهداری می‌شود. برای مثال فرض کنید قصد داریم در جدول Orders دیتابیس Northwind ، نام فیلد OrderDate را تغییر دهیم. قبل از این‌کار بهتر است کوئری زیر را اجرا کنیم تا نام اشیاء وابسته را بدست آوریم:
SELECT NAME
FROM syscomments c
JOIN sysobjects o
ON c.id = o.id
WHERE TEXT LIKE '%OrderDate%'
AND TEXT LIKE '%Orders%'


این روش انعطاف پذیری بیشتری را نسبت به امکانات قسمت الف ، ارائه می‌دهد. برای نمونه فرض کنید می‌خواهید در یک دیتابیس کلیه اشیایی که عملیات delete را انجام می‌دهند پیدا کنید (جستجوی اشیاء حاوی یک عبارت خاص). در این مورد خواهیم داشت:

SELECT NAME
FROM syscomments c
JOIN Northwind.dbo.sysobjects o
ON c.id = o.id
WHERE TEXT LIKE '%delete%'

ج) استفاده از رویه ذخیره شده سیستمی sp_depends

جدول سیستمی دیگری در اس کیوال سرور به نام sysdepends وجود دارد که اطلاعات وابستگی‌های اشیاء در آن‌ها نگهداری می‌شود. برای دسترسی به اطلاعات این جدول ، اس کیوال سرور رویه ذخیره شده سیستمی sp_depends را ارائه داده است. برای مثال فرض کنید می‌خواهیم لیست اشیایی را که به جدول Oredres دیتابیس Northwind وابسته هستند، پیدا کنیم. در این حالت داریم:
USE Northwind
EXEC sp_depends 'Orders'


د) استفاده از schema view

با استفاده از view سیستمی INFORMATION_SCHEMA.ROUTINES ، که از ترکیب جداول syscolumns و sysobjects ایجاد شده است نیز می‌توان عملکرد sp_depends را شبیه سازی کرد اما جداول و view ها از گزارش آن حذف شده‌اند.
SELECT routine_name,
routine_type
FROM INFORMATION_SCHEMA.ROUTINES
WHERE routine_definition LIKE '%Orders%'

در جدول زیر مقایسه‌ای از امکانات و گزارش حاصل از این چهار روش با هم مقایسه شده‌اند:



ه) استفاده از برنامه SQL Dependency Tracker

نسخه آزمایشی برنامه ذکر شده را از این آدرس می‌توان دریافت کرد.


همانطور که ملاحظه می‌کنید این جستجوها بر روی اطلاعات ذخیره شده در اس کیوال سرور صورت می‌گیرند و اگر در کدهای خود در خارج از اس کیوال سرور مخلوطی از عبارات اس کیوال را داشته باشید، نگهداری آنها بسیار مشکل خواهد بود. بنابراین تا حد ممکن باید عملیات مرتبط را در دیتابیس و توسط اشیاء اس کیوال سرور مانند رویه‌های ذخیره شده، view ها و امثال آن‌ها انجام داد تا این جدا سازی به‌خوبی صورت گرفته و در زمان نیاز به انجام تغییرات، ردگیری اشیاء وابسته به‌سادگی صورت گیرد.


مطالب
MVVM و فراخوانی متدهای اشیاء View از طریق ViewModel

ما در ViewModel دسترسی مستقیمی به هیچ یک از اشیاء موجود در View نداریم (و درستش هم همین است). الان فرض کنید که می‌خواهیم از طریق ViewModel یک View را ببندیم؛ مثلا متد Close آن پنجره را فراخوانی کنیم. به عبارتی در حالت کلی می‌خواهیم یکی از متدهای تعریف شده یکی از عناصر بصری موجود در View را از طریق ViewModel فراخوانی نمائیم.
برای حل این مساله از فایل‌های همان SDK‌ مرتبط با Expression blend استفاده خواهیم کرد.

ابتدا ارجاعاتی را به اسمبلی‌های System.Windows.Interactivity.dll و Microsoft.Expression.Interactions.dll اضافه می‌کنیم.
سپس دو فضای نام مرتبط هم باید اضافه شوند:

  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"  
  xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

یک مثال عملی:
قصد داریم از طریق ViewModel ، پنجره‌ای را ببندیم. کدهای XAML این مثال را در ادامه مشاهده خواهید کرد:

<Window x:Class="WpfCallMethodActionSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:vm="clr-namespace:WpfCallMethodActionSample.ViewModels"
Name="ThisWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<vm:MainWindowViewModel x:Key="vmMainWindowViewModel" />
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource vmMainWindowViewModel}}">

<Button Content="Save &amp; Close" VerticalAlignment="Top" Margin="5">
<i:Interaction.Triggers>
<!--فراخوانی متدی در ویوو مدل-->
<i:EventTrigger EventName="Click">
<ei:CallMethodAction
TargetObject="{Binding}"
MethodName="SaveButtonClicked" />
</i:EventTrigger>

<!--فراخوانی متدی در شیء جاری از طریق ویوو مدل-->
<i:EventTrigger SourceObject="{Binding}" EventName="CloseMainWindow">
<ei:CallMethodAction
TargetObject="{Binding ElementName=ThisWindow}"
MethodName="Close"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
</Window>

همچنین ViewModel تعریف شده نیز همین چند سطر زیر است:

using System;

namespace WpfCallMethodActionSample.ViewModels
{
public class MainWindowViewModel
{
public void SaveButtonClicked()
{
close();
}

public event EventHandler CloseMainWindow;
private void close()
{
if (CloseMainWindow != null) CloseMainWindow(this, EventArgs.Empty);
}
}
}

توضیحات:
اگر به ViewModel دقت کنید خبری از DelegateCommand در آن نیست. بله، به کمک ترکیبی از EventTrigger و CallMethodAction می‌توان جایگزینی را جهت DelegateCommand معرفی شده در قسمت‌های قبل این سری مباحث MVVM ارائه داد.
EventTrigger در اینجا به این معنا است که اگر EventName ذکر شده رخ داد، آنگاه این اعمال را انجام بده. مثلا در اینجا CallMethodAction را فراخوانی کن.
CallMethodAction در اسمبلی Microsoft.Expression.Interactions.dll تعریف شده است و تنها متدی از نوع void و بدون پارامتر را می‌تواند به صورت خودکار فراخوانی کند (محدودیت مهم آن است).
اینکه این متد کجا قرار دارد، توسط TargetObject آن مشخص می‌شود. اگر TargetObject را مساوی Binding قرار دادیم، یعنی به دنبال متدی که در DataContext گرید وجود دارد بگرد. به عبارتی به صورت خودکار به SaveButtonClicked تعریف شده در ViewModel ما متصل خواهد شد و آن‌را فراخوانی می‌کند.

تا اینجا رخداد Click دکمه تعریف شده را به متد SaveButtonClicked موجود در ViewModel سیم کشی کردیم.

در مرحله بعد می‌خواهیم از طریق ViewModel ، متدی را در View فراخوانی کنیم. نکته آن هم پیشتر ذکر شد؛ TargetObject صحیحی را باید انتخاب کرد. در اینجا برای پنجره جاری نام ThisWindow تعریف شده است و از طریق تعریف:

TargetObject="{Binding ElementName=ThisWindow}"

به CallMethodAction خواهیم گفت که قرار است متد Close را در شیء ThisWindow فراخوانی کنی.
همچنین نحوه تعریف EventTrigger ما هم در اینجا برعکس شده است:

<i:EventTrigger SourceObject="{Binding}"  EventName="CloseMainWindow">

قبلا به دنبال مثلا رخداد Click یک دکمه بودیم، اکنون با توجه به SourceObject تعریف شده، در ViewModel به دنبال این رخداد که برای نمونه در اینجا CloseMainWindow نام گرفته خواهیم گشت.

بنابراین View اینبار به رخداد CloseMainWindow تعریف شده در ViewModel سیم کشی خواهد شد. اکنون اگر این رخداد در ViewModel فراخوانی شود، CallMethodAction متناظر فعال شده و متد Close پنجره را فراخوانی می‌کند.

مطالب
BloggerToCHM

این آخرین مطلب ارسالی من در سال 87 خواهد بود. پیشاپیش فرا رسیدن سال جدید را خدمت شما تبریک عرض کرده و برای همه‌ی شما آرزوی سالی خوب و با برکت را دارم.

برنامه‌ی کوچکی را تهیه کرده‌ام که با دریافت لینک یک وبلاگ بلاگری، تمامی مطالب آن‌را (اعم از پست‌ها، کامنت‌ها و تصاویر) دریافت کرده و سپس حاصل را به صورت خودکار به یک فایل chm تبدیل می‌کند.
دریافت برنامه



پیش‌نیاز اجرا:
- نصب دات نت فریم ورک 2 یا بالاتر (دات نت فریم ورک 3 و نیم، سرویس پک یک توصیه می‌شود زیرا حاوی سرویس پک 2 دات نت فریم ورک 2 نیز هست و این سرویس پک به صورت جدا ارائه نشده است)
- نصب برنامه‌ی معروف و رایگان html help work shop (که از کامپایلر آن برای تولید فایل نهایی chm استفاده می‌شود)

طرز استفاده از برنامه هم بسیار ساده‌است.
پس از نصب پیشنیازهای ذکر شده، و نصب برنامه، یک shortcut روی دسکتاپ شما ایجاد می‌شود که به کمک آن می‌توان برنامه را اجرا نمود.
سپس از منوی فایل، گزینه‌ی new blog را انتخاب کرده و آدرس اصلی یک وبلاگ بلاگری را وارد کنید. همچنین یک نام گروه دلخواه را نیز برای آن وارد نمائید و در آخر کلیک بر روی دکمه‌ی add . لازم به ذکر است که حتما هنگام ثبت بلاگ‌ها نیاز به اتصال به اینترنت می‌باشد، زیرا باید بتوان آمار اولیه‌ی وبلاگ را دریافت نمود و همچنین مطمئن شد که این وبلاگ بلاگری است و فرمت مربوطه را دارد.
پس از ثبت یک بلاگ، یا می‌توان بر روی آن کلیک راست کرد و گزینه‌ی start processing را انتخاب نمود و یا وبلاگ‌های مورد نظر را تیک زد و سپس از منوی process گزینه‌ی start را انتخاب کرد تا عملیات دریافت اطلاعات وبلاگ‌های مورد نظر به ترتیب انجام شود.
در برنامه قسمت db to chm منظور حالت آفلاین است. وبلاگی را دریافت نموده‌اید اما می‌خواهید مجددا فایل chm آن‌را تهیه کنید. به این صورت اطلاعات از دیتابیس برنامه دریافت خواهد شد بجای دریافت از اینترنت.

نمونه‌ی فایل تولیدی
دریافت خلاصه‌ی وبلاگ جاری


اگر به هر دلیلی از طرح و رنگ پیش فرض فایل نهایی راضی نبودید، به پوشه‌ی template برنامه مراجعه کرده و فایل‌های htm و css مورد استفاده را ویرایش کنید و طرح و رنگ دلخواه خود را اعمال نمائید. فقط دقت داشته باشید که در این فایل‌های htm ، هرجایی کلمه‌ای با $ شروع شده بود یعنی قسمتی است که محتوای نهایی در آن‌جا قرار می‌گیرد و این نام نباید تغییری کند (محل آن مهم نیست، نام آن مهم است). همچنین بدیهی است که نام سلکتورهای فایل css مورد استفاده هم نباید تغییر کند.

موفق باشید.


پ.ن.
اگر در حین اجرای برنامه به مشکلی برخوردید، تمامی خطاهای برنامه در فایلی به نام errors.log ثبت می شود (در کنار فایل اجرایی برنامه تولید خواهد شد). لطفا این فایل را جایی آپلود کنید و سپس لینک دهید تا بتوان مشکل را دقیق‌تر بررسی نمود.