Entity Framework 6.2 منتشر شد
- Reduce start up time by loading finished code first models from a persistent cache
- Fluent API to define indexes
- DbFunctions.Like() to enable writing LINQ queries that translate to LIKE in SQL
- Migrate.exe should support -script option
- EF6 does not work with primary key from sequence
- Update error numbers for SQL Azure Execution Strategy
- Bug: Retrying queries or SQL commands fails with “The SqlParameter is already contained by another SqlParameterCollection”
- Bug: Evaluation of DbQuery.ToString() frequently times out in the debugger
کتابخانه dragula
Drag and drop so simple it hurts Demo
Framework support includes vanilla JavaScript, Angular, and React.
- Official Angular bridge for
dragula
(demo) - Official Angular 2 bridge for
dragula
(demo) - Official React bridge for
dragula
(demo)
Features
- Super easy to set up
- No bloated dependencies
- Figures out sort order on its own
- A shadow where the item would be dropped offers visual feedback
- Touch events!
- Seamlessly handles clicks without any configuration
animation در angular
نقشه راه آنگولار
کتاب Angular Essentials
فراخوانی سرویس های WCF به صورت Async
Etag چیست و چه کاربردی دارد
روش محافظت از مسیریابیهای تعریف شدهی در برنامه
شبیه به روشی را که در قسمت قبل، برای انتقال شیء user، به مسیریابی کامپوننت Movies استفاده کردیم:
<Route path="/movies" render={props => <Movies {...props} user={this.state.currentUser} />} />
<Route path="/movies/:id" component={MovieForm} />
<Route path="/movies/:id" render={props => { if (!this.state.currentUser) { return <Redirect to="/login" />; } return <MovieForm {...props} />; }} />
اکنون اگر این تغییرات را ذخیره کرده و در حالت Logout، مسیر http://localhost:3000/movies/new را مستقیما درخواست دهیم، به صفحهی لاگین هدایت خواهیم شد.
ایجاد کامپوننتی با قابلیت استفادهی مجدد، برای محافظت از مسیریابیها
هرچند روشی که تا اینجا برای محافظت از مسیریابیها معرفی شد، بدون مشکل کار میکند، اما اگر قرار باشد برای تمام مسیریابیهای اینگونه، استفاده شود، به تکرار بیش از اندازهی کدهای یکسانی خواهیم رسید. به همین جهت میتوان این منطق را تبدیل به یک کامپوننت با قابلیت استفادهی مجدد کرد؛ تا دیگر نیازی به تکرار این if/elseها نباشد. برای این منظور، فایل جدید src\components\common\protectedRoute.jsx را ایجاد میکنیم. کامپوننت جدید protectedRoute را هم در پوشهی common قرار دادهایم؛ چون وابستگی به دومین این برنامه نداشته و میتواند در سایر برنامه نیز مورد استفاده قرار گیرد. سپس با استفاده از میانبرهای imrc و sfc، یک کامپوننت تابعی بدون حالت را به نام ProtectedRoute ایجاد کرده و در آن، همان کامپوننت اصلی Route را بازگشت میدهیم. بنابراین هر زمانیکه از ProtectedRoute استفاده شود، خروجی آن، همان کامپوننت استاندارد Route خواهد بود که اینبار قرار است از وضعیت کاربر جاری وارد شدهی به سیستم، مطلع باشد. به همین جهت در اولین قدم، همان قطعه کد Route فوق را که به همراه if/else نوشتیم، از فایل app.js کپی کرده و به اینجا، داخل متد رندر کامپوننت، منتقل میکنیم. سپس شروع میکنیم به متغیر کردن عباراتی که در آن به صورت صریح و ثابت، مقدار دهی شدهاند تا به یک کامپوننت با قابلیت استفادهی مجدد برسیم:
import React from "react"; import { Route, Redirect } from "react-router-dom"; import * as auth from "../../services/authService"; const ProtectedRoute = ({ path, component: Component, render, ...rest }) => { return ( <Route {...rest} render={props => { if (!auth.getCurrentUser()) return ( <Redirect to={{ pathname: "/login", state: { from: props.location } }} /> ); return Component ? <Component {...props} /> : render(props); }} /> ); }; export default ProtectedRoute;
- در این کامپوننت نیاز است اطلاعات کاربر جاری وارد شدهی به سیستم در دسترس باشد. یا میتوان آنرا به عنوان یکی از خواص props دریافت کرد و یا همانند این مثال، امکان دریافت مستقیم آن از authService نیز وجود دارد.
- در ادامه اگر CurrentUser مقدار دهی نشده باشد، کامپوننت Redirect را که کاربر را به صفحهی لاگین هدایت میکند، بازگشت میدهیم. در غیراینصورت نیاز است یک کامپوننت را بجای برای مثال MovieForm، بازگشت دهیم. علت استفادهی از component: Component این است که React انتظار دارد، کامپوننتها با نام بزرگ شروع شوند. به همین جهت خاصیت component را از props دریافت کرده و آنرا به Component تغییر نام میدهیم.
- زمانیکه از کامپوننت Route استاندارد استفاده میشود، یا از ویژگی component آن استفاده میشود و یا از ویژگی render آن که یک تابع است، تا بتوان داخل آن، کدهای پویایی را درج کرد. به همین جهت ممکن است که مقدار متغیر کامپوننت دریافت شده، نال باشد. بنابراین در اینجا بررسی میشود که آیا Component، مقدار دهی شدهاست یا خیر؟ اگر بله، همان کامپوننت را به همراه props آن بازگشت میدهیم. در غیراینصورت، متد render مقدار دهی شده را به همراه props ارسالی به آن، بازگشت خواهیم داد.
- علت وجود پارامتر rest نیز این است که این کامپوننت علاوه بر ویژگیهایی که تاکنون پیش بینی کردهایم، ممکن است در آینده ویژگیهای دیگری را نیز نیاز داشته باشد. به همین جهت مابقی آنها را توسط {rest...}، به صورت خودکار در اینجا درج میکنیم. برای نمونه در اینجا ذکر path={path} را مشاهده نمیکنید؛ چون توسط همان {rest...} به صورت خودکار تامین میشود.
اکنون به app.js بازگشته و کدهای قبلی را با این کامپوننت جدید ProtectedRoute، جایگزین میکنیم:
import ProtectedRoute from "./components/common/protectedRoute"; // ... <ProtectedRoute path="/movies/:id" component={MovieForm} />
مدیریت بازگشت کاربران، پس از لاگین به سیستم
پس از خروج از برنامه، اگر سعی در ویرایش یکی از فیلمهای موجود کنیم، به صفحهی لاگین هدایت خواهیم شد. پس از لاگین موفق، مجددا به ریشهی سایت بازگشت داده میشویم و نه به صفحهای که پیش از لاگین، مدنظر کاربر بودهاست. برای رفع این مشکل نیاز است بتوان به آدرس قبلی درخواستی، دسترسی یافت و این مورد توسط سیستم مسیریابی، به کامپوننتها به صورت خودکار تزریق میشود. برای مثال اگر در کامپوننت ProtectedRoute، مقدار شیء props دریافتی را لاگ کنیم:
return ( <Route {...rest} render={props => { console.log(props);
همانطور که مشخص است، شیء location دریافتی از props، به همراه اطلاعات آدرسی است که پیش از هدایت خودکار به صفحهی لاگین، درخواست کرده بودیم. به همین جهت یک چنین تنظیمی، در تعاریف کامپوننت ProtectedRoute درنظر گرفته شدهاند:
<Redirect to={{ pathname: "/login", state: { from: props.location } }} />
اکنون که این شیء، به کامپوننت لاگین، پس از Redirect خودکار ارسال میشود، نیاز است به src\components\loginForm.jsx مراجعه کرده و تغییرات زیر را اعمال کنیم:
doSubmit = async () => { try { const { data } = this.state; await auth.login(data.username, data.password); const { state } = this.props.location; window.location = state ? state.from.pathname : "/"; } catch (ex) { //...
تا اینجا اگر برنامه را ذخیره کرده، از سیستم خارج شویم و سعی در ویرایش اولین رکورد موجود در لیست فیلمها کنیم، ابتدا به صفحهی لاگین هدایت میشویم. پس از لاگین موفق، اینبار بجای مشاهدهی ریشهی سایت که در اینجا به لیست فیلمها تنظیم شده، دقیقا صفحهی ویرایش جزئیات اولین فیلم را مشاهده خواهیم کرد.
عدم نمایش مجدد صفحهی لاگین، به کاربران وارد شدهی به سیستم
آخرین تغییری را که در اینجا اعمال خواهیم کرد، رفع مشکل امکان مشاهدهی مجدد صفحهی لاگین، با وارد کردن مستقیم آدرس آن در مرورگر، پس از ورود موفقیت آمیز به سیستم است. برای این منظور، ابتدای متد رندر کامپوننت فرم لاگین را به صورت زیر تغییر میدهیم تا اگر کاربر، پیشتر به سیستم وارد شده بود، به صورت خودکار به ریشهی سایت هدایت شده و مجددا فرم لاگین برای او رندر نشود:
import { Redirect } from "react-router-dom"; //... render() { if (auth.getCurrentUser()) return <Redirect to="/" />;
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: sample-29-backend.zip و sample-29-frontend.zip
معرفی C# Source Generators
مخلص کلام اینکه : اگه با Fody یا PostSharp و همچنین Code Analyzerها آشنایی دارین. این قابلیت یه چیزی تو مایههای ترکیب ایناس و بهتون اجازه میده موقع Compile شدن کد پروژه رو Analyze کنین و یه کد جدیدی بهش اضافه کنین. (مثلا پیاده سازی اینترفیس INotifyPropertyChanged به صورت خودکار به هنگام کامپایل)
We’re pleased to introduce the first preview of Source Generators, a new C# compiler feature that lets C# developers inspect user code and generate new C# source files that can be added to a compilation. This is done via a new kind of component that we’re calling a Source Generator.
To get started with Source Generators, you’ll need to install the latest .NET 5 preview and the latest Visual Studio preview.
نمونه ای از پیاده سازی INotifyPropertyChanged with C# 9.0 Source Generators