پرسش‌ها
HttpContext در BlazorSSR

سلام

مشابه سایت جاری از یک CascadingValue بنام ApplicationState در برنامه استفاده کرده ام. در این ApplicationState اعضایی وجود دارند مانند

 public CurrentUserModel? CurrentUser { set; get; }
 public string? UserName { get; set; } 
[CascadingParameter]
 public HttpContext HttpContext { set; get; } 

چنانچه فایل App برنامه بصورت زیر باشد.

<head>
      <HeadOutlet  />  
</head>
<body>
    <Routes  />
</body>

</html>

HttpContext نال نیست ولی اعضای دیگر مانند CurrentUser , UserName در سایر صفحات نال نشان میدهد. نمونه عکس زیر

پس از تغییر HeadOutlet و Routes فایل App به InteractiveServer اینبار برعکس میشود و HttpContext نال میشود و اعضای دیگر ApplicationState مقدار دارند

<body>
    <Routes @rendermode="RenderModeForPage" />
    <script src="_framework/blazor.web.js"></script>
</body>

</html>

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? RenderModeForPage => HttpContext.Request.Path.StartsWithSegments("/Account")
        ? null
        : InteractiveServer;
}

مشابه عکس زیر

راه حل نال نشدن همه اعضاء در هردو صورت InteractiveServer و یا غیر InteractiveServer چیست؟

با تزریق

[Inject] IHttpContextAccessor HttpContextAccessor{ get; set; }

در ApplicationState و مقدار دهی HttpContext مشکل حل میشود ولی شما در سایت از این روش استفاده نکرده اید

 protected override async Task OnInitializedAsync()
 {
     this.HttpContext = HttpContextAccessor.HttpContext;
     CurrentUser = new CurrentUserModel
     {
         IsAdmin = true
     };

 }
نظرات مطالب
آموزش TypeScript #1
یکی از دلایل محبوبیت زبان JavaScript، راحتی در نوشتن کد با این زبان است. اگر قرار باشد این زبان یک محصول همه منظوره باشد به طور قطع دچار پیچیدگی‌های پیاده سازی شده و این همه محبوبیت به دست نمی‌آورد. هدف اولیه از تولید و توسعه زبان JavaScript، استفاده از آن در پروژه‌های سمت کلاینت بود. اما با مرور زمان و محبوبیت بیش از اندازه، توسعه گران مختلف تصمیم به توسعه این زبان گرفتند که هر محصول برای یک منظور خاص به وجود آمد.  برای مثال Node.Js برای پروژه‌های RealTime استفاه می‌شود و بر مبنای منطق event-driven می‌باشد که خیلی‌ها از آن به عنوان Server side JavaScript یاد می‌کنند یا به عنوان مثال دیگر Dart محصول شرکت گوگل در سال 2011 (طراحی شده بر مبنای Scratch)و TypeScript محصول  شرکت مایکروسافت در سال 2012 (طراحی شده بر مبنای JavaScript)عرضه شدند که هدف اصلی از تولید این زبان‌ها پشتیبانی از مبحث static typing و مباحث OOP برای پیاده سازی پروژه‌های در سطوحی با مقیاس بزرگ بود. JavaScript به عنوان زبان پایه باقی خواهد ماند و نسخه‌های مختلف در شکل سایر زبان‌ها و فریم ورک‌های مختلف عرضه می‌شوند تا هر کدام یک نیاز را برطرف سازند. البته در پایان این نکته را هم متذکر شوم که JavaScript هم روند با توسعه ECMAScript تغییر می‌کند. برای مثال در نسخه ECMASCript 6، امکان تعریف کلاس و ماژول در JavaSCript فراهم شده است.
مطالب
استفاده از چند دکمه با عملکردهای مختلف برای ارسال یک EditForm در Blazor
به صورت پیش فرض یک EditForm تنها یک دکمه‌ی submit دارد و معمولا برای اعتبارسنجی فرم، قبل از ارسال اطلاعات به شکل زیر از آن استفاده می‌شود:
<EditForm Model="@selectedCar" OnValidSubmit="@SaveObject">
    <DataAnnotationsValidator />
    <ValidationSummary />

    ....My <InputText>'s for all values I have in my object

    <button type="submit" value="Save">Save</button>    
</EditForm>
@code {
    [Parameter]
    public string Id { get; set; }

    CarModel selectedCar;

    protected override async Task OnInitializedAsync()
    {
        selectedCar = await _CarService.GetCar(int.Parse(Id));
    }

    protected async Task SaveObject()
    {
        selectedCar.Id = await _CarService.SaveCar(selectedCar);
    }    
}
حال اگر بخواهیم از چند دکمه با عملکردهای مختلفی در یک EditForm استفاده کنیم چه؟ آیا امکان آن وجود دارد که برای یک دکمه اعتبارسنجی صورت پذیرد، اما برای دکمه‌ی دیگری در همان EditForm هیچ اعتبارسنجی اعمال نشود؟
پاسخ: بله؛ می‌توان به شکل زیر عمل نمود:
<EditForm Model="@selectedCar" Context="formContext">
    <DataAnnotationsValidator />
    <ValidationSummary />

    ....My <InputText>'s for all values I have in my object

    <button type="submit" @onclick="@(() => SaveCar(formContext))">Save</button>
    <button type="submit" @onclick="@(() => UpdateStockQuantity(formContext))">Update stock quantity</button>
    <button type="submit" @onclick="@(() => DeleteCar(formContext))">Delete</button>
</EditForm>

@code {
    [Parameter]
    public string Id { get; set; }

    CarModel selectedCar;

    protected override async Task OnInitializedAsync()
    {
        selectedCar = await _CarService.GetCar(int.Parse(Id));
    }

    protected async Task SaveCar(EditContext formContext)
    {
        bool formIsValid = formContext.Validate();
        if (formIsValid == false)
            return;

        selectedCar.Id = await _CarService.SaveCar(selectedCar);
    }

     protected async Task DeleteObject(EditContext formContext)
    {
        selectedCar.Id = await _CarService.DeleteCar(selectedCar);
    }   

    // ... plus same approach with UpdateStockQuantity.
}
در اینجا به جای OnValidSubmit، از Context استفاده می‌کنیم و توسط Anonymous Function ها، متدهای مربوط به onclick‌ها را صدا می‌زنیم و formContext را به آن‌ها منتقل می‌نماییم. برای اعتبارسنجی نیز در متد مربوطه با استفاده از Context.Validate اعتبار فرم را برای متد مربوطه چک می‌کنیم. قاعدتا نیازی نیست موقع حذف یک خودرو، اعتبارسنجی فرم، برای نام آن خودرو انجام گردد؛ اما برای ثبت یک خودرو ممکن است بخواهیم مطمئن شویم که حتما نامی برای آن اختیار شود.
مطالب
تولید SiteMap استاندارد و ایجاد یک ActionResult اختصاصی برای Return کردن SiteMap تولید شده
یکی از item‌های مهم در بهینه سازی SEO یک وب‌سایت وجود یک SiteMap استاندارد متشکل از لینک‌های موجود در سایت هست که در وب‌سایت‌های داینامیک معمولا این لینک‌ها بر اساس داده‌های موجود در بانک اطلاعاتی ایجاد میشه. برای مثال مطالب، اخبار و ....
در اینجا بنده قبلا یک کلاس برای تولید SiteMap آماده کردم که در پروژه‌های خودم ازش استفاده میکنم. توسط این کلاس میتونید به صورت داینامیک SiteMap وب‌سایت مبتنی بر ASP.NET MVC خودتون رو ایجاد کنید.

برای آشنایی با ساختار یک SiteMap استاندارد میتونید به لینک رسمی روبرو مراجعه کنید : http://www.sitemaps.org/de/protocol.html 

بنده کلاس‌های زیر رو بر مبنای لینک مذکور در سایت رسمی SiteMaps تولید کردم.  بعد از تولید SiteMap نیاز دارید که اون رو مثلا به عنوان خروجی یک ActionResult بازگردونید. برای این کار هم یک کلاس با نام XmlResult  مشتق شده از ActionResult آماده سازی کردم که کلاس تولید شده SiteMap رو Serialize میکنه و به عنوان نتیجه‌ی یک Action باز می‌گردونه .
using System;
using System.Collections;
using System.Web.Mvc;
using System.Xml.Serialization;

namespace Neoox.Core.SeoTools
{
    [XmlRoot("urlset", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
    public class Sitemap
    {
        private ArrayList map;

        public Sitemap()
        {
            map = new ArrayList();
        }

        [XmlElement("url")]
        public Location[] Locations
        {
            get
            {
                Location[] items = new Location[map.Count];
                map.CopyTo(items);
                return items;
            }
            set
            {
                if (value == null)
                    return;
                Location[] items = (Location[])value;
                map.Clear();
                foreach (Location item in items)
                    map.Add(item);
            }
        }

        public int Add(Location item)
        {
            return map.Add(item);
        }
    }

    public class Location
    {
        public enum eChangeFrequency
        {
            always,
            hourly,
            daily,
            weekly,
            monthly,
            yearly,
            never
        }

        [XmlElement("loc")]
        public string Url { get; set; }

        [XmlElement("changefreq")]
        public eChangeFrequency? ChangeFrequency { get; set; }
        public bool ShouldSerializeChangeFrequency() { return ChangeFrequency.HasValue; }

        [XmlElement("lastmod")]
        public DateTime? LastModified { get; set; }
        public bool ShouldSerializeLastModified() { return LastModified.HasValue; }

        [XmlElement("priority")]
        public double? Priority { get; set; }
        public bool ShouldSerializePriority() { return Priority.HasValue; }
    }

    public class XmlResult : ActionResult
    {
        private object objectToSerialize;

        public XmlResult(object objectToSerialize)
        {
            this.objectToSerialize = objectToSerialize;
        }

        public object ObjectToSerialize
        {
            get { return this.objectToSerialize; }
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (this.objectToSerialize != null)
            {
                context.HttpContext.Response.Clear();
                var xs = new System.Xml.Serialization.XmlSerializer(this.objectToSerialize.GetType());
                context.HttpContext.Response.ContentType = "text/xml";
                xs.Serialize(context.HttpContext.Response.Output, this.objectToSerialize);
            }
        }
    }
}
 و اما نحوه استفاده از این کلاس‌ها هم خیلی سادست. به مثال زیر توجه کنید ... فقط این نکته رو در نظر داشته باشید که item هایی که به sitemap اضافه میشه واکشی شده از بانک اطلاعاتی هست، در این مثال چون خواستم ساده توضیح داده بشه نحوه استفاده از این کلاس‌ها، این داده‌ها به صورت static در نظر گرفته شد ولی شما میتونید داده‌ها رو بر اساس ساختار بانک اطلاعاتی خودتون واکشی کرده و به SiteMap اضافه کنید تا یک SiteMap کاملا پویا و Dynamic داشته باشید...
        public ActionResult Sitemap()
        {
            Sitemap sm = new Sitemap();
            sm.Add(new Location()
            {
                Url = string.Format("http://www.TechnoDesign.ir/Articles/{0}/{1}", 1, "SEO-in-ASP.NET-MVC"),
                LastModified = DateTime.UtcNow,
                Priority = 0.5D
            });
            return new XmlResult(sm);
        }
نظرات مطالب
ASP.NET MVC #22

سلام

ResourceType یکبار می‌بایست برای Display  ست شود و یکبار هم برای  ErrorMessageResourceType

که هر دوی این‌ها معمولا یکی است . همچنین در کلاس هر پراپرتی (Poco) ممکن است یک ErrorMessageResourceType داشته باشد که برای کل کلاس تکراری است.

میشه ResourceType  را برای کل یک کلاس یا یک NameSpace مشخص کرد؟

نظرات مطالب
EF Code First #2
با سلام
من تمام مراحل توضیح داده شده رو انجام دادم ولی متاسفانه دیتابیس رو نمیسازه که ناچار شدم برم از خود منو  ado.net entity data modal  بسازم ولی باز مشکل اینه که تیبل‌ها رو اضافه نمی‌کنه ممنون میشم راهنمایی بفرمایید
 protected void Application_Start()
        {
          
            System.Data.Entity.Database.SetInitializer(new DropCreateDatabaseAlways<SchoolContext>());

            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);            
        }
   public partial class SchoolContext : DbContext
    {
        public SchoolContext(): base("name=SchoolDBContext")
        {
           // Database.SetInitializer<SchoolContext>(new CreateDatabaseIfNotExists<SchoolContext>());
        }
        public DbSet<student> Students { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Course> Courses { get; set; }
  
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
        }

        public class Sample2DbInitializer : DropCreateDatabaseAlways<SchoolContext>
        {
            protected override void Seed(SchoolContext context)
            {
                context.Courses.Add(new Course
                {
                    Credits = 20,
                    Title = "Vahid"
                   
                });

                base.Seed(context);
            }
        }
    }
}
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 19 - بومی سازی
در حالت کلی همانطور که عنوان شد، برای تغییر فرهنگ ترد جاری از یکی از سه روش کوکی، کوئری استرینگ و هدر زبان استفاده می‌شود. این سه تامین کننده، تامین کننده‌های پیش فرض هستند.
اگر می‌خواهید برای مثال از روش کوکی ذکر شده (در متد public IActionResult SetFaLanguage ابتدای بحث) استفاده نکنید، می‌توان تامین کنند‌ه‌ی چهارمی را هم تدارک دید:
    public class FaRequestCultureProvider : RequestCultureProvider
    {
        public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
        {
            return Task.FromResult(new ProviderCultureResult("fa-IR"));
        }
    }
و بعد آن‌را به ابتدای لیست تامین کننده‌ها (insert 0 ذیل) اضافه کرد:
        public void Configure(IApplicationBuilder app)
        {
            var requestLocalizationOptions = new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture(new CultureInfo("fa-IR")),
                SupportedCultures = new[]
                {
                    new CultureInfo("en-US"),
                    new CultureInfo("fa-IR")
                },
                SupportedUICultures = new[]
                {
                    new CultureInfo("en-US"),
                    new CultureInfo("fa-IR")
                }
            };
            requestLocalizationOptions.RequestCultureProviders.Insert(0, new FaRequestCultureProvider());
            app.UseRequestLocalization(requestLocalizationOptions);
به این صورت فرهنگ پیش فرض ترد جاری به fa-IR استاندارد تنظیم می‌شود. برای حالت غیر استاندارد از همان اکشن فیلتر استفاده کنید.
نظرات مطالب
ASP.NET MVC #6
در اصل تمام این‌ها نیاز به وهله سازی دارند. اما برای ساده‌تر شدن کار، در کلاس پایه Controller، این وهله سازی‌ها صورت گرفته (^) و یک متد اضافی برای آن‌ها تعریف شده‌است. به این صورت به نظر می‌رسد که وهله سازی انجام نمی‌شود؛ ولی در اصل این‌کار محول شده به متدهای کمکی کلاس پایه کنترلر. برای مثال:
protected internal virtual JavaScriptResult JavaScript(string script)
{
     return new JavaScriptResult { Script = script };
}
در اینجا return new، داخل یک متد کلاس پایه محصور شده‌است.
مطالب
UnitTest برای کلاس های Abstract با استفاده از Rhino Mocks
در این پست قصد دارم کلاس زیر رو براتون آزمایش کنم:
public abstract class myabstractclass
{
    public abstract string dosomething( string input );
 
    public double round( double number , int decimals )
    {
        return math.round( number , decimals );
    }
}
در کلاس بالا که abstract هستش، متدی دارم که abstract است و بدنه‌ای نداره و از متد بعدی به اسم round برای گرد کردن اعداد استفاده می‌شه. برای تست کلاس بالا و اطمینان از درست بودن متد‌ها باید به روش زیر عمل نمود:

روش اول:
در این روش ابتدا باید کلاسی نوشت تا کلاس abstract بالا رو پیاده سازی کنه:
   public class mynewclass : myabstractclass
   {
       public override string dosomething( string input )
       {
           return input;
       }
   }
بعد می‌شه خیلی راحت برای کلاس دوم متد‌های تست رو نوشت. به روش زیر:
    [testclass]
    public class mytest
    {
        [testmethod]
        public void testround()
        {
            mynewclass mynewclass = new mynewclass();
 
            var result = mynewclass.round( 5.55 , 1 );
 
            assert.areequal( 5.6 , result );
        }
    }
که بعد از اجرا نتیجه زیر رو خواهید دید


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

در روش دوم که من خیلی بیشتر بهش علاقه دارم دیگه نیازی به استفاده از یک کلاس دوم برای پیاده سازی کلاس abstract نیست. بلکه در این روش از ابزار rhinomocks  برای این کار استفاده می‌کنیم . استفاده از rhino mocks به چندین روش امکان پذیره که امروز 2 روش اونو براتون توضیح میدم:
در روش اول از mockrepository استفاده می‌کنیم  و در روش دوم از روش aaa یا arrange-act-assert

استفاده از mockrepository :
ابتدا کد‌های مربوطه رو می‌نویسم:
       [testmethod]
       public void testwithmockrepository()
       {
           var mockrepository = new rhino.mocks.mockrepository();
           var mock = mockrepository.partialmock<myabstractclass>();
 
           using ( mockrepository.record() )
           {
               expect.call( mock.dosomething( arg<string>.is.anything ) ).return( "hi..." ).repeat.once();
           }
           using ( mockrepository.playback() )
           {
               assert.areequal( "hi..." , mock.dosomething( "salam" ) );             
           }
       }
همانطور که در کد‌های نوشته شده بالا می‌بینید ابتدا یک mockrepository ساخته شده، سپس از نمونه اون کلاس برای ساخت partialmock کلاس myabstractclass استفاده کردم. در این روش متد‌های expect حتما باید بین بلاک record نوشته شوند تا بتونیم از اون‌ها در بلاک playback استفاده کنیم. نتیجه اجرای این متد تست هم مثل متد تست قبلی درست است.
در مورد expect.call باید بگم که از این کلاس برای شبیه سازی رفتار یک متد استفاده میشه (مثلا در مواقعی که یک متد برای انجام عملیات باید به دیتا بیس وصل شده و یک query را اجرا کنه) برای اینکه در تست، از این عملیات صرف نظر بشه از mock‌ها استفاده کرده و رفتار متد رو به روش بالا شبیه سازی می‌کنیم. البته کار کردن با rhino mocks به صورت بالا دیگه از مد افتاده و جدیدا از روش aaa استفاده میشه که اونو در پایین توضیح می‌دم:
      [testmethod]
      public void testwithaaa()
      {
          var mock = mockrepository.generatepartialmock<myabstractclass>();
 
          mock.expect( x => x.dosomething( arg<string>.is.anything ) ).return( "hi..." ).repeat.once();//arange
 
          var result = mock.dosomething( "salam" );//act
 
          assert.areequal( "hi..." , result );//assert
      }
توی این روش دیگه خبری از record و playback نیست و همانطور که مشخصه از سه مرحله arrange-act-assert تشکیل شده که هر مرحله رو براتون مشخص کردم. مزیت استفاده از این روش اینه که اولا تعداد خطوط کمتری برای کد نویسی نیاز داره و دوما سرعت اجراش از روش قبلی خیلی بیشتره. در مورد repeat.once هم بگم که این دستور نشون می‌ده فقط یک بار اجازه انجام عملیات act رو دارید. یعنی اگر کد هارو به صورت زیر تغییر بدیم با خطا روبرو می‌شیم:
       [testmethod]
       public void testwithaaa()
       {
           var mock = mockrepository.generatepartialmock<myabstractclass>();
 
           mock.expect( x => x.dosomething( arg<string>.is.anything ) ).return( "hi..." ).repeat.once();//arange
 
           var result = mock.dosomething( "salam" );//act
           var result2 = mock.dosomething( "bye" );//act
           assert.areequal( "hi..." , result );//assert
       }



خطای آن هم واضح داره میگه که expected#1 هستش در حالی که actual#2 (تعداد دفعات حقیقی از دفعات مورد انتظار بیشتره)
توی پست‌های بعدی (اگه وقت بشه) حتما در مورد rhino mocks بیشتر توضیح میدم 
نظرات مطالب
ASP.NET MVC #18
- نیازی نیست تمام متدهای RoleProvider دات نت پیاده سازی شوند. برای یک برنامه پیاده سازی دو متد IsUserInRole، GetRolesForUser کافی است. 
- سپس دو کلاس Role و User را باید تعریف کنید. این دو رابطه many-to-many با هم دارند؛ یعنی هر کدام با یک ICollection به دیگری ارتباط پیدا می‌کنند. سپس این دو کلاس را در کلاس Context برنامه مطابق معمول توسط DbSetها در معرض دید EF قرار می‌دهید. مابقی آن کارکردن معمولی با این دو جدول اضافه شده به برنامه است:
    public class EfRolesService : IRolesService
    {
        readonly IUnitOfWork _uow;
        readonly IDbSet<Role> _roles;
        public EfRolesService(IUnitOfWork uow)
        {
            _uow = uow;
            _roles = _uow.Set<Role>();
        }

        public IList<Role> FindUserRoles(int userId)
        {
            var query = from role in _roles
                        from user in role.Users
                        where user.Id == userId
                        select role;

            return query.OrderBy(x => x.Name).ToList();
        }

        public string[] GetRolesForUser(int userId)
        {
            var roles = FindUserRoles(userId);
            if (roles == null || !roles.Any())
            {
                return new string[] { };
            }

            return roles.Select(x => x.Name).ToArray();
        }

        public bool IsUserInRole(int userId, string roleName)
        {
            var query = from role in _roles
                        where role.Name == roleName
                        from user in role.Users
                        where user.Id == userId
                        select role;
            var userRole = query.FirstOrDefault();
            return userRole != null;
        }
    }
و در این حالت CustomRoleProvider به صورت زیر خواهد بود. در این روش فرض شده حین لاگین، user.Id در FormsAuthentication.SetAuthCookie تنظیم می‌شود؛ یعنی userName در این RoleProvider به id آن تنظیم شده:
    public class CustomRoleProvider : RoleProvider
    {
        public override bool IsUserInRole(string username, string roleName)
        {
            // Since the role provider, in this case the CustomRoleProvider is instantiated by 
            // the ASP.NET framework the best solution is to use the service locator pattern. 
            // The service locator pattern is normally considered to be an anti-pattern but 
            // sometimes you have to be pragmatic and accept the limitation on the framework 
            // that is being used (in this case the ASP.NET framework).

            var rolesService = ObjectFactory.GetInstance<IRolesService>();
            return rolesService.IsUserInRole(username.ToInt(), roleName);
        }

        public override string[] GetRolesForUser(string username)
        {
            var rolesService = ObjectFactory.GetInstance<IRolesService>();
            return rolesService.GetRolesForUser(username.ToInt());
        }
// مابقی نیازی نیست پیاده سازی شوند