نظرات اشتراک‌ها
معرفی کتابخانه‌ی DNTCaptcha.Core
سلام وقت بخیر 
بنده از این کپچا دروبسایت خودم استفاده کردم ، از آنجاییکه که این کپچا از کوکی برای نگه داشتن مقدار استفاده میکنه ، در بعضی از سیستم‌های مشتریانم با خطا مواجه شدم که پس از بررسی متوجه شدم که کوکی مربوط به کپچا در لود صفحه ایجاد نمیشه و همین باعث میشه که نتونن لاگین بشن . مشکل چیه و چطور قابل حله ؟؟
سپاس
نظرات مطالب
نحوه صحیح تولید Url در ASP.NET MVC
سلام و خسته نباشید خدمت شما آقای نصیری. وبلاگتون واقعا مفید و عالیه
ممنون از زحماتتون بابت مطالبی که به اشتراک میگذارید
یه سوال از خدمتتون داشتم
من روی یه پروژه MVC کار میکنم. به این صورت کار کردم که یک View کلی دارم که توی اون نمایش اطلاعات و "ایجاد" و "حذف" و "ویرایش" همه یکجا انجام میشن. این View را کاملا با Jquery کار کردم و Insert , Update , Delete  کلا توسط Jquery انجام میشه. اما توی یکی از Viewهای دیگه که Strongly Type هم هستش، نمیخام به طور کامل از Jquery استفاده کنم. به این صورت که من اطلاعات جدول مربوطه رو توسط Jquery از پایگاه داده میگیرم و در یک گرید نمایش میدم. توی این گرید برای هر ردیف دوتا لینک "حذف" و "ویرایش" وجود داره. برای حذف هم با Jquery کارمو انجام میدم. اما برای "ایجاد" یک فرم از نوع فرم‌های MVC دارم که داخل یه dialog از نوع Jquery قرارشون دادم. برای ایجاد هم مشکلی نیست. اما برای ویرایش، نمیدونم که چطوری باید اطلاعات رو از پایگاه داده لود کنم که خودش مستقیما داخل TextBox‌ها قرار بگیره. البته توسط Jquery اومدم تک تک textbox‌ها رو به صورت زیر مقدار دادم. حالا نمیدونم کارم درسته یا روش بهتری هست واسه این کار. اگر نیاز هست تا سورس برنامه رو واستون بفرستم
function editmode(val) {
        $.ajax({ url: "/User/SelectUser", data: { Username: val }, type: "post", dataType: "json", success: function (data) {
            if (data != "timeout") {
                if (data.isRedirect) { window.location.href = data.redirectUrl; return; }
                try {
                    $("#dvEdit").dialog({ modal: 'true', title: 'ویرایش', hide: 'clip' });
                    //alert($("#dvEdit").html());

                    $("#UsernameEdit").val(data.Username);
                    $("#FirstNameEdit").val(data.FirstName);
                    $("#LastNameEdit").val(data.LastName);
                    $("#NationalCodeEdit").val(data.NationalCode);
                    $("#EmailEdit").val(data.Email);
                    $("#PhoneNoEdit").val(data.PhoneNo);
                    $("#MobileNoEdit").val(data.MobileNo);
                    $("#CreationDateEdit").val(data.CreationDate);
                    $("#CreationDateEdit").prop('disabled', true);
                    $("#LastActivityDateEdit").val(data.LastActivityDate);
                    $("#LastActivityDateEdit").prop('disabled', true);
                    $("#LastLoginDateEdit").val(data.LastLoginDate);
                    $("#LastLoginDateEdit").prop('disabled', true);
                    $("#IsLockedOutEdit").val(data.IsLockedOut);
                    $("#AddressEdit").val(data.Address);


                }
                catch (err) {
                    $("#dverr").show(); $("#lblErr").html(err);
                }
            }
            else
                AjaxTimeout();
        }
        , error: function (req, textstatus, errorthrown) { AjaxError(req, textstatus, "#dverr", "#lblErr"); }
        , complete: function (xhr, e) { AjaxComplete(xhr, "#dverr", "#lblErr"); }
        });
    }

نظرات مطالب
در مورد ادامه ...
سلام آقای نصیری عزیز
واقعــــــــــــا جای تشکر داره این همه زحمته بدون چشم داشت
خسته نباشید.
دو نظر داشتم راجب سیستم جدید:
1- چه خوب میشه اگه جز این قسمت نظرات که ما میتونیم باهاتون ارتباط برقرار کنیم، یه فرم ارتباطی هم بزارید که مطمئن باشیم در اسرع وقت پیاممون بهتون میرسه ( البته شما همیشه اینقدر لطف دارید که نظرات رو هم زود به زود چک میکنید)
2- امکان گرفتن خروجی PDF که توی سیستم‌های مدیریت محتوا هست رو اگه بشه اینجا پیاده کنید خیلی مفید میشه.
3- خیلی ماهید :)
بازم ممنون
مطالب
نحوه نمایش فیلدهای تصویری و همچنین بارگذاری تصاویر از مسیری مشخص در PdfReport
عموما برای نمایش تصاویر در گزارشات، یکی از دو حالت زیر وجود دارد:
الف) مسیر تصاویر موجود در فایل سیستم، در بانک اطلاعاتی ذخیره شده‌اند و قرار است گزارش نهایی در ستونی مشخص شامل این تصاویر باشد.
ب) محتوای بایناری تصاویر در خود بانک اطلاعاتی ذخیره شده‌اند و نیاز است آن‌ها را در گزارشات نمایش دهیم.

هر دو حالت فوق در PdfReport پشتیبانی می‌شوند و در ادامه نحوه انجام این موارد را بررسی خواهیم کرد.

الف) بارگذاری تصاویر از فایل سیستم

ابتدا مدل زیر را در نظر بگیرید:
namespace PdfReportSamples.Models
{
    public class ImageRecord
    {
        public int Id { set; get; }
        public string ImagePath { set; get; }
        public string Name { set; get; }
    }
}
توسط آن تعدادی رکورد را که ImagePath آن‌ها فایل‌هایی بر روی سیستم هستند، خواهیم ساخت:
using System;
using System.Collections.Generic;
using iTextSharp.text.pdf;
using PdfReportSamples.Models;
using PdfRpt.Core.Contracts;
using PdfRpt.FluentInterface;

namespace PdfReportSamples.ImageFilePath
{
    public class ImageFilePathPdfReport
    {
        public IPdfReportData CreatePdfReport()
        {
            return new PdfReport().DocumentPreferences(doc =>
            {
                doc.RunDirection(PdfRunDirection.RightToLeft);
                doc.Orientation(PageOrientation.Portrait);
                doc.PageSize(PdfPageSize.A4);
                doc.DocumentMetadata(new DocumentMetadata { Author = "Vahid", Application = "PdfRpt", Keywords = "Test", Subject = "Test Rpt", Title = "Test" });
            })
            .DefaultFonts(fonts =>
            {
                fonts.Path(AppPath.ApplicationPath + "\\fonts\\irsans.ttf",
                                  Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\verdana.ttf");
            })
            .PagesFooter(footer =>
            {
                footer.DefaultFooter(DateTime.Now.ToString("MM/dd/yyyy"));
            })
            .PagesHeader(header =>
            {
                header.DefaultHeader(defaultHeader =>
                {
                    defaultHeader.ImagePath(AppPath.ApplicationPath + "\\Images\\01.png");
                    defaultHeader.Message("گزارش جدید ما");
                });
            })
            .MainTableTemplate(template =>
            {
                template.BasicTemplate(BasicTemplate.SnowyPineTemplate);
            })
            .MainTablePreferences(table =>
            {
                table.ColumnsWidthsType(TableColumnWidthType.Relative);
            })
            .MainTableDataSource(dataSource =>
            {
                var listOfRows = new List<ImageRecord>
                                             {
                                                 new ImageRecord
                                                     {
                                                         Id=1,
                                                         ImagePath =  AppPath.ApplicationPath + "\\Images\\01.png",
                                                         Name = "Rnd"
                                                     },
                                                 new ImageRecord
                                                     {
                                                         Id=2,
                                                         ImagePath =  AppPath.ApplicationPath + "\\Images\\02.png",
                                                         Name = "Bug"
                                                     },
                                                 new ImageRecord
                                                     {
                                                         Id=3,
                                                         ImagePath =  AppPath.ApplicationPath + "\\Images\\03.png",
                                                         Name = "Stuff"
                                                     },
                                                 new ImageRecord
                                                     {
                                                         Id=4,
                                                         ImagePath =  AppPath.ApplicationPath + "\\Images\\04.png",
                                                         Name = "Sun"
                                                     }
                                             };
                dataSource.StronglyTypedList(listOfRows);
            })
            .MainTableColumns(columns =>
            {
                columns.AddColumn(column =>
                {
                    column.PropertyName("rowNo");
                    column.IsRowNumber(true);
                    column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                    column.IsVisible(true);
                    column.Order(0);
                    column.Width(1);
                    column.HeaderCell("ردیف");
                });

                columns.AddColumn(column =>
                {
                    column.PropertyName<ImageRecord>(x => x.Id);
                    column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                    column.IsVisible(true);
                    column.Order(1);
                    column.Width(3);
                    column.HeaderCell("شماره");
                    column.ColumnItemsTemplate(t => t.Barcode(new Barcode39()));
                });

                columns.AddColumn(column =>
                {
                    column.PropertyName<ImageRecord>(x => x.ImagePath);
                    column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                    column.IsVisible(true);
                    column.Order(2);
                    column.Width(3);
                    column.HeaderCell("تصویر");
                    column.ColumnItemsTemplate(t => t.ImageFilePath(defaultImageFilePath: string.Empty, fitImages: false));
                });

                columns.AddColumn(column =>
                {
                    column.PropertyName<ImageRecord>(x => x.Name);
                    column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                    column.IsVisible(true);
                    column.Order(3);
                    column.Width(2);
                    column.HeaderCell("نام");
                });
            })
            .MainTableEvents(events =>
            {
                events.DataSourceIsEmpty(message: "There is no data available to display.");
            })
            .Export(export =>
            {
                export.ToExcel();
                export.ToXml();
            })
            .Generate(data => data.AsPdfFile(AppPath.ApplicationPath + "\\Pdf\\RptImageFilePathSample.pdf"));
        }
    }
}

توضیحات:
- در متد MainTableDataSource، یک سری رکورد دلخواه را بر اساس تعدادی تصویر مشخص ایجاد کرده‌ایم. این تصاویر در پوشه bin\images مثال‌های PdfReport قرار دارند. سپس آن‌ها را توسط متد dataSource.StronglyTypedList، در اختیار PdfReport قرار داده‌ایم.
- در مرحله بعد، توسط متد MainTableColumns، ستون‌های دلخواه گزارش را ایجاد کرده‌ایم.
دو نکته در اینجا مهم هستند:
الف) برای نمایش یک تصویر از فایل سیستم، فقط کافی است از ColumnItemsTemplate متناظر با آن استفاده کرد (حالت پیش فرض، نمایش متنی اطلاعات است). برای نمونه قالب پیش فرض ImageFilePath به نحو زیر قابل استفاده است:
 column.ColumnItemsTemplate(t => t.ImageFilePath(defaultImageFilePath: string.Empty, fitImages: false));
در اینجا در آرگومان اول آن می‌توان مسیر تصویری را مشخص کرد که در صورت موجود نبودن تصویر مشخص شده در منبع داده، بهتر است نمایش داده شود. اگر string.Empty وارد شد، از این مورد صرفنظر خواهد شد. آرگومان دوم آن مشخص می‌کند که آیا تصویر نمایش داده شده باید با ابعاد سلول متناظر با آن هماهنگ شده و نمایش داده شود یا خیر.
ب) در کتابخانه iTextSharp که پایه PdfReport است، امکان تهیه بارکد هم وجود دارد. برای مثال این بارکدها توسط قالب زیر، قابل استفاده خواهند شد:
 column.ColumnItemsTemplate(t => t.Barcode(new Barcode39()));
تصویری از حاصل این گزارش را در ذیل مشاهده می‌کنید:


ب) بارگذاری محتوای تصاویر از بانک اطلاعاتی

ابتدا کدهای کامل این مثال را در نظر بگیرید:
using System;
using PdfRpt.Core.Contracts;
using PdfRpt.FluentInterface;

namespace PdfReportSamples.DbImage
{
    public class DbImagePdfReport
    {
        public IPdfReportData CreatePdfReport()
        {
            return new PdfReport().DocumentPreferences(doc =>
            {
                doc.RunDirection(PdfRunDirection.RightToLeft);
                doc.Orientation(PageOrientation.Portrait);
                doc.PageSize(PdfPageSize.A4);
                doc.DocumentMetadata(new DocumentMetadata { Author = "Vahid", Application = "PdfRpt", Keywords = "Test", Subject = "Test Rpt", Title = "Test" });
            })
             .DefaultFonts(fonts =>
             {
                 fonts.Path(AppPath.ApplicationPath + "\\fonts\\irsans.ttf",
                            Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\verdana.ttf");
             })
             .PagesFooter(footer =>
             {
                 footer.DefaultFooter(DateTime.Now.ToString("MM/dd/yyyy"));
             })
             .PagesHeader(header =>
             {
                 header.DefaultHeader(defaultHeader =>
                 {
                     defaultHeader.ImagePath(AppPath.ApplicationPath + "\\Images\\01.png");
                     defaultHeader.Message("گزارش جدید ما");
                 });
             })
             .MainTableTemplate(template =>
             {
                 template.BasicTemplate(BasicTemplate.AutumnTemplate);
             })
             .MainTablePreferences(table =>
             {
                 table.ColumnsWidthsType(TableColumnWidthType.FitToContent);
             })
             .MainTableDataSource(dataSource =>
             {
                 dataSource.GenericDataReader(
                   providerName: "System.Data.SQLite",
                   connectionString: "Data Source=" + AppPath.ApplicationPath + "\\data\\blogs.sqlite",
                   sql: @"SELECT [url], [name], [NumberOfPosts], [AddDate], [thumbnail]
                               FROM [tblBlogs]
                               WHERE [NumberOfPosts]>=@p1",
                   parametersValues: new object[] { 10 }
               );
             })
             .MainTableEvents(events =>
             {
                 events.DataSourceIsEmpty(message: "There is no data available to display.");
             })
             .MainTableSummarySettings(summary =>
             {
                 summary.OverallSummarySettings("جمع کل");
                 summary.PreviousPageSummarySettings("نقل از صفحه قبل");
             })
             .MainTableColumns(columns =>
             {
                 columns.AddColumn(column =>
                 {
                     column.PropertyName("rowNo");
                     column.IsRowNumber(true);
                     column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                     column.IsVisible(true);
                     column.Order(0);
                     column.HeaderCell("ردیف");
                 });

                 columns.AddColumn(column =>
                 {
                     column.PropertyName("url");
                     column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                     column.IsVisible(true);
                     column.Order(1);
                     column.HeaderCell("آدرس");
                 });

                 columns.AddColumn(column =>
                 {
                     column.PropertyName("name");
                     column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                     column.IsVisible(true);
                     column.Order(2);
                     column.HeaderCell("نام");
                 });

                 columns.AddColumn(column =>
                 {
                     column.PropertyName("NumberOfPosts");
                     column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                     column.IsVisible(true);
                     column.Order(3);
                     column.HeaderCell("تعداد پست");
                     column.ColumnItemsTemplate(template =>
                     {
                         template.TextBlock();
                         template.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj));
                     });
                     column.AggregateFunction(aggregateFunction =>
                     {
                         aggregateFunction.NumericAggregateFunction(AggregateFunction.Sum);
                         aggregateFunction.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj));
                     });
                 });

                 columns.AddColumn(column =>
                 {
                     column.PropertyName("AddDate");
                     column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                     column.IsVisible(true);
                     column.Order(4);
                     column.HeaderCell("تاریخ ثبت");
                     column.ColumnItemsTemplate(template =>
                     {
                         template.TextBlock();
                         template.DisplayFormatFormula(obj => obj == null ? string.Empty : ((DateTime)obj).ToString("dd/MM/yyyy HH:mm"));
                     });
                 });

                 columns.AddColumn(column =>
                 {
                     column.PropertyName("thumbnail");
                     column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                     column.IsVisible(true);
                     column.Order(5);
                     column.HeaderCell("تصویر");
                     column.ColumnItemsTemplate(t => t.ByteArrayImage(defaultImageFilePath: string.Empty, fitImages: false));
                 });
             })
             .Export(export =>
             {
                 export.ToXml();
                 export.ToExcel();
             })
             .Generate(data => data.AsPdfFile(AppPath.ApplicationPath + "\\Pdf\\RptDbImageSample.pdf"));
        }
    }
}

توضیحات:
بانک اطلاعاتی SQLite موجود در پوشه bin\data سورس PdfReport، حاوی فیلدی است به نام thumbnail که در آن محتوای یک سری تصویر ذخیره شده‌اند.
در اینجا توسط کوئری زیر قصد داریم این اطلاعات را خوانده و نمایش دهیم:
SELECT [url], [name], [NumberOfPosts], [AddDate], [thumbnail]
FROM [tblBlogs]
WHERE [NumberOfPosts]>=@p1
همانطور که ملاحظه می‌کنید، در اینجا نیز تنها کافی است قالب ستون مرتبطی را انتخاب کنیم:
column.ColumnItemsTemplate(t => t.ByteArrayImage(defaultImageFilePath: string.Empty, fitImages: false));
قالب ByteArrayImage، اطلاعات باینری فیلد thumbnail را خوانده و تبدیل به تصاویر قرار داده شده در فایل گزارش نهایی می‌کند. پارامترهای آن، با پارامترهای قالب ImageFilePath که پیشتر توضیح داده شد، یکی هستند. 
مطالب
پیاده سازی Basic Authentication در ASP.NET MVC
در سیستم‌های اتصال از راه دور به خصوص اتصال تلفن‌های همراه به وب سرویس، یکی از مواردی که مرتبا قبل از هر درخواستی بررسی میگردد، صحت نام کاربری و کلمه عبور درخواستی است. در این روش کاربر، الزامات امنیتی (نام کاربری و کلمه عبور) را در بدنه درخواست قرار داده و هر api باید قبل از انجام عملیات، صحت آن را بررسی کند. این مورد باعث میشود که کدها از حالت بهینه خارج شده و در سمت سرور، Api مربوطه باید صحت آن را بررسی کند. در این مقاله قصد داریم با پیاده سازی Basic Authentication این مشکل را رفع کرده تا به کد یکدست‌تری برسیم. Basic Authentication طبق گفته ویکی پدیا در واقع یک روش در درخواست‌های ارسالی http میباشد که با فراهم سازی الزامات امنیتی، درخواست خود را به سرور ارائه میدهد. در این روش نام کاربری و کلمه عبور به جای ارسال در بدنه درخواست، در هدر درخواست قرار گرفته و الزامات امنیتی به صورت رمزگذاری شده (عموما Base64) به سمت سرور ارسال می‌شوند.
این روش به دلیل عدم وجود ذخیره کوکی، ایجاد Session و دیگر مباحث امنیتی، جز ساده‌ترین روش‌های تشخیص هویت میباشد و همچنین مشخص است به دلیل رمزگذاری ساده‌ای چون Base64 و همچنین در صورت ارسال از طریق http نه https، حفاظت چندانی در ارسال الزامات امنیتی ندارند. ولی عموما برای گوشی‌های همراه تا حد زیادی قابل قبول است. همچنین در این روش مکانیزم logout فراهم نیست و تنها در طی یک درخواست پردازش اطلاعات انجام شده و بعد از آن هویت شما نابود خواهد شد.

برای ارسال اطلاعات در هدر درخواستی، به شیوه زیر اطلاعات را ارسال میکنیم:
Authorization: Basic  Username:Password
از آنجا که گفتیم اطلاعات بالا بهتر هست در قالب خاصی رمزگذاری (encoding) شوند، خط بالا به صورت نهایی، به شکل زیر خواهد بود:
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
از آنجا که این کد اعتبارسنجی باید مرتبا بررسی شود، باعث میشود که اصل تک مسئولیتی اکشن زیر سوال رفته و کدها در ابتدا مرتبا تکرار شوند. این وظیفه را بر عهده Attribute ‌ها میگذاریم. در Attribute‌های موجود در سیستم دات نت، می‌توان به AuthorizationFilterAttribute اشاره کرد که امکانات Authorization را در اختیار ما قرار میدهد. کد زیر را برای آن وارد میکنیم:
public class BasicAuthetication:AuthorizationFilterAttribute
    {
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            if (actionContext.Request.Headers.Authorization == null)
            {
                SayYouAreUnAuthorize(actionContext);
                return;
            }

            var param = actionContext.Request.Headers.Authorization.Parameter;
            var decodedCridential = Encoding.UTF8.GetString(Convert.FromBase64String(param));
            var splitedArray = decodedCridential.Split(':');
            if (splitedArray[0] == "username" && splitedArray[1] == "password")
            {
                var userId = 1;
                var genericIdentity=new GenericIdentity(userId.ToString());
                var genericPrincipal=new GenericPrincipal(genericIdentity,null);
                Thread.CurrentPrincipal = genericPrincipal;
                return;
            }
            SayYouAreUnAuthorize(actionContext);
        }

        private void SayYouAreUnAuthorize(HttpActionContext actionContext)
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);            
        }
    }

  در اولین خط از کد بررسی میشود که خاصیت Authorization در هدر درخواست وجود دارد یا خیر؛ در صورت که وجود نداشته باشد متد SayYouAreUnAuthorize  صدا زده میشود. این متد وظیفه دارد، در صورتیکه صحت نام کاربری و کلمه عبور تایید نشد، خطای مورد نظر را که با کد 401 شناخته میشود، بازگرداند که در متد اصلی دو بار مورد استفاده قرار گرفته است. با استفاده از این بازگردانی و دادن پاسخ کاربر، دیگر api مورد نظر به مرحله اجرا نمیرسد.

در صورتیکه کد ادامه پیدا کند، مقدار تنظیم شده Authorization را دریافت کرده و در خط بعدی آن را از حالت انکود شده خارج میکنیم. از آنجاکه الگوی ارسالی ما به شکل username:password میباشد، با استفاده از متد الحاقی Split هر دو عبارت را جدا کرده و در خط بعد، صحت آن دو را مشخص میکنیم. از آنجا که این تکه کد تنها یک تست است، من آن را به شکل ساده و استاتیک نوشته‌ام. بدیهی است که در یک مثال واقعی، این تایید صحت توسط یک منبع داده انجام می‌شود. در صورتی که صحت آن تایید نشود مجددا متد SayYouAreUnAuthorize مورد استفاده قرار میگیرد. در غیر این صورت باید این تایید هویت را در ترد جاری تایید کرده و حفظ کنیم و حتی در صورت لزوم Id کاربر و نقش‌های آن را ذخیره کنیم تا اگر api مورد نظر بر اساس آن تصمیم میگیرد، آن‌ها را در اختیار داشته باشیم. به عنوان مثال ممکن است اطلاعات دریافتی پرداختی‌های یک کاربر باشد که به UserId نیاز است.

از آنجا که در این روش نه ذخیره session و نه کوکی و نه مورد دیگری داریم و قصد داریم تنها در ترد یا درخواست جاری این اعتبار را نگه داریم، میتوانیم از thread.CurrentPrincipal استفاده کنیم. این خصوصیت نوع GenericPrincipal را نیاز دارد که دو پارامتر   GenereicIdentity و آرایه‌ای از نوع رشته را دریافت میکنید. این آرایه‌ها متعلق به زمانی است که شما قصد دارید نقش‌های یک کاربر را ارسال کنید و شیء GenericIdentity شیءایی است که شامل اطلاعات Authorization بوده و هیچ وابستگی به windows Domain ندارد. این شیء از شما تنها یک نام را به صورت رشته میگیرد که میتوانیم از طریق آن UserId را پاس کنیم. برای دریافت آن نیز داریم:
var userId=int.Parse(Thread.CurrentPrincipal.Identity.Name);
حال برای api به کد زیر نیاز داریم:
[BasicAuthetication]
        public HttpResponseMessage GetPayments(int type)
        {
            var userId = int.Parse(Thread.CurrentPrincipal.Identity.Name);
            if (type == 1)
            {
                return Request.CreateResponse(HttpStatusCode.OK, new
                {
                    Id = 4,
                    Price = 20000,
                    userId=userId
                });
            }
          
                return Request.CreateResponse(HttpStatusCode.OK, new
                {
                    Id = 3,
                    Price = 10000,
                    userId = userId
                });
            
        }

در api بالا attribute مدنظر بر روی آن اعمال شده و تنها مقادیر ورودی این api همان پارامترهای درخواست اصلی میباشد و ویژگی BasicAuthentication کدهای اعتبارسنجی را از کد اصلی دور نگه داشته است و api اصلی هیچگاه متوجه قضیه نمی‌شود و تنها کار اصلی خود را انجام می‌دهد. همچین در اینجا از طریق کلاس thread به UserId دسترسی داریم.

حال تنها لازم است کلاینت، قسمت هدر را پر کرده و آن را به سمت سرور ارسال کند. در اینجا من از نرم افزار I'm only resting استفاده میکنیم تا درخواست رسیده را در WebApi تست نمایم.


مسیرراه‌ها
الگوهای طراحی
الگوهای Gang Of Four

دسته تکوینی Creational
Abstract Factory
پیاده سازی Abstract Factory با جنریک ها
Buillder
Factory Method
ProtoType
Singleton
پشتیبانی توکار الگوی Singleton از دات نت 4 به بعد

دسته ساختاری Structural
Adapter
Bridge
Composite
Decorator
Facade
Flyweight
Proxy

دسته رفتاری Behavioral
Chain of Responsibility
Mediator
Command
Interpreter
Iterator
memento
Observer
State
Strategy
Template Method
Visitor

الگوهای همزمانی Concurrency Patterns

Active Object
Balking
Binding Properties
Double-Checked Locking
Event-Based Asyncronous
Guarded Suspension
Join
Lock
Monitor
Proactor
Reactor
ReadWrite Lock
Scheduler
Thread Pool
Thread-Local Storage

الگوهای معماری Architectural Pattern

Front Controller
Interceptor
MVC
MVP
n-Tier
Specification
Publish-Scribe
Service Locator
Active Record
Identity Map
Data Access Object
Data Transfer Object
ADR
Inversion Of Control 

 دیگر الگوها
Black Broad
  Business Delegate
Composite Entity
Dependency Injection
و یکی دیگر
Intercepting Filter
Lazy Loading
Mocking Object
Null Object
الگوی Special Case مکمل Null Object 
Object Pool
Servant
Tween
Type Tunnel
نظرات مطالب
Embed کردن SQL Server Express 2008 در یک برنامه
خواهش می‌کنم.
بله، بسته به سناریو می‌شود از پایگاه داده‌های سبکتر نیز استفاده کرد.
LocalDB متاسفانه محدودیت‌های زیادی دارد، مثلا در XP ساپورت نمی‌شود، فقط توسط Sql server 2012 management studio در دسترس هست که برای محصولات عمومی مناسب نیست. البته محل استفاده خاص خودش را دارد.
باز هم همه چیز به نحوه و محل استفاده بستگی دارد.
مطالب
breeze js به همراه ایجاد سایت آگهی قسمت سوم
در مطلب قبلی، پیش نیازهای مربوطه را نصب کردیم. در این قسمت به ساخت صفحات ورود و خروج، ثبت نام کاربران و تغییر رمز عبور خواهیم پرداخت.
در اینجا ما از Account Controller پیش فرض Asp.net Mvc استفاده میکنیم که متدهای مورد استفاده ما در آن قرار دارد و به BreezeController مزین شده است.
 [BreezeController]
    public class AccountController : ApiController
    {
      ...
    }

 اینترفیس IAuthService:
module Interfaces {
    export interface IAuthService {
        user: Models.IUserToken
        getUserInfo(accessToken);
        login(data);
        logOut();
        register(data);
        changePassword(data);
        accessToken(accessToken, data);
    }
}

سرویس AuthService 
پیاده سازی اینترفیس IAuthService را برعهده دارد. در سازنده آن، وابستگی‌های آن مقداردهی شده‌است و همچنین تنظیمات manager را انجام داده‌ایم.
متد accessToken: وظیفه ارسال توکن  را به سرور و همچنین نگهداری آن‌را در local storage، برعهده دارد.
متد getUserInfo: اطلاعات کاربر لاگین شده را  از سرور دریافت مینماید.
متد login: فرمت مورد قبول سرور به نحو زیر میباشد. در صورت موفقیت آمیز بودن، توکن را به متد accessToken  پاس میدهیم و آبجکت user را با مقادیر دریافتی پر می‌نماییم.
"grant_type=password & username=myusername & password=mypassword";
برای فراخوانی متدهای post، همانطوری که در مطلب ارسال کوئری‌های پست به آن اشاره شده‌است، عمل می‌نماییم. در ابتدا فایل breeze.ajaxpost.js را اضافه می‌کنیم سپس در فایل breeze.angular  قطعه کد زیر را در متد useNgHttp اضافه می‌کنیم.
var ajaxAdapter = breeze.config.getAdapterInstance("ajax");
breeze.ajaxpost(ajaxAdapter);
با این تنظیمات میتوانیم توسط withParameters، متدهای post را فراخوانی کنیم. 
.withParameters({
                    $method: 'POST',
                    $encoding: 'JSON',
                    $data: newData
                }
متد logOut: خروج از برنامه را برای ما انجام می‌دهد و درصورت موفقیت آمیز بودن، به صفحه اصلی هدایت می‌شود.
متد register: ثبت نام کاربران را بر عهده دارد.
متد changePassword: تغییر رمز عبور کاربران را برعهده دارد.
module AdApps {
    var securityUrls = {
        site: '/',
        login: '/token',
        logout: 'logout',
        register: 'register',
        userInfo: 'getUserInfo',
        changePassword: 'changePassword',
    }
    export class AuthService implements Interfaces.IAuthService {
        private manager: breeze.EntityManager;

        constructor(
            private _breeze: typeof breeze,
            private $http: ng.IHttpProvider,
            private toaster: ngtoaster.IToasterService,
            private $location: ng.ILocationService) {

            var dataService = new _breeze.DataService({
                serviceName: "/breeze/Account",
                hasServerMetadata: false
            });
            var metadataStore = new _breeze.MetadataStore({
                namingConvention: _breeze.NamingConvention.camelCase
            });
            this.manager = new _breeze.EntityManager({
                dataService: dataService,
                metadataStore: metadataStore,
                saveOptions: new _breeze.SaveOptions({
                    allowConcurrentSaves: true, tag: [{}]
                })
            });
        }

        user: Models.IUserToken;
        accessToken(accessToken, data): string {
            if (accessToken === 'clear') {
                localStorage.removeItem('accessToken');
                delete this.$http.defaults.headers.common.Authorization;
            }
            else {
                window.localStorage.setItem("accessToken", accessToken);
                this.$http.defaults.headers.common.Authorization = 'Bearer ' + accessToken;
            }
            return accessToken;
        }
        getUserInfo(): ng.IPromise<any> {
            var query = this._breeze.EntityQuery.from(securityUrls.userInfo);
            return this.manager.executeQuery(query).then(data => {
                return data.results[0];
            });
        }
        login(data: any): ng.IPromise<any> {
            var newData = "grant_type=password&username=" + data.userName + "&password=" + data.password;
            var query = this._breeze.EntityQuery.from(securityUrls.login)
                .withParameters({
                    $method: 'POST',
                    $encoding: 'JSON',
                    $data: newData
                });
            return this.manager.executeQuery(query).then(data => {
                var self = this;
                var result = data.results[0] as any;
                self.accessToken(result.access_token, data.results[0]);
                self.user = <Models.IUserToken>{};
                self.user = <Models.IUserToken>result;
                return result;
            });
        }
        logOut(): ng.IPromise<any> {
            var query = this._breeze.EntityQuery.from(securityUrls.logout)
                .withParameters({
                    $method: 'POST',
                    $encoding: 'JSON',
                });
            return this.manager.executeQuery(query).then(data => {
                this.user = null;
                this.accessToken('clear', null);
                this.$location.path("/");
            });
        }
        register(data: Object): ng.IPromise<any> {
            var query = this._breeze.EntityQuery.from(securityUrls.register)
                .withParameters({
                    $method: 'POST',
                    $encoding: 'JSON',
                    $data: data
                });
            return this.manager.executeQuery(query).then(data => { });
        }
        changePassword(data: Object): ng.IPromise<any> {
            var query = this._breeze.EntityQuery.from(securityUrls.changePassword)
                .withParameters({
                    $method: 'POST',
                    $encoding: 'JSON',
                    $data: data
                });
            return this.manager.executeQuery(query).then(data => { });
        }
    }
}

سرویس HttpInterceptor 
: رهگیری و پیگیری کردن نتیجه درخواست‌های http را بر عهده دارد.
درrequest : توکن امنیتی را به هدر درخواست‌ها اضافه میکنیم.
در response : در صورت موفقیت درخواست http، پیغام مناسبی را نمایش میدهیم.
در responseError : در صورت عدم موفقیت درخواست http، پیغام مناسبی را نمایش میدهیم.
module AdApps {
    export class HttpInterceptor {
        private static _toaster: ngtoaster.IToasterService;
        private static _$q: ng.IQService;
        constructor(
            private $q: ng.IQService,
            private toaster: ngtoaster.IToasterService,
            private $location: ng.ILocationService) {
            HttpInterceptor._toaster = toaster;
            HttpInterceptor._$q = $q;
        }
        request(config): string {
            config.headers = config.headers || {};
            var authData = window.localStorage.getItem("accessToken");
            if (authData) {
                config.headers.Authorization = "Bearer " + authData;
            }
            return config;
        };
        response(response): ng.IPromise<any> {
            if (response.data && response.data.message && response.status === 200) {
                HttpInterceptor._toaster.success(response.data.message)
            }
            return HttpInterceptor._$q.resolve(response);
        };
        responseError(response): ng.IPromise<any> {
            var self = this;
            var data = response.data;
            var title = "خطا";
            var messages = [];
            if (data) {
                if (data.error) {
                    title = data.error;
                }
                if (data.message) {
                    messages.push(data.message);
                }
                if (data.Message) {
                    messages.push(data.Message);
                }
                if (data.ModelState) {
                    angular.forEach(data.ModelState, function (errors, key) {
                        if (key.substr(0, 1) != "$")
                        { messages.push(errors); }

                    });
                }
                if (data.exceptionMessage) {
                    messages.push(data.exceptionMessage);
                }
                if (data.ExceptionMessage) {
                    messages.push(data.ExceptionMessage);
                }
                if (data.error_description) {
                    messages.push(data.error_description);
                }
                if (messages.length > 0) {
                    HttpInterceptor._toaster.error(title, messages.join("<br/>"));
                }
                if (response.status === "401") {
                    self.$location.path("/ورود");
                }
            }
            return HttpInterceptor._$q.reject(response);
        }
    }
}

معرفی کردن مسیرهای ورود، ثبت نام و تغییر رمز عبور به انگولار
module AdApps {
    class SecurityCtrl {
        constructor(private $scope: Interfaces.IAuthScope, private authService: AuthService) {
            $scope.authService = authService;
            if (window.localStorage.getItem("accessToken") != null) {
                authService.getUserInfo().then(function (data) {
                    $scope.authService.user = data;
                });
            }
            $scope.logOut = function () {
                return authService.logOut().then(function () { });
            }
        }
    }
    define(["angularAmd", "angular", "factory/AuthService", "factory/httpInterceptor"], (angularAmd, ng) => {
        angularAmd = angularAmd.__proto__;
        var app = ng.module("AngularTypeScript", ['ngRoute', 'breeze.angular', 'toaster']);
        var viewPath = "app/views/";
        var controllerPath = "app/controller/";
        app.config(['$routeProvider', '$httpProvider', function ($routeProvider, $httpProvider) {
            $httpProvider.interceptors.push("HttpInterceptor");
            $routeProvider
                .when("/", angularAmd.route({
                    templateUrl: viewPath + "home.html",
                    controllerUrl: controllerPath + "home.js"
                }))
                .when("/login", angularAmd.route({
                    templateUrl: viewPath + "login.html",
                    controllerUrl: controllerPath + "login.js"
                }))
                .when("/register", angularAmd.route({
                    templateUrl: viewPath + "register.html",
                    controllerUrl: controllerPath + "register.js"
                }))
                .when("/changePassword", angularAmd.route({
                    templateUrl: viewPath + "change-password.html",
                    controllerUrl: controllerPath + "changePassword.js"
                }))
                .otherwise({ redirectTo: '/' });
        }
        ]);
        app.service('AuthService', ['breeze', '$http', 'toaster', '$location', AuthService]);
        app.service("HttpInterceptor", ["$q", "toaster", "$location", HttpInterceptor]);
        app.controller('SecurityCtrl', ['$scope', 'AuthService', SecurityCtrl]);
        return angularAmd.bootstrap(app);
    });
}

ایجاد کنترلر .login.ts و ارسال سرویس‌های لازم به کلاس LoginCtrl
در صورت صحیح بودن نام کاربری و رمز عبور به صفحه اصلی هدایت خواهد شد.
module AdApps {
    define(['app'], function (app) {
        app.controller('LoginCtrl', ["$scope", "AuthService", "$location", LoginCtrl]);
    });
   export  class LoginCtrl {
        constructor($scope: Interfaces.ILoginScope, authService: AuthService, $location: ng.ILocationService) {
           $scope.submit = function () {
               authService.login(angular.copy($scope.form))
                    .then(function (data) {
                        this.$location.path("/");
                    })
            };
        }
    }
}

ایجاد login.html
<div  ng-controller="LoginCtrl">
    <div>
        <i></i>
        <span>ورود</span>
        <div>
            <div>
            </div>
        </div>
    </div>
    <div>
        <div>
            <div>
                <form name="Form" id="form1">
                    <fieldset>
                        <div>
                            <div>
                                <input
                                       name="username"
                                       ng-model="form.userName"
                                       placeholder="نام کاربری"
                                       required>
                                <span>
                                    <i></i>
                                </span>
                            </div>
                        </div>
                        <div>
                            <div>
                                <input name="password"
                                       type="password"
                                       ng-model="form.password"
                                       placeholder="{{'Password'}}"
                                       validator="required">
                                <span>
                                    <i></i>
                                </span>
                            </div>
                        </div>

                    </fieldset>
                    <div>
                        <button type="submit" ng-click="submit()">ورود</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>
فایل‌های مربوط به ثبت نام و تغییر رمز عبور، مشابه لاگین می‌باشد و از ذکر آن خودداری می‌نماییم و فایل‌های مربوطه در پروژه قرار دارند.
با تغییرات بالا، فایل main.ts دارای محتویات زیر میباشد:
requirejs.config({
    paths: {
        "app": "app",
        "angularAmd": "/Scripts/angularAmd",
        "angular": "/Scripts/angular",
        "breezeAjaxpost": "/Scripts/breeze/breeze.ajaxpost",
        "breeze": "/Scripts/breeze/breeze.debug",
        "breezeAngular": "/Scripts/breeze/breeze.angular",
        "bootstrap": "/Scripts/bootstrap",
        "angularRoute": "/Scripts/angular-route",
        "jquery": "/Scripts/jquery-2.2.2",
        "entityManagerService": "factory/entityManagerService",
        "toaster": "/Scripts/toaster",
    },
    waitSeconds: 0,
    shim: {
        "angular": { exports: "angular" },
        "angularRoute": { deps: ["angular"] },
        "bootstrap": { deps: ["jquery"] },
        "breeze": { deps: ["jquery"] },
        "breezeAngular": {
            deps: ["angular", "breeze"]
        },
        "toaster": { deps: ["angular"] },
        "app": {
            deps: ["bootstrap", "angularRoute", "toaster", "breezeAngular", "breezeAjaxpost"]
        }
    }
});
require(["app"]);
فایل پروژه :AngularTypeScript.zip
در قسمت‌های بعدی به ثبت و نمایش آگهی در سایت خواهیم پرداخت.