اشتراک‌ها
پیاده سازیِ سیاست دسترسی به داده ها توسط ویژگی RLS در SQL Server 2016

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

در EF6 قابلیتی به نام Interception وجود دارد که با استفاده از آن می‌توان سیاست دسترسی به داده را در لایه‌های پایینی طراحی کرد. در این روش برنامه نویس لایه هایی بالا، بدون آنکه درگیر مفاهیمی مانند Tenant و سیاست‌ها بشود، می‌تواند به راحتی کوئری هایش را تولید کند. سپس EF به طور خودکار تغییری در کوئری‌ها خواهد داد تا دسترسی‌های لازم رعایت کرده باشد. برای اینکار می‌توانید از کتابخانه EntityFramework.DynamicFilters استفاده کنید.

این روش هم علی رغم همه مزایا معایبی هم دارد. اگر بخواهیم از همین پایگاه داده استفاده کنیم ولی در محیط دات نت نباشیم و یا از EF6 استفاده نکنیم، دوباره مشکلات اغاز می‌شوند. سیاست‌ها را باید در همه جا کپی کنیم و در صورت لزوم هم، مجددا همه را تغییر دهیم.

در SQL Server 2016 قابلیتی به نام Row Level Security وجود دارد، که به ما اجازه می‌دهد سیاست‌های دسترسی با داده را در لایه پایگاه داده متمرکز کنیم. در این صورت اپلیکشن‌ها هیچگونه آگاهی ایی نسبت به سیاست‌ها نخواهند داشت و درگیر این مفاهیم در سطح کد نخواهیم بود. همچنین در صورت لزوم به تغییر سیاست ها، فقط لازم است تغییراتی را در پایگاه داده بدهیم. با این روش، به هر طریقی و از هر ابزاری که به پایگاه داده کوئری هایمان را ارسال کنیم، سیاست‌های دسترسی به داده اعمال خواهند شد و امنیت بالا و البته ریزدانه ای (granular) را خواهیم داشت.

در مثال زیر خواهیم دید که چگونه می‌توان با استفاده از EF6 از ویژگی RLS بهره برد. این مثال یکی دیگر از کاربرد‌های Interception را نیز توضیح می‌دهد.
 

پیاده سازیِ سیاست دسترسی به داده ها توسط ویژگی RLS در SQL Server 2016
اشتراک‌ها
کتابخانه ای جهت مرتب سازی کدهای html

موقعی که شما یک کد html را در یک ادیتور متنی باز می‌کنید ممکن است شکل مناسبی از کد نداشته باشد یا همه کدها در یک خط باشند و نامنظمی‌های دیگر در کد دیده شود، این پروژه کدهای شما را مرتب می‌کند و نسخه دمو آن در اینجا دیده می‌شود.

کتابخانه ای جهت مرتب سازی کدهای html
بازخوردهای دوره
تزریق وابستگی‌ها در فیلترهای ASP.NET MVC
ضمن تشکر ویژه از توجه شما، بله، از فایلهای همین مخزن استفاده کردم. در اینجا هم همان Attribute کامنت شده است. با حذف آن، مجددا همان پیام را دریافت می‌کنم. مگر مطابق با این قطعه کد:
        public LogAttribute(IContainer container)
        {
            _container = container;
        }
استفاده از این Attribute نیازمند پارامتر ورودی IContainer نیست؟
لطف می‌کنید راهنمایی بفرمایید.
نظرات مطالب
ایده‌ی ثبت خودکار سرویس‌ها، به همراه تنظیمات؛ بدون نوشتن هیچ کدی در ConfigureServices با روش Installer
با سلام. میشه لطفا  کد پایینو بیشتر توضیح بدین و بفرمایید که چه کاربردی دارد و اگر ما این قسمت را کامنت کنیم آیا مشکلی به وجود می‌آید یا خیر؟
sqlServerOptionsBuilder =>{
sqlServerOptionsBuilder.CommandTimeout((int)TimeSpan.FromMinutes(1).TotalSeconds); //Default is 30 seconds
sqlServerOptionsBuilder.EnableRetryOnFailure();
sqlServerOptionsBuilder.MigrationsAssembly(typeof(AppDbContext).Assembly.FullName);
}


نظرات مطالب
دسترسی رایگان به کل مجموعه Pluralsight به مدت 10 روز
دو روش اینجا گفته شده
روش اول: نیاز به کردیت کارت خواهید داشت اما تا 10 روز از آن برداشت نمی‌شود و رایگان است. بعد از 10 روز شما رو شارژ می‌کنند.
روش دوم: به آدرس ذکر شده در کامنت بالایی من مراجعه کنید. کد داده شده رو وارد کنید به همراه یک نام کاربری و کلمه عبور دلخواه برای ثبت نام و سپس ... بدون مشکل از مجموعه استفاده کنید. از زمان شروع، یک هفته وقت خواهید داشت.
مطالب
بررسی مقدمات کتابخانه‌ی JSON.NET
چرا JSON.NET؟
JSON.NET یک کتابخانه‌ی سورس باز کار با اشیاء JSON در دات نت است. تاریخچه‌ی آن به 8 سال قبل بر می‌گردد و توسط یک برنامه نویس نیوزیلندی به نام James Newton King تهیه شده‌است. اولین نگارش آن در سال 2006 ارائه شد؛ مقارن با زمانی که اولین استاندارد JSON نیز ارائه گردید.
این کتابخانه از آن زمان تا کنون، 6 میلیون بار دانلود شده‌است و به علت کیفیت بالای آن، این روزها پایه اصلی بسیاری از کتابخانه‌ها و فریم ورک‌های دات نتی می‌باشد؛ مانند RavenDB تا ASP.NET Web API و SignalR مایکروسافت و همچنین گوگل نیز از آن جهت تدارک کلاینت‌های کار با API خود استفاده می‌کنند.
هرچند دات نت برای نمونه در نگارش سوم آن جهت مصارف WCF کلاسی را به نام DataContractJsonSerializer ارائه کرد، اما کار کردن با آن محدود است به فرمت خاص WCF به همراه عدم انعطاف پذیری و سادگی کار با آن. به علاوه باید درنظر داشت که JSON.NET از دات نت 2 به بعد تا مونو، Win8 و ویندوز فون را نیز پشتیبانی می‌کند.

برای نصب آن نیز کافی است دستور ذیل را در کنسول پاورشل نیوگت اجرا کنید:
 PM> install-package Newtonsoft.Json

معماری JSON.NET

کتابخانه‌ی JSON.NET از سه قسمت عمده تشکیل شده‌است:
الف) JsonSerializer
ب) LINQ to JSON
ج) JSON Schema


الف) JsonSerializer
کار JsonSerializer تبدیل اشیاء دات نتی به JSON و برعکس است. مزیت مهم آن امکانات قابل توجه تنظیم عملکرد و خروجی آن می‌باشد که این تنظیمات را به شکل ویژگی‌های خواص نیز می‌توان اعمال نمود. به علاوه امکان سفارشی سازی هر کدام نیز توسط کلاسی به نام JsonConverter، پیش بینی شده‌است.
یک مثال:
 var roles = new List<string>
{
   "Admin",
   "User"
};
string json = JsonConvert.SerializeObject(roles, Formatting.Indented);
در اینجا نحوه‌ی استفاده از JSON.NET را جهت تبدیل یک شیء دات نتی، به معادل JSON آن مشاهده می‌کنید. اعمال تنظیم Formatting.Indented سبب خواهد شد تا خروجی آن دارای Indentation باشد. برای نمونه اگر در برنامه‌ی خود قصد دارید فرمت JSON تو در تویی را به نحو زیبا و خوانایی نمایش دهید یا چاپ کنید، همین تنظیم ساده کافی خواهد بود.
و یا در مثال ذیل استفاده از یک anonymous object را مشاهده می‌کنید:
 var jsonString = JsonConvert.SerializeObject(new
{
   Id =1,
   Name = "Test"
}, Formatting.Indented);
به صورت پیش فرض تنها خواص عمومی کلاس‌ها توسط JSON.NET تبدیل خواهند شد.


تنظیمات پیشرفته‌تر JSON.NET

مزیت مهم JSON.NET بر سایر کتابخانه‌ها‌ی موجود مشابه، قابلیت‌های سفارشی سازی قابل توجه آن است. در مثال ذیل نحوه‌ی معرفی JsonSerializerSettings را مشاهده می‌نمائید:
var jsonData = JsonConvert.SerializeObject(new
{
   Id = 1,
   Name = "Test",
   DateTime = DateTime.Now
}, new JsonSerializerSettings
{
   Formatting = Formatting.Indented,
   Converters =
   {
      new JavaScriptDateTimeConverter()
   }
});
در اینجا با استفاده از تنظیم JavaScriptDateTimeConverter، می‌توان خروجی DateTime استانداردی را به مصرف کنندگان جاوا اسکریپتی سمت کاربر ارائه داد؛ با خروجی ذیل:
 {
  "Id": 1,
  "Name": "Test",
  "DateTime": new Date(1409821985245)
}


نوشتن خروجی JSON در یک استریم

خروجی متد JsonConvert.SerializeObject یک رشته‌است که در صورت نیاز به سادگی توسط متد File.WriteAllText در یک فایل قابل ذخیره می‌باشد. اما برای رسیدن به حداکثر کارآیی و سرعت می‌توان از استریم‌ها نیز استفاده کرد:
using (var stream = File.CreateText(@"c:\output.json"))
{
    var jsonSerializer = new JsonSerializer
   {
      Formatting = Formatting.Indented
   };
   jsonSerializer.Serialize(stream, new
   {
     Id = 1,
     Name = "Test",
     DateTime = DateTime.Now
   });
}
کلاس JsonSerializer و متد Serialize آن یک استریم را نیز جهت نوشتن خروجی می‌پذیرند. برای مثال response.Output برنامه‌های وب نیز یک استریم است و در اینجا نوشتن مستقیم در استریم بسیار سریعتر است از تبدیل شیء به رشته و سپس ارائه خروجی آن؛ زیرا سربار تهیه رشته JSON از آن حذف می‌گردد و نهایتا GC کار کمتری را باید انجام دهد.


تبدیل JSON رشته‌ای به اشیاء دات نت

اگر رشته‌ی jsonData ایی را که پیشتر تولید کردیم، بخواهیم تبدیل به نمونه‌ای از شیء User ذیل کنیم:
public class User
{
   public int Id { set; get; }
   public string Name { set; get; }
   public DateTime DateTime { set; get; }
}
خواهیم داشت:
 var user = JsonConvert.DeserializeObject<User>(jsonData);
در اینجا از متد DeserializeObject به همراه مشخص سازی صریح نوع شیء نهایی استفاده شده‌است.
البته در اینجا با توجه به استفاده از JavaScriptDateTimeConverter برای تولید jsonData، نیاز است چنین تنظیمی را نیز در حالت DeserializeObject مشخص کنیم:
var user = JsonConvert.DeserializeObject<User>(jsonData, new JsonSerializerSettings
{
   Converters = {  new JavaScriptDateTimeConverter() }
});


مقدار دهی یک نمونه یا وهله‌ی از پیش موجود

متد JsonConvert.DeserializeObject یک شیء جدید را ایجاد می‌کند. اگر قصد دارید صرفا تعدادی از خواص یک وهله‌ی موجود، توسط JSON.NET مقدار دهی شوند از متد PopulateObject استفاده کنید:
 JsonConvert.PopulateObject(jsonData, user);


کاهش حجم JSON تولیدی

زمانیکه از متد JsonConvert.SerializeObject استفاده می‌کنیم، تمام خواص عمومی تبدیل به معادل JSON آن‌ها خواهند شد؛ حتی خواصی که مقدار ندارند. این خواص در خروجی JSON، با مقدار null مشخص می‌شوند. برای حذف این خواص از خروجی JSON نهایی تنها کافی است در تنظیمات JsonSerializerSettings، مقدار NullValueHandling = NullValueHandling.Ignore مشخص گردد.
var jsonData = JsonConvert.SerializeObject(object, new JsonSerializerSettings
{
   NullValueHandling = NullValueHandling.Ignore,
   Formatting = Formatting.Indented
});
مورد دیگری که سبب کاهش حجم خروجی نهایی خواهد شد، تنظیم DefaultValueHandling = DefaultValueHandling.Ignore است. در این حالت کلیه خواصی که دارای مقدار پیش فرض خودشان هستند، در خروجی JSON ظاهر نخواهند شد. مثلا مقدار پیش فرض خاصیت int مساوی صفر است. در این حالت کلیه خواص از نوع int که دارای مقدار صفر می‌باشند، در خروجی قرار نمی‌گیرند.
به علاوه حذف Formatting = Formatting.Indented نیز توصیه می‌گردد. در این حالت فشرده‌ترین خروجی ممکن حاصل خواهد شد.


مدیریت ارث بری توسط JSON.NET

در مثال ذیل کلاس کارمند و کلاس مدیر را که خود نیز در اصل یک کارمند می‌باشد، ملاحظه می‌کنید:
public class Employee
{
    public string Name { set; get; }
}

public class Manager : Employee
{
    public IList<Employee> Reports { set; get; }
}
در اینجا هر مدیر لیست کارمندانی را که به او گزارش می‌دهند نیز به همراه دارد. در ادامه نمونه‌ای از مقدار دهی این اشیاء ذکر شده‌اند:
 var employee = new Employee { Name = "User1" };
var manager1 = new Manager { Name = "User2" };
var manager2 = new Manager { Name = "User3" };
manager1.Reports = new[] { employee, manager2 };
manager2.Reports = new[] { employee };
با فراخوانی
 var list = JsonConvert.SerializeObject(manager1, Formatting.Indented);
یک چنین خروجی JSON ایی حاصل می‌شود:
{
  "Reports": [
    {
      "Name": "User1"
    },
    {
      "Reports": [
        {
          "Name": "User1"
        }
      ],
      "Name": "User3"
    }
  ],
  "Name": "User2"
}
این خروجی JSON جهت تبدیل به نمونه‌ی معادل دات نتی خود، برای مثال جهت رسیدن به manager1 در کدهای فوق، چندین مشکل را به همراه دارد:
- در اینجا مشخص نیست که این اشیاء، کارمند هستند یا مدیر. برای مثال مشخص نیست User2 چه نوعی دارد و باید به کدام شیء نگاشت شود.
- مشکل دوم در مورد کاربر User1 است که در دو قسمت تکرار شده‌است. این شیء JSON اگر به نمونه‌ی معادل دات نتی خود نگاشت شود، به دو وهله از User1 خواهیم رسید و نه یک وهله‌ی اصلی که سبب تولید این خروجی JSON شده‌است.

برای حل این دو مشکل، تغییرات ذیل را می‌توان به JSON.NET اعمال کرد:
var list = JsonConvert.SerializeObject(manager1, new JsonSerializerSettings
{
   Formatting = Formatting.Indented,
   TypeNameHandling = TypeNameHandling.Objects,
   PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
با این خروجی:
{
  "$id": "1",
  "$type": "JsonNetTests.Manager, JsonNetTests",
  "Reports": [
    {
      "$id": "2",
      "$type": "JsonNetTests.Employee, JsonNetTests",
      "Name": "User1"
    },
    {
      "$id": "3",
      "$type": "JsonNetTests.Manager, JsonNetTests",
      "Reports": [
        {
          "$ref": "2"
        }
      ],
      "Name": "User3"
    }
  ],
  "Name": "User2"
}
- با تنظیم TypeNameHandling = TypeNameHandling.Objects سبب خواهیم شد تا خاصیت اضافه‌ای به نام $type به خروجی JSON اضافه شود. این نوع، در حین فراخوانی متد JsonConvert.DeserializeObject جهت تشخیص صحیح نگاشت اشیاء بکار گرفته خواهد شد و اینبار مشخص است که کدام شیء، کارمند است و کدامیک مدیر.
- با تنظیم PreserveReferencesHandling = PreserveReferencesHandling.Objects شماره Id خودکاری نیز به خروجی JSON اضافه می‌گردد. اینبار اگر به گزارش دهنده‌ها با دقت نگاه کنیم، مقدار $ref=2 را خواهیم دید. این مورد سبب می‌شود تا در حین نگاشت نهایی، دو وهله متفاوت از شیء با Id=2 تولید نشود.

باید دقت داشت که در حین استفاده از JsonConvert.DeserializeObject نیز باید JsonSerializerSettings یاد شده، تنظیم شوند.


ویژگی‌های قابل تنظیم در JSON.NET

علاوه بر JsonSerializerSettings که از آن صحبت شد، در JSON.NET امکان تنظیم یک سری از ویژگی‌ها به ازای خواص مختلف نیز وجود دارند.
- برای نمونه ویژگی JsonIgnore معروفترین آن‌ها است:
public class User
{
   public int Id { set; get; }

   [JsonIgnore]
   public string Name { set; get; }

   public DateTime DateTime { set; get; }
}
JsonIgnore سبب می‌شود تا خاصیتی در خروجی نهایی JSON تولیدی حضور نداشته باشد و از آن صرفنظر شود.

- با استفاده از ویژگی JsonProperty اغلب مواردی را که پیشتر بحث کردیم مانند NullValueHandling، TypeNameHandling و غیره، می‌توان تنظیم نمود. همچنین گاهی از اوقات کتابخانه‌های جاوا اسکریپتی سمت کاربر، از اسامی خاصی که از روش‌های نامگذاری دات نتی پیروی نمی‌کنند، در طراحی خود استفاده می‌کنند. در اینجا می‌توان نام خاصیت نهایی را که قرار است رندر شود نیز صریحا مشخص کرد. برای مثال:
[JsonProperty(PropertyName = "m_name", NullValueHandling = NullValueHandling.Ignore)]
public string Name { set; get; }
همچنین در اینجا امکان تنظیم Order نیز وجود دارد. برای مثال مشخص کنیم که خاصیت X در ابتدا قرار گیرد و پس از آن خاصیت Y رندر شود.

- استفاده از ویژگی JsonObject به همراه مقدار OptIn آن به این معنا است که از کلیه خواصی که دارای ویژگی JsonProperty نیستند، صرفنظر شود. حالت پیش فرض آن OptOut است؛ یعنی تمام خواص عمومی در خروجی JSON حضور خواهند داشت منهای مواردی که با JsonIgnore مزین شوند.
[JsonObject(MemberSerialization.OptIn)]
public class User
{
    public int Id { set; get; }

    [JsonProperty]
    public string Name { set; get; }
 
    public DateTime DateTime { set; get; }
}

- با استفاده از ویژگی JsonConverter می‌توان نحوه‌ی رندر شدن مقدار خاصیت را سفارشی سازی کرد. برای مثال:
[JsonConverter(typeof(JavaScriptDateTimeConverter))]
public DateTime DateTime { set; get; }


تهیه یک JsonConverter سفارشی

با استفاده از JsonConverterها می‌توان کنترل کاملی را بر روی اعمال serialization و deserialization مقادیر خواص اعمال کرد. مثال زیر را در نظر بگیرید:
public class HtmlColor
{
   public int Red { set; get; }
   public int Green { set; get; }
   public int Blue { set; get; }
}

var colorJson = JsonConvert.SerializeObject(new HtmlColor
{
  Red = 255,
  Green = 0,
  Blue = 0
}, Formatting.Indented);
در اینجا علاقمندیم، در حین عملیات serialization، بجای اینکه مقادیر اجزای رنگ تهیه شده به صورت int نمایش داده شوند، کل رنگ با فرمت hex رندر شوند. برای اینکار نیاز است یک JsonConverter سفارشی را تدارک دید:
    public class HtmlColorConverter : JsonConverter
    {

        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(HtmlColor);
        }

        public override object ReadJson(JsonReader reader, Type objectType,
                                        object existingValue, JsonSerializer serializer)
        {
            throw new NotSupportedException();
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var color = value as HtmlColor;
            if (color == null)
                return;

            writer.WriteValue("#" + color.Red.ToString("X2")
                + color.Green.ToString("X2") + color.Blue.ToString("X2"));
        }
    }
کار با ارث بری از کلاس پایه JsonConverter شروع می‌شود. سپس باید تعدادی از متدهای این کلاس پایه را بازنویسی کرد. در متد CanConvert اعلام می‌کنیم که تنها اشیایی از نوع کلاس HtmlColor را قرار است پردازش کنیم. سپس در متد WriteJson منطق سفارشی خود را می‌توان پیاده سازی کرد.
از آنجائیکه این تبدیلگر صرفا قرار است برای حالت serialization استفاده شود، قسمت ReadJson آن پیاده سازی نشده‌است.

در آخر برای استفاده از آن خواهیم داشت:
var colorJson = JsonConvert.SerializeObject(new HtmlColor
{
  Red = 255,
  Green = 0,
  Blue = 0
},  new JsonSerializerSettings
    {
      Formatting = Formatting.Indented,
      Converters = { new HtmlColorConverter() }
    });   
مطالب
ارسال پارامتر از سی شارپ به مایکروسافت Word
فرض کنید نامه‌ای را می‌خواهیم تنظیم کنیم. سمت برنامه، شماره، تاریخ و نام مدیر عامل و ... را مشخص می‌کنیم و می‌خواهیم این اطلاعات را به ورد بفرستیم؛ همچنین متن نامه را هم در ورد تایپ کنیم و در آخر هم نامه را آرشیو کنیم. برای اینکار چندین روش وجود دارد. ما در این مقاله از روش MailMergeField و Bookmark استفاده میکنیم.

روش ایجاد الگوهای Word

ابتدا می‌خواهیم یک الگو یا Template را درست کنیم و بعد‌ها از روی آن، نامه‌ی جدیدی را ایجاد کنیم و فیلدهایش را پرکنیم. برای اینکار یک سند جدید را در Word ایجاد و به سربرگ Mailings مراجعه میکنیم. سپس دکمه‌ی Select Recipients را بزنید. در ادامه از منوی باز شده، Type a NewList را بزنید. با اینکار پنجره‌ای باز می‌شود. در اینجا دکمه‌ی Customize Columns را بزنید. این پنجره شامل فیلدهایی می‌شود که میتوانید از آن استفاده کنید و بر روی سند قرار دهید و داخل برنامه با پیدا کردن این فیلدها میتوانید بجای آن‌ها، مقدار مورد نظرتان را پاس دهید. حالا شما نیاز دارید تا از طریق دکمه‌ی Add، تمامی فیلدهای لازم یک نامه را بسازید. پس از این کار، در هر دو پنجره ، دکمه‌ی OK را بزنید. بدین صورت یک پنجره‌ی ذخیره برای شما باز می‌شود تا این فیلدهایی  را که ایجاد کردید، به عنوان یک دیتابیس کوچک ذخیره شود که تمامی فیلدها را دارا می‌باشد و هر موقع که خواستید دوباره میتوانید از همین فیلد‌ها استفاده کنید.

حالا می‌رسیم به قرار دادن این فیلد‌ها داخل سند. با ذخیره کردن فیلدها، تمامی گزینه‌های سربرگ Mailings فعال می‌شود. شما برای اینکه فیلدی را بر روی سند قرار دهید، روی Insert Merge Field کلیک و متناسب با نیازتان، فیلدها را قرار دهید و الگو را طراحی کنید. یک نمونه:


حالا فایل را با پسوند DOT. ذخیره کنید. در ادامه این فایل را در دیتابیس، به این روش ذخیره کنید: 

String FilePath = "Template Path"
// Converting File to ByteArray
byte[] FileBuffer = System.IO.File.ReadAllBytes(FilePath);
// Now you can insert this file buffer to DB

الان، الگوی ما آماده‌است و میتوانیم از طریق برنامه، به این الگو دسترسی داشته باشیم و به آن پارامتر ارسال کنیم.


روش ارسال پارامترها به الگوهای Word

حالا فرضا شما یک فرم دارید که از کاربر، اطلاعاتی را دریافت میکند و میخواهید همین اطلاعات را به Word ارسال کنید. برای اینکار ابتدا باید یک نمونه از الگویی را که طراحی کرده‌ایم، داخل سیستم ذخیره کنیم. یعنی باید آن‌را از دیتابیس فراخوانی کنیم و آن آرایه‌ی بایتی را، بر روی سیستم، تبدیل به فایل کنیم. سپس از سمت برنامه، تمامی فیلدهای موجود در این الگو را خوانده و بجای تک تک آن‌ها، مقدار مناسبی را قرار دهیم. در نهایت این فایل را توسط کدنویسی بر روی سیستم کاربر ذخیره میکنیم. فایل را تبدیل به آرایه بایتی میکنیم، داخل دیتابیس درج میکنیم و فایل را از سیستم کاربر حذف میکنیم.

بنابراین در ادامه ابتدا Assembly مربوط به MicroSoft.Office.Interop.Word را به رفرنس‌های پروژه اضافه میکنیم و سربرگش را هم Using میکنیم.


حالا می‌رسیم به کد نویسی:

کدهای زیر را به صورت سراسری داخل فرم تعریف میکنیم:

//LOCATION OF THE TEMPLATE FILE ON THE MACHINE;
Object oTemplatePath = string.Format("{0}\\NewDocument.dot", Application.StartupPath);
 
//OBJECT OF MISSING "NULL VALUE"
Object oMissing = System.Reflection.Missing.Value;
 
//OBJECTS OF FALSE AND TRUE
Object oTrue = true;
Object oFalse = false;
 
//CREATING OBJECTS OF WORD AND DOCUMENT
Microsoft.Office.Interop.Word.Application oWord = null;
Microsoft.Office.Interop.Word.Document oWordDoc = null;

سپس کدهای زیر را داخل رخ‌داد گردان کلیک دکمه‌ی مثلا "پیشنمایش" مینویسیم:
// Fetching Template ByteArray From Database => Byte[] YourTemplateByteArray = Fetch Template;

System.IO.File.WriteAllBytes(oTemplatePath.ToString(), YourByteArray);

oWord = new Microsoft.Office.Interop.Word.Application();
oWordDoc = new Microsoft.Office.Interop.Word.Document();

//Adding A New Document From A Template
oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);

int iTotalFields = 0;
// Finding Mailmerge Fields
foreach(Microsoft.Office.Interop.Word.Field myMergeField in oWordDoc.Fields) {
  iTotalFields++;
  Microsoft.Office.Interop.Word.Range rngFieldCode = myMergeField.Code;
  String fieldText = rngFieldCode.Text;

  // Only Get The Mailmerge Fields
  if (fieldText.StartsWith(" MERGEFIELD")) {
    // Gives The Fieldnames as Entered in .DOT File
    string fieldName = fieldText.Substring(12, fieldText.IndexOf(" ", 12) - 12);

    switch (fieldName) {
    case "Letter_No":
      myMergeField.Select();
      oWord.Selection.TypeText(txtLetterNo.Text);
      break;

    case "Letter_Date":
      myMergeField.Select();
      oWord.Selection.TypeText(DateTime.Now);
      break;

    case "Letter_Has_Attachment":
      myMergeField.Select();
      oWord.Selection.TypeText("دارد یا ندارد");
      break;

      // And So On
    default:
      break;
    }
  }
}

//Showing The Document To The User
oWord.Visible = true;

در ادامه یک دکمه را برای ذخیره‌ی فایل ورد قرار می‌دهیم. زمانیکه کاربر تایپ کردنش تمام شد و هنوز برنامه‌ی ورد در حال اجراست، این دکمه را اجرا می‌کند. دقت کنید برنامه‌ی ورد نباید بسته شود؛ باید باز باشد. بعد دکمه‌ی ذخیره را می‌زنیم. با کدنویسی، برنامه‌ی Word را خودمان می‌بندیم؛ نیازی به دخالت کاربر نیست. 

oWordDoc.Save();

//Closing the file
oWordDoc.Close(ref oFalse, ref oMissing, ref oMissing);

//Quitting the application
oWord.Quit(ref oMissing, ref oMissing, ref oMissing);
byte[] FileBuffer = System.IO.File.ReadAllBytes(oTemplatePath.ToString  ());
 
// Now Insert The FileBuffer Into Database as A Letter


خوب؛ کار تمام است! حالا فیلد FileBuffer را باید بسته به کدنویسی خودتان، داخل دیتابیس ذخیره کنید که برای بعدها بتوانید آن‌را واکشی کرده و به کاربر نمایش دهید. این هم نمونه‌ی نهایی جایگذاری فیلدها: 


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

نظرات مطالب
معرفی ELMAH
در ASP.NET برای تعریف smtp authentication یا باید از طریق code behind عمل کنید که این حالت نیازی به تعریف همان موارد در web.config ندارد.
یا این تنظیمات رو مطابق مقاله‌ای که ذکر کردم می‌تونید به web.config انتقال بدید (قسمت system.net -- mailSettings -- smtp -- network) و نیازی به تعریف مجدد آن‌ها در code behind نیست و به صورت سراسری به برنامه اعمال می‌شود. یکی از این دو حالت رو انتخاب کنید.
در elmah مطابق مقاله https://www.dntips.ir/2010/08/elmah-wcf-ria-services.html باید قسمت errorMail اضافه شود که در آن مقاله البته comment شده که باید comment آن برداشته شود.
سپس elmah هم چون از همان کدهای متداول دات نتی استفاده می‌کند تنظیمات smtp authentication را که بحث مجزایی است می‌تواند از web.config هم دریافت کند. راه دیگر هم این است که این یوزر نیم و پسورد را در همان تگ errorMail هم مطابق مثال web.config موجود در پوشه samples آن هم می‌شود تعریف کرد. تمام این‌ها یک اثر را دارند و فقط یکی باید اعمال شود.

ضمنا یک مطلب رو هم به صراحت خدمت شما عرض کنم. تابحال هاستی رو ندیدم که با همان تنظیمات local شما بدون مشکل کار کند. علت هم این است که کسی نتواند از امکانات ارسال ایمیل آن‌ها سوء استفاده کند. بنابراین بر روی هاست حتما نیاز به smtp authentication هست. یا این اطلاعات را باید از هاست بگیرید. یا اگر کنترل پنل ارسال ایمیل هم سایت دارد یک یوزر جدید در آن تعریف کنید و مشخصات آن‌را در برنامه استفاده کنید. در غیر اینصورت آن هاست از لحاظ امنیتی به شدت مشکل دارد و دیر یا زود زیر بار ارسال میلیون‌ها اسپم از پا در خواهد آمد.
مطالب
معرفی برنامه انتخاب واحد
حتما همه‌ی شما با فرآیند انتخاب واحد دانشگاه‌ها آشنا هستید. معمولا دانشجویان سعی می‌کنند، دروسی را انتخاب کنند تا در حداقل تعداد روز‌های هفته، بیشترین تعداد واحد ممکن را بگیرند. اما این کار وقتی که تعداد دروس و اساتید زیاد باشد، مشکل است و باید وقت زیادی  را صرف آن کرد. در نتیجه تصمیم گرفتم تا برنامه‌ای را بنویسم که با گرفتن لیست دروس مورد نظر، تمامی برنامه‌های هفتگی ممکن را نمایش دهد.
   
فناوری‌های استفاده شده:
  
- ASP.NET MVC برای سرور
- AngularJS برای کلاینت
   
الگوریتم پیاده سازی شده:
  
در مورد الگوریتم نیز باید بگویم که من از همان ابتدا ساده‌ترین راه، یعنی تست کردن تمامی حالات ممکن را پیاده سازی کردم. متاسفانه این روش منابع زیادی را مصرف  می‌کند و زمان بر است. البته قطعا می‌توان همین روش را با بهینه سازی‌هایی از جمله انتخاب ساختمان داده‌های مناسب‌تر و تغییراتی در الگوریتم، کاراتر کرد.
همچنین پس از پایان کار، با کمی تحقیق فهمیدم که برای حل این مساله، راه سر راست و ساده ای وجود ندارد. ولی قطعا می‌توان با استفاده از الگوریتم‌های خاصی، راه حل بهتر و بهینه‌تری را پیاده سازی کرد که هدف از به اشتراک گذاری این برنامه همین مساله هست.

برای مثال لینک‌های زیر به توضیح راه‌حل‌هایی برای مسائل مشابه پرداخته‌اند:  
 
دریافت سورس کد
برای دریافت سورس کد برنامه به لینک زیر مراجعه کنید:
   
تصاویری از برنامه: