echo off cls rem --------------- Variables --------------- set packName=DbName set connection=-S Server -U User -P Password set path=PathForSaveBackup rem --------------- Variables --------------- echo create backup sqlcmd %connection% -Q "BACKUP DATABASE %packName% TO DISK = '%path%\%packName%.bak'" echo compress backup file ..\tools\7za.exe a %path%\%packName%.7z %path%\%packName%.bak echo delete backup file del %path%\%packName%.bak
ASP.NET MVC #10
چطور میشه از نمایش این پارامترها جلوگیری کرد ؟
و در url تنها نام همان اکشن نمایش داده شود
و اینکه من از FormCollection برای دریافت مقادیر فرم استفاده میکنم
بهبود SEO در ASP.NET MVC
- ضمنا یک Url میتونه کوئری استرینگی با چندین name-value داشته باشه. ضرورتی به بررسی تمام موارد و کند کردن کار نیست که آیا مقدار دارند همگی یا خیر.
سلام مرسی بابت مطلبتون لطفاً راهنماییم کنین
مسیری هم که توی path دادم به
این شکل هست
C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program
Files\Microsoft SQL Server\120\DTS\Binn\;C:\Program Files\Microsoft SQL
Server\Client SDK\ODBC\110\Tools\Binn\;C:\Program Files (x86)\Microsoft SQL
Server\120\Tools\Binn\;C:\Program Files\Microsoft SQL
Server\120\Tools\Binn\;C:\Program Files (x86)\Microsoft SQL
Server\120\Tools\Binn\ManagementStudio\;C:\Program Files (x86)\Microsoft SQL
Server\120\DTS\Binn\;C:\Program Files (x86)\Windows Kits\8.1\Windows
Performance Toolkit\;C:\Program Files\Microsoft SQL
Server\110\Tools\Binn\;C:\Program Files (x86)\Skype\Phone\;C:\Program Files
(x86)\CodeSmith\v5.2\;C:\Program Files (x86)\nodejs\;C:\Program Files
(x86)\Microsoft
SDKs\TypeScript\1.0\;%JAVA_HOME%\bin;%ADT_HOME%\tools;%ADT_HOME%\platform-tools;%ANT_HOME%\bin;%GIT_HOME%\cmd;C:\Program
Files (x86)\nodejs\;%JAVA_HOME%\bin;%ANT_HOME%\bin;%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools;E:\Android
Softwares\android-sdk Complete\android-sdk;
مسیر sdk هم اینجا
هست
E:\Android Softwares\android-sdk Complete\android-sdk
در ضمن path قبلی هم این بود
C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Microsoft SQL Server\120\DTS\Binn\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\110\Tools\Binn\;C:\Program Files (x86)\Microsoft SQL Server\120\Tools\Binn\;C:\Program Files\Microsoft SQL Server\120\Tools\Binn\;C:\Program Files (x86)\Microsoft SQL Server\120\Tools\Binn\ManagementStudio\;C:\Program Files (x86)\Microsoft SQL Server\120\DTS\Binn\;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Program Files\Microsoft SQL Server\110\Tools\Binn\;C:\Program Files (x86)\Skype\Phone\;C:\Program Files (x86)\CodeSmith\v5.2\;C:\Program Files (x86)\nodejs\;C:\Program Files (x86)\Microsoft SDKs\TypeScript\1.0\;%JAVA_HOME%\bin;%ADT_HOME%\tools;%ADT_HOME%\platform-tools;%ANT_HOME%\bin;%GIT_HOME%\cmd
اما ارور زیر همچنان بر قرار است
خوب، تا اینجا ممکن است مشکلی به نظر نرسد و هدف از کش کردن اطلاعات یک اکشن متد نیز همین مورد است. اما اگر این اکشن متد کش شده، به اشتباه در یک کنترلر مزین شده با ویژگی Authorize قرار گیرد، چه خواهد شد؟ مثلا این کنترلر امن، برای ارائه فایلها یا حتی نمایش قسمتی از صفحه یا کل صفحه، از کش استفاده کرده است. در بار اول دریافت فایل، بدیهی است که تمام مسایل اعتبارسنجی باید مطابق طول عمر یک کنترلر روی دهند. اما در بار دوم فراخوانی آدرس دریافت صفحه یا فایل، اصلا کار به فراخوانی کنترلر نمیرسد. به عبارتی کلیه کاربران سایت (اعم از لاگین شده، نشده، دارای دسترسی مشاهده صفحه یا آدرس امن و یا بدون دسترسی)، به این محتوای خاص بدون مشکلی دسترسی خواهند داشت (فقط کافی است که از آدرس نهایی به نحوی مطلع شوند).
سؤال: چگونه میتوان کلیه اکشن متدهای یک پروژه ASP.NET MVC را که دارای ویژگی OutputCache در یک کنترلر امن هستند، یافت؟
using System; using System.Linq; using System.Reflection; // Add a ref. to \Program Files\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies\System.Web.Mvc.dll using System.Web.Mvc; // Add a ref. to System.Web using System.Web.UI; namespace FindOutputCaches { class Program { static void Main(string[] args) { var path = @"D:\site\bin\Web.dll"; var asmTarget = Assembly.LoadFrom(path); checkSecuredControllers(asmTarget); Console.WriteLine("Press a key..."); Console.Read(); } private static void checkSecuredControllers(Assembly asmTarget) { // یافتن کلیه کنترلرهایی که فیلتر اوتورایز دارند var securedControllers = asmTarget.GetTypes() .Where(type => typeof(IController).IsAssignableFrom(type) && Attribute.IsDefined(type, typeof(AuthorizeAttribute)) && !type.Name.StartsWith("T4MVC")) .ToList(); foreach (var controller in securedControllers) { // یافتن کلیه اکشن متدهای کنترلر جاری var actionMethods = controller.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) .Where(method => typeof(ActionResult).IsAssignableFrom(method.ReturnType)) .ToList(); foreach (var method in actionMethods) { // یافتن متدهایی که دارای آوت پوت کش هستند var attributes = method.GetCustomAttributes(typeof(OutputCacheAttribute), true); if (attributes == null || !attributes.Any()) continue; var outputCache = (OutputCacheAttribute)attributes[0]; // AllowMultiple = false if (outputCache.Location == OutputCacheLocation.None) continue; //سبب عدم کش شدن شده است؛ مثلا برای کارهای ایجکسی Console.WriteLine("Detected incorrect usage of OutputCache in:\n {0}-->{1}", controller.FullName, method.Name); } } } } }
ابتدا مسیر اسمبلی کامپایل شده پروژه ASP.NET MVC که حاوی کنترلرهای برنامه است، باید مشخص گردد.
سپس در این اسمبلی کلیه نوعهای تعریف شده، یافت گردیده و آنهایی که پیاده سازی کننده IController هستند (یعنی کلاسهای کنترلر واقعی برنامه) و همچنین دارای ویژگی AuthorizeAttribute نیز میباشند، جدا خواهند شد.
در ادامه، در هر کنترلر امن یافت شده، متدهایی را بررسی خواهیم کرد که دارای خروجی از نوع ActionResult باشند (فقط اکشن متدها مدنظر هستند). اگر این اکشن متد یافت شده دارای ویژگی OutputCacheAttribute بود و همچنین Location آن به None تنظیم نشده بود ... یعنی مشکل امنیتی وجود دارد که باید برطرف شود.
البته برای تکمیل این مطلب باید دو حالت زیر هم پیاده سازی و بررسی شوند:
- کلیه Viewهای برنامه بررسی شوند. اگر در View خاصی که متعلق است به یک کنترلر یا حتی اکشن متد امن، ارجاعی به اکشن متدی کش شده در کنترلری دیگر وجود داشت، این مورد هم یک باگ امنیتی است.
- کلیه کنترلرهای عمومی که دارای اکشن متدی امن هستند نیز باید جهت یافتن OutputCache بررسی شوند.
قابلیت جالبی از SQL Server 2005 به بعد به این محصول اضافه شده است که امکان ایجاد یک وب سرویس بومی را بر اساس رویههای ذخیره شده و یا توابع تعریف شده در دیتابیسهای موجود، فراهم میسازد. این قابلیت نیازی به IIS یا هر هاست دیگری برای اجرا ندارد و توسط خود اس کیوال سرور راه اندازی و مدیریت میشود.
توضیحات مفصل آنرا در MSDN میتوانید ملاحظه کنید و در اینجا یک مثال عملی از آن را با هم مرور خواهیم کرد:
الف) ایجاد یک جدول آزمایشی به همراه تعدادی رکورد دلخواه در آن
CREATE TABLE [tblWSTest](
[id] [int] IDENTITY(1,1) NOT NULL,
[f1] [nvarchar](50) NULL,
[f2] [nvarchar](500) NULL,
CONSTRAINT [PK_tblWSTest] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
SET IDENTITY_INSERT [tblWSTest] ON
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (1, N'a1', N'a2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (2, N'b1', N'b2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (3, N'c1', N'c2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (4, N'd1', N'd2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (5, N'e1', N'e2')
SET IDENTITY_INSERT [dbo].[tblWSTest] OFF
CREATE PROCEDURE GetAllData
AS
SELECT f1,
f2
FROM tblWSTest
CREATE ENDPOINT GetDataService
STATE = STARTED
AS HTTP(
PATH = '/GetData',
AUTHENTICATION = (INTEGRATED),
PORTS = (CLEAR),
CLEAR_PORT = 8080,
SITE = '*'
)
FOR SOAP(
WEBMETHOD 'GetAllData'
(NAME = 'testdb2009.dbo.GetAllData'),
WSDL = DEFAULT,
DATABASE = 'testdb2009',
NAMESPACE = DEFAULT
)
توضیحات:
Ports در حالت clear و یا ssl میتواند باشد. همچنین برای اینکه با IIS موجود بر روی سیستم هم تداخل نکند CLEAR_PORT به 8080 تنظیم شده است. سایر پارامترهای آن بسیار واضح هستند. برای مثال تعیین دیتابیسی که این رویه ذخیره شده در آن قرار دارد و همچنین مسیر کامل دسترسی به آن دقیقا مشخص میگردند.
این وب سرویس هم اکنون آغاز به کار کرده است. برای مشاهده wsdl آن، آدرس زیر را در مرورگر وب خود وارد نمائید (PATH و CLEAR_PORT معرفی شده در endPoint اینجا بکار میرود):
د) استفاده از این وب سرویس در یک برنامه ویندوزی
یک برنامه ساده winForms را شروع کنید. سپس یک DataGridView را بر روی فرم قرار دهید (بدیهی است این مورد میتواند یک برنامه ASP.Net هم باشد و موارد مشابه دیگر). سپس از منوی پروژه، یک service reference را در VS2008 بر اساس آدرس wdsl فوق اضافه کنید (شکل زیر):
برای اینکه این مثال در VS2008 درست کار کند باید فایل app.config ایجاد شده را کمی ویرایش کرد. قسمت security آن را یافته و تغییرات زیر را با توجه به AUTHENTICATION مورد نیاز تغییر دهید:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
using System;
using System.Data;
using System.Windows.Forms;
namespace WebServiceTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
ServiceReference1.GetDataServiceSoapClient data =
new ServiceReference1.GetDataServiceSoapClient();
dataGridView1.DataSource = (data.GetAllData()[0] as DataSet).Tables[0];
}
}
}
- بهبود کپسوله سازی قسمتهای مختلف برنامه با بسته بندی آنها در ماژولهای متفاوت
- فراهم آوردن امکان lazy loading و بهبود کارآیی برنامه
انواع ماژولهای توصیه شدهی در برنامههای Angular
منهای App Module پیشفرض یک برنامههای Angular، ایجاد سه نوع ماژول دیگر نیز در جهت سازماندهی اینگونه برنامهها توصیه میشوند:
- Core Module
هدف از آن فراهم آوردن سرویسهای Singleton اشتراکی بین کامپوننتها و ماژولهای مختلف برنامه است. علت اینجا است که سیستم تزریق وابستگیهای Angular، به ازای هر ماژولی که Lazy loaded باشد، سرویس تزریقی در آنها را مجددا وهله سازی میکند. به همین جهت نیاز است تک ماژول اختصاصی را برای مدیریت سرویسهایی که نیازی است تنها یکبار در طول عمر برنامه وهله سازی شوند، تدارک ببینیم و Core Module مکان مناسبی برای اینکار است.
همچنین Code Module باید شامل کامپوننتهایی در سطح برنامه باشد. دراینجا منظور از «در سطح برنامه»، کامپوننتهایی که قرار است در بین تمام ماژولها به اشتراک گذاشته شوند، نیست. منظور تنها کامپوننتهایی هستند که در App Component اصلی برنامه قرار است استفاده شوند؛ مانند منوی راهبری بالای سایت.
- Shared Module
هدف از آن مدیریت و بسته بندی کامپوننتها، دایرکتیوها و Pipes اشتراکی بین تمام اجزای برنامه است. برای مثال کامپوننت «لطفا منتظر بمانید ...» اگر قرار است در تمام قسمتهای برنامه استفاده شود، نیاز است در Shared Module تعریف شود. از این جهت که در یک برنامهی Angular نمیتوان یک کامپوننت را بین دو ماژول مختلف به اشتراک گذاشت. به همین جهت نیاز است یک مکان مرکزی برای تعریف این کامپوننتهای اشتراکی ایجاد شود و سپس این تک ماژول را در قسمتهای مختلف برنامه، بدون مشکل مورد استفاده قرار داد.
- Feature Module
این ماژولها به ازای هر ویژگی برنامه ایجاد شده و کامپوننتها، سرویسها، دایرکتیوها و Pipes اختصاصی آن ویژگی را بسته بندی میکنند.
ایجاد Core Module
فرض کنید میخواهید اطلاعات کاربر جاری لاگین شده را در طول عمر برنامه نگهداری کنید و از آن در تمام قسمتهای برنامه استفاده نمائید. یک چنین سرویسی نیاز است دارای طول عمر Singleton باشد و تنها یکبار وهله سازی شود تا اطلاعات کاربر جاری از دست نرود. به همین جهت بهترین مکان تعریف این سرویس، در Core Module است.
برای این منظور در ساختار برنامهی خود، پوشهی جدید src\app\core را ایجاد میکنیم. سپس فایل core.module.ts را به صورت ذیل در آن تعریف خواهیم کرد:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { UserRepositoryService } from './user-repository.service'; import { NavBarComponent } from './nav-bar.component'; import { AccountMenuComponent } from './account-menu.component'; @NgModule({ imports: [ CommonModule, RouterModule ], exports: [ NavBarComponent, AccountMenuComponent ], declarations: [ NavBarComponent, AccountMenuComponent ], providers: [ UserRepositoryService ] }) export class CoreModule { };
- سپس سرویسهای اشتراکی و Singleton برنامه در قسمت providers آن قرار میگیرند.
- در اینجا همچنین دو کامپوننت منو که توسط app.component.ts مورد استفاده قرار میگیرند نیز import شدهاند.
- فایلهای account-menu.component.ts، nav-bar.component.ts و user-repository.service.ts نیز به درون پوشهی src\app\core منتقل خواهند شد (به همراه تمام فایلهای html و css متناظر با آنها).
- اگر دقت کنید، قسمت exports این ماژول نیز مقدار دهی شدهاست. چون این کامپوننتها قرار است خارج از این ماژول و در AppModule استفاده شوند، نیاز است آنها را به صورت خروجی نیز معرفی کنیم.
اکنون جهت استفادهی از این قابلیتها، تنها کافی است تعریف CoreModule را به AppModule در فایل app.module.ts اضافه کنیم:
import { CoreModule } from "./core/core.module"; @NgModule({ imports: [ //... CoreModule, //... RouterModule.forRoot(appRoutes) ], //... }) export class AppModule { }
ایجاد Shared Modules
در Shared Module اجزایی را قرار خواهیم داد که قرار است در بیش از یک ماژول مورد استفاده قرار گیرند. به همین جهت در ساختار برنامهی خود، پوشهی جدید src\app\shared را ایجاد میکنیم. سپس در آن، ماژول جدید shared.module.ts را ایجاد خواهیم کرد:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { LoadingSpinnerComponent } from './loading-spinner.component'; @NgModule({ imports: [ CommonModule ], declarations: [ LoadingSpinnerComponent ], exports: [ LoadingSpinnerComponent, CommonModule ], providers: [ ] }) export class SharedModule { };
از این جهت که اجزای خروجی این ماژول قرار است در Feature Moduleها استفاده شوند، CommonModule مورد استفادهی در آنها نیز در قسمت exports ذکر شدهاست.
اکنون جهت استفادهی از این قابلیتها، تنها کافی است تعریف SharedModule را به AppModule در فایل app.module.ts اضافه کنیم:
import { CoreModule } from "./core/core.module"; import { SharedModule } from "./shared/shared.module"; @NgModule({ imports: [ //... CoreModule, SharedModule, //... RouterModule.forRoot(appRoutes) ], //... }) export class AppModule { }
ایجاد Feature Modules
این مورد نکتهی ویژهای را به همراه ندارد و همانند ایجاد سایر ماژولهای برنامهاست. برای مثال ویژگی مدیریت کاربران، به همراه تمام اجزای آن درون ماژول کاربران قرار میگیرد و به همین ترتیب برای سایر ویژگیهای دیگر برنامه. ایجاد و مدیریت اینگونه ماژولها توسط Angular CLI بسیار سادهاست:
> ng g m users -m app.module --routing > ng g c users/users-list
دستور دوم نیز کامپوننتی را به این ماژول اضافه میکند؛ به همراه به روز رسانی تعاریف این ماژول.
فقط در اینجا SharedModule ایی را که پیشتر اضافه کردیم، به قسمت imports آن اضافه میکنیم:
import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { SharedModule } from '../shared/shared.module'; import { UsersListComponent } from './users-list.component'; @NgModule({ imports: [ RouterModule, SharedModule ], declarations: [ UsersListComponent ], exports: [ ], providers: [ ] }) export class UsersModule { };
1- باز کردن فایل hosts و نوشتن کدهای زیر (البته شما میتوانید هر اسم دلخواهی وارد نمایید)
127.0.0.1 localhost 127.0.0.1 mysite.com 127.0.0.1 master.mysite.com 127.0.0.1 store1.mysite.com 127.0.0.1 store2.mysite.com 127.0.0.1 store3.mysite.com 127.0.0.1 store4.mysite.com 127.0.0.1 store5.mysite.com 127.0.0.1 store6.mysite.com 127.0.0.1 store7.mysite.com 127.0.0.1 store8.mysite.com 127.0.0.1 store9.mysite.com
<bindings> <!--<binding protocol="http" bindingInformation="*:80:localhost" />--> <binding protocol="http" bindingInformation="*:80:mysite.com" /> <binding protocol="http" bindingInformation="*:80:master.mysite.com" /> <binding protocol="http" bindingInformation="*:80:store1.mysite.com" /> <binding protocol="http" bindingInformation="*:80:store2.mysite.com" /> <binding protocol="http" bindingInformation="*:80:store3.mysite.com" /> <binding protocol="http" bindingInformation="*:80:store4.mysite.com" /> <binding protocol="http" bindingInformation="*:80:store5.mysite.com" /> <binding protocol="http" bindingInformation="*:80:store6.mysite.com" /> <binding protocol="http" bindingInformation="*:80:store7.mysite.com" /> <binding protocol="http" bindingInformation="*:80:store8.mysite.com" /> <binding protocol="http" bindingInformation="*:80:store9.mysite.com" /> </bindings>
برای این کار ابتدا cmd را با دسترسی مدیریتی اجرا کنید و با استفاده از دستور زیر میتوان تک تک دامنهها را رجیستر کرد:
netsh http add urlacl url=http://mysite.com:80/ user=everyone netsh http add urlacl url=http://master.mysite.com:80/ user=everyone . . . netsh http add urlacl url=http://store9.mysite.com:80/ user=everyone
پ.ن: در صورتی که نمیخواهید از پورت 80 استفاده کنید میتوانید به جای 80 پورت دلخواه خود را وارد نمایید. در این صورت از طریق آدرس mysite.com:mportnumber در دسترس خواهد بود
در دات نت یکسری رخداد وجود دارند که مربوط به سیستم عامل میشوند و از کلاس SystemEvents قابل دسترسی هستند. در اینجا ایونتی داریم به اسم UserPreferenceChanged که شامل مواردی میشود که کاربر، تنظیمات ویندوز را تغییر میدهد. هر تغییری که در تنظیمات ویندوز اعمال بشود، درون یکی از Categoryها صدا زده میشود. پس اگر ما این ایونت را رجیستر کنیم، هر موقع تغییری در تنظیمات ویندوز اعمال بشود، برنامهی ما نیز متوجه میشود.
برای این منظور یک کلاس را ایجاد میکنیم و در متد سازندهی آن، این رخداد را ثبت میکنیم:
pubic class ThemeHelper { public ThemeHelper() { SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; } private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) { switch (e.Category) { case UserPreferenceCategory.Accessibility: break; case UserPreferenceCategory.Color: break; case UserPreferenceCategory.Desktop: break; case UserPreferenceCategory.General: break; case UserPreferenceCategory.Icon: break; case UserPreferenceCategory.Keyboard: break; case UserPreferenceCategory.Menu: break; case UserPreferenceCategory.Mouse: break; case UserPreferenceCategory.Policy: break; case UserPreferenceCategory.Power: break; case UserPreferenceCategory.Screensaver: break; case UserPreferenceCategory.Window: break; case UserPreferenceCategory.Locale: break; case UserPreferenceCategory.VisualStyle: break; } } }
private const string RegistryKeyPathTheme = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"; private const string RegSysMode = "SystemUsesLightTheme"; public static UITheme GetWindowsTheme() { return GetThemeFromRegistry(RegSysMode); } private static UITheme GetThemeFromRegistry(string registryKey) { using var key = Registry.CurrentUser.OpenSubKey(RegistryKeyPathTheme); var themeValue = key?.GetValue(registryKey) as int?; return themeValue != 0 ? UITheme.Light : UITheme.Dark; } public enum UITheme { Light, Dark }
public event EventHandler<FunctionEventArgs<UIWindowTheme>> WindowsThemeChanged; protected virtual void OnWindowsThemeChanged(UIWindowTheme theme) { EventHandler<FunctionEventArgs<UIWindowTheme>> handler = WindowsThemeChanged; handler?.Invoke(this, new FunctionEventArgs<UIWindowTheme>(theme)); }
public class FunctionEventArgs<T> : RoutedEventArgs { public FunctionEventArgs(T theme) { Theme = theme; } public FunctionEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { } public T Theme { get; set; } }
FunctionEventArgs<UIWindowTheme>
public class UIWindowTheme { public Brush AccentBrush { get; set; } public UITheme CurrentTheme { get; set; } }
case UserPreferenceCategory.General: var changedTheme = new UIWindowTheme() { AccentBrush = SystemParameters.WindowGlassBrush, CurrentTheme = GetWindowsTheme() }; OnWindowsThemeChanged(changedTheme); break;
ThemeHelper tm = new ThemeHelper(); tm.WindowsThemeChanged +=OnWindowsThemeChanged; private void OnWindowsThemeChanged(object? sender, FunctionEventArgs<RegistryThemeHelper.UIWindowTheme> e) { rec.Fill = e.Theme.AccentBrush; if (e.Theme.CurrentTheme == ThemeHelper.UITheme.Light) { Background = Brushes.White; } else { Background = Brushes.Black; } }
در این مقاله قصد داریم یک Api تحت وب را با استفاده از فریمورک ASP.NET Core توسعه دهیم تا عملیات CRUD را بر روی دیتابیس MongoDb که یکی از محبوبترین دیتابیسهای NoSql است، انجام دهد. قبل از شروع کار باید ویژوال استودیو نسخهی 2019 را نصب داشته باشید؛ بهطوریکه ورک لود ASP.NET and web development را هم حتما همراه آن نصب کرده باشید. علاوه بر آن باید .Net Core SDK 3.0+ و دیتابیس MongoDb را هم نصب کنید که میتوانید آنها را از آدرسهای زیر دانلود کنید. نگران نصب MongoDb هم نباشید چون نکته خاصی ندارد.
https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/
https://dotnet.microsoft.com/download/dotnet-core
نسخهی جاری MongoDb، 4.4 است که پس از نصب، به صورت پیشفرض در آدرس C:\Program Files\MongoDB قرار میگیرد. در مسیر C:\Program Files\MongoDB\Server\4.4\bin فایلهای اصلی MongoDb قرار دارند و برای تعامل با MongoDb، به این فایلها نیاز خواهیم داشت. پس برای اینکه به راحتی بتوان در هر جای سیستم از طریق پاورشل به این فایلها دسترسی داشته باشید، این مسیر را به Path environment variable ویندوز اضافه کنید.
MongoDb دارای یک بخش اصلی یا اصطلاحا یکdaemon است که وظیفهی آن، پردازش درخواستهایی است که برای کار با دادهها صادر میشود. در حقیقت همه کارهایی که ما با دادهها انجام میدهیم مثلا دسترسی به دادهها و دستکاری آنها، از طریق این daemon انجام میگیرد و پشت صحنهی این daemon، با Storage Engine کار خواهد کرد. برای اجرای daemon، پاور شل را باز کنید و دستور mongod را وارد کنید. اگر با تنظیمات پیشفرض اجرا کنید، بر روی پورت 27017 بالا آمده و فایلهای دیتابیس را هم در مسیر C:\data\db قرار میدهد. اگر این مسیر را نداشته باشید، با خطا مواجه میشوید. یا باید این مسیر را تعریف کنید و یا از سوئیچ dbpath -- استفاده کنید تا مسیر فایل دیتابیس را تغییر دهید. پس پاور شل را باز کنید و دستور زیر را وارد کنید.
>> mongod --dbpath C:\BooksData
>> mongo
>> use BookstoreDb
بعد از ساختن دیتابیس، باید یک کالکشن بسازید. کالکشنها را میتوان معادل جداول، در دیتابیسهای رابطهای تصور کرد. با دستور createCollection می توان اینکار را انجام داد. برای اینکار دستور زیر را وارد کنید.
>> db.createCollection('Books')
بعد از ساختن کالکشن، میخواهیم مقداری دیتا را در آن قرار دهیم. معادل رکورد در دیتابیسهای رابطهای، در دیتابیس مونگو دیبی، Document نام دارد که مانند رکوردهای دیتابیسهای رابطهای نیست و ساختار و اسکیمای خاصی ندارد؛ یعنی میتوان هر دیتایی را با هر ساختاری در آن ذخیره کرد. میخواهیم دو Document را به کالکشن Books اضافه کنیم. پس دستور زیر را وارد میکنیم. توجه کنید دادهها با ساختار json وارد میشوند.
>> db.Books.insertMany([{'Name':'Design Patterns','Price':54.93,'Category':'Computers','Author':'Ralph Johnson'}, {'Name':'Clean Code','Price':43.15,'Category':'Computers','Author':'Robert C. Martin'}])
{ "acknowledged" : true, "insertedIds" : [ ObjectId("5bfd996f7b8e48dc15ff215d"), ObjectId("5bfd996f7b8e48dc15ff215e") ] }
>> db.Books.find().pretty()
{ "_id" : ObjectId("5bfd996f7b8e48dc15ff215d"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" }, { "_id" : ObjectId("5bfd996f7b8e48dc15ff215e"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }