موقع ویرایش کاربر خطا داره
using System.Windows.Forms; public static class GlobalData { public static Form ScheduleForm { get; set; } }
GlobalData.ScheduleForm = this;
namespace SchedulerDemo.Jobs { using System.Linq; using System.Windows.Forms; using Quartz; public class HelloJob : IJob { private delegate void ButtonTextWriter(string buttonId, string text); MainForm form = GlobalData.ScheduleForm as MainForm; private void SetButtonText(string buttonId, string text) { (form.Controls.Find(buttonId, true).FirstOrDefault() as Button).Text = text; } public void Execute(IJobExecutionContext context) { form.BeginInvoke(new ButtonTextWriter(SetButtonText), new object[] { "myButton", "My Text" }); } } }
- Performance : کارآیی - که در ارتباط با مدت زمان پاسخ گویی و قابل استفاده شدن برنامه میباشد. (مقایسه به درصد - هرچه بیشتر عملکرد بهتر)
- Size : اندازه - که نشان دهنده حجم نهایی فایلهای تولید شده ( Css-Html-JavaScript ) فریم ورک است. این مقایسه اندازه فریم ورک و تمام وابستگیهای آن است که به bundle نهایی برنامه اضافه شده است (هر چه اندازه فایل کمتر باشد بهتر است چراکه توسط کاربر نهایی زودتر دانلود میشود).
- Lines of Code : تعداد خطوط کد - نشان دهنده این است که یک نویسنده بر اساس این فریم ورکها چند سطر کد را باید برای تهیهی یک برنامهی جدید بنویسد.
npx degit sveltejs/template my-svelte-project cd my-svelte-project npm install npm run dev
برای تعریف المانهای فرمها نیاز است ویژگیهای قابل توجهی را مانند placeholder ،required ،maxlength و غیره، تعریف کرد که در صورت زیاد بودن تعداد المانهای یک فرم، مدیریت تعریف این ویژگیها مشکل میشود. به همین جهت قابلیت ویژهای مخصوص اینکار به نام Attribute Splatting در Blazor درنظر گرفته شدهاست. برای توضیح آن، ابتدا کامپوننت والد Pages\LearnBlazor\AttributeSplatting.razor و کامپوننت فرزند Pages\LearnBlazor\LearnBlazorComponents\AttributeSplattingChild.razor را ایجاد میکنیم.
در کامپوننت فرزند یا همان AttributeSplattingChild، یک المان را به همراه تعدادی ویژگی تعریف شده مشاهده میکنید:
<div> <h4 class="text-primary pt-3">Attribute Splatting Child Component</h4> <input id="roomName" placeholder="@Placeholder" required="@Required" maxlength="@MaxLength" class="form-control" /> </div> @code { [Parameter] public string Placeholder { get; set; } = "Initial Text"; [Parameter] public string Required { get; set; } = "required"; [Parameter] public string MaxLength { get; set; } = "10"; }
@page "/AttributeSplatting" <h1>Attribute Splatting</h1> <AttributeSplattingChild Placeholder="Enter the Room Name From Parent" MaxLength="5"> </AttributeSplattingChild>
مشکل! کامپوننت AttributeSplattingChild که فقط به همراه یک المان است، تا این لحظه نیاز به تعریف سه پارامتر جدید را جهت تامین ویژگیهای آن المان داشتهاست. اگر تعداد این المانها افزایش پیدا کرد، آیا راه بهتری برای مدیریت تعداد بالای ویژگیهای مورد نیاز وجود دارد؟
پاسخ: در یک چنین حالتی میتوان ویژگیهای هر المان را توسط پارامتری از نوع Dictionary مدیریت کرد؛ بجای تعریف تک تک آنها به صورت خواصی مجزا. به این قابلیت، Attribute Splatting میگویند.
در این حالت تمام کدهای AttributeSplattingChild.razor به صورت زیر خلاصه میشوند:
<div> <h4 class="text-primary pt-3">Attribute Splatting Child Component</h4> <input id="roomName" @attributes="InputAttributes" class="form-control" /> </div> @code { [Parameter] public Dictionary<string, object> InputAttributes { get; set; } = new Dictionary<string, object> { { "required" , "required"}, { "placeholder", "Initial Text"}, { "maxlength", 10} }; }
و همچنین در ادامه کامپوننت والد یا AttributeSplatting.razor نیز به صورت زیر تغییر میکند:
@page "/AttributeSplatting" <h1>Attribute Splatting</h1> <AttributeSplattingChild InputAttributes="InputAttributesFromParent"></AttributeSplattingChild> @code{ Dictionary<string, object> InputAttributesFromParent = new Dictionary<string, object> { { "required" , "required"}, { "placeholder", "Enter the Room Name From Parent"}, { "maxlength", 5} }; }
ساده سازی روش تعریف key/valueهای شیء دیکشنری Attribute Splatting
تا اینجا موفق شدیم تعداد قابل ملاحظهای از پارامترهای عمومی یک کامپوننت را تنها توسط یک شیء Dictionary مدیریت کنیم. همچنین همانطور که ملاحظه میکنید، هم Dictionary سمت کامپوننت فرزند و هم سمت کامپوننت والد، نیاز به مقدار دهی اولیهای را دارند. این مقدار دهی اولیه را میتوان به نحو دیگری نیز در حین استفادهی از قابلیت Attribute Splatting، انجام داد:
<div> <h4 class="text-primary pt-3">Attribute Splatting Child Component</h4> <input id="roomName" @attributes="InputAttributes" placeholder="Initial Text" class="form-control" /> </div> @code { [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object> InputAttributes { get; set; } = new Dictionary<string, object>(); }
پس از این تغییر، کامپوننت والد هم به صورت زیر خلاصه میشود و دیگر نیازی به تعریف و مقدار دهی InputAttributes و یا تعریف مجزای یک دیکشنری را ندارد. در اینجا هر ویژگی که به المان نسبت داده شود، به عنوان Unmatched Values تفسیر شده و مورد استفاده قرار میگیرد.
@page "/AttributeSplatting" <h1>Attribute Splatting</h1> <AttributeSplattingChild placeholder="Placeholder default"></AttributeSplattingChild>
اگر به تصویر فوق دقت کنید، هرچند در کامپوننت والد مقدار placeholder، به متن دیگری تنظیم شده، اما متن تنظیم شدهی در کامپوننت فرزند، تقدم بیشتری پیدا کرده و نمایش داده شدهاست. علت اینجا است که محل قرارگیری آن در مثال فوق، در سمت راست دایرکتیو attributes@ است. اگر آنرا در سمت چپ attributes@ قرار دهیم، حق تقدم attributes@ بیشتر شده و مقدار تنظیم شدهی در سمت کامپوننت والد، بجای placeholder اولیهی تعریف شدهی در اینجا مورد استفاده قرار میگیرد:
<input id="roomName" placeholder="Initial Text" @attributes="InputAttributes" class="form-control" />
روش انتقال پارامترها به چندین زیر سطح
در قسمت قبل، ParentComponent.razor و ChildComponent.razor را تعریف و تکمیل کردیم. هدف از آنها، بررسی ویژگی Render Fragmentها بود. در ادامهی آن، یک زیر کامپوننت دیگر را نیز به نام Pages\LearnBlazor\LearnBlazorComponents\GrandChildComponent.razor اضافه میکنیم. هدف این است که کامپوننت Parent، کامپوننت Child را فراخوانی کند و کامپوننت Child، کامپوننت GrandChild را تا یک سلسله مراتب از کامپوننتها را تشکیل دهیم.
محتوای GrandChildComponent را هم بسیار ساده نگه میداریم، تا پارامتری رشتهای را دریافت کرده و نمایش دهد:
<div class="row"> <h4 class="text-primary pl-4 pt-2 col-12">Grand Child Component</h4> <br /> <p> There is a message - @MessageForGrandChild </p> </div> @code { [Parameter] public string MessageForGrandChild { get; set; } }
<div class="mt-2"> <GrandChildComponent MessageForGrandChild="@MessageForGrandChild"></GrandChildComponent> </div> @code { [Parameter] public string MessageForGrandChild { get; set; } // ... }
<ChildComponent MessageForGrandChild="This is a message from Grand Parent" Title="This is the second child component"> <p><b>@MessageText</b></p> </ChildComponent>
بنابراین اکنون این سؤال مطرح میشود که آیا میتوان پارامتری را در همان کامپوننت Parent تعریف کرد که توسط کامپوننت GrandChild قابل شناسایی و استفاده باشد، بدون اینکه کامپوننت Child را در این بین تغییر دهیم؟
پاسخ: بله. برای اینکار ویژگیهای CascadingValue و CascadingParameter در Blazor پیش بینی شدهاند.
در ابتدا، پارامتر MessageForGrandChild کامپوننت Child حذف کرده و سپس آنرا توسط کامپوننت توکار CascadingValue محصور میکنیم. در اینجا نیاز است مقدار انتقالی را نیز مشخص کنیم:
<CascadingValue Value="@MessageForGrandChild"> <ChildComponent Title="This is the second child component"> <p><b>@MessageText</b></p> </ChildComponent> </CascadingValue> @code { string MessageForGrandChild = "This is a message from Grand Parent";
<GrandChildComponent></GrandChildComponent>
[CascadingParameter] public string MessageForGrandChild { get; set; }
چند نکته:
- در اینجا نوع CascadingParameter تعریف شده، باید با نوع Value کامپوننت CascadingValue، در بالاترین سطح سلسله مراتب کامپوننتها، یکی باشد.
- نام CascadingParameter تعریف شده مهم نیست. فقط نوع آن مهم است.
- تمام کامپوننتهای موجود و پوشش داده شدهی در سلسله مراتب جاری، قابلیت تعریف CascadingParameter ای مانند مثال فوق را دارند و این تعریف، محدود به پایینترین سطح موجود نیست. برای مثال در اینجا در کامپوننت Child هم در صورت نیاز میتوان همین CascadingParameter را تعریف و استفاده کرد.
روش تعریف پارامترهای آبشاری نامدار
تا اینجا روش انتقال یک پارامتر را از بالاترین سطح، به پایینترین سطح سلسله مراتب کامپوننتهای تعریف شده، بررسی کردیم. اکنون شاید این سؤال مطرح شود که اگر خواستیم بیش از یک پارامتر را بین اجزای این سلسله، به اشتراک بگذاریم چه باید کرد؟
در این حالت میتوان پارامتر جدید را توسط یک کامپوننت CascadingValue تو در تو، به صورت زیر معرفی کرد؛ که اینبار نامدار نیز هست:
<CascadingValue Value="@MessageForGrandChild" Name="MessageFromGrandParent"> <CascadingValue Value="@Number" Name="GrandParentsNumber"> <ChildComponent Title="This is the second child component"> <p><b>@MessageText</b></p> </ChildComponent> </CascadingValue> </CascadingValue> @code { string MessageForGrandChild = "This is a message from Grand Parent"; int Number = 7;
پس از این تغییر، GrandChildComponent، این پارامترهای نامدار را از طریق ذکر صریح خاصیت Name ویژگی CascadingParameter، دریافت میکند:
<div class="row"> <h4 class="text-primary pl-4 pt-2 col-12">Grand Child Component</h4> <br /> There is a message: @Message <br /> GrandParentsNumber: @Number </div> @code { [CascadingParameter(Name = "MessageFromGrandParent")] public string Message { get; set; } [CascadingParameter(Name = "GrandParentsNumber")] public int Number { get; set; } }
یک نکته: چون نوع پارامترهای ارسالی یکی نیست، الزامی به ذکر نام آنها نبود. در این حالت بر اساس نوع پارامترهای آبشاری، عملیات اتصال مقادیر صورت میگیرد. اما اگر نوع هر دو را برای مثال رشتهای تعریف میکردیم، مقدار Number، بر روی مقدار MessageForGrandChild بازنویسی میشد. یعنی در UI، هر دو پارامتر هم نوع، یک مقدار را نمایش میدادند که در حقیقت مقدار پایینترین CascadingValue تعریف شدهاست. بنابراین ذکر نام پارامترهای آبشاری، روشیاست جهت تمایز قائل شدن بین پارامترهای هم نوع.
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: Blazor-5x-Part-09.zip
ایجاد گزارش با داده های ثابت و متغیر
public class Documents { [Key] public int Id { set; get; } [Display(Name = "تاریخ")] public string Date { set; get; } [Display(Name = "تاریخ میلادی")] public DateTime? EnDate { set; get; } [Display(Name = "روز هفته")] public string Day { set; get; } [Display(Name = "بهداشتی نقدی ")] public string BehdashtiNaghdi { set; get; } [Display(Name = "بهداشتی کارتخوان")] public string BehdashtiPose { set; get; } [Display(Name = "فیش بستری نقدی")] public string FishBastariNaghdi { set; get; } [Display(Name = "فیش بستری کارتخوان")] public string FishBastariPose { set; get; } [Display(Name = "تعداد فیش")] public string FishCount { set; get; } [Display(Name = "سرپایی نقدی")] public string SarepayiNaghdi { set; get; } [Display(Name = "سرپایی کارتخوان")] public string SarepayiPose { set; get; } [Display(Name = "تعداد نسخه")] public string Noskhecount { set; get; } [Display(Name = "صندوق شماره 1")] public string SandoghNumberOne { set; get; } [Display(Name = "صندوق شماره 2")] public string SandoghNumberTow { set; get; } [Display(Name = "تعداد فیشهای کارتخوان")] public string PoseResidCount { set; get; } [Display(Name = "نمره دکتر")] public string DoctosrRate { set; get; } [Display(Name = "توضیحات")] public string Description { set; get; } [Display(Name = "توسط کاربر")] [ForeignKey("User")] public virtual Users Users { get; set; } public int User { get; set; } [Display(Name = "پزشک شیفت")] [ForeignKey("Doctor")] public virtual Doctors Doctors { get; set; } public int Doctor { get; set; } [Display(Name = "شیفت")] [ForeignKey("Shift")] public virtual Shift ShiftsShift { get; set; } public int Shift { get; set; } [Display(Name = "نام بیمارستان")] [ForeignKey("HospitalId")] public virtual Hospitals Hospitals { get; set; } public int? HospitalId { get; set; } }
ng generate component [name] یا ng g c [name]
<template> <v-app> <v-toolbar app> <v-toolbar-title> <span>Vuetify</span> <span>MATERIAL DESIGN</span> </v-toolbar-title> <v-spacer></v-spacer> <v-btn flat href="https://github.com/vuetifyjs/vuetify/releases/latest" target="_blank" > <span>Latest Release</span> </v-btn> </v-toolbar> <v-content> <HelloWorld/> </v-content> </v-app> </template> <script> export default { name: 'App', components: { }, data () { return { // } } } </script>
<template> <v-container v-if="loading"> <div> <v-progress-circular indeterminate :size="150" :width="8" color="green"> </v-progress-circular> </div> </v-container> <v-container v-else grid-list-xl> <v-layout wrap> <v-flex xs4 v-for="(item, index) in wholeResponse" :key="index" mb-2> <v-card> <v-img :src="item.Poster" aspect-ratio="1" ></v-img> <v-card-title primary-title> <div> <h2>{{item.Title}}</h2> <div>Year: {{item.Year}}</div> <div>Type: {{item.Type}}</div> <div>IMDB-id: {{item.imdbID}}</div> </div> </v-card-title> <v-card-actions> <v-btn flat color="green" @click="singleMovie(item.imdbID)" >View</v-btn> </v-card-actions> </v-card> </v-flex> </v-layout> </v-container> </template> <script> import movieApi from '@/services/MovieApi' export default { data () { return { wholeResponse: [], loading: true } }, mounted () { movieApi.fetchMovieCollection('indiana') .then(response => { this.wholeResponse = response.Search this.loading = false }) .catch(error => { console.log(error) }) }, methods: { singleMovie (id) { this.$router.push('/movie/' + id) } } } </script> <style scoped> .v-progress-circular margin: 1rem </style>
<template> <v-container v-if="loading"> <div> <v-progress-circular indeterminate :size="150" :width="8" color="green"> </v-progress-circular> </div> </v-container> <v-container v-else> <v-layout wrap> <v-flex xs12 mr-1 ml-1> <v-card> <v-img :src="singleMovie.Poster" aspect-ratio="2" ></v-img> <v-card-title primary-title> <div> <h2>{{singleMovie.Title}}-{{singleMovie.Year}}</h2> <p>{{ singleMovie.Plot}} </p> <h3>Actors:</h3>{{singleMovie.Actors}} <h4>Awards:</h4> {{singleMovie.Awards}} <p>Genre: {{singleMovie.Genre}}</p> </div> </v-card-title> <v-card-actions> <v-btn flat color="green" @click="back">back</v-btn> </v-card-actions> </v-card> </v-flex> </v-layout> <v-layout row wrap> <v-flex xs12> <div> <v-dialog v-model="dialog" width="500"> <v-btn slot="activator" color="green" dark> View Ratings </v-btn> <v-card> <v-card-title primary-title > Ratings </v-card-title> <v-card-text> <table style="width:100%" border="1" > <tr> <th>Source</th> <th>Ratings</th> </tr> <tr v-for="(rating,index) in this.ratings" :key="index"> <td align="center">{{ratings[index].Source}}</td> <td align="center"><v-rating :half-increments="true" :value="ratings[index].Value"></v-rating></td> </tr> </table> </v-card-text> <v-divider></v-divider> <v-card-actions> <v-spacer></v-spacer> <v-btn color="primary" flat @click="dialog = false" > OK </v-btn> </v-card-actions> </v-card> </v-dialog> </div> </v-flex> </v-layout> </v-container> </template> <script> import movieApi from '@/services/MovieApi' export default { props: ['id'], data () { return { singleMovie: '', dialog: false, loading: true, ratings: '' } }, mounted () { movieApi.fetchSingleMovie(this.id) .then(response => { this.singleMovie = response this.ratings = this.singleMovie.Ratings this.ratings.forEach(function (element) { element.Value = parseFloat(element.Value.split(/\/|%/)[0]) element.Value = element.Value <= 10 ? element.Value / 2 : element.Value / 20 } ) this.loading = false }) .catch(error => { console.log(error) }) }, methods: { back () { this.$router.push('/') } } } </script> <style scoped> .v-progress-circular margin: 1rem </style>
<template> <v-container v-if="loading"> <div> <v-progress-circular indeterminate :size="150" :width="8" color="green"> </v-progress-circular> </div> </v-container> <v-container v-else-if="noData"> <div> <h2>No Movie in API with {{this.name}}</h2> </div> </v-container> <v-container v-else grid-list-xl> <v-layout wrap> <v-flex xs4 v-for="(item, index) in movieResponse" :key="index" mb-2> <v-card> <v-img :src="item.Poster" aspect-ratio="1" ></v-img> <v-card-title primary-title> <div> <h2>{{item.Title}}</h2> <div>Year: {{item.Year}}</div> <div>Type: {{item.Type}}</div> <div>IMDB-id: {{item.imdbID}}</div> </div> </v-card-title> <v-card-actions> <v-btn flat color="green" @click="singleMovie(item.imdbID)" >View</v-btn> </v-card-actions> </v-card> </v-flex> </v-layout> </v-container> </template> <script> // در همه کامپوننتها جهت واکشی اطلاعات ایمپورت میشود import movieApi from '@/services/MovieApi' export default { // route پارامتر مورد استفاده در props: ['name'], data () { return { // آرایه ای برای دریافت فیلمها movieResponse: [], // جهت نمایش لودینگ در زمان بارگذاری اطلاعات loading: true, // مشخص کردن آیا اطللاعاتی با سرچ انجام شده پیدا شده یا خیر noData: false } }, // تعریف متدهایی که در برنامه استفاده میکنیم methods: { // این تابع باعث میشود که // route // تعریف شده با نام // Movie // فراخوانی شود و آدرس بار هم تغییر میکنید به آدرسی شبیه زیر // my-site/movie/tt4715356 singleMovie (id) this.$router.push('/movie/' + id) }, fetchResult (value) { movieApi.fetchMovieCollection(value) .then(response => { if (response.Response === 'True') { this.movieResponse = response.Search this.loading = false this.noData = false } else { this.noData = true this.loading = false } }) .catch(error => { console.log(error) }) } }, // جز توابع // life cycle // vue.js // میباشد و زمانی که تمپلیت رندر شد اجرا میشود // همچنین با هر بار تغییر در // virtual dom // این تابع اجرا میشود mounted () { this.fetchResult(this.name) }, // watchها // کار ردیابی تغییرات را انجام میدهند و به محض تغییر مقدار پراپرتی // name // کد مورد نظر در بلاک زیر انجام میشود watch: { name (value) { this.fetchResult(value) } } } </script> <style scoped> .v-progress-circular margin: 1rem </style>
import axios from 'axios'
import axios from 'axios' export default { fetchMovieCollection (name) { return axios.get('&s=' + name) .then(response => { return response.data }) }, fetchSingleMovie (id) { return axios.get('&i=' + id) .then(response => { return response.data }) } }
axios.defaults.baseURL = 'http://www.omdbapi.com/?apikey=b76b385c&page=1&type=movie&Content-Type=application/json'
import Vue from 'vue' import VueRouter from 'vue-router' // برای رجیستر کردن کامپوننتها در بخش روتر، آنها را ایمپورت میکنیم import LatestMovie from '@/components/LatestMovie' import Movie from '@/components/Movie' import SearchMovie from '@/components/SearchMovie' Vue.use(VueRouter) export default new VueRouter({ routes: [ { // مسیری هست که برای این کامپوننت در نظر گرفته شده(صفحه اصلی)بدون پارامتر path: '/', // نام روت name: 'LatestMovie', // نام کامپوننت مورد نظر component: LatestMovie }, { // پارامتری هست که به این کامپوننت ارسال میشه id // برای دستیابی به این کامپوننت نیاز هست با آدرسی شبیه زیر اقدام کرد // my-site/movie/tt4715356 path: '/movie/:id', name: 'Movie', // در کامپوننت جاری یک پراپرتی وجود دارد //id که میتوان با نام // به آن دسترسی پیدا کرد props: true, component: Movie }, { path: '/search/:name', name: 'SearchMovie', props: true, component: SearchMovie } ], // achieve URL navigation without a page reload // When using history mode, the URL will look "normal," e.g. http://oursite.com/user/id. Beautiful! // در آدرس # قرار نمیگیرد mode: 'history' })
npm install
اس کیو ال سرور بوسیله ایجاد پلنهای اجرایی کامپایل شده، سعی در بهینه سازی پروسیجرها دارد. هنگامیکه اس کیو ال سرور یک پروسیجر را کامپایل مینماید، به پارامترهای ارسال شده توجه دارد و یک پلن اجرایی را بر اساس پارامترهای ارسالی ایجاد میکند. به فرآیند تماشا یا توجه به پارامترهای ارسالی به پروسیجر، شنود پارامترها گفته میشود. شنود پارامترها میتواند بعضی از اوقات به کاهش کارآیی پلن اجرایی منجر شود؛ مخصوصا زمانیکه پارامترهایی با کاردینالیتی متفاوت، فراخوانی شوند.
شنود پارامتر چیست؟
شنود پارامتر، قابلیتی است که اس کیو ال سرور توسط آن یک پلن مناسب و بهینه اجرایی را برای پروسیجری با پارامترهای ارسالی، در اولین مرتبه اجرا، تولید خواهد کرد. در ادامه هر فراخوانی پروسیجر با پارامترهای مشابه، منجر به استفاده از پلن اجرایی ذخیره شده خواهد شد. شاید در اولین نگاه این استفاده مجدد، مناسب به نظر برسد. ولی در صورتیکه پروسیجر با پارامترهای متفاوتی فراخوانی شود، ممکن است پلن اجرایی تولید شده بر اساس آن پارامترهای اولیه، برای پارامترهای جدید بهینه نباشد.
پلنهای اجرایی بر اساس چیزهایی که از SQL Server خواسته میشوند، بهینه سازی میشوند. اس کیو ال سرور کوئری را بررسی کرده و یک استراتژی بهینه را برای اجرای آن مشخص میکند. به کارهایی که کوئری قرار است انجام دهد نگاه میکند؛ از مقادیر پارامترها برای استفاده از اطلاعات آماری استفاده کرده و محاسباتی را انجام خواهد داد.
مثالی از مصرف شدید I/O بدلیل شنود پارامتر
در ادامه، برای درک بهتر شنود پارامتر، با مثالی خواهید دید که پروسیجر ذیل، باعث مصرف بالای منابع، بر اساس پارامترهای ارسالی خواهد شد. در این مثال دو دسته متفاوت پارامتر برای اجرای پروسیجر ارسال خواهند شد و خواهید دید که فراخوانی دوم، منابع I/O بیشتری را نسبت به فراخوانی اول، مصرف خواهد کرد. در ادامه کدهای جدولی را که پروسیجر قرار است بر روی آن فراخوانی اطلاعات را انجام دهد، میبینید.
SET NOCOUNT ON; DROP TABLE BillingInfo; CREATE TABLE BillingInfo( ID INT IDENTITY, BillingDate DATETIME, BillingAmt MONEY, BillingDesc varchar(500)); DECLARE @I INT; DECLARE @BD INT; SET @I = 0; WHILE @I < 1000000 BEGIN SET @I = @I + 1; SET @BD=CAST(RAND()*10000 AS INT)%3650; INSERT BillingInfo (BillingDate, BillingAmt) VALUES (DATEADD(DD,@BD, CAST('1999/01/01' AS DATETIME)), RAND()*5000); END ALTER TABLE BillingInfo ADD CONSTRAINT [PK_BillingInfo_ID] PRIMARY KEY CLUSTERED (ID); CREATE NONCLUSTERED INDEX IX_BillingDate ON dbo.BillingInfo(BillingDate);
در جدول BilingInfo بالا، یک میلیون رکورد با مقادیر BilingDate و BilingAmt به صورت تصادفی ایجاد شده است. بر روی ستون ID، ایندکس خوشهای و ستون ایندکس غیر خوشهای بر روی ستون BilingDate ایجاد شدهاست.
بوسیله پروسیجر زیر هم قرار است اطلاعات درخواستی فراهم شود:
CREATE PROC [dbo].[DisplayBillingInfo] @BeginDate DATETIME, @EndDate DATETIME AS SELECT BillingDate, BillingAmt FROM BillingInfo WHERE BillingDate between @BeginDate AND @EndDate;
SET STATISTICS IO ON; DBCC FREEPROCCACHE; EXEC dbo.DisplayBillingInfo @BeginDate = '1999-01-01', @EndDate = '1999-12-31'; EXEC dbo.DisplayBillingInfo @BeginDate = '2005-01-01', @EndDate = '2005-01-03';
در فراخوانی اول، اطلاعات در بازه یک سال و در فراخوانی دوم، در بازه چند روز، درخواست شدهاند. همانطور که گفته شد، پلن اجرایی بر اساس فراخوانی اول ایجاد خواهد شد و فراخوانی دوم نیز براساس همین پلن اجرایی ایجاد شده، اجرا میشود.
همانطور که مشاهده میکنید عملیات Clustered Index Scan، اجرا شده و اطلاعات I/O نیز بشرح زیر است (خط اول فراخوانی اول، خط دوم فراخوانی دوم):
Table 'BillingInfo'. Scan count 1, logical reads 3593, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'BillingInfo'. Scan count 1, logical reads 3593, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SET STATISTICS IO ON; DBCC FREEPROCCACHE; EXEC dbo.DisplayBillingInfo @BeginDate = '2005-01-01', @EndDate = '2005-01-03'; EXEC dbo.DisplayBillingInfo @BeginDate = '1999-01-01', @EndDate = '1999-12-31';
اکنون عملیات Index Seek را بجای Index Scan مشاهده میکنید. اطلاعات I/O هم بشرح زیر است:
Table 'BillingInfo'. Scan count 1, logical reads 2965, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'BillingInfo'. Scan count 1, logical reads 337040, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
DeviceDetector.NET
انقضای اهراز هویت کاربر پس از رفرش کردن صفحه در پروژه ای مشابه
برای یادگیری من دارم پروژه ای شبیه به پروژه شما میسازم. یعنی به عبارتی مراحل شمارو یکی ، یکی طی میکنم. حالا به جایی رسیدم که هرچقدر هم تلاش کردم متاسفانه پاسخی براش پیدا نکردم.
مشکل من اینه. زمانی که کاربر دکمه ورود رو میزنه و وارد سیستم میشه ، زمانی که صفحه رو رفرش کنه یا از صفحه ای به صفحهی دیگه بره اهراز هویتیش تموم میشه. با اینکه "مرا به خاطر داشته باش" رو هم تیک میزنم ولی باز این مشکل پیش میاد. جالب اینجاست کدهای خودتون به درستی در پروژه خودتون کار میکنه ولی وقتی میارمشون تو پروژهی خودم این مشکل پیش میاد. نمیدونم کجارو اشتباه کردم ولی میدونم یک چیزی کمه.
توجه کنید زمانی که کاربر ورود میکنه مقدار @User.Identity.IsAuthenticated برابر با true هستش. پس قطعا کاربر ورود میکنه ولی زمانی که صفحه تغییر میکنه این مقدار برابر false میشه.
کدهای کلاس Startup دقیقا همون کدهای شما و من تغییری بهشون ندادم فقط اسم کوکی رو عوض کردم یعنی اینطوری :
public class Startup { public void Configuration(IAppBuilder app) { ConfigureAuth(app); app.MapSignalR(); } private static void ConfigureAuth(IAppBuilder appBuilder) { const int twoWeeks = 14; ProjectObjectFactory.Container.Configure(config => config.For<IDataProtectionProvider>() .HybridHttpOrThreadLocalScoped() .Use(() => appBuilder.GetDataProtectionProvider())); appBuilder.CreatePerOwinContext( () => ProjectObjectFactory.Container.GetInstance<ApplicationUserManager>()); appBuilder.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), ExpireTimeSpan = TimeSpan.FromDays(twoWeeks), SlidingExpiration = true, CookieName = "MyFirstCms", Provider = new CookieAuthenticationProvider { OnValidateIdentity = ProjectObjectFactory.Container.GetInstance<IApplicationUserManager>().OnValidateIdentity() } }); ProjectObjectFactory.Container.GetInstance<IApplicationRoleManager>() .SeedDatabase(); ProjectObjectFactory.Container.GetInstance<IApplicationUserManager>() .SeedDatabase(); appBuilder.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process. //appBuilder.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5)); // Enables the application to remember the second login verification factor such as phone or email. // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from. // This is similar to the RememberMe option when you log in. // appBuilder.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie); appBuilder.UseFacebookAuthentication( appId: "fdsfdsfs", appSecret: "fdfsfs"); appBuilder.UseGoogleAuthentication( clientId: "fdsfsdfs", clientSecret: "fdsfsf"); } }
این هم کدهای صفحه ورود :
[HttpPost] [AllowAnonymous] //[CheckReferrer] [ValidateAntiForgeryToken] public virtual async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (!ModelState.IsValid) { return View(model); } if (!_userManager.CheckUserNameExist(model.UserName,null)) { this.AddErrors("UserName", "نام کاربری یا کلمه عبور وارد شده نادرست است"); return View(model); } if (_userManager.CheckIsUserBannedOrDelete(model.UserName)) { this.AddErrors("UserName", "حساب کاربری شما مسدود شده است"); return View(model); } if (!_userManager.IsEmailConfirmedByUserNameAsync(model.UserName)) { this.NotyWarning("برای ورود به سایت لازم است حساب خود را فعال کنید"); return RedirectToAction(MVC.Account.ActionNames.ReceiveActivatorEmail, MVC.Account.Name); } var result = await _signInManager.PasswordSignInAsync (model.UserName.ToLower(), model.Password, model.RememberMe, shouldLockout: true); switch (result) { case SignInStatus.Success: this.NotySuccess("شما با موفقیت وارد سیستم شدید"); return RedirectToLocal(returnUrl); case SignInStatus.LockedOut: this.NotyError( $"دقیقه دوباره امتحان کنید {_userManager.DefaultAccountLockoutTimeSpan} حساب شما قفل شد ! لطفا بعد از "); return View(model); case SignInStatus.Failure: this.NotyError(ModelState.GetListOfErrors()); return View(model); default: this.NotyError( "در این لحظه امکان ورود به سابت وجود ندارد . مراتب را با مسئولان سایت در میان بگذارید"); return View(model); } }
ممنون میشم اگر میدونید کجارو اشتباه کردم بهم بگید.
با سپاس