اشتراک‌ها
ارسال ایمیل در برنامه های ASP.NET MVC

This article takes a comprehensive look at the business of generating and sending email from an ASP.NET MVC application. It covers the most common use cases as well as some advanced scenarios. It also explores some of the more common errors that arise from attempting to generate and send email programmatically from an ASP.NET MVC site. 

ارسال ایمیل در برنامه های ASP.NET MVC
نظرات مطالب
Build Events
با سلام 
در پاسخ به مشکل شما چند نکته باید اشاره بشه. 

نکته اول: ماکروی TargetFileName فقط اسم فایل خروجی پروژه رو برمی‌گردونه، درصورتیکه برای کارکردن دستور فوق مسیر کامل فایل نیازه. چون برنامه editbin.exe درون مسیر خروجی پروژه شما اجرا نمی‌شه. شما می‌تونین از ماکروی TargetPath استفاده کنید که مسیر کامل فایل خروجی پروژه رو برمی‌گردونه.

نکته دوم: کد خطای 9009 مربوط به پیدا نکردن فایل هست. البته فایلی که در اینجا پیدا نشده خروجی پروژه شما نیست بلکه خود ابزار editbin هستش. مسیر درستش در سیستم 32 بیتی برای ویژوال استودیو 2010 اینه:
C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\editbin.exe
اما چون این مسیرها معمولا حاوی فاصله هستند نیاز به استفاده از دابل کوتیشن در ابتدا و انتها وجود داره. بنابراین دستور کامل باید به صورت زیر باشه:
"C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\editbin.exe" /STACK:1000000 "$(TargetPath)"
اما با اجرای دستور فوق باز هم خطایی صادر میشه که کمی خطرناکتر از قبلیه. و اما دلیلش:

نکته سوم: متن زیر از msdn گرفته شده:
You can start this tool only from the Visual Studio command prompt. You cannot start it from a system command prompt or from Windows Explorer.
البته منظور دقیق‌تر این جمله اینه که ابزار editbin نیاز به یکسری تنظیمات و متغیرهای ازپیش تعیین شده داره که در Visual Studio command prompt انجام شده. اما نگران نباشید برای تنظیم این تنظیمات و تبدیل خط فرمان Build Events در ویژوال استودیو به یک Visual Studio command prompt کافیه که خط زیر رو در ابتدای مجموعه دستورات build events خودتون قرار بدین:
call "$(DevEnvDir)..\Tools\vsvars32.bat"
این بچ فایل حاوی دستوراتی نسبتا مفصل برای تنظیم تنظیمات موردنیاز است. درواقع با اجرای این بچ فایل هر خط فرمانی تقریبا تبدیل به Visual Studio command prompt خواهد شد. با توجه به ماکروی (DevEnvDir)$ مسیر کامل این فایل در سیستم 32 بیتی و برای ویژوال استودیوی 2010 به صورت زیر است:
C:\Program Files\Microsoft Visual Studio 10.0\Common7\Tools\vsvars32.bat
بنابراین برای کار کردن دستور موردنظر شما کافیه که این دو دستور به صورت زیر در Post Build Event اضافه بشه:
call "$(DevEnvDir)..\Tools\vsvars32.bat"
"C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\editbin.exe" /STACK:1000000 "$(TargetPath)"

نکته چهارم: با توجه به اشاره‌ای که در نکته قبلی شد ("با اجرای این فایل هر خط فرمانی تقریبا تبدیل به Visual Studio command prompt خواهد شد.") بنابراین دستور فوق را میتوان به صورت زیر خلاصه کرد:
call "$(DevEnvDir)..\Tools\vsvars32.bat"
"editbin.exe" /STACK:1000000 "$(TargetPath)"

موفق باشید.
اشتراک‌ها
AutoMapper 11.0.0 منتشر شد

starting with this version, AutoMapper drops support for full .NET framework, as this release targets only netstandard2.1. 

AutoMapper 11.0.0 منتشر شد
مطالب
C# 8.0 - Ranges & Indices
نوع Span به همراه NET Core 2.1. ارائه شد. یکی از مهم‌ترین مزایای آن امکان دسترسی به قسمتی از حافظه (توسط متد Split آن)، بدون ایجاد سربار کپی یا تخصیص مجدد حافظه‌ای برای دسترسی به آن است. قدم بعدی، بسط این قابلیت به امکانات ذاتی زبان #C است؛ تحت عنوان ویژگی Ranges که امکان دسترسی مستقیم به بازه‌ای/قسمتی از آرایه‌ها، رشته‌ها و یا Spanها را میسر می‌کند.


معرفی عملگر Hat

برای دسترسی به آخرین عضو یک آرایه عموما از روش زیر استفاده می‌شود:
var integerArray = new int[3];
var lastItem = integerArray[integerArray.Length - 1];
یعنی از آخر شروع به شمارش کرده و 1 واحد از آن کم می‌کنیم (این عدد 1 را به‌خاطر داشته باشید) و یا اگر بخواهیم از LINQ استفاده کنیم می‌توان از متد Last آن استفاده کرد:
var integerList = integerArray.ToList();
integerList.Last();
همچنین اگر بخواهیم دومین عنصر از آخر آن‌را دریافت کنیم:
var secondToLast = integerArray[integerArray.Length - 2];
نیز مجددا از آخر شروع به شمارش کرده و 2 واحد، از آن کم می‌کنیم (این عدد 2 را نیز به‌خاطر داشته باشید).

این شمردن‌های از آخر در C# 8.0 توسط ارائه‌ی عملگر hat یا همان ^ که پیشتر کار xor را انجام می‌داد (و البته هنوز هم در جای خودش همین مفهوم را دارد)، میسر شده‌است:
var lastItem = integerArray[^1];
این قطعه کد یعنی به دنبال ایندکس X، از آخر آرایه هستیم.

نکته‌ی مهم: کسانیکه شروع به آموزش برنامه نویسی می‌کنند، مدتی طول می‌کشد تا عادت کنند که اولین ایندکس یک آرایه از صفر شروع می‌شود. در اینجا باید درنظر داشت که با بکارگیری «عملگر کلاه»، آخرین ایندکس یک آرایه از «یک» شروع می‌شود و نه از صفر. برای نمونه در مثال زیر به خوبی تفاوت بین ایندکس از ابتدا و ایندکس از انتها را می‌توانید مشاهده کنید:
var words = new string[]
{
                // index from start    index from end
    "The",      // 0                   ^9
    "quick",    // 1                   ^8
    "brown",    // 2                   ^7
    "fox",      // 3                   ^6
    "jumped",   // 4                   ^5
    "over",     // 5                   ^4
    "the",      // 6                   ^3
    "lazy",     // 7                   ^2
    "dog"       // 8                   ^1
};              // 9 (or words.Length) ^0
آرایه‌ی فوق، 9 عضو دارد. در این حالت اولین عنصر آن با ایندکس صفر قابل دسترسی است. در همین حالت همین ایندکس را اگر از آخر محاسبه کنیم، 9 خواهد بود و همینطور برای مابقی.
در حالت کلی ایندکس n^ معادل sequence.Length - n است. بنابراین sequence[^0] به معنای sequence[sequence.Length] است و هر دو مورد یک index out of range exception را صادر می‌کنند.

IDE نیز با فعال سازی C# 8.0، زمانیکه به قطعه کد زیر می‌رسد، زیر words.Length - 1 خط کشیده و پیشنهاد می‌دهد که بهتر است از 1^ استفاده کنید:
Console.WriteLine($"The last word is {words[words.Length - 1]}");



معرفی نوع جدید Index

در C# 8.0 زمانیکه می‌نویسم 1^، در حقیقت قطعه کد زیر را ایجاد کرده‌ایم:
var index = new Index(value: 1, fromEnd: true);
Index indexStruct = ^1;
var indexShortHand = ^1;
Index یک struct و نوع جدید در C# 8.0 می‌باشد که در فضای نام System قرار گرفته‌است. سه سطر فوق دقیقا به یک معنا هستند و هر کدام خلاصه شده و ساده شده‌ی سطر قبلی است.
در سطر اول، پارامتر fromEnd نیز قابل تعریف است. این fromEnd با مقدار true، همان عملگر ^ در اینجا است و عدم ذکر این عملگر به معنای false بودن آن است:
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine(a[a.Length – 2]); // will write 8 on console.
Console.WriteLine(a[^2]); // will write 8 on console.

Index i5 = 5;
Console.WriteLine(a[i5]);        //will write 5 on console.

Index i2fromEnd = ^2;
Console.WriteLine(a[i2fromEnd]); // will write 8 on console.
در این مثال دو نمونه کاربرد fromEnd با مقدار false و سپس true را ملاحظه می‌کنید. در حالتیکه Index i5 = 5 تعریف شده‌است، دسترسی به عناصر آرایه همانند قبل از ایندکس صفر و از آغاز شروع می‌شود و نه از ایندکس یک.


روش دسترسی به بازه‌ای از اعضای یک آرایه تا پیش از C# 8.0

فرض کنید آرایه‌ای از اعداد بین 1 تا 10 را به صورت زیر ایجاد کرده‌اید:
var numbers = Enumerable.Range(1, 10).ToArray();
اکنون اگر بخواهیم به بازه‌ی مشخصی درون این آرایه دسترسی پیدا کنیم، می‌توان حداقل به یکی از دو روش زیر عمل کرد:
var (start, end) = (1, 7); 
var length = end - start; 

// Using LINQ 
var subset1 = numbers.Skip(start).Take(length);
 
// Or using Array.Copy 
var subset2 = new int[length];
Array.Copy(numbers, start, subset2, 0, length);
یا می‌توان برای مثال توسط LINQ، از متدهای Skip و Take آن برای جدا کردن بازه‌ای از آرایه‌ی numbers استفاده کرد و یا حتی می‌توان از روش کپی کردن آرایه‌ها به آرایه‌ای جدید نیز کمک گرفت که در هر دو حالت، مراحلی که باید طی شوند قابل توجه است. با ارائه‌ی C# 8.0، این نوع دسترسی‌ها جزئی از قابلیت‌های زبان شده‌اند.


روش دسترسی به بازه‌ای از اعضای یک آرایه در C# 8.0

در C# 8.0 برای دسترسی به بازه‌ای از عناصر یک آرایه می‌توان از range expression که به صورت x..y نوشته می‌شود، استفاده کرد. در ادامه، مثال‌هایی را از کاربردهای عبارت .. ملاحظه می‌کنید:
var myArray = new string[] { "Item1", "Item2", "Item3", "Item4", "Item5" };
3..1 به معنای انتخاب بازه‌ای از المان 2 تا المان 3 است. در اینجا به واژه‌ی «المان» دقت کنید که معادل ایندکس آن در آرایه نیست. یعنی عدد ابتدای یک بازه دقیقا به ایندکس آن در آرایه اشاره می‌کند و عدد انتهای بازه، به ایندکس ماقبل آن (از این جهت که بتوان توسط 0^، انتهای بازه را مشخص کرد؛ بدون دریافت استثنای index out of range). به همین جهت به ابتدای بازه می‌گویند inclusive و به انتهای آن exclusive:
 var fromIndexToX = myArray[1..3]; // = [Item2, Item3]
1^..1 به معنای انتخاب بازه‌ای از المان 2، تا المان یکی مانده به آخر است:
var fromIndexToXFromTheEnd = myArray[1..^1]; // = [ "Item2", "Item3", "Item4" ]

ذکر انتهای بازه اجباری نیست و اگر ذکر نشود به معنای 0^ است. برای مثال ..1 به معنای انتخاب بازه‌ای از المان 2، تا آخرین المان است:
var fromAnIndexToTheEnd = myArray[1..]; // = [ "Item2", "Item3", "Item4", "Item5" ]

ذکر ابتدای بازه نیز اجباری نیست و اگر ذکر نشود به معنای عدد صفر است. برای مثال 3.. به معنای انتخاب بازه‌ای از اولین المان، تا سومین المان است:
 var fromTheStartToAnIndex = myArray[..3]; // = [ "Item1", "Item2", "Item3" ]

اگر ابتدا و انتهای بازه ذکر نشوند، کل بازه و تمام عناصر آن بازگشت داده می‌شوند:
 var entireRange = myArray[..]; // = [ "Item1", "Item2", "Item3", "Item4", "Item5" ]
همچنین [0^..0] نیز به معنای کل بازه است.

مثالی دیگر: بازنویسی یک حلقه‌ی for با foreach
حلقه‌ی for زیر را
var myArray = new string[] { "Item1", "Item2", "Item3", "Item4", "Item5" };
for (int i = 1; i <= 3; i++)
{
  Console.WriteLine(myArray[i]);
}
توسط range expression می‌توان به صورت زیر بازنویسی کرد:
foreach (var item in myArray[1..4]) // = [ "Item2", "Item3", "Item4" ]
{
  Console.WriteLine(item);
}
بنابراین همانطور که مشاهده می‌کنید، ذکر بازه‌ی 4..1 به صورت حلقه‌ی for (int i = 1; i < 4; i++) تفسیر می‌شود و نه حلقه‌ی for (int i = 1; i <= 4; i++)
یعنی ابتدای آن inclusive است و انتهای آن exclusive


چند مثال کاربردی و متداول از بازه‌ها

using System;
using System.Linq;

namespace ConsoleApp
{
    class Program
    {
        private static readonly int[] _numbers = Enumerable.Range(1, 10).ToArray();

        static void Main()
        {
            var skip2CharactersAndTake2Characters = _numbers[2..4]; // صرفنظر کردن از دو عنصر اول و سپس انتخاب دو عنصر
            var skipFirstAndLastCharacter = _numbers[1..^1]; // صرفنظر کردن از دو عنصر اول و آخر
            var last3Characters = _numbers[^3..]; // انتخاب بازه‌ای شامل سه عنصر آخر
            var first4Characters = _numbers[0..4]; // دریافت بازه‌ای از 4 عنصر اول
            var rangeStartFrom2 = _numbers[2..]; // دریافت بازه‌ای شروع شده از المان دوم تا آخر
            var skipLast3Characters = _numbers[..^3]; // صرفنظر کردن از سه المان آخر
            var rangeAll = _numbers[..]; // انتخاب کل بازه
        }
    }
}


معرفی نوع جدید Range

در C# 8.0 زمانیکه می‌نویسم 4..1، در حقیقت قطعه کد زیر را ایجاد کرده‌ایم:
var range = new Range(1, 4);
Range rangeStruct = 1..4;
var rangeShortHand = 1..4;
Range نیز یک struct و نوع جدید در C# 8.0 می‌باشد که در فضای نام System قرار گرفته‌است. سه سطر فوق دقیقا به یک معنا هستند و هر کدام خلاصه شده و ساده شده‌ی سطر قبلی است.

یک مثال: استفاده از نوع جدید Range به عنوان پارامتر یک متد
using System;
using System.Linq;

namespace ConsoleApp
{
    class Program
    {
        private static readonly int[] _numbers = Enumerable.Range(1, 10).ToArray();
        static void Print(Range range) => Console.WriteLine($"{range} => {string.Join(", ", _numbers[range])}");

        static void Main()
        {
            Print(1..3); // 1..3 => 2, 3
            Print(..3);      // 0..3 => 1, 2, 3
            Print(3..);      // 3..^0 => 4, 5, 6, 7, 8, 9, 10
            Print(1..^1);    // 1..^1 => 2, 3, 4, 5, 6, 7, 8, 9
            Print(^2..^1);   // ^2..^1 => 9
        }
    }
}
همانطور که ملاحظه می‌کنید، Range را می‌توان به عنوان پارامتر متدها نیز استفاده و بر روی آرایه‌ها اعمال کرد؛ اما با <List<T سازگار نیست.

مثالی دیگر: استفاده از Range به عنوان جایگزینی برای متد String.Substring

از Range می‌توان برای کار بر روی رشته‌ها و انتخاب قسمتی از آن‌ها نیز استفاده کرد:
Console.WriteLine("123456789"[1..4]); // Would output 234
چند مثال دیگر:
var helloWorldStr = "Hello, World!";

var hello = helloWorldStr[..5];
Console.WriteLine(hello); // Output: Hello

var world = helloWorldStr[7..];
Console.WriteLine(world); // Output: World!

var world2 = helloWorldStr[^6..]; // Take the last 6 characters
Console.WriteLine(world); // Output: World!


سؤال: زمانیکه بازه‌ای از یک آرایه را انتخاب می‌کنیم، آیا یک آرایه‌ی جدید ایجاد می‌شود، یا هنوز به همان آرایه‌ی قبلی اشاره می‌کند؟

پاسخ: یک آرایه‌ی جدید ایجاد می‌شود؛ اما می‌توان با فراخوانی متد ()array.AsSpan پیش از انتخاب یک بازه، بازه‌ای را تولید کرد که دقیقا به همان آرایه‌ی اصلی اشاره می‌کند و یک کپی جدید نیست:
var arr = (new[] { 1, 4, 8, 11, 19, 31 }).AsSpan();
var range = arr[2..5];

ref int elt1 = ref range[1];
elt1 = -1;

int copiedElement = range[2];
copiedElement = -2;

Console.WriteLine($"range[1]: {range[1]}, range[2]: {range[2]}"); // output: range[1]: -1, range[2]: 19
Console.WriteLine($"arr[3]: {arr[3]}, arr[4]: {arr[4]}"); // output: arr[3]: -1, arr[4]: 19
در این مثال، آرایه‌ی اصلی را ابتدا تبدیل به یک Span کرده‌ایم و سپس بازه‌ای از روی آن انتخاب شده‌است. به همین جهت است که زمانیکه از ref locals برای تغییر عضوی از این بازه استفاده می‌شود، این تغییر بر روی آرایه‌ی اصلی نیز تاثیر می‌گذارد.
نظرات مطالب
C# 6 - String Interpolation
معرفی «Constant interpolated strings» در C# 10.0

C# 10.0 به همراه تغییر و بهبود جزئی در مورد interpolated strings است. تا پیش از آن، امکان تعریف یک interpolated strings به صورت const وجود نداشت؛ اما اکنون این محدودیت برطرف شده‌است و قطعه کد زیر مجاز است:
const string constStrFirst = "FirstStr";
const string summaryConstStr = $"SecondStr {constStrFirst}";

محدودیت: این نکته تنها در مورد const string‌ها صادق است. برای مثال اگر از const char استفاده شود:
const char a = 'a';
const string constStrFirst = "FirstStr";
const string summaryConstStr = $"SecondStr {constStrFirst} {a}";
با خطای زیر مواجه می‌شویم:
// Error CS0133
// The expression being assigned to
// 'summaryConstStr' must be constant
نظرات مطالب
آشنایی با Window Function ها در SQL Server بخش دوم
سلام
من یه کوئری توسط Sum() Over() .. نوشتم که تو در تو هست که ترتیب جمع دستور بیرونی برام مهمه .
;WITH cteBed ([Counter], id_doc , [Year] ,id_Total , date_duc ,Number_Temp , number_fix , sumbed , sumbes , row_no ) AS (
SELECT [Counter], d.id_doc , d.[Year] ,r.id_Total , d.date_duc ,d.Number_Temp ,d.number_fix ,  
SUM( r.Mablagh_bed) OVER(PARTITION BY d.[Year] ,r.id_Total , d.Number_Temp) AS sumbed , 
 sumbes= 0,
ROW_NUMBER() OVER (PARTITION BY d.[Year] ,r.id_Total , d.date_duc , d.Number_Temp , d.number_fix  ORDER BY  d.date_duc )AS  row_no
FROM tbl_Records r JOIN tbl_Documents d ON d.id_doc = r.id_doc  ) ,
     
 cteBes ([Counter], id_doc , [Year] ,id_Total , date_duc ,Number_Temp , number_fix , sumbed , sumbes  , row_no) AS (
SELECT   [Counter], d.id_doc , d.[Year] ,r.id_Total , d.date_duc ,d.Number_Temp ,d.number_fix , sumbed = 0 , 
SUM( r.Mablagh_bes ) OVER(PARTITION BY d.[Year] ,r.id_Total , d.Number_Temp ) AS sumbes,
ROW_NUMBER() OVER (PARTITION BY d.[Year] ,r.id_Total ,  d.date_duc ,d.Number_Temp , d.number_fix ORDER BY  d.date_duc )AS row_no 
FROM tbl_Records r JOIN tbl_Documents d ON d.id_doc = r.id_doc ) 

SELECT [Counter], id_doc , [Year] ,id_Total , date_duc ,Number_Temp , number_fix , sumbed , sumbes , amountBed ,amountBes 
,SUM(amountBed)OVER(  ORDER BY [Year] ,id_Total , date_duc , number_Temp, number_Fix ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS bed
,SUM(amountBes)OVER(  ORDER BY [Year] ,id_Total , date_duc , number_Temp, number_Fix ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS bes
FROM (
SELECT [Counter], id_doc , [Year] ,id_Total , date_duc ,Number_Temp , number_fix , sumbed , sumbes ,  
amountBed = CASE WHEN id_Total  LIKE '1%' OR  Id_Total LIKE '2%' OR  Id_Total LIKE '7%' OR  Id_Total LIKE '8%' THEN (tt.sumbed-tt.sumbes) ELSE 0 END ,
amountBes=CASE WHEN Id_Total LIKE '3%' OR Id_Total LIKE '4%' OR Id_Total LIKE '5%' OR Id_Total LIKE '6%' OR Id_Total LIKE '9%' THEN (tt.sumbes-tt.sumbed)ELSE 0 END ,
ROW_NUMBER() OVER (PARTITION BY [Year] ,id_Total , date_duc , Number_Temp , number_fix  ORDER BY  date_duc )AS  row_no
FROM (
SELECT * FROM cteBed cb WHERE cb.row_no = 1
UNION ALL
SELECT * FROM cteBes cb WHERE cb.row_no = 1
) AS tt ([Counter], id_doc , [Year] ,id_Total , date_duc ,Number_Temp , number_fix , sumbed , sumbes,row_no ) WHERE not(sumbed = 0 AND sumbes = 0)
) AS rr

اگه تو یه دستور Select از Row_Number استفاده کرده باشم ، اول خروجی رو بدست میاره بعد خروجی رو بر حسب نوع مرتب سازی مربوط به Row_Number مرتب میکنه ؟ و دیگه اینکه خروجی دستور اول که شامل Row_Number هست بعد از مرتب شدن به همون صورت به دست دستور دوم (یا همون Select بیرونی) میرسه یا باز باید روی اون نیز مرتب سازی انجام بدم ؟ اصلا جای ستونی که مربوط به Row_Number هست اول یا آخر فرق میکنه ؟
اینارو به این خاطر پرسیدم ، چون هر بار داده هام جواب متفاوتی میداد و نتونستم تشخیص بدم . ممنون
اشتراک‌ها
کتاب رایگان Scala Succinctly

Learning a new programming language can be a daunting task, but Scala Succinctly makes it a simple matter. Author Chris Rose guides readers through the basics of Scala, from installation to syntax shorthand, so that they can get up and running quickly.

Table of Contents
  1. Introduction
  2. Variables and Values
  3. Expressions and Functions
  4. Control Structures
  5. Arrays and Lists
  6. Other Collection Types
  7. Classes and Objects
  8. Pattern Matching
  9. Closures
  10. Conclusion 
کتاب رایگان Scala Succinctly
اشتراک‌ها
مقایسه AngularJS و React

React can be used to achieve the same things as AngularJS, it’s much simpler to use, and it has some nice optimisations that AngularJS doesn’t. All up I greatly prefer React to AngularJS. 

مقایسه AngularJS و React