سایت codecrap.com
فکر کنم فقط مرگ من رو از برنامه نویسی جدا کنه.
Full C# Project: Inventory Management System | ASP.NET Core Blazor, EF Core, SQL Server, Identity - YouTube
00:00:00 Project Demo (ASP.Net Core Blazor Server)
00:05:26 View Inventories
00:14:29 Add Entity Framework Core
00:27:16 View Inventory Use Case
00:36:35 View Inventory Component (Blazor Component)
00:58:04 View Inventory Page
01:08:18 Adding new Inventory
01:34:46 Edit Inventory
02:10:26 View Products Use Case
02:45:52 Search Inventory Component
03:05:50 Add Product
03:52:39 Refactor Product Inventories
04:16:51 Validate Product Price
04:49:14 Edit Product
05:23:34 Delete Product
05:47:48 Purchase Inventory
07:07:40 Produce Products
07:36:29 UI of Producing Products
08:16:05 Sell Product
08:46:36 Inventory Transaction Report
09:43:48 Product Transaction Report
10:10:10 Print Reports
10:19:56 Switch to SQL Server
10:51:30 Add Authentication and Authorization with ASP.NET Core Identity
10:59:57 Look and Feel with Bootstrap 5
Blazor WebAssembly 6x به همراه قابلیتی است به نام ahead-of-time (AOT) compilation که در این حالت، کدهای دات نتی برنامه، مستقیما به native WebAssembly کامپایل میشوند. این مورد سبب بالا رفتن کارآیی برنامه خواهد شد؛ در عوض بالا رفتن حجم نهایی قابل توزیع.
اگر از AOT compilation استفاده نشود (یعنی حالت متداول)، Blazor WebAssembly در مرورگر، به کمک مفسر IL یا همان NET Intermediate Language. که به صورت WebAssembly تهیه شدهاست، اجرا خواهد شد. یک چنین حالتی به دلیل استفادهی از مفسر، نسبت به حالت استفادهی از JIT سمت سرور (یا همان NET just-in-time (JIT) runtime.)، اندکی کندتر است. AOT compilation جهت رفع یک چنین کمبودی ارائه شدهاست تا کدهای دات نتی را مستقیما و بدون نیاز به مفسر، تبدیل به یک native WebAssembly کند. این مورد سرعت و کارآیی برنامههایی را که کارهای محاسباتی مبتنی بر CPU را انجام میدهند، به نحو قابل ملاحظهای افزایش میدهد. در مقابل باید درنظر داشت که حجم نهایی WebAssemblyهای واقعی تولید شده، از نمونهی IL آنها بالاتر است (حدود 2 برابر) که مدت زمان ابتدایی دریافت برنامه را افزایش میدهند.
روش فعالسازی کامپایل AOT
ابتدا نیاز است work load آنرا توسط دستور زیر دریافت کرد (ابزارهای کامپایل AOT، جزئی از SDK نیستند):
dotnet workload install wasm-tools
<PropertyGroup> <RunAOTCompilation>true</RunAOTCompilation> </PropertyGroup>
یک نکته: هنوز در نگارش 6.0 RTM، یکسری از قابلیتهای AOT اضافه نشدهاند که باید منتظر سرویسپکهای آن بود. برای مثال اگر این کامپایل، بر روی پروژهای که فقط سورس کد است اجرا شود، با موفقیت به پایان میرسد؛ اما با اضافه شدن کتابخانههای ثالث ممکن است با شکست مواجه شود. اگر در این حالت خطایی را دریافت کردید، عملیات publish را به صورت dotnet publish -p:RunAOTCompilation=true -bl انجام دهید. سوئیچ bl- سبب میشود تا فایلی به نام msbuild.binlog در ریشهی پروژهی شما تولید شود. این فایل در حقیقت لاگ باینری MSBuild است که توسط برنامهی Viewer آن قابل مشاهدهاست. در اینجا به دنبال exit codeها بگردید؛ یک نمونهی آن.
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