سفر به Angular بخش اول
In the eighteen years that I’ve been doing Web development, a lot has changed. We started out creating HTML pages to present static information to our users. We then used classic ASP to get database data and incorporate that into our pages. To use both of these technologies, we had to know a lot about HTML, CSS, and JavaScript. Along came .NET and we started rendering everything on the server-side. We forgot a lot about HTML, CSS, and JavaScript as Web Forms wrapped up a lot of that for us. Web Forms’ architecture closely mimicked the way developers created desktop applications. This was great for helping developers move to the Web, but unfortunately hid a lot of the power of the Web, and also tended to be a little slow.
ایجاد کردن اولین Remote app
npm init --yes
npm install html-webpack-plugin webpack webpack-cli webpack-dev-server --save
{ "name": "remote1", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "webpack serve" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "html-webpack-plugin": "^5.3.2", "webpack": "^5.57.0", "webpack-cli": "^4.8.0", "webpack-dev-server": "^4.3.1" } }
<!DOCTYPE html> <html> <head> <title> Remote1(Localhost:7001) </title> </head> <body> <div id="dev-remote1"></div> </body> </html>
const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); module.exports = { mode: 'development', devServer: { port: 7001, }, plugins: [ new ModuleFederationPlugin({ name: 'remote1', filename: 'remoteEntry.js', exposes: { './RemoteApp1': './src/startup', }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ], };
import('./startup');
const mount = (el) => { el.innerHTML = '<div>Remote 1 Content</div>'; }; if (process.env.NODE_ENV === 'development') { const el = document.querySelector('#dev-remote1'); if (el) { mount(el); } } export { mount };
ایجاد کردن دومین Remote app
{ "name": "remote2", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "webpack serve" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "html-webpack-plugin": "^5.3.2", "webpack": "^5.57.0", "webpack-cli": "^4.8.0", "webpack-dev-server": "^4.3.1" } }
<!DOCTYPE html> <html> <head> <title> Remote2(Localhost:7002) </title> </head> <body> <div id="dev-remote2"></div> </body> </html>
const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); module.exports = { mode: 'development', devServer: { port: 7002, }, plugins: [ new ModuleFederationPlugin({ name: 'remote2', filename: 'remoteEntry.js', exposes: { './RemoteApp2': './src/startup', }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ], };
import('./startup');
const mount = (el) => { el.innerHTML = '<div>Remote 2 Content</div>'; }; if (process.env.NODE_ENV === 'development') { const el = document.querySelector('#dev-remote2'); if (el) { mount(el); } } export { mount };
ایجاد کردن Host app و یکپارچه کردن آن با Remote app ها
{ "name": "container", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "webpack serve" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "html-webpack-plugin": "^5.3.2", "webpack": "^5.57.0", "webpack-cli": "^4.8.0", "webpack-dev-server": "^4.3.1" } }
<!DOCTYPE html> <html> <head> <title>Host App (Localhost:7000)</title> </head> <body> <div id="remote1-app"></div> <div id="remote2-app"></div> </body> </html>
const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); module.exports = { mode: 'development', devServer: { port: 7000, }, plugins: [ new ModuleFederationPlugin({ name: 'container', remotes: { remote1: 'remote1@http://localhost:7001/remoteEntry.js', remote2: 'remote2@http://localhost:7002/remoteEntry.js', }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ], };
import('./startup');
import { mount as remote1Mount } from 'remote1/RemoteApp1'; import { mount as remote2Mount } from 'remote2/RemoteApp2'; remote1Mount(document.querySelector('#remote1-app')); remote2Mount(document.querySelector('#remote2-app'));
ملاحظات
new ModuleFederationPlugin({ name: 'remote1', filename: 'remoteEntry.js', exposes: { './RemoteApp1': './src/startup', }, shared:['react', 'react-dom'] }),
بررسی تصویر امنیتی (Captcha) سایت - قسمت دوم
ممنون
مدیریت سفارشی سطوح دسترسی کاربران در MVC
ASP.NET MVC #18
<location path="content"> <system.web> <authorization> <allow users="*" /> </authorization> </system.web> </location> <authentication mode="forms"> <forms loginurl="~/account/logon" slidingexpiration="true" timeout="2"/> </authentication> <authorization> <!--<allow roles="?"/>--> <deny users="?"/> </authorization>
سلام آقای نصیری
ممنون از مطالب خوبتون
من تو این قسمت مشکل دارم تا اینجا درست کار میکنه که کسانی که authenticate نکردن برن به صفحه لاگین اما cssها رو با اینکه location هم گذاشتم نمیاره
بالای system.web هم میزنم
در Asp.net دو چرخهی حیات مهم
وجود دارند که اساس چارچوب MVC را تشکیل میدهند
:
- چرخهی حیات برنامه (Application)؛ از لحظهای که برنامه برای اولین بار اجرا میشود و تا لحظهی خاتمهی آن را شامل میشود.
- چرخهی حیات یک درخواست ( Request )؛ مسیری که یک درخواست طی میکند، اصطلاحا PipeLine نامیده میشود که همان چرخهی حیات یک درخواست نیز هست و از لحظهای که درخواست تحویل asp.net شده، تا زمانیکه درخواست ارسال میشود را شامل میشود.
تمرکز بنده بیشتر بر روی روند و مسیری است که یک درخواست طی میکند و قصد دارم با بهره گیری از کتاب Pro Asp.net Mvc 5 و دیگر منابع، چرخهی حیات درخواست را در برنامههای Mvc بررسی کرده و در مقالات آتی ماژولها و هندلرها را بررسی کنم.
در asp.net ، برنامه global فایلهای شامل دو فایل Global.asax , Global.asax.cs است.
فایل Global.asax که هیچ گاه نیاز به ویرایش آن نداریم محتویاتی مانند زیر دارد:
<%@ Application Codebehind="Global.asax.cs" Inherits="YourAppName.MvcApplication" Language="C#" %>
در این مقاله منظور از فایل global فایل Global.asax.cs است که مشتق شده از کلاس System.Web.HttpApplication است:
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { ...// } }
Asp.net برای پاسخگویی به درخواستهای واصله، وهلههایی از کلاس MvcApplication را میسازد ولی این دو متد صرفا در نقاط شروع و پایان برنامه فراخوانی شده و عملا در وهلههای یاد شده صدا زده نخواهند شد و به جای آنها رویدادهایی را که در ذیل آنها را معرفی میکنیم، فراخوانی شده و چرخهی حیات درخواست را برای ما مشخص میسازند .
BeginRequest : به عنوان اولین رویداد، به محض وصول یک درخواست جدید رخ خواهد داد.AuthenticateRequest ,PostAuthenticateRequest : رویداد AuthenticateRequest برای شناسایی کاربر ارسال کننده درخواست، کاربرد دارد و پس از پردازش کلیهی توابع، رویداد PostAuthenticateRequest صدا زده میشود.
AuthorizeRequest :بههنگام صدور مجوزهای یک درخواست رخ میدهد و مشابه رویداد بالا پس از پردازش کلیهی توابع، رویداد PostAuthorizeRequest صدا زده خواهد شد.ResolveRequestCache : پس از صدور مجوزهای یک درخواست در رویداد authorization زمانیکه ماژولهای کش میخواهند اطلاعاتی را از کش سرور مطالبه کنند، رخ میدهد و به مانند دو رخداد قبلی، PostResolveRequestCache نیز پس از اتمام پردازش توابع رویداد رخ میدهد.
MapRequestHandler : زمانی که Asp.net میخواهد هندلری را برای پاسخگویی به درخواست واصله انتخاب کند رخ میدهد و PostMapRequestHandler نیز پس از این انتخاب، تریگر میشود.AcquireRequestState : جهت بدست آوردن دادههایی نظیر سشن و ... مرتبط با درخواست جاری کاربرد داشته و PostAcquireRequestState نیز پس از پردازش توابع رویداد رخ خواهد داد.
PreRequestHandlerExecute : بالافاصله قبل و همچنین بلافاصله بعد از این که یک هندلر بخواهد درخواستی را پردازش کند، رخ میدهد. PostRequestHandlerExecute نیز همانند دیگر رویدادهای گذشته، پس از اتمام پردازش توابع، این رویداد رخ خواهد داد.ReleaseRequestState : زمانی رخ میدهد که دادههای مرتبط با درخواست جاری، در ادامهی روند پردازش درخواست مورد نیاز نباشند و پس از پردازش توابع رویداد، PostReleaseRequestState رخ خواهد داد .
UpdateRequestCache : به جهت اینکه ماژولهای مسئول کش، توانایی به روز رسانی دادههای خود، برای پاسخگویی به درخواستهای بعدی را داشته باشند، این رویداد رخ میدهد.
LogRequest : قبل از انجام عملیات لاگین برای درخواست جاری رخ میدهد و پس از پردازش توابع رویداد نیز PostLogRequest تریگر میشود.EndRequest : پس از پایان کار پردازش درخواست جاری و مهیا شدن پاسخ مرتبط جهت ارسال به مرورگر تریگر خواهد شد.
PreSendRequestHeaders : قبل از ارسال HTTP headers به مرورگر این رویداد رخ خواهد داد.
PreSendRequestContent : بعد از ارسال شدن هدرها و قبل از ارسال محتوای صفحه به مرورگر رخ میدهد.Error : هر زمان و در هر مرحله از پردازش درخواست، چنانچه خطایی صورت پذیرد این رویداد رخ خواهد داد.
فریم ورک Asp.net جهت مدیریت بهتر یک درخواست، در تمام مسیر پردازش، رویدادهای بالا را مهیا کرده است. در ادامه نحوهی هندل کردن رویدادهای چرخهی حیات درخواست را در فایل global توضیح میدهم. هر چند که استفاده از این فایل بدین منظور، صرفا برای مدیریت مسائل ابتدایی مناسب بوده و در یک پروژهی بزرگ موجب به هم ریختگی فایل global با کدهای زیاد و خوانایی پایین بوده که قابلیت استفاده مجدد در دیگر پروژهها را نیز ندارد.
Asp.net این مشکل را با معرفی ماژولها که در مقالات آتی توضیح خواهم داد، مرتفع کرده است.
در فایل global هر گاه متدی را با پیشوند Application_ و نام یکی از رویدادهای بالا بنویسید Asp.net آن را به عنوان هندلری برای رویداد مذکور میشناسد. به عنوان مثال متدی با نام Application_BeginRequest متد رویداد BeginRequest میباشد.
ابتدا یک پروژهی MVC جدید را به نام SimpleApp ایجاد کرده و فایل global آن را مطابق ذیل تغییر میدهیم:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace SimpleApp { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); } protected void Application_BeginRequest() { RecordEvent("BeginRequest"); } protected void Application_AuthenticateRequest() { RecordEvent("AuthenticateRequest"); } protected void Application_PostAuthenticateRequest() { RecordEvent("PostAuthenticateRequest"); } private void RecordEvent(string name) { List<string> eventList = Application["events"] as List<string>; if (eventList == null) { Application["events"] = eventList = new List<string>(); } eventList.Add(name); } } }
در اینجا متدی به نام RecordEvent را در کدهای ذکر شده مشاهده میکنید که نام یک رویداد را دریافت و جهت در دسترس قرار دادن در کل برنامه به خاصیت Application از کلاس HttpApplication نسبت داده و متد مذکور را از سه متد دیگر فراخوانی کردهایم. این متدها در زمان رخ دادن رویدادهای BeginRequest, AuthenticateRequest, PostAuthenticateRequest صدا زده خواهند شد.
حال جهت نمایش اطلاعات رویداد نیاز است تغییراتی مشابه ذیل در کنترلر Home ایجاد نماییم.
using System.Web.Mvc; namespace SimpleApp.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(HttpContext.Application["events"]); } } }
ویوی مرتبط با اکشن متد index را مطابق کدهای ذیل بازنویسی میکنیم:
@model List<string> @{ ViewBag.Title = "Events List"; } <h5>Events</h5> <table> @foreach (string eventName in Model) { <tr> <td>@eventName</td> </tr> } </table>
در این مقاله سعی کردیم ابتدا چرخهی حیات یک Request را فرا گرفته و سپس از طریق فایل global و توسط متدهایی با پیشوند Application_ +نام رویداد (اصطلاحا متدهای ویژه نامیده میشوند) چرخه حیات یک درخواست را مدیریت کنیم.
SQL Server 2016 و تماس با خانه
How to Turn Off the Phone-Home Option for Standard and Enterprise Edition
Enterprise customers may construct Group Policy to opt in or out of telemetry collection by setting a registry-based policy. The relevant registry key and settings are as follows:
Key = HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server\130
RegEntry name = CustomerFeedback
Entry type DWORD: 0 is opt out, 1 is opt in