مسیرراه‌ها
ASP.NET MVC
              مطالب
              بررسی جزئیات برنامه نویسی افزونه تاریخ فارسی برای outlook 2007 - قسمت دوم

              اضافه کردن یک ستون در آوت لوک کار ساده‌ای است. برای مثال زمانیکه inbox باز است ، بر روی قسمت نمایش ایمیل‌ها کلیک راست کرده و مسیر زیر را طی کنید:
              در اینجا فرض بر این است که از منوی اصلی view->reading pane->bottom انتخاب شده است.
              Customize current view -> fields -> new field

              به این صورت می‌شود یک UserDefinedProperties را تعریف و سپس ‌آن‌را به ViewFields موجود اضافه کرد. نحوه انجام اینکار را در تابع addNewCol می‌توانید مشاهده نمائید.

              اما مقدار دهی ردیف‌های این ستون ایجاد شده کار ساده‌ای نیست و نیاز است تا با نکته زیر آشنا بود:
              <view type="table">
              <viewname>Messages</viewname>
              <column>
              <heading>تاریخ دریافت</heading>
              <prop>http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/تاریخ%20دریافت</prop>
              <type>string</type>
              <width>150</width>
              <style>padding-left:3px;;text-align:left</style>
              <editable>1</editable>
              </column>
              </view>

              Outlook ساختار ستون‌های موجود را با فرمت xml نگهداری می‌کند و اگر نیاز داشتید تا ردیف ستونی را مقدار دهی کنید باید ابتدا مقدار تگ prop مربوط به آن ستون را دریافت کرده و سپس بر اساس آن، کار مقدار دهی را انجام دهید. نحوه انجام این‌کار را در تابع getColumnProp می‌توانید ملاحظه نمائید و نهایتا نحوه استفاده از این خاصیت دریافت شده جهت مقدار دهی یک ردیف در تابع expSelectionChange ارائه شده است.
              اگر علاقمند بودید که مقدار کامل این ساختار را مشاهده نمائید در تابع addNewCol ، پس از تعریف curView سطر زیر را اضافه کنید:

              MessageBox.Show(curView.XML);


              مطالب
              نمایش رکوردها به ترتیب اولویت به کمک jQuery UI sortable در ASP.NET MVC

              همان طور که می‌دانید کاربرد پذیری در خیلی از پروژه‌ها حرف اول رو می‌زند و کاربر دوست دارد کارهایی که انجام می‌دهد خیلی راحت و با استفاده از موس باشد.یکی از کار هایی که در اکثر پروژه‌ها نیاز است ، چیدمان ترتیب رکورد‌ها است. ما می‌خواهیم در این پست ترتیبی اتخاذ کنیم که کاربر بتواند رکورد‌ها را به هر ترتیبی که دوست دارد نمایش دهد.

              از توضیحاتی که قبلا  دادم مشخص است که این کار احتمالا در ASP.NET WebForm  کار سختی نیست ولی این کار باید در MVC  از ابتدا طراحی شود.

              طرح سوال : یک سری رکورد از یک Table داریم که می‌خواهیم به ترتیب وارد شدن رکورد‌ها نباشد و  ترتیبی که ما می‌خواهیم نمایش داده شود.

              پاسخ کوتاه : خب باید ابتدا یک فیلد (برای اولویت بندی)  به Table  اضافه کنیم  بعد اون فیلد رو بنا به ترتیبی که دوست داریم رکورد‌ها نمایش داده شود پر کنیم (Sort  می کنیم ) و در آخر هم هنگام نمایش در View رکورد‌ها را بر اساس این فیلد نمایش می‌دهیم.

              (این پست هم در ادامه پست قبلی در همان پروژه است و از همان Table  ها استفاده شده است)

              اضافه کردن فیلد :

              ابتدا یک فیلد به Table  مورد نظر اضافه می‌کنیم. من اسم این فیلد رو Priority گذاشتم. Table  من چنین وضعیتی دارد.

              افزودن فایل‌های jQuery UI :

              در این مرحله شما نیاز دارید فایل‌های مورد نیاز برای Sort  کردن رکورد‌ها را اضافه کنید. شما می‌توانید فقط فایل‌های مربوط به Sortable  را به صفحه خودتان اضافه کنید و یا مثل من فایل هایی که حاوی تمام قسمت‌های jQuery UI  هست را اضافه کنید.

              من برای این کار از Section  استفاده کردم ، ابتدا در Head  فایل Layout  دو Section  تعریف کردم برای CSS  و JavaScript . و فایل‌های مربوط به Sort کردن را در صفحه ای که باید عمل Sort انجام بشود در  این Section ها قرار دادم.

              فایل Layout

              <head>
                  <meta charset="utf-8" />
                  @RenderSection("meta", false)
                  <title>@ViewBag.Title</title>
                  <link href="@Url.Content("~/Content/~Site.css")" rel="stylesheet" type="text/css" />
                  <link href="@Url.Content("~/Content/redactor/css/redactor.css")" rel="stylesheet" type="text/css" />
                  <link href="@Url.Content("~/Content/css/bootstrap-rtl.min.css")" rel="stylesheet" type="text/css" />
                  @RenderSection("css", false)
                  <script src="@Url.Content("~/Scripts/jquery-1.8.2.min.js")" type="text/javascript"></script>
                  <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
                  <script src="@Url.Content("~/Content/js/bootstrap-rtl.js")" type="text/javascript"></script>
                  <script src="@Url.Content("~/Content/redactor/redactor.min.js")" type="text/javascript"></script>
                  <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
                  @RenderSection("js", false)
              
              </head>

              فایل Index.chtml  در پوشه کنترلر Type


              @model IEnumerable<KhazarCo.Models.Type>
              @{
                  ViewBag.Title = "Index";
                  Layout = "~/Areas/Administrator/Views/Shared/_Layout.cshtml";
              }
              @section css
              {<link href="@Url.Content("~/Content/themes/base/jquery-ui.css")" rel="stylesheet" type="text/css" />
              }
              @section js
              {
                  <script src="@Url.Content("~/Scripts/jquery-ui-1.9.0.min.js")" type="text/javascript"></script>
              }


              در آخر فایل Index.chtml  به اینصورت شده است:

              <h2>
                  نوع ها</h2>
              <p>
                  @Html.ActionLink("ایجاد یک مورد جدید", "Create", null, new { @class = "btn btn-info" })
              </p>
              <table>
                  <thead>
                      <tr>
                          <th>
                              عنوان
                          </th>
                          <th>
                              توضیحات
                          </th>
                          <th>
                              فعال
                          </th>
                          <th>
                          </th>
                      </tr>
                  </thead>
                  <tbody>
                      @foreach (var item in Model.OrderBy(m => m.Priority))
                      {
                          <tr id="@item.Id">
                              <td>
                                  @Html.DisplayFor(modelItem => item.Title)
                              </td>
                              <td>
                                  @(new HtmlString(item.Description))
                              </td>
                              <td>
                                  @Html.DisplayFor(modelItem => item.IsActive)
                              </td>
                              <td>
                                  @Html.ActionLink("ویرایش", "Edit", new { id = item.Id }, new { @class = "btnEdit label label-warning" })
                                  |
                                  @Html.ActionLink("مشاهده", "Details", new { id = item.Id }, new { @class = "btnDetails label label-info" })
                                  |
                                  @Html.ActionLink("حذف", "Delete", new { id = item.Id }, new { @class = "btnDelete label label-important" })
                              </td>
                          </tr>
                      }
                  </tbody>
              </table>

              ** توجه داشته باشید که من به هر tr  یک id  اختصاص داده ام که این مقدار id  همان مقدار فیلد Id  همان رکورد هست ، ما برای مرتب کردن به این Id  نیاز داریم (خط 25).

              افزودن کد‌های کلاینت:

              حالا باید کدی بنویسم که دو کار را برای ما انجام دهد : اول حالت Sort  پذیری را به سطر‌های Table  بدهد و دوم اینکه هنگامی که ترتیب سطر‌های تغییر کرد ما را با خبر کند:


              <script type="text/javascript">
                  $(function () {
                      $("table tbody").sortable({
                          helper: fixHelper,
                          update: function (event, ui) {
                              jQuery.ajax('@Url.Action("Sort", "Type", new { area = "Administrator" })', {
                                  data: { s: $(this).sortable('toArray').toString() }
                              });
                          }
                      }).disableSelection();
                  });
                  var fixHelper = function (e, ui) {
                      ui.children().each(function () {
                          $(this).width($(this).width());
                      });
                      return ui;
                  };
              </script>


              توضیح کد :

              در این کد ما حالت ترتیب پذیری را به Table  می دهیم و هنگامی که عمل Update  در Table  انجام شد تابع مربوطه اجرا می‌شود. ما در این تایع، ترتیب جدید سطر‌ها را می‌گیریم ( ** به کمک مقدار Id  که به هر سطر دادیم ، این مقدار Id  برابر بود با Id خود رکورد در Database )  و به کمکjQuery.ajax  به تابع Sort  از کنترلر Type  در منطقه (area ) Administrator  ارسال می‌کنیم و در آنجا ادامه کار را انجام میدهیم.

              تابع fixHelper  هم به ما کمک می‌کند که هنگامی که سطر‌ها از جای خود جدا می‌شوند ، دارای عرض یکسانی باشند و عرض آن‌ها تغییری نکند.


              افزودن کد Server:

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


                      public EmptyResult Sort(string s)
                      {
                          if (s != null)
                          {
                              var ids = new List<int>();
                              foreach (var item in s.Split(','))
                              {
                                  ids.Add(int.Parse(item));
                              }
                              int intpriority = 0;
              
                              foreach (var item in ids)
                              {
                                  intpriority++;
                                  db.Types.Single(m => m.Id == item).Priority = intpriority;
                              }
                              db.SaveChanges();
                          }
                          return new EmptyResult();
                      }

              در ایتدا مقادیر Id  که از کلاینت  به صورت String  ارسال شده است را می‌گیریم و بعد به همان ترتیب ارسال در لیستی از int قرار می‌دهیم ids.

              سپس به اضای هر رکورد Type  مقدار اولویت را به فیلدی که برای همین مورد اضافه کردیم Priority اختصاص می‌دهیم. و در آخر هم تغییرات را ذخیره می‌کنیم. (خود کد کاملا واضح است و نیاری به توضیح بیشتر نیست )

              حالا باید هنگامی که لیست Type  ها نمایش داده می‌شود به ترتیب (OrderBy) فیلد Priority    نمایش داده شود پس تابع Index را اینطور تغییر می‌دهیم.

                      public ViewResult Index()
                      {
                          return View(db.Types.Where(m => m.IsDeleted == false).OrderBy(m => m.Priority));
                      }

              این هم خروجی کار من:

              این عکس مربوط به است به قسمت مدیریت پروژه شیرآلات مرجان خزر


              مطالب
              عبارات باقاعده‌ای در مورد کار با تگ‌ها

              حذف تمامی تگ‌های یک عبارت HTML
              این تابع و عبارت باقاعده به کار رفته در آن هنگام جستجو بر روی یک فایل html که حاوی انبوهی از تگ‌ها است می‌تواند مفید باشد و یا جهت حذف هر نوع فرمت اعمالی به یک متن.

              private static readonly Regex _htmlRegex = new Regex("<.*?>", RegexOptions.Compiled);
              /// <summary>
              /// حذف تمامی تگ‌های موجود
              /// </summary>
              /// <param name="html">ورودی اچ تی ام ال</param>
              /// <returns></returns>
              public static string CleanTags(string html)
              {
              return _htmlRegex.Replace(html, string.Empty);
              }

              حذف یک تگ ویژه بدون حذف محتویات آن
              فرض کنید می‌خواهید تمام تگ‌های script بکار رفته در یک محتوای html را حذف کنید.

              private static readonly Regex _contentRegex = new Regex(@"<\/?script[^>]*?>", RegexOptions.Compiled | RegexOptions.IgnoreCase);

              /// <summary>
              /// تنها حذف یک تگ ویژه
              /// </summary>
              /// <param name="html">ورودی اچ تی ام ال</param>
              /// <returns></returns>
              public static string CleanScriptTags(string html)
              {
              return _contentRegex.Replace(html, string.Empty);
              }

              حذف یک تگ خاص به همراه محتویات آن تگ
              فرض کنید می‌خواهیم در محتوای html دریافتی اثری از تگ‌ها و کدهای جاوا اسکریپتی یافت نشود.

              private static readonly Regex _safeStrRegex = new Regex(@"<script[^>]*?>[\s\S]*?<\/script>",
              RegexOptions.Compiled | RegexOptions.IgnoreCase);

              /// <summary>
              /// حذف یک تگ ویژه به همراه محتویات آن
              /// </summary>
              /// <param name="html">ورودی اچ تی ام ال</param>
              /// <returns></returns>
              public static string CleanScriptsTagsAndContents(string html)
              {
              return _safeStrRegex.Replace(html, "");
              }

              و اگر فرض کنیم که متدهای فوق در کلاسی به نام CRegExHelper قرار گرفته‌اند، کلاس آزمون واحد آن به صورت زیر می‌تواند باشد:

              using NUnit.Framework;

              namespace testWinForms87
              {
              [TestFixture]
              public class CTestRegExHelper
              {
              #region Methods (3)

              // Public Methods (3)

              [Test]
              public void TestCleanScriptsTagsAndContents()
              {
              Assert.AreEqual(
              CRegExHelper.CleanScriptsTagsAndContents("data1 <script> ... </script> data2"),
              "data1 data2");
              }

              [Test]
              public void TestCleanScriptTags()
              {
              Assert.AreEqual(
              CRegExHelper.CleanScriptTags("<b>data1</b> <script> ... </script> data2"),
              "<b>data1</b> ... data2");
              }

              [Test]
              public void TestCleanTags()
              {
              Assert.AreEqual(
              CRegExHelper.CleanTags("<b>data</b>"),
              "data");
              }

              #endregion Methods
              }

              }




              مطالب
              سفارشی سازی صفحه‌ی اول برنامه‌های Angular CLI توسط ASP.NET Core
              در مطلب «Angular CLI - قسمت پنجم - ساخت و توزیع برنامه» با نحوه‌ی ساخت و توزیع برنامه‌های Angular، در دو حالت محیط توسعه و محیط ارائه‌ی نهایی آشنا شدیم. همچنین در مطلب «یکپارچه سازی Angular CLI و ASP.NET Core در VS 2017» نحوه‌ی ترکیب یک برنامه‌ی ASP.NET Core و Angular را بررسی کردیم. در اینجا می‌خواهیم فایل index.html ایی را که Angular CLI تولید می‌کند، با فایل Layout برنامه‌های ASP.NET Core جایگزین کنیم؛ تا بتوانیم در صورت نیاز، سفارشی سازی‌های بیشتری را به صفحه‌ی اول سایت اعمال نمائیم.


              استفاده از Tag Helpers ویژه‌ی ASP.NET Core برای مدیریت محیط‌های توسعه و تولید

              فایل‌های برنامه‌ی تک صفحه‌ای تولید شده‌ی توسط Angular CLI، در نهایت یک چنین شکلی را خواهند داشت:


              این فایل‌ها نیز در حالت توسعه تهیه شده‌اند. در یک برنامه‌ی واقعی، صفحه‌ی ساده‌ی index.html تولیدی آن، تنها می‌تواند یک قالب شروع به کار باشد و نه فایل نهایی که قرار است ارائه شود. نیاز است به این فایل تگ‌های بیشتری را اضافه کرد و سفارشی سازی‌های خاصی را به آن اعمال نمود. در این حالت با توجه به بازنویسی و تولید مجدد این فایل در هر بار ساخت برنامه، می‌توان از فایل Layout پروژه‌ی ASP.NET Core جاری استفاده کرد. به این ترتیب از مزایای Razor و تمام زیرساختی که در اختیار داریم نیز محروم نخواهیم شد.
              بنابراین تنها کاری را که باید انجام دهیم، کپی ساختار فایل index.html تولیدی به فایل Layout برنامه است.

              مشکل! در حالت توسعه، نام فایل‌های تولید شده به همین سادگی است که ملاحظه می‌کنید. اما در حالت ارائه‌ی نهایی، این فایل‌ها به همراه یک هش نیز تولید می‌شوند (پیاده سازی مفهوم cache busting و اجبار به به‌روز رسانی کش مرورگر، باتوجه به تغییر آدرس فایل‌ها)؛ مانند vendor.ea3f8329096dbf5632af.bundle.js

              راه حل اول: تولید فایل‌های نهایی بدون هش
               ng build -prod --output-hashing=none
              در حین ساخت و تولید یک برنامه‌ی Angular CLI در حالت ارائه‌ی نهایی، تنها کافی است سوئیچ output-hashing، به none تنظیم شود، تا این هش‌ها به نام فایل‌های تولیدی اضافه نشوند.
              درکل بهتر است از این روش استفاده نشود، چون با وجود پروکسی‌های کش کردن اطلاعات در بین راه، احتمال اینکه کاربران نگارش‌های قدیمی برنامه را مشاهده کنند، بسیار زیاد است.

              راه حل دوم: تگ Script در ASP.NET Core اجازه‌ی ذکر تمام فایل‌های اسکریپت یک پوشه را نیز می‌دهد
               <script type="text/javascript" asp-src-include="*.js"></script>
              هرچند این قابلیت جالب است و سبب الحاق یکجای تمام فایل‌های js موجود در پوشه‌ی wwwroot خواهد شد، اما پاسخگوی کار ما نخواهد بود؛ چون ترتیب قرارگیری این فایل‌ها مهم است.

              راه حل واقعی
              در اینجا کدهای کامل فایل Views\Shared\_Layout.cshtml را که می‌تواند جایگزین فایل index.html تولیدی توسط Angular CLI باشد، ملاحظه می‌کنید:
              <!DOCTYPE html>
              <html>
              <head>
                  <meta charset="utf-8" />
                  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
                  <link rel="icon" type="image/x-icon" href="favicon.ico">
                  <title>ng2-lab</title>
                  <base href="/">
              
                  <environment names="Development">
                  </environment>
                  <environment names="Staging,Production">
                      <link rel="stylesheet" asp-href-include="~/styles*.css" />
                  </environment>
              </head>
              <body>
                  @RenderBody()
              
              <app-root></app-root>
              <environment names="Development">
                  <script type="text/javascript" src="/inline.bundle.js"></script>
                  <script type="text/javascript" src="/polyfills.bundle.js"></script>
                  <script type="text/javascript" src="/scripts.bundle.js"></script>
                  <script type="text/javascript" src="/styles.bundle.js"></script>
                  <script type="text/javascript" src="/vendor.bundle.js"></script>
                  <script type="text/javascript" src="/main.bundle.js"></script>
              </environment>
              <environment names="Production,Staging">
                  <script type="text/javascript" asp-src-include="~/inline*.js"></script>
                  <script type="text/javascript" asp-src-include="~/polyfills*.js"></script>
                  <script type="text/javascript" asp-src-include="~/scripts*.js"></script>
                  <script type="text/javascript" asp-src-include="~/vendor*.js"></script>
                  <script type="text/javascript" asp-src-include="~/main*.js"></script>
              </environment>
              </body>
              </html>
              در اینجا دو حالت توسعه و همچنین ارائه‌ی نهایی مدنظر قرار گرفته‌اند. در حالت توسعه، دقیقا از همان نام‌های ساده‌ی تولیدی استفاده شده‌است و در حالت ارائه‌ی نهایی چون نام فایل‌ها به صورت
              [name].[hash].bundle.js
              تولید می‌شوند، می‌توان قسمت هش را با * جایگزین کرد؛ مانند "asp-src-include="~/vendor*.js
              همچنین باید دقت داشت که در حالت توسعه، تمام شیوه نامه‌های برنامه در فایل styles.bundle.js قرار می‌گیرند. اما در حالت ارائه‌ی نهایی، این فایل وجود نداشته و با نام کلی styles*.css تولید می‌شود که باید در head صفحه قرار گیرد (مانند تنظیمات حالت تولید در Layout فوق).


              اصلاح قسمت URL Rewrite برنامه

              در حالت کار با برنامه‌های تک صفحه‌ای وب، در اولین درخواست رسیده‌ی به برنامه ممکن است آدرسی درخواست شود که معادل کنترلر و اکشن متدی را در برنامه‌ی سمت سرور نداشته باشد. در این حالت کاربر را به همان صفحه‌ی index.html هدایت می‌کنیم تا سیستم مسیریابی سمت کلاینت، کار نمایش آن صفحه را انجام دهد:
              app.Use(async (context, next) =>
              {
                  await next();
                  var path = context.Request.Path.Value;
                  if (path != null &&
                      context.Response.StatusCode == 404 &&
                      !Path.HasExtension(path) &&
                      !path.StartsWith("/api/", StringComparison.OrdinalIgnoreCase))
                      {
                          context.Request.Path = "/index.html";
                          await next();
                      }
              });
              از آنجائیکه پس از اصلاحات فوق دیگر از این فایل استفاده نمی‌شود، باید تغییر ذیل را نیز اعمال کرد:
               //context.Request.Path = "/index.html";
              context.Request.Path = "/"; // since we are using views/shared/_layout.cshtml now.


              کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید.
              پروژه‌ها
              بات تلگرامی پیدا کردن افردا در شعاع 10 کیلومتری
              با توجه به بات‌های موجود در زمینه چت و  جستجو افراد تصمیم گرفتم پروژه مهندسی نرم افزاری خود را شبیه بات‌های موجود بعلاوه امکانات اضافه‌تر و ایده‌ای جدید بنویسم.
              GoogleMapBot تنها یک بات تلگرامی نمیباشد. شما با دانلود سورس کد پروژه میتوانید دستگاه گوشی خودتان را وصل کنید و از همان سرویس استفاده کنید.
              همانطور که از نام بات مشخص میباشد Googlemap بخش مهمی در این پروژه ایفا میکند.
              کاربران آنلاین بات به محض لاگین شدن در بات، عکس پروفایل و مکان فعلی خود و سایر کاربران را میتوانند به صورت آنی بر روی صفحه html مشاهده نمایند.
              سمت سرور پروژه با Web Api  و کلاینت آن با جی‌کوئری ایجکس پیاده سازی شده است. همچین با استفاده ازSignalR کاربران را هنگام ورود و خروج بر روی گوگل مپ به صورت آنی مشخص کرده‌ایم.
              از امکانات آن میتوان به موارد زیر اشاره کرد
              • چت روم: هر منطقه دارای یک چت روم میباشد که بدون تداخل با همدیگر میتوانند کار خود را انجام دهند.
              • وب سایت: بات داری وبسایت میباشد که در بات میتوان با کلیک بر دکمه آن وارد وبسایت شد و درون وب میتوان نظرات خود را برای ادمین فرستاد.
              • ذخیره شدن  اطلاعات کاربران: تمام چت‌ها، عکس‌ها و حتی مکان‌های کاربر در بانک ذخیره میشود.
              • قابلیت آپدیت:  هنگام آپدیت برنامه، کاربران کاملا مدیریت شده و تداخلی در برنامه ایجاد نخواهد شد و پیغامی به تمام کاربران فرستاده میشود.
              • زمان بندی کاربران:  امکانی که در هیچ کدام از بات‌های دیگر موجود نیست، مدیریت کاربران آنلاین  میباشد. GooglemapBot با استفاده از  الگوریتمی که برای آن طراحی شده است، میتواند بعد از زمان مشخصی در صورتیکه کاربر فعالیت نداشته باشد، او را از بات خارج کند. 
              • نمایش افراد آنلاین: یکی دیگر از قابلیت‌های بات، امکان نمایش کاربران بر روی نقشه میباشد. هر کاربری بعد از ورود و خروج به صورت آنی با عکس پروفایلش بر روی نقشه نمایش داده میشود.
              •  محاسبه دقیق فاصله: هنگام ورود به بات، فاصله دقیق کاربر تا تهران محاسبه شده و نمایش داده میشود.
              • پنل مدیریت: داخل بات مدیر با وارد کردن پسورد خود شاهد پنل مدیریتی خواهد بود و با خروج پنل بات نمایش داده میشود.
              امکانات بالا جزو سرویس‌هایی بودند که در بات‌های مشابهی که مشاهده کردم، وجود نداشتند و از  ذکر امکانات مشابه خوداری کردم. شما میتوانید سورس آن را دانلود کنید و آن را به شیوه دلخواه خود طراحی کنید. 
              تصاویر برنامه


              توجه کنید برای راه اندازی بات میتوانید از این لینک استفاده کنید.
              مطالب
              مشکل IIS6 و دریافت فایل‌های آفیس 2007

              IIS6 فایل‌هایی را که نشناسد، سرو نخواهد کرد. بنابراین اگر یکی از کاربران مثلا یک فایل docx آفیس 2007 را آپلود کرده باشد، به محض کلیک بر روی لینک دریافت فایل، با خطای زیر متوقف خواهد شد:

              HTTP Error 404 - File or directory not found

              فایل بر روی سرور موجود است اما کاربر قادر به دریافت آن نیست.

              برای شناساندن فرمت‌های جدید به IIS6 می‌توان به یکی از دو روش زیر عمل کرد:
              الف) اضافه کردن mime-type جدید از طریق کنسول IIS
              ب) ویرایش کردن فایل MetaBase.xml مربوط به IIS

              در هر دو روش فوق نیاز است تا با mime-type فایل‌های جدید آشنا بود. برای مثال لیست کامل mime-types مربوط به فایل‌های آفیس 2007 به صورت زیر است:

              .docm,application/vnd.ms-word.document.macroEnabled.12
              .docx,application/vnd.openxmlformats-officedocument.wordprocessingml.document
              .dotm,application/vnd.ms-word.template.macroEnabled.12
              .dotx,application/vnd.openxmlformats-officedocument.wordprocessingml.template
              .potm,application/vnd.ms-powerpoint.template.macroEnabled.12
              .potx,application/vnd.openxmlformats-officedocument.presentationml.template
              .ppam,application/vnd.ms-powerpoint.addin.macroEnabled.12
              .ppsm,application/vnd.ms-powerpoint.slideshow.macroEnabled.12
              .ppsx,application/vnd.openxmlformats-officedocument.presentationml.slideshow
              .pptm,application/vnd.ms-powerpoint.presentation.macroEnabled.12
              .pptx,application/vnd.openxmlformats-officedocument.presentationml.presentation
              .xlam,application/vnd.ms-excel.addin.macroEnabled.12
              .xlsb,application/vnd.ms-excel.sheet.binary.macroEnabled.12
              .xlsm,application/vnd.ms-excel.sheet.macroEnabled.12
              .xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
              .xltm,application/vnd.ms-excel.template.macroEnabled.12
              .xltx,application/vnd.openxmlformats-officedocument.spreadsheetml.template

              روش ب)
              ابتدا IIS6 را stop کنید (در غیر اینصورت قادر به ذخیره سازی تغییرات نخواهید بود):
              iisreset /stop
              سپس فایل متابیس آن‌را در یک ادیتور متنی باز کنید. این فایل در آدرس زیر قرار دارد:
              C:\WINDOWS\system32\inetsrv\MetaBase.xml

              تگ مربوط به IIsMimeMap را یافته و خطوط فوق را دقیقا به همین صورتیکه ملاحظه می‌کنید به آن اضافه نمائید.



              و در آخر IIS را راه اندازی کنید:
              iisreset /start

              روش الف)
              این روش نیازی به stop و start وب سرور ندارد و به محض اضافه شدن، به صورت خودکار اعمال خواهد شد اما کمی طولانی‌تر است:
              کنسول IIS را باز کنید
              بر روی web sites کلیک راست کنید. (منظور بالاترین سطح ممکن است)
              گزینه properties‌ را انتخاب کرده و سپس به برگه http headers‌ مراجعه نمائید.
              در اینجا بر روی دکمه mime-types کلیک کرده و در صفحه باز شده باید تک تک موارد جدید را به صورت دستی وارد نمائید (در اینجا نیازی به ذکر نقطه مربوط به پسوند فایل نیست)



              لازم به ذکر است که این نوع mime-types به IIS7 اضافه شده‌اند.

              مطالب
              تبدیل خودکار استثنای HttpRequestValidationException به یک ModelError در ASP.NET MVC
              فرم هایی که اطلاعاتی را از یک کاربر دریافت کرده و به سمت سرور Post می‌کنند، از مهمترین اجزای لاینفک یک وب سایت می‌باشند. بی شک همه‌ی ما از چنین فرمهایی حتی در یک پروژه‌ی هرچند کوچک استفاده کرده‌ایم. ممکن است هنگام ارسال این فرمها، کاربری شیطنت به خرج داده و درون یکی از فیلدهای فرم، از عبارت‌های HTML و یا یک اسکریپت استفاده کرده باشد. در ASP.Net + MVC از مکانیزم ValidationRequest برای مقابله با چنین حملاتی (XSS) استفاده شده است.
              یک فرم با یک Textbox در یک صفحه قرار دهید و درون Textbox یک تگ HTML بنویسید و آنرا به سرور ارسال کنید، در حالت پیش فرض اتفاقی که خواهد افتاد اینست که با یک صفحه‌ی خطا روبرو خواهید شد که به شما هشدار می‌دهد داده‌های ارسال شده، دارای مقادیر غیرمجازی می‌باشند. شما می‌توانید این مکانیزم اعتبارسنجی-امنیتی را غیرفعال کنید. برای غیرفعال کردن آن هم در لینکی که در فوق معرفی گردید توضیحات کافی داده شده است. ولی توصیه میشود برای جلوگیری از حملات XSS هیچگاه این مکانیزم را غیرفعال نکنید، مگر اینکه هیچ داده‌ای را بدون Encode کردن در صفحه نمایش ندهید.
              راه‌های زیادی برای هندل کردن این خطا و مطلع کردن کاربر وجود دارند و معمولا از صفحه‌ی خطای سفارشی برای اینکار استفاده میشود. اما ایده‌ی بهتری نیز برای مقابله با این خطا وجود دارد!
              فرض کنید اطلاعات فرم شما از طریق Ajax به سرور ارسال می‌شود و نتیجه بصورت Json به مروگر برگشت داده می‌شود. در حالت معمول در صورت رخ دادن خطای فوق، سرور کد 500 را برگشت می‌دهد و تنها راه هندل کردن آن در رویداد error شئ Ajax شما می‌باشد؛ آن‌هم با یک پیغام ساده. ولی من ترجیح می‌دهم به جای صادر کردن خطای 500، در صورت وقوع این خطا آن‌را بصورت یک خطای ModelState به کاربر نمایش دهم. به نظر من این‌کار وجهه‌ی بهتری دارد و ضمنا لازم نیست در هر رویدادی این خطا را هندل کنید. برای رسیدن به این هدف هم چندین راه وجود دارد که ساده‌ترین آن‌ها اینست که یک ModelBinder سفارشی ایجاد کنید و با هندل کردن این خطا، یک پیام خطا را به ModelState اضافه کنید و بعد به MVC بگویید که از این ModelBinder برای پروژه‌ی من استفاده کن. با این روش هرگاه کاربر داده‌ای حاوی کدهای HTML درون فیلدهای فرم وارد کرده باشد، بدون هیچ کار اضافه‌ای وضعیت ModelState شما Invalid می‌شود و خطای مدل به کاربر نمایش داده خواهد شد.
              ابتدا کلاسی برای ModelBinder سفارشی خود ایجاد کنید و از کلاس DefaultModelBinder ارث بری کنید. سپس با بازنویسی متد BindModel آن منطق خود را پیاده سازی کنید:
              using System.Web;
              using System.Web.Mvc;
              using System.Web.Helpers;
              using System.Globalization;
              
              namespace Parsnet
              {
                  public class ParsnetModelBinder : DefaultModelBinder
                  {
                      public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
                      {
                          try
                          {
                              return base.BindModel(controllerContext, bindingContext);
                          }
                          catch (HttpRequestValidationException ex)
                          {
                              var modelState = new ModelState();
                              modelState.Errors.Add("اطلاعات ارسالی شما دارای کدهای HTML می‌باشند.");
                              var key = bindingContext.ModelName;
                              var value = controllerContext.RequestContext.HttpContext.Request.Unvalidated().Form[key];
                              modelState.Value = new ValueProviderResult(value, value, CultureInfo.InvariantCulture);
                              bindingContext.ModelState.Add(key, modelState);
                          }
              
                          return null;
                      }
                  }
              }

              در این کلاس ابتدا سعی میکنیم بطور عادی کار را به متد BindModel کلاس پایه بسپاریم. اگر داده‌های ارسال شده حاوی کد HTML نباشد، بدون هیچ خطایی Model Binding صورت می‌گیرد. ولی در صورتیکه کاربر در فیلدی، از کدهای HTML استفاده کرده باشد، یک خطای HttpRequestValidationException  رخ خواهد داد که با هندل کردن آن هدف خود را تامین می‌کنیم.
              برای اینکار در قسمت catch بلوک مدیریت خطا، ابتدا یک نمونه از کلاس ModelState را میسازیم. بعد پیام خطای مورد نظر خود را به Errors‌های آن اضافه میکنیم. حال باید یک زوج کلید/مقدار برای این ModelState تعریف کنیم و به bindingContext اضافه کنیم. کلید ما در اینجا نام مدل جاری و مقدار آن هم نام فیلدی از فرم است که سبب بروز این خطا شده است.
              حالا نهایت کاری که باید انجام دهیم اینست که در رویداد Application_Start این مدل بایندیگ سفارشی را جایگزین مدل بایندیگ پیش فرض کنیم:
                  ModelBinders.Binders.DefaultBinder = new ParsnetModelBinder();

              کار تمام است. از حالا به بعد در صورتیکه کاربر در فیلدهای هر فرمی از سایت شما از کدهای HTML استفاده کند دیگر خطایی رخ نمی‌دهد و فقط ModelState در وضعیت Invalid قرار میگیرد که میتوانید با قرار دادن یک ValidationMessage یا ValidationSummary به راحتی خطا را به کاربر نشان دهید.
              نظرات مطالب
              ASP.NET MVC #18
              من دسترسی به کل محتوای سایت همانطور که فرمودید محدود کردم و به درستی بروی کنترلرها اعمال میشه اما بروی محتوای استاتیک ( پوشه Content,Scripts و ... ) اعمال نمیشه.
              میدونم که نباید برای این محتوا سطح دسترسی تعیین کرد اما میخوام بدونم مشکل از کجاست و چرا این درخواست‌ها مستقیم توسط IIS مدیریت میشن و کنترل به برنامه منتقل نمیشه.
              اصلا چرا نمیشه درخواست به این محتوا رو به یک کنترلر هدایت کرد؟