نظرات مطالب
ASP.NET MVC #4
درود؛ دو سوال داشتم.
1)  هنگامی که من می‌خواستم یک View رو ایجاد کنم، فایل ایجاد شده برای من Index.ascx بود نه Index.cshtml. علت چی می‌تونه باشه؟
2) چرا وقتی در صفحه Index شروع به کد نویسی کردم، VS برای من ادامه دستورات رو نشون نمی‌داد؟ یعنی وقتی Ctrl+Space می‌زدم. من دستورات رو خودم نوشتم، یعنی:
 @{
ViewBag.....
مشکلی وجود دارد یا جز ویژگی‌های MVC محسوب میشود؟
نظرات مطالب
آشنایی با الگوی M-V-VM‌ - قسمت پنجم
دو نوع کلاس اینجا وجود دارند:
domain models : کلاس‌های معادل جداول و موجودیت‌های بانک اطلاعاتی
viewmodels : مقصود از این viewmodelها، کلاس مدل معادل عناصر بصری UI است و منظور viewmodel تعریف شده در MVVM نیست که دقیقا معادل Controller در MVC است.
بنابراین اگر domain model شما با مدل معادل view یکی است، همه رو یکجا هم می‌تونید تعریف کنید ولی عموما این‌ها یکی نیستند. بنابراین نیاز است بین این دو فرق گذاشت و در صورت نیاز نگاشت لازم را انجام داد.
نظرات نظرسنجی‌ها
آیا به یادگیری یا ادامه‌ی استفاده از AngularJS خواهید پرداخت؟
به نظرم در کنار ایراد هایی که به Angular وارد می‌شود در حال حاضر کامل‌ترین فریم ورک به همراه مستندات فراوان است . اگر بخواهیم فریم ورک دیگری انتخاب کنیم گزینه‌های موجود یا Emberjs است یا Backbone یا Reactjs که آخری صرفا یک View Layer در مدل MVC محسوب می‌شود . Emberjs هم در ورژن 2 تغییرات زیادی دارد . وقتی همه این موارد را به شخصه کنار هم می‌گذارم گزینه ای غیر از Angular وجود ندارد شاید بعد از آمدن ورژن 2 انگولار و emberjs بتوان بهتر تصمیم گیری کرد .
اشتراک‌ها
بررسی جزئیات ASP.NET Core 1.1 Preview 1

What’s new?

The following new features are available for preview in this release:

  • URL Rewriting middleware
  • Response caching middleware
  • Response compression middleware
  • WebListener server
  • View Components as Tag Helpers
  • Middleware as MVC filters
  • Cookie-based TempData provider
  • View compilation
  • Azure App Service logging provider
  • Azure Key Vault configuration provider
  • Redis and Azure Storage Data Protection Key Repositories 
بررسی جزئیات  ASP.NET Core 1.1 Preview 1
نظرات مطالب
رمزنگاری و رمزگشایی خودکار خواص مدل‌ها در ASP.NET Core
- آیا برای رندر یک partial view حتما باید return PartialView نوشت؟ خیر. همان return View هم در اینجا کار می‌کند.
- اگر اصرار به نوشتن return PartialView بود، یک سطر PartialViewResult زیر را اضافه کنید:
namespace EncryptedModelBinder.Utils
{
    public class EncryptedFieldResultFilter : ResultFilterAttribute
    {
        // ...

        public override void OnResultExecuting(ResultExecutingContext context)
        {
            var model = context.Result switch
            {
                PageResult pageResult => pageResult.Model, // For Razor pages
                ViewResult viewResult => viewResult.Model, // For MVC Views
                PartialViewResult partialViewResult => partialViewResult.Model, // For `return PartialView`
                ObjectResult objectResult => objectResult.Value, // For Web API results
                _ => null
            };
نظرات مطالب
ASP.NET MVC #9
سلام و خسته نباشید، شما در قسمت آخر گفتید که Id برای پیدا کردن بلاگ در پایگاه داده است، در سایت شما هنگامی که این ادرس وارد شود
https://www.dntips.ir/post/812/asp-net-ddddddddd وارد شود خود به خود وارد آدرس صحیح می‌شود یعنی https://www.dntips.ir/post/812/asp-net-mvc-9 سوالم این است که شما به جای return View از return RedirectToAction استفاده می‌کنید ؟؟
چون اگه return View بود آدرس همان آدرس اشتباه بود در url مرورگر، اگر از return RedirectToAction استفاده میکنید آیا این کار در سایت‌های دیگر هم مرسوم است ؟
نظرات مطالب
بررسی Bad code smell ها: دلال یا Middle Man
View Model در MVVM شبیه به کنترلرها در MVC هستند. این‌ها بالاترین لایه برنامه هستند که با تزریق امکانات دیگر سرویس‌های برنامه به آن‌ها امکان استفاده‌ی نهایی از آن‌ها فراهم می‌شود. بنابراین این‌ها بله ... دلال سرویس‌های برنامه به رابط کاربری آن هستند، اما با مفهوم فوق یکی نیستند. کار کنترلرها یا ViewModelها مدیریت و سامان دهی درخواست‌ها و هدایت آن‌ها به سرویس‌های متناظر، گاهی از اوقات ترکیب چند سرویس با هم و ارائه‌ی یک پاسخ به مصرف کننده نهایی است. بنابراین این‌ها واسط بین View برنامه و Model هستند و مدیریت کننده‌ی تعاملات با برنامه.
نظرات مطالب
ASP.NET MVC #8
- فراخوانی این متد کمکی به چه نحوی بوده؟ (اکشن متد آن که Model@ را مقدار دهی می‌کند و همچنین کدهای View فراخوان ذکر نشده)
- مثال اصلی بحث جاری از اینجا قابل دریافت است: MVC_Samples  
در کدهای پوشه MVC-08 به HomeController و متد Index آن دقت کنید (برای مقدار دهی مدل). همچنین در View فراخوان، در پوشه Views\Home، در فایل Index.cshtml، نحوه‌ی تعریف نوع مدل را توسط model@ و استفاده از مقدار آن‌را توسط Model@، بررسی کنید. (نوع مدل با m کوچک شروع می‌شود و مقدار مدل با M بزرگ)
نظرات مطالب
اهمیت Controller های ساده در ASP.NET MVC
Controller فقط مصرف کننده‌ی منطق نهایی است ، بدنه‌ی کنترلر‌ها جای مناسبی برای پیاده سازی منطق تجاری نیست. BL که شما از آن یاد می‌کنید در لایه‌ی دیگری رخ می‌دهد ، یکی اسم آم را Task می‌گذارد ، یکی Service و دیگری BlaBla ..
MVC جایگزینی برای N-Tier  نیست ، بلکه روشی برای سازماندهی لایه‌ی نمایش می‌باشد.
ViewModel‌ها  (ViewModel === Model Of View) اشیایی هستند که از طریق لایه‌ی سرویس تولید می‌شوند و در واقع داده ای که باید در View به کاربر نمایش داده شود را نگهداری می‌کنند.
نگرانی و مسئولیت Controller فراهم کردن داده  (از طریق اجرای Business logic) برای UI می‌باشد.
مطالب
breeze js به همراه ایجاد سایت آگهی قسمت دوم
نصب: پکیج‌های متنوعی از breeze وجود دارند. برای ما بسته‌ی زیر بهترین انتخاب می‌باشد. با نصب پکیج زیر، breeze در سمت سرور و کلاینت، به همراه ASP.NET Web API 2.2 and Entity Framework 6 نصب می‌شود:
Install-Package Breeze.WebApi2.EF6
بعد از نصب، دو فایل جاوا اسکریپتی به پروژه اضافه میشوند: breeze.debug.js  فایل اصلی breeze می‌باشد که از Backbone و Knockout پشتیبانی می‌کند و breeze.min.js که فایل فشرده شده breeze.debug میباشد. برای بهتر کار کردن با angularjs و breezejs، کتابخانه‌ی Breeze.Angular را  نصب نمایید. یکی از مواردی که این سرویس برای ما انجام می‌دهد،interceptor ایی را برای درخواست‌های http فعال می‌کند. یکی از موارد استفاده‌ی آن، ارسال token امنیتی، قبل از درخواست‌های breeze به کنترلر میباشد:
var instance = breeze.config.initializeAdapterInstance("ajax", "angular");
instance.setHttp($http);
Install-Package Breeze.Angular
 قلب تپنده‌ی breezejs در کلاینت EntityManager است که نقش data context را در کلاینت، بازی می‌کند. به برخی از خصوصیات آن می‌پردازیم:
  var manager = new breeze.EntityManager({  
  dataService: dataService,          
  metadataStore: metadataStore,                     
  saveOptions: new breeze.SaveOptions({    allowConcurrentSaves: true, tag: [{}] })   
                 });

var dataService = new breeze.DataService({  
serviceName: "/breeze/"+ "Automobile",             
hasServerMetadata: false,
namingConvention: breeze.NamingConvention.camelCase        
});
var metadataStore = new breeze.MetadataStore({});

- serviceName: نام سرویس دهنده یا کنترلر سمت سرور میباشد. درمورد کنترلر سمت سرور کمی جلوتر بحث می‌کنیم.
- metadataStore: اطلاعاتی را در مورد تمام آبجکت‌ها (جداول دیتابیس) می‌دهد. مثل نام فیلدها، نوع فیلدها و...
برای کار با متادیتا دو راه وجود دارد:
1- متا دیتا را خودتان در سمت کلاینت ایجاد نمایید:
var myMetadataStore = new breeze.MetadataStore();
myMetadataStore.addEntityType({...});
یا برای اضافه کردن فیلد شهر به جدول customer:
 var customer = function () {
                    this.City = "";
                };
myMetadataStore.registerEntityTypeCtor("Customer", customer);
2- اطلاعات  را از سرور دریافت  نمایید. در این صورت  کنترلر شما باید دارای متد Metadata باشد. بنابراین کنترلی را در سرور به نام Automobile و با محتویات زیر ایجاد نمایید. همانطور که مشاهده می‌کنید، این کنترلر از ApiController مشتق شده است که تفاوت خاصی با Api‌‌های دیگر ندارد و تنها به BreezeController مزین شده است. این attribute به NET WebApi  کمک میکند که فیلترینگ و مرتب سازی با فرمت oData را فراهم کند و همچنین درک صحیح فرمت json را نیز به کنترلر می‌دهد.
EFContextProvider: کامپوننتی که تعامل بین کنترلر breeze با Entity Framework را ساده‌تر می‌کند و در واقع یک  wrapper بر روی دیتاکانتکس یا آبجکت کانتکس می‌باشد. یکی از وظایف آن  ارسال متا دیتا، برای کلاینت‌های breeze است.
[BreezeController]
public class AutomobileController : ApiController
    {
        readonly EFContextProvider<ApplicationDbContext> _contextProvider =
        new EFContextProvider<ApplicationDbContext>();
        [HttpGet]
        public string Metadata()
        {
            return _contextProvider.Metadata();
        }
        [HttpGet]
        public IQueryable<Customer> Customers() {
           return _contextProvider.Context.Customers;
        }

        [System.Web.Http.HttpPost]
        public SaveResult SaveChanges(JObject saveBundle)
        {
           _contextProvider.BeforeSaveEntitiesDelegate = BeforeSaveEntities;
           _contextProvider.AfterSaveEntitiesDelegate = afterSaveEntities;
            return _contextProvider.SaveChanges(saveBundle);
        }
protected Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap)
        {
        }
private void afterSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap, List<KeyMapping> keyMappings)
        {
        }
    }
در اینجا متدی مانند Customers، از طریق کلاینت‌های breeze قابل دسترسی می‌باشد.

- saveOptions: نحوه‌ی چگونگی برخورد با ذخیره کردن اطلاعات را مشخص می‌کند. با ذخیره سازی تغییرات، متد SaveChanges سمت سرور فراخوانی می‌شود. در breeze می‌توان به قبل و بعد از ذخیره سازی اطلاعات دسترسی داشت. یکی از موارد رایج کاربرد آن، اعمال چک کردن دسترسی‌ها، قبل از ذخیره سازی می‌باشد.
برای ذخیره سازی تغییرات:
manger.saveChanges().then(function success() {
                    }, function failer(e) {
                    });
برای نادیده گرفتن تغییرات:
manger.rejectChanges()

کوئری:
بعد از تعریف Entity Manger می‌توانیم کوئری خود را اجرا نماییم. کوئری ما شامل گرفتن اطلاعات از جدول Customer، با مرتب سازی بر روی فیلد آیدی می‌باشد و با اجرا کردن کوئری می‌توانیم موفقیت یا عدم موفقیت آن‌را بررسی نماییم. 
   var query = breeze.EntityQuery
            .from("Customer")   
            .orderBy("Id");
   var result= manager.executeQuery(query);
   result.then(querySucceeded)
    .fail(queryFailed);

   query = query.where("Id", "==", 1)
با نوشتن Predicate تکی یا ترکیب آنها نیز می‌توان شرط‌های پیچیده‌تری را ایجاد کرد:
var predicate = new breeze.Predicate("Id", "==", false);
query = query.where(predicate)

var p1 = new breeze.Predicate("IsArchived", "==", false);
var p2 = breeze.Predicate("IsDone", "==", false); 
var predicate = p1.and(p2);
query = query.where(predicate).orderBy("Id")  
در اینجا خروجی مشابه زیر برای کنترلر ارسال میشود:
?$filter=IsArchived eq false&IsDone eq false  &$orderby=Id

اعتبارسنجی
:اعتبارسنجی در breeze، هم در سمت کلاینت و هم در سمت سرور امکان پذیر می‌باشد که در مثالی، در قسمت بعدی، validator سفارشی خودمان را خواهیم ساخت و به entity مورد نظر اعمال خواهیم کرد.
breeze دارای یک سری Validator در سطح پراپرتی‌ها است:
- برای انواع اقسام dataType ها مانند Int,string,..
- برای نیازهای رایجی چون: emailAddress,creditCard,maxLength,phone,regularExpression,required,url 
هم چنین در breeze امکان تغییر دادن اعتبارسنجی‌های پیش فرض نیز وجود دارند. برای مثال برای اینکه در فیلدهای required بتوان متن خالی هم وارد کرد، از دستور زیر می‌توان استفاده کرد:
breeze.Validator.required({ allowEmptyStrings: true });

ردیابی تغییرات
: هر آیتم Entity دارای EntityAspect است که وضعیت آن‌را مشخص می‌کند و می‌تواند یکی از وضعیت‌های Added،Modified،Deleted،Detached،Unchanged باشد. با مشخص کردن حالت هر آیتم، با فراخوانی SaveChanges تغییرات بر روی دیتابیس اعمال می‌گردد.
ایجاد آیتم جدید:
manager.createEntity('Customer', jsonValue);
 ویرایش اطلاعات:
manager.createEntity("Customer", jsonValue, breeze.EntityState.Modified, breeze.MergeStrategy.OverwriteChanges)
 حذف اطلاعات:
manager.createEntity("Customer", item, breeze.EntityState.Deleted)

برای اشنایی بیشتر با امکانات Breeze، قصد داریم یک سایت ایجاد آگهی را راه اندازی کنیم. پیش نیازهای ضروری این بخش typescript ،angularjs ،requirejs هستند. قصد داریم سایتی را برای آگهی‌های خرید و فروش خودرو، مشابه با سایت باما ایجاد نماییم:

امکانات این سایت:
- ثبت نام کاربران 
- ثبت آگهی توسط کاربران 
- ایجاد برچسب‌های آگهی‌ها 
- امتیاز دهی به آگهی‌ها
- جستجوی آگهی‌ها
- و....
ابتدا نصب پکیج‌های زیر 
Install-Package angularjs
Install-Package angularjs.TypeScript.DefinitelyTyped

Install-Package bootstrap
Install-Package bootstrap.TypeScript.DefinitelyTyped

Install-Package jQuery
Install-Package jquery.TypeScript.DefinitelyTyped

Install-Package RequireJS
Install-Package requirejs.TypeScript.DefinitelyTyped

bower install angularAMD

مدلهای برنامه:
ایجاد کلاس BaseEntity 
 public  class BaseEntity
    {
        public int Id { get; set; }
        public bool Status { get; set; }
        public DateTime CreatedDateTime { get; set; }
    }
ایجاد جدول آگهی
    public class Ad : BaseEntity
    {
        public string Title { get; set; }
        public float Price { get; set; }
        public double Rating { get; set; }
        public int? RatingNumber { get; set; }
        public string UserId { get; set; }
        public DateTime ModifieDateTime { get; set; }
        public string Description { get; set; }
        public virtual ICollection<Comment> Comments { get; set; }
        public virtual IdentityUser User { get; set; }
        public virtual ICollection<AdLabel> Labels { get; set; }
        public virtual ICollection<AdMedia> Medias { get; set; }
    }
ایجاد جدول برچسب 
public class Label 
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public int? ParentId { get; set; }
        public virtual Label Parent { get; set; }
        public virtual ICollection<Label> Items { get; set; }
    }
ایجاد جدول مدیا
 public class Media 
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string MimeType { get; set; }
    }
ایجاد جدول واسط برچسب‌های آگهی
  public class AdLabel
    {
        public int Id { get; set; }
        public virtual Ad Ad { get; set; }
        public virtual Label Label { get; set; }
        [Index("IX_AdLabel", 1, IsUnique = true)]
        public int AdId { get; set; }
        [Index("IX_AdLabel", 2, IsUnique = true)]
        public int LabelId { get; set; }
        public string Value { get; set; }
    }
ایجاد جدول واسط مدیا‌های مرتبط با آگهی
 public class AdMedia
    {
        public int Id { get; set; }
        public virtual Ad Ad { get; set; }
        public virtual Media Media { get; set; }
        [Index("IX_AdMedia", 1, IsUnique = true)]
        public int AdId { get; set; }
        [Index("IX_AdMedia", 2, IsUnique = true)]
        public int MediaId { get; set; }
    }
ایجاد جدول کامنت‌ها
  public class Comment : BaseEntity
    {
        public string Body { get; set; }
        public double Rating { get; set; }
        public int? RatingNumber { get; set; }
        public string EntityName { get; set; }
        public string UserId { get; set; }
        public int? ParentId { get; set; }
        public int? AdId { get; set; }
        public virtual Comment Parent { get; set; }
        public virtual Ad Ad { get; set; }
        public virtual ICollection<Comment> Items { get; set; }
        public virtual IdentityUser User { get; set; }
    }
ایجاد جدول اعضاء
public class Customer:BaseEntity
    {
        public string UserId { get; set; }
        public virtual string DisplayName { get; set; }
        public virtual string BirthDay { get; set; }
        public string City { get; set; }
        public string Address { get; set; }
        public int? MediaId { get; set; }
        public bool? NewsLetterSubscription { get; set; }
        public string PhoneNumber { get; set; }
        public virtual IdentityUser User { get; set; }
        public virtual Media Media { get; set; }
    }
ایجاد جدول امتیاز دهی به آگهی‌ها
public class Rating 
    {
      public int Id { get; set; }
       public string UserId { get; set; }
       public Double Rate { get; set; }
       public string EntityName { get; set; }
       public int DestinationId { get; set; }
    }

اضافه کردن مدلهای برنامه به ApplicationDbContext 
 public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }
        public DbSet<Ad> Ads { get; set; }
        public DbSet<AdLabel> AdLabels { get; set; }
        public DbSet<AdMedia> AdMedias { get; set; }
        public DbSet<Comment> Comments { get; set; }
        public DbSet<Label> Labels { get; set; }
        public DbSet<Media> Medias { get; set; }
        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }
    }

لود کردن فایل main.js در فایل layout.cshtml ترجیحا در انتهای body
    <script src="~/Scripts/require.js" data-main="/app/main"></script>
RequireJS  کتابخانه‌ی جاوااسکریپتی برای بارگزاری فایل‌ها در صورت نیاز می‌باشد. تنها کاری که ما باید انجام بدهیم این است که کدهای خود را داخل module‌ها قرار دهیم (در فایل‌های جداگانه) و RequireJS در صورت نیاز آنها را load خواهد کرد. همچنین RequireJS وابستگی بین module‌ها را نیز مدیریت می‌کند.

ایجاد فایل main.ts 
path: مسیر فایل‌های جاوا اسکریپتی
shim: وابستگی‌های فایل‌ها(ماژول ها) و export کردن آنها را مشخص می‌کند.
requirejs.config({
    paths: {
        "app": "app",
        "angularAmd":"/Scripts/angularAmd",
        "angular": "/Scripts/angular",
        "bootstrap": "/Scripts/bootstrap",
        "angularRoute": "/Scripts/angular-route",
        "jquery": "/Scripts/jquery-2.2.2",
    },
    waitSeconds: 0,
    shim: {
        "angular": { exports: "angular" },
        "angularRoute": { deps: ["angular"] },
        "bootstrap": { deps: ["jquery"] },
        "app": {
            deps: ["bootstrap","angularRoute"]
        }
    }
});
require(["app"]);

ایجاد فایل app.ts: کارهایی که در فایل app انجام داده‌ایم:
ایجاد کنترلر SecurityCtrl و اعمال آن به تگ body
<body ng-controller="SecurityCtrl">
...
</body>
ایجاد ماژول AdApps و قرار دادن کلاس SecurityCtrl در آن. از این به بعد برای مدیریت بهتر، تمام کدهای خود را درون ماژول‌ها قرار می‌دهیم. 
"use strict";
module AdApps {
    class SecurityCtrl {
        private $scope: Interfaces.IAdvertismentScope;
        constructor($scope: Interfaces.IAdvertismentScope) {
           // security check
      this.$scope = $scope;
        }
    }
 define(["angularAmd", "angular"], (angularAmd, ng) => {
   angularAmd = angularAmd.__proto__;
        var app = ng.module("AngularTypeScript", ['ngRoute']);
        var viewPath = "app/views/";
        var controllerPath = "app/controller/";
        app.config(['$routeProvider', $routeProvider => {
                $routeProvider
                    .when("/", angularAmd.route({
                        templateUrl: viewPath + "home.html",
                        controllerUrl: controllerPath + "home .js"
                    }))
                    .otherwise({ redirectTo: '/' });
            }
        ]);
        app.controller('SecurityCtrl', ['$scope', SecurityCtrl]);
        return angularAmd.bootstrap(app);
 })}