یک احتمال اینه، شما Virtual Box نسخه مثلا 6 رو نصب کردید، ولی Extension مربوط به نسخه 5 رو روش اضافه کردید، یا بالعکس. این مورد رو بررسی کنید و خبر بدید.
آیا میتوان یک برنامهی ASP.NET Core را به صورت Virtual Directory درون یک برنامهی ASP.NET Core دیگر میزبانی کرد؟ در اینحالت سیستم مسیریابی درون Child با Parent تداخل ایجاد نمیکند؟
خیر. نمیتوان. چندین Application جدید در IIS میتوانند از یک App Pool استفاده کنند. اما به Virtual Directory نمیتوان App Pool ایی را نسبت داد و بیشتر برای ارائهی محتوای استاتیک از آن استفاده میشود.
نظرات مطالب
آشنایی با mocking frameworks - قسمت دوم
برای نمونه با کتابخانه Moq میتوانید کلاسهای معمولی بدون اینترفیس را هم mock کنید؛ با این شرط که متدهای مدنظر آن virtual باشند تا بتوانند پروکسیهای لازم را جهت بازنویسی آنها تشکیل دهند.
خاصیتی که یک entity را به entity دیگر وصل میکند؛ navigation property
در مثال بالا خاصیتهایی که به صورت virtual تعریف شدند، از این دست هستند.
در مثال بالا خاصیتهایی که به صورت virtual تعریف شدند، از این دست هستند.
نظرات مطالب
الگوی استراتژی - Strategy Pattern
در صورتی از virtual استفاده میکنیم که یک پیاده سازی از متد Sort در SortStrategy داشته باشیم ، اما در اینجا طبق فرموده دوستمون کلاس ما فقط انتزاعی (Abstract) هست.
سلام آقای نصیری.
فرض کنید کلاسی مانند زیر وجود دارد:
public class Project
{
public virtual int Id { get; set; }
public virtual long ProjectCode { get; set; }
public virtual string ProjectName { get; set; }
public virtual int CreateDate { get; set; }
}
در فیلد CreateDate مقادیر زیر وجود دارد:
CreateDate
890102
891210
و ...
که تاریخ شروع پروژه ها می باشد. سوال من اینجاست که در NH کجا باید این تاریخ ها رو به 89/01/02 و 89/12/10 تبدیل کنم و در UI به کاربر نشون بدم.
با تشکر فراوان.
فرض کنید کلاسی مانند زیر وجود دارد:
public class Project
{
public virtual int Id { get; set; }
public virtual long ProjectCode { get; set; }
public virtual string ProjectName { get; set; }
public virtual int CreateDate { get; set; }
}
در فیلد CreateDate مقادیر زیر وجود دارد:
CreateDate
890102
891210
و ...
که تاریخ شروع پروژه ها می باشد. سوال من اینجاست که در NH کجا باید این تاریخ ها رو به 89/01/02 و 89/12/10 تبدیل کنم و در UI به کاربر نشون بدم.
با تشکر فراوان.
استفاده از Redux درون پروژههای React، به روشهای مختلفی قابل انجام است؛ یعنی محدودیتی از لحاظ نحوه چیدمان فایلها، تغییر state و نحوهی dispatch کردن action وجود ندارد. به عبارتی این آزادی عمل را خواهیم داشت تا خودمان سیمکشی پروژه را انجام دهیم؛ ولی مشکل اصلی اینجاست که نمیتوانیم مطمئن شویم روشی که پروژه را با آن ستاپ کردهایم آیا به عنوان یک best-practice محسوب میشود یا خیر. در نهایت خروجی را که خواهیم داشت، حجم انبوهی از کدهای boilerplate و پکیجهای زیادی است که در حین توسعهی پروژه، به همراه Redux اضافه شدهاند. همچنین در نهایت یک store پیچیده را خواهیم داشت که مدیریت آن به مراتب سخت خواهد شد. یک مشکل دیگر این است که روال گفته شده را باید به ازای هر پروژهی جدید تکرار کنیم. برای حل این مشکل، یکی از maintainerهای اصلی تیم ریداکس، یک پروژه را تحت عنوان Redux Toolkit، مدتها قبل برای حل مشکلات عنوان شده شروع کرده است و این پکیج، جدیداً به قالب رسمی create-react-app اضافه شده است. که در واقع یک روش استاندارد و به اصطلاح opinionated برای ایجاد پروژههای ریداکسی میباشد و شامل تمامی وابستگیهای موردنیاز برای کار با Redux از قبیل redux-thunk و همچنین Redux DevTools است.
در کد فوق، نحوهی ایجاد store، نسبت به حالت معمول، خیلی تمیزتر است. نکتهی جالب این است که به همراه کد فوق، Redux DevTools و همچنین redux-thunk هم از قبل تنظیم شدهاند و در نتیجه، نیازی به تنظیم و نصب آنها نیست. تغییر مهم دیگر، پوشهی features میباشد که یک روش رایج برای گروهبندی کامپوننتها، همراه با فایلهای وابستهی آنها است. درون این پوشه، یک پوشه جدید را تحت عنوان counter داریم که حاوی فایلهای زیر میباشد:
Counter.js، کامپوننتی است که در نهایت درون صفحه رندر خواهد شد. درون این فایل با استفاده از Redux Hooks کار اتصال به store و همچنین dispatch کردن اکشنها انجام گرفته است:
کاری که immer انجام میدهد، تغییر یک شیء، به صورت مستقیم نیست؛ در واقع یک draftState را ایجاد خواهد کرد که در عمل یک proxy برای state فعلی میباشد. یعنی با mutate کردن state، یک شیء جدید را در نهایت clone خواهد کرد و به عنوان state نهایی برمیگرداند.
ایجاد یک برنامهی خالی React با قالب redux
در ادامه برای بررسی این قالب جدید، یک پروژهی جدید React را ایجاد خواهیم کرد:
> npx create-react-app redux-template --template redux > cd redux-template > yarn start
بررسی ساختار پروژهی ایجاد شده
ساختار پروژهی ایجاد شده به صورت زیر است:
این ساختار خیلی شبیه به قالب پیشفرض create-react-app میباشد. همانطور که در تصویر فوق نیز مشاهده میکنید، پروژهی ایجاد شدهی با قالب redux (تصویر سمت چپ)، یک فایل با نام store و همچنین یک دایرکتوری را به نام features دارد. اگر به فایل store.js مراجعه کنید، خواهید دید که تنظیمات اولیهی ایجاد store را در قالب یک مثال Counter ایجاد کردهاست:
import { configureStore } from '@reduxjs/toolkit'; import counterReducer from './features/counter/counterSlice'; export default configureStore({ reducer: { counter: counterReducer, }, });
Counter Counter.module.css counterSlice.js
import React, { useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { decrement, increment, incrementByAmount, selectCount, } from './counterSlice'; import styles from './Counter.module.css'; export function Counter() { const count = useSelector(selectCount); const dispatch = useDispatch(); const [incrementAmount, setIncrementAmount] = useState(2); return ( <div> <div className={styles.row}> <button className={styles.button} aria-label="Increment value" onClick={() => dispatch(increment())} > + </button> <span className={styles.value}>{count}</span> <button className={styles.button} aria-label="Decrement value" onClick={() => dispatch(decrement())} > - </button> </div> <div className={styles.row}> <input className={styles.textbox} value={incrementAmount} onChange={e => setIncrementAmount(e.target.value)} /> <button className={styles.button} onClick={() => dispatch( incrementByAmount({ amount: Number(incrementAmount) || 0 }) ) } > Add Amount </button> </div> </div> ); }
فایل Counter.module.css نیز در واقع استایلهای مربوط به کامپوننت فوق میباشد که به صورت CSS module اضافه شدهاست. در نهایت فایل counterSlice.js را داریم که کار همان reducer سابق را برایمان انجام خواهد داد؛ اما اینبار با یک ساختار جدید و تحت عنوان slice. اگر به فایل عنوان شده مراجعه کنید، کدهای زیر را خواهید دید:
import { createSlice } from '@reduxjs/toolkit'; export const slice = createSlice({ name: 'counter', initialState: { value: 0, }, reducers: { increment: state => { // Redux Toolkit allows us to 'mutate' the state. It doesn't actually // mutate the state because it uses the immer library, which detects // changes to a "draft state" and produces a brand new immutable state // based off those changes state.value += 1; }, decrement: state => { state.value -= 1; }, incrementByAmount: (state, action) => { state.value += action.payload.amount; }, }, }); export const selectCount = state => state.counter.value; export const { increment, decrement, incrementByAmount } = slice.actions; export default slice.reducer;
در این قالب جدید، ترکیب این قطعات هستند که شیء اصلی یا در واقع همان state کلی پروژه را تشکیل خواهند داد. همانطور که مشاهده میکنید، برای ایجاد یک قطعه جدید، از تابع createSlice استفاده شده است. این تابع، تعدادی پارامتر را از ورودی دریافت میکند:
- name: برای هر بخش از state، میتوانیم یک نام را تعیین کنیم و این همان عنوانی خواهد بود که میتوانید توسط Redux DevTools مشاهده کنید.
- initialValue: در اینجا میتوانیم مقادیر اولیهای را برای این بخش از state، تعیین کنیم که در مثال فوق، value به مقدار صفر تنظیم شدهاست.
- reducers: این قسمت محل تعریف actionهایی هستند که قرار است state را تغییر دهند. نکته جالب توجه این است که state در هر کدام از متدهای فوق، به ظاهر mutate شده است؛ اما همانطور که به صورت کامنت نیز نوشتهاست، در پشت صحنه از کتابخانهای با عنوان immer استفاده میکند که در عمل بجای تغییر state اصلی، یک کپی از state جدید را جایگزین state قبلی خواهد کرد.
توسط selectCount نیز کار انتخاب مقدار موردنظر از state انجام شدهاست که معادل همان mapPropsToState است و در اینجا امکان دسترسی به state ذخیره شده در مخزن redux فراهم شده است. همچنین در خطوط پایانی فایل نیز اکشنها برای دسترسی سادهتر به درون کامپوننت، به صورت Object Destructuring به بیرون export شدهاند. در نهایت reducer نهایی را از slice ایجاد شده استخراج کردهایم. این پراپرتی برای ایجاد store مورداستفاده قرار میگیرد.
چرا قالب Redux Toolkit از immer برای تغییر state استفاده میکند؟
همانطور که در این قسمت از سری Redux توضیح داده شد، اعمال تغییرات بر روی آرایهها و اشیاء، باعث ایجاد ناخالصی خواهد شد؛ بنابراین به جای تغییر شیء اصلی، باید توسط یکی از روشهای Object.assign و یا spread operator، یک clone از state اصلی را ایجاد کرده و آن را به عنوان state نهایی لحاظ کنیم. اما در حین کار با اشیاء nested، انجام اینکار سخت خواهد شد و همچنین خوانایی کد را نیز کاهش میدهد:
return { ...state, models: state.models.map(c => c.model === action.payload.model ? { ...c, on: action.payload.toggle } : c ) };
اما با کمک immer میتوانیم به صورت مستقیم state را تغییر دهیم:
state.models.forEach(item => { if (item.model === action.payload.model) { item.on = action.payload.toggle; } });