‫۱۰ سال و ۱۱ ماه قبل، یکشنبه ۲۶ آبان ۱۳۹۲، ساعت ۱۶:۰۹
من برای شرکتی چندسال قبل یک چنین برنامه‌ای رو تهیه کردم:
یک سرویس ویندوز ان تی که روزهای اول به پورت سریال دستگاه کارتخوان متصل می‌شد و بعدها این پورت تبدیل شد به پورت شبکه و ریموت هم می‌شد به آن وصل شد؛ اما باز هم این پورت شبکه تبدیلگری بود برفراز سیستم اصلی RS232 آن دستگاه. کار این سرویس که نیاز به دسترسی بالایی برای اتصال به پورت‌های سیستم داشت و همچنین همیشه در حال اجرا بود و راه اندازی آن نیازی به لاگین شخصی و اجرای دستی برنامه نداشت (مزیت سرویس‌های ویندوز ان تی)، اتصال هر 5 دقیقه یکبار به دستگاه کارتخوان، تخلیه اطلاعات آن و ثبت آن‌ها در بانک اطلاعاتی یک برنامه ASP.NET بود. به این ترتیب کارکنان آن سازمان می‌توانستند از ورود و خروج خودشان با یک برنامه تحت وب (در شبکه داخلی شرکت) گزارشگیری کنند.
‫۱۰ سال و ۱۱ ماه قبل، یکشنبه ۲۶ آبان ۱۳۹۲، ساعت ۱۵:۴۲
- easyhook کار global hooking را انجام نمی‌دهد؛ به ازای یک یا چند پروسه مشخص کار می‌کند.
- برای تغییر یک متن در حال نمایش در ویندوز عموما از هوک کردن متد ExtTextOutW استفاده می‌شود. خروجی این متد را در ویندوز XP راحت می‌شود تغییر داد. در ویندوز 7 به علت پیشرفته شدن خروجی‌های متنی و پشتیبانی از انواع و اقسام فرهنگ‌های مختلف، خروجی آن به صورت گلیف است و نه متن. یعنی به مقدار پارامتر fuOptions آن باید دقت داشت و اگر مساوی ETO_GLYPH_INDEX بود، تا جایی که تحقیق کردم قابل برگشت به متن یونیکد اصلی آن نیست (یا کار ساده‌ای نیست این پردازش). (قبل از اینکه از متد دریافت تاریخ استفاده کنم، سعی کردم از این روش کمک بگیرم و روی ویندوز XP جواب داد اما روی ویندوز 7 کار نکرد)
‫۱۰ سال و ۱۱ ماه قبل، شنبه ۲۵ آبان ۱۳۹۲، ساعت ۱۵:۰۱
return View نهایتا یک رشته را باز می‌گرداند که حاوی اطلاعات رندر شده نهایی یک View است. این رشته دریافتی (که فرمت HTML را دارد) دیگر فرمت JSON استاندارد را نخواهد داشت و در قسمت success قابل پردازش نیست. البته اگر به مثال‌ها دقت کنید، می‌شود توسط jQuery Ajax یک محتوای HTMLایی از پیش پردازش شده را هم دریافت و سپس آن‌را به صفحه اضافه کرد (نمونه‌اش function LoadEmployeeInfo در مطلب فوق است). اینکار باید در قسمت complete انجام شود. ضمنا بهتر است از return PartialView برای این نوع کارهای خاص Ajaxایی که HTML بر می‌گردانند، استفاده شود تا ارجاعی به فایل layout در این partial view بازگشتی وجود نداشته باشد.
‫۱۰ سال و ۱۱ ماه قبل، شنبه ۲۵ آبان ۱۳۹۲، ساعت ۱۳:۱۶
به متد protected override void Seed در مطلب جاری و همچنین قسمت‌های بعدی این بحث، دقت کنید.
‫۱۰ سال و ۱۱ ماه قبل، شنبه ۲۵ آبان ۱۳۹۲، ساعت ۰۱:۰۱
- نام این کتابخانه XML Worker هست. یعنی HTML شما باید معتبر باشد و تگ‌های آن همانند یک فایل XML درست تشکیل و باز و بسته شده باشند؛ چیزی مثل XHTML ها.
- می‌توانید از کتابخانه HTML Agility pack برای درست کردن XHTML استفاده کنید:
var sb = new StringBuilder(); 
var stringWriter = new StringWriter(sb);
var doc = new HtmlDocument
            {
                OptionOutputAsXml = true,
                OptionCheckSyntax = true,
                OptionFixNestedTags = true,
                OptionAutoCloseOnEnd = true,
                OptionDefaultStreamEncoding = Encoding.UTF8
            };
doc.LoadHtml(htmlContent);
doc.Save(stringWriter);
var xhtml = sb.ToString();
خاصیت OptionOutputAsXml آن‌را true کنید تا در حد توانش مشکلات HTML شما را برطرف و یک خروجی XHTML را تولید کند.
سایر مشکلات آن‌را بهتر است در mailing لیست آن‌ها به همراه ارائه مثال قابل بازتولیدی ارسال کنید.
‫۱۰ سال و ۱۱ ماه قبل، سه‌شنبه ۲۱ آبان ۱۳۹۲، ساعت ۱۶:۵۱
جهت تکمیل بحث، اگر مدل‌های برنامه به این صورت باشند (محل تولد اجباری است و Id کلید خارجی آن نال پذیر نیست؛ به همراه محل صدور اختیاری، که Id نال پذیر دارد):
    public class Place
    {
        public int Id { set; get; }
        public string Name { set; get; }

        public virtual ICollection<Person> Personnel { set; get; }
    }

    public class Person
    {
        public int Id { set; get; }
        public string FirstName { set; get; }
        public string LastName { set; get; }

        [ForeignKey("BirthPlaceId")]
        public virtual Place BirthPlace { set; get; }
        public int BirthPlaceId { set; get; }

        [ForeignKey("IssuanceLocationId")]
        public virtual Place IssuanceLocation { set; get; }
        public int? IssuanceLocationId { set; get; }
    }
با این Context :
public class MyContext : DbContext
    {
        public DbSet<Place> Places { get; set; }
        public DbSet<Person> Personnel { get; set; }

        public MyContext()
        {
            this.Database.Log = sql => Console.WriteLine(sql);
        }
    }
آنگاه خروجی کوئری ذیل (که یک include دارد روی خاصیت راهبری که مقدار Id کلید خارجی آن ممکن است نال باشد (محل صدور) و نه مورد دومی که Id غیرنال پذیر دارد (محل تولد))
context.Personnel.Include(x => x.IssuanceLocation)
معادل خواهد بود با (left outer join به صورت خودکار تشکیل شده)
SELECT
    [Extent1].[Id] AS [Id],
    [Extent1].[FirstName] AS [FirstName],
    [Extent1].[LastName] AS [LastName],
    [Extent1].[BirthPlaceId] AS [BirthPlaceId],
    [Extent1].[IssuanceLocationId] AS [IssuanceLocationId],
    [Extent2].[Id] AS [Id1],
    [Extent2].[Name] AS [Name],
    [Extent1].[Place_Id] AS [Place_Id]
    FROM  [dbo].[People] AS [Extent1]
    LEFT OUTER JOIN [dbo].[Places] AS [Extent2] ON [Extent1].[IssuanceLocationId] = [Extent2].[Id]

و خروجی کوئری زیر که DefaultIfEmpty را هم لحاظ کرده و join نویسی صریحی هم دارد (مطابق مقاله فوق):
var query = from personnel in context.Personnel
                            join issuanceLocation in context.Places on
                                  personnel.IssuanceLocationId equals issuanceLocation.Id into aIssuanceLocation
                            from IL in aIssuanceLocation.DefaultIfEmpty()
                            join birthLocation in context.Places on
                                  personnel.BirthPlaceId equals birthLocation.Id into aBirthLocation
                            from BL in aBirthLocation.DefaultIfEmpty()
                            select new
                               {
                                   personnel.Id,
                                   personnel.FirstName,
                                   personnel.LastName,
                                   IssuanceLocation = IL.Name,
                                   BirthLocation = BL.Name
                               };
معادل است با:
SELECT
                        [Extent1].[Id] AS [Id],
                        [Extent1].[FirstName] AS [FirstName],
                        [Extent1].[LastName] AS [LastName],
                        [Extent2].[Name] AS [Name],
                        [Extent3].[Name] AS [Name1]
                        FROM [dbo].[People] AS [Extent1]
                        LEFT OUTER JOIN [dbo].[Places] AS [Extent2] ON [Extent1].[IssuanceLocationId] = [Extent2].[Id]
                        INNER JOIN [dbo].[Places] AS [Extent3] ON [Extent1].[BirthPlaceId] = [Extent3].[Id]
و البته این خروجی دوم فقط در صورتی تشکیل می‌شود که قسمت select new ذکر شود. در غیراینصورت مشکل select n+1 را پیدا می‌کند و اصلا چنین join ایی تشکیل نخواهد شد (در یک حلقه، به ازای هر شخص، یکبار کوئری select به جدول مکان‌ها تشکیل می‌شود). همچنین یک inner join هم علاوه بر left outer join تشکیل شده (برای فیلد غیرنال پذیر).
حتی همین حالت دوم را هم با کوئری ذیل که از خواص راهبری استفاده کرده، می‌توان تولید کرد:
var query = context.Personnel.Select(x => new
             {
              x.Id,
              x.FirstName,
              x.LastName,
              BirthPlaceName = x.BirthPlace.Name,
              IssuanceLocationName = x.IssuanceLocation == null ? "" : x.IssuanceLocation.Name
             });
با این خروجی SQL (به صورت خودکار برای فیلد نال پذیر، left outer join و برای غیر نال پذیر inner join تشکیل داده)
SELECT
    [Extent1].[Id] AS [Id],
    [Extent1].[FirstName] AS [FirstName],
    [Extent1].[LastName] AS [LastName],
    [Extent2].[Name] AS [Name],
    CASE WHEN ([Extent3].[Id] IS NULL) THEN N'' ELSE [Extent3].[Name] END AS [C1]
    FROM   [dbo].[People] AS [Extent1]
    INNER JOIN [dbo].[Places] AS [Extent2] ON [Extent1].[BirthPlaceId] = [Extent2].[Id]
    LEFT OUTER JOIN [dbo].[Places] AS [Extent3] ON [Extent1].[IssuanceLocationId] = [Extent3].[Id]
‫۱۰ سال و ۱۱ ماه قبل، دوشنبه ۲۰ آبان ۱۳۹۲، ساعت ۱۷:۲۰
- از RenderBody در فایل layout باید استفاده شود و نه در یک فایل View.
- runat server چرا؟ این MVC هست نه وب فرم.
- در MVC می‌شود به ازای یک صفحه چندین فرم داشت که هر کدام به اکشن متد و کنترلر خاصی اشاره می‌کنند. فرق دارد با وب فرم‌های تک فرمه.
- در MVC نباید یک فرم را به صورت کلی در فایل layout قرار داد. باید در جای مناسب در View مرتبط قرار گیرد آن‌هم با ذکر Html.BeginForm تا action فرم به صورت خودکار به اکشن متد متناظر در کنترلری خاص هدایت شود. آن هم قسمت کوچکی از صفحه و نه post کل صفحه به سرور؛ برخلاف وب فرم‌ها (MVC بهینه‌تر عمل می‌کند از این لحاظ و حجم کمتری را به سرور ارسال می‌کند). اگر فرمی action نداشته باشد، الزامی ندارد که حتما به اکشن متد مدنظر شما هدایت شود. در این حالت محتویات آن به آدرس جاری صفحه ارسال می‌شوند (یعنی اکشن متد پیش فرض تعریف شده در مسیریابی سایت).
- زمانی اجزای فرم در Url به صورت کوئری استرینگ نمایان می‌شوند که متد ارسال اطلاعات Get باشد و نه FormMethod.Post (اگر نحوه ارسال اطلاعات صریحا ذکر نشود، از حالت Get استفاده می‌شود).