Today is the official GA release for .NET 5, and along with it we are excited to share the latest updates with our recent release of C#/WinRT version 1.0. C#/WinRT provides WinRT projection support for .NET 5 based apps. The Windows SDK leverages this technology and is now integrated with the .NET 5.0 SDK to expose Windows APIs through the new Target Framework Monikers. In addition to the Windows SDK support added for .NET 5, C#/WinRT itself allows component authors to build their own .NET 5 projections using the CsWinRT NuGet package.
منابع اصلی Ember.js
پیش از شروع به بحث نیاز است با تعدادی از سایتهای اصلی مرتبط با Ember.js آشنا شد:
سایت اصلی: http://emberjs.com
مخزن کدهای آن: https://github.com/emberjs
انجمن اختصاصی پرسش و پاسخ: http://discuss.emberjs.com
موتور قالبهای آن: http://handlebarsjs.com
لیست منابع مطالعاتی مرتبط مانند ویدیوهای آموزشی و لیست مقالات موجود: http://emberwatch.com
و بستهی نیوگت آن: https://www.nuget.org/packages/EmberJS
مفاهیم پایهای Ember.js
شیء Application
App = Ember.Application.create();
مسیر یابی
با مرور قسمتهای مختلف برنامه توسط کاربر، نیاز است حالات برنامه را مدیریت کرد؛ اینجا است که کار قسمت مسیریابی شروع میشود. مسیریابی، منابع مورد نیاز جهت آدرسهای مشخصی را تامین میکند.
App.Router.map(function() { this.resource('accounts'); // takes us to /accounts this.resource('gallery'); // takes us to /gallery });
به این ترتیب مسیرهای accounts/ و gallery/ قابل پردازش خواهند شد.
این مسیرها، تو در تو نیز میتوانند باشند. برای مثال:
App.Router.map(function() { this.resource('news', function() { this.resource('images', function () { // takes us to /news/images this.route('add');// takes us to /news/images/add }); }); });
مدلها
مدلها همان اشیایی هستند که برنامه مورد استفاده قرار میدهد و میتوانند یک آرایهی ساده و یا اشیاء JSON دریافتی از وب سرور باشند.
حداقل به دو روش میتوان مدلها را تعریف کرد:
الف) با استفاده از افزونهی Ember Data
ب) با کمک شیء Ember.Object
App.SiteLink = Ember.Object.extend({}); App.SiteLink.reopenClass({ findAll: function() { var links = []; //… $.getJSON … return links; } });
در ادامه متد دلخواهی را ایجاد کرده و برای مثال آرایهای از اشیاء دلخواه جاوا اسکریپتی را بازگشت خواهیم داد.
پس از تعریف مدل، نیاز است آنرا به سیستم مسیریابی معرفی کرد:
App.GalleryRoute = Ember.Route.extend({ model: function() { return App.SiteLink.findAll(); } });
کنترلرها
کنترلرها جهت ارائهی اطلاعات مدلها به View و قالب برنامه تعریف میشوند. در اینجا همیشه باید بخاطر داشت که model تامین کنندهی اطلاعات است. کنترلر جهت در معرض دید قرار دادن این اطلاعات، به View برنامه کاربرد دارد و مدلها هیچ اطلاعی از وجود کنترلرها ندارند.
کنترلرها علاوه بر اطلاعات model، میتوانند حاوی یک سری خواص و اشیاء صرفا نمایشی که قرار نیست در بانک اطلاعاتی ذخیره شوند نیز باشند.
در Ember.js قالبها (templates) اطلاعات خود را از کنترلر دریافت میکنند. کنترلرها اطلاعات مدل را به همراه سایر خواص نمایشی مورد نیاز در اختیار View و قالبهای برنامه قرار میدهند.
برای تعریف یک کنترلر میتوان درون شیء مسیریابی، با تعریف متد setupController شروع کرد:
App.GalleryRoute = Ember.Route.extend({ setupController: function(controller) { controller.set('content', ['red', 'yellow', 'blue']); } });
روش دوم تعریف کنترلرها با ایجاد یک زیر کلاس از شیء Ember.Controller انجام میشود:
App.GalleryController = Ember.Controller.extend({ search: '', content: ['red', 'yellow', 'blue'], query: function() { var data = this.get('search'); this.transitionToRoute('search', { query: data }); } });
قالبها یا templates
قالبها قسمتهای اصلی رابط کاربری را تشکیل خواهند داد. در اینجا از کتابخانهای به نام handlebars برای تهیه قالبهای سمت کاربر کمک گرفته میشود.
<script type="text/x-handlebars" data-template-name="sayhello"> Hello, <strong>{{firstName}} {{lastName}}</strong>! </script>
<script type="text/x-handlebars" data-template-name="sayhello"> Hello, <strong>{{firstName}} {{lastName}}</strong>! {{#if person}} Welcome back, <strong>{{person.firstName}} {{person.lastName}}</strong>! {{/if}} <ul> {{#each friend in friends}} <li> {{friend.name}} </li> {{/each}} </ul> <img {{bindAttr src="link.url" }} /> {{#linkTo ''about}}About{{/linkTo}} </script>
بهترین مرجع آشنایی با ریز جزئیات کتابخانهی handlebars، مراجعه به سایت اصلی آن است.
قواعد پیش فرض نامگذاری در Ember.js
اگر به مثالهای فوق دقت کرده باشید، خواصی مانند GalleryController و یا GalleryRoute به شیء App اضافه شدهاند. این نوع نامگذاریها در ember.js بر اساس روش convention over configuration کار میکنند. برای نمونه اگر مسیریابی خاصی را به نحو ذیل تعریف کردید:
this.resource('employees');
کنترلر آن App.EmployeesController
مدل آن App.Employee
View آن App.EmployeesView
و قالب آن employees
بهتر است تعریف شوند. به عبارتی اگر اینگونه تعریف شوند، به صورت خودکار توسط Ember.js یافت شده و هر کدام با مسئولیتهای خاص مرتبط با آنها پردازش میشوند و همچنین ارتباطات بین آنها به صورت خودکار برقرار خواهد شد. به این ترتیب برنامه نظم بهتری خواهد یافت. با یک نگاه میتوان قسمتهای مختلف را تشخیص داد و همچنین کدنویسی پردازش و اتصال قسمتهای مختلف برنامه نیز به شدت کاهش مییابد.
تهیهی اولین برنامهی Ember.js
تا اینجا نگاهی مقدماتی داشتیم به اجزای تشکیل دهندهی هستهی Ember.js. در ادامه مثال سادهای را جهت نمایش ساختار ابتدایی یک برنامهی Ember.js، بررسی خواهیم کرد.
بستهی Ember.js را همانطور که در قسمت منابع اصلی آن در ابتدای بحث عنوان شد، میتوانید از سایت و یا مخزن کد آن دریافت کنید و یا اگر از VS.NET استفاده میکنید، تنها کافی است دستور ذیل را صادر نمائید:
PM> Install-Package EmberJS
در این حالت ترتیب تعریف اسکریپتهای مورد نیاز صفحه به صورت ذیل خواهند بود:
<script src="Scripts/jquery-2.1.1.js" type="text/javascript"></script> <script src="Scripts/handlebars.js" type="text/javascript"></script> <script src="Scripts/ember.js" type="text/javascript"></script> <script src="Scripts/app.js" type="text/javascript"></script>
App = Ember.Application.create(); App.IndexRoute = Ember.Route.extend({ setupController:function(controller) { controller.set('content', ['red', 'yellow', 'blue']); } });
App.Router.map(function() { this.resource('application'); this.resource('index'); });
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script src="Scripts/jquery-2.1.1.js" type="text/javascript"></script> <script src="Scripts/handlebars.js" type="text/javascript"></script> <script src="Scripts/ember.js" type="text/javascript"></script> <script src="Scripts/app.js" type="text/javascript"></script> </head> <body> <script type="text/x-handlebars" data-template-name="index"> Hello, <strong>Welcome to Ember.js</strong>! <ul> {{#each item in content}} <li> {{item}} </li> {{/each}} </ul> </script> </body> </html>
مقدار data-template-name در اینجا مهم است. اگر آنرا به هر نام دیگری بجز index تنظیم کنید، منبع دریافت اطلاعات آن مشخص نخواهد بود. نام index در اینجا به معنای اتصال این قالب به اطلاعات ارائه شده توسط کنترلر index است.
تا همینجا اگر برنامه را اجرا کنید، به خوبی کار خواهد کرد. نکتهی دیگری که در مورد قالبهای Ember.js قابل توجه هستند، قالب پیش فرض application است. با تعریف Ember.Application.create یک چنین قالبی نیز به ابتدای هر صفحه به صورت خودکار اضافه خواهد شد:
<body> <script type="text/x-handlebars" data-template-name="application"> <h1>Header</h1> {{outlet}} </script>
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید:
EmberJS01.zip
یک: ASP.NET Core مستقل از Platform است
دو: Open Source است
سه: جدا بودن از Web Server
using System; using Microsoft.AspNetCore.Hosting; namespace aspnetcoreapp { public class Program { public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseStartup<Startup>() .Build(); host.Run(); } } }
چهار: تزریق وابستگی (Dependency Injection) تو کار
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices (IServiceCollection services) { // Add framework services. services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.AddMvc(); // Add application services. services.AddTransient<IEmailSender, AuthMessageSender>(); services.AddTransient<ISmsSender, AuthMessageSender>(); }
پنج: یکپارچگی با frameworkهای مدرن سمت کلاینت
- bundle و minify کردن فایلهای جاوا اسکریپت و همینطور CSS
- اجرای ابزارهایی برای bundle و minify کردن قبل از هر build
- کامپایل کردن فایلهای LESS و SASS در CSS
- کامپیال کردن فایلهای CoffeeScript و TypeScript در JavaScript
روش دوم - بوم میکروسرویس (microservice canvas)
یکی دیگر از روشهای مناسب برای مستند سازی یک سرویس و ساختار درونی آن، استفاده از روش بوم میکروسرویس میباشد. بوم میکروسرویس نیز تا حدودی شبیه به کارتهای CRC و همچنین روش microservice design card که پیشتر بررسی گردید، میباشد؛ با این تفاوت که اطلاعات بیشتری را نگهداری مینماید.
• Description – ارائه یک توضیح مختصر در مورد سرویس
• Capabilities – معرفی بخشهایی از منطق کسب و کار که در این سرویس پیاده سازی شدهاست.
• Service APIs – معرفی عملیات یا operations (شامل commands و queries) که در این سرویس پیاده سازی شدهاند و همچنین معرفی وقایع یا همان domain event هایی که توسط سرویس منتشر میشوند.
• Quality attributes – معرفی non-functional requirementsهای سرویس
• Observability (قابلیتهای مشاهده و بررسی سرویس) – معرفی health check endpoints و key metrics و ... .
وابستگیهای یک سرویس (A service’s dependencies) که لزوما استفاده بیرونی ندارد و بیشتر منبعی برای خود اعضای تیم خواهد بود، در بخشی تحت عنوان dependencies مشخص میشوند که خود شامل دو قسمت به شرح زیر میباشد:
• Subscribes – اشتراک در کانال پیامهایی که شامل وقایع سایر سرویسها میباشند.
موارد مربوط به پیاده سازی یک سرویس (A service’s implementation)
تولید بوم میکروسرویس
هم چنین در قسمت Add folders and core references تیک گزینهی Web Api را نیز فعال مینماییم.
حال احتیاج به نصب پکیج OData با استفاده از nuget package manager داریم. کافیست دستور زیر را در package manager console وارد نماییم.
Install-Package Microsoft.AspNet.Odata
این دستور آخرین ورژن Odata package را از nuget دانلود مینماید.
بعد از نصب شدن OData نیاز به اضافه کردن یک Model داریم. کلاسی را به نام Product در پوشهی Models میسازیم.
کلاس Product.cs حاوی فیلدهای زیر است.
namespace ProductService.Models { public class Product { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } public string Category { get; set; } } }
پراپرتی Id، کلید این entity است و کلاینت میتواند کوئری را بر روی entity، به وسیلهی key بزند. برای مثال برای گرفتن Product با Id برابر 2، باید این url را ارسال نمود "(2)Products/"
پرواضح است که Id در Database به عنوان Primary key در نظر گرفته شده است.
حال احتیاج به نصب Entity Framework داریم که با ارسال دستور زیر از طریق nuget نصب خواهد شد
Install-Package EntityFramework
بعد از نصب کردن ef نیاز به اضافه کردن connection string در web config داریم.
<connectionStrings> <add name="ProductsContext" connectionString="Data Source=.; Initial Catalog=ProductsContext; Integrated Security=True;MultipleActiveResultSets=True;" providerName="System.Data.SqlClient" /> </connectionStrings>
الان میتوانیم کلاس ProductsContext را درون پوشهی Models ایجاد نماییم. محتویات آن را به صورت زیر وارد مینماییم
using System.Data.Entity; namespace ProductService.Models { public class ProductsContext : DbContext { public ProductsContext() : base("name=ProductsContext") { } public DbSet<Product> Products { get; set; } } }
درون Constructor کلاس ProductsContext، داریم name=ProductsContext که باید برابر name درون connection string باشد.
حال نیاز به کانفیگ OData داریم. درون پوشهی App_Start و کلاس WebApiConfig.cs محتویات زیر را جایگزین متد register نمایید:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { ODataModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<Product>("Products"); config.MapODataServiceRoute( routeName: "ODataRoute", routePrefix: null, model: builder.GetEdmModel()); } }
این کد دو فرآیند زیر را انجام میدهد
1) ساخت Entity Data Model (EDM)
2) اضافه کردن route
EDM یک مدل انتزاعی از data است. EDM برای تولید سند metadata استفاده میشود. کلاس ODataModelBuilder برای ساخت EDM با استفاده از default naming convention میباشد که باعث کاهش کدها میشود. ضمنا کلاس MapODataServiceRoute برای ساخت OData v4 route میباشد. همانگونه که اطلاع دارید، تعریف route برای مدیریت کردن WebApi و چگونگی مسیریابی درخواستهای http میباشد.
اگر application شما احتیاج به چند OData endpoint داشته باشد، میتوانید برای هر کدام routeهای جدا و همچنین نام یکتایی را برای routeName و routePrefix آن در نظر بگیرید.
اضافه کردن OData Controller
یک Controller، کلاسی برای مدیریت کردن درخواستهای http میباشد. شما باید Controllerهای مجزایی را برای هر entity set در OData service خود بسازید. در این مقاله Controller مربوط به موجودیت Product را میسازیم.
در Solution Explorer با کلیک راست بر روی پوشهی Controller، کلاسی به نام ProducsController را میسازیم. دقت کنید نام آن حتما باید به Controller ختم شود.
در OData V3 میتوانیم Controller را با استفاده از Scaffolding بسازیم؛ ولی در V4 این ویژگی وجود ندارد!
محتویات زیر را در این کنترلر اضافه مینماییم:
using ProductService.Models; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Linq; using System.Net; using System.Threading.Tasks; using System.Web.Http; using System.Web.OData; namespace ProductService.Controllers { public class ProductsController : ODataController { ProductsContext db = new ProductsContext(); private bool ProductExists(int key) { return db.Products.Any(p => p.Id == key); } protected override void Dispose(bool disposing) { db.Dispose(); base.Dispose(disposing); } } }
این مرحلهی ابتدایی از پیاده سازی کنترلر میباشد و در قسمت بعد به پیاده سازی CRUD مربوط به آن میپردازیم.
Querying The Entity Set
این 2 متد را به کنترلر خود اضافه مینماییم
[EnableQuery] public IQueryable<Product> Get() { return db.Products; } [EnableQuery] public SingleResult<Product> Get([FromODataUri] int key) { IQueryable<Product> result = db.Products.Where(p => p.Id == key); return SingleResult.Create(result); }
ویژگی EnableQuery به معنای امکان Query زدن از سمت کلاینت به آن میباشد. FromODataUri نیز برای امکان پاس دادن پارامتر از طریق Uri است.
متد Get بدون پارامتر، قادر به برگرداندن تمامی Productها میباشد و متد Get با پارامتر، قادر به برگرداندن آن Product خاص با استفاده از unique Id است.
در صورت داشتن EnableQuery با استفاده از Query Option هایی مثل filter$ و sort$ و غیره از سمت کلاینت قادر به تغییر دادن کوئریهای خود هستیم.
Adding and Entity to Entity Set
برای اجازه دادن به کلاینت، جهت اضافه کردن یک Product به دیتابیس، متد Post زیر را اضافه مینماییم
public async Task<IHttpActionResult> Post(Product product) { if (!ModelState.IsValid) { return BadRequest(ModelState); } db.Products.Add(product); await db.SaveChangesAsync(); return Created(product); }
Updation an Entity
OData از دو روش متفاوت برای Update کردن یک موجودیت استفاده مینماید.
1) Patch : امکان partial update برای موجودیت مربوطه را فراهم میسازد.
2) Put : موجودیت جدید را به صورت کامل جایگزین مینماید.
مشکل روش Put این است که کلاینت مجبور به ارسال تمامی فیلدهای مربوطه میباشد. حتی آن هایی که اساسا تغییری نکردهاند. بنابراین روش Patch ترجیح داده میشود.
در هر صورت ما به پیاده سازی هر دو روش میپردازیم:
public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Product> product) { if (!ModelState.IsValid) { return BadRequest(ModelState); } var entity = await db.Products.FindAsync(key); if (entity == null) { return NotFound(); } product.Patch(entity); try { await db.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!ProductExists(key)) { return NotFound(); } else { throw; } } return Updated(entity); } public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update) { if (!ModelState.IsValid) { return BadRequest(ModelState); } if (key != update.Id) { return BadRequest(); } db.Entry(update).State = EntityState.Modified; try { await db.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!ProductExists(key)) { return NotFound(); } else { throw; } } return Updated(update); }
در قسمت Patch کنترلر از <Delta<T استفاده میکند که typeی است برای track کردن تغییرات در مدل مربوطه.
Deleting an Entity
برای حذف هر موجودیت نیز کافیست متد زیر را به کنترلر خود اضافه نمایید:
public async Task<IHttpActionResult> Delete([FromODataUri] int key) { var product = await db.Products.FindAsync(key); if (product == null) { return NotFound(); } db.Products.Remove(product); await db.SaveChangesAsync(); return StatusCode(HttpStatusCode.NoContent); }
من چند رکورد تستی را به صورت زیر وارد کردهام:
حال پروژهی خود را run نموده و آدرس زیر را وارد نمایید:
http://localhost:YourPort/Products
پاسخ، مجموعهای از entityهای زیر خواهد بود:
{ "@odata.context":"http://localhost:4516/$metadata#Products","value":[ { "Id":1,"Name":"Ali","Price":2.00,"Category":"aaa" },{ "Id":2,"Name":"Reza","Price":1.00,"Category":"bbb" },{ "Id":3,"Name":"Ahmad","Price":0.00,"Category":"ccc" } ] }
شما میتوانید از هر کدام از فیلترهای زیر برای کوئری زدن از کلاینت به سمت سرور استفاده نمایید. بطور مثال هر کدام از اینها پاسخ متفاوت و مربوط به خود را برگشت میدهد:
/Products(2)
Productی با آی دی 2 را بر میگرداند.
/Products?$filter=Id gt 1
محصولی را با آی دی بزرگتر از 1، بر میگرداند.
Products?$select=Name
روی محصولات select زده و فقط فیلد Name آنها را بر میگرداند.
Products?$select=Name,Price
آرایهای از objectهایی با پراپرتی Name و Price را بر میگرداند.
/Products?$top=3
فقط 3 رکورد اول را بر میگرداند.
همانطور که ملاحظه میفرمایید، استفاده از OData باعث کمتر شدن کدهای سمت سرور و همچنین امکان کوئری زدن از سمت کلاینت به سمت سرور را مهیا میکند.
بعد از خواندن این مقاله ممکن است به این مساله فکر کنید که این کار باعث کاهش امنیت میشود. باید عرض کنم که امکانات زیادی برای محدود کردن کوئریها، فراهم شده است و هیچ نگرانی از این بابت وجود ندارد. بطور مثال میتوانید تعیین کنید که از entity مربوطه فقط حداکثر 3 پراپرتی قابلیت کوئری زدن را دارند؛ یا اینکه حداکثر در هر کوئری، 10 رکورد قابلیت پاسخ دادن خواهد داشت.
پس بدین صورت میباشد که شما حداکثر امکانات ممکن را به سمت کلاینت میدهید و اختیار بدان واگذار شده که آیا از این امکانات حداکثری، استفاده نماید یا خیر.
امکانات این پروتکل منحصر به فرد است و در مقالههای بعدی به جزئیات بیشتر و دقیقتری خواهیم پرداخت.
قسمت قبل از دید یک مصرف کننده بود؛ این قسمت جهت توسعه دهندهها تهیه شده است. کسانی که قصد دارند تا بستههای NuGet ایی از کارشان تهیه کنند. مراحل اینکار به شرح زیر است:
الف) برای این منظور نیاز است تا برنامهی خط فرمان NuGet.exe معرفی شده در قسمت قبل را ابتدا دریافت کنید : (+)
ب) برای بسته نرم افزاری خود یک پوشه جدید درست کنید. سپس فرمان nuget.exe spec را در این پوشه صادر نمائید. بلافاصله فایلی به نام Package.nuspec تشکیل خواهد شد:
D:\Prog\1389\CodePlex\slpdatepicker\SlPDatePickerNuGet>NuGet.exe spec
Created 'Package.nuspec' successfully.
فایل Package.nuspec، یک فایل XML ساده است. آنرا با یک ادیتور متنی باز کرده و تغییرات لازم را اعمال نمائید. برای مثال من جهت پروژه Silverlight 4 Persian DatePicker ، محتویات آنرا به صورت زیر تغییر دادهام:
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Silverlight.4.Persian.DatePicker</id>
<version>1.0</version>
<authors>Vahid Nasiri</authors>
<owners>Vahid Nasiri</owners>
<licenseUrl>http://slpdatepicker.codeplex.com/license</licenseUrl>
<projectUrl>http://slpdatepicker.codeplex.com/</projectUrl>
<iconUrl>https://slpdatepicker.svn.codeplex.com/svn/SilverlightPersianDatePicker/Views/Images/date.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Silverlight 4 Persian DatePicker Control</description>
<tags>Silverlight WPF Persian DatePicker</tags>
</metadata>
<files>
<file src="..\SilverlightPersianDatePicker\Bin\Release\*.dll" target="lib" />
<file src="..\SilverlightPersianDatePicker\Bin\Release\*.pdb" target="lib" />
<file src="..\SilverlightPersianDatePicker\Bin\Release\*.xml" target="lib" />
</files>
</package>
همانطور که ملاحظه میکنید یک سری اطلاعات عمومی از پروژه مورد نظر درخواست شده است؛ برای مثال آدرس آیکن آن چیست یا کجا میتوان آنرا یافت؟ مجوز استفاده از آن چیست و مواردی از این دست. به کمک تگ files هم فایلهای کتابخانه در اینجا لحاظ شدهاند. فایل آیکن معرفی شده باید در اندازهی 32*32 و با فرمت png باشد. باید دقت داشت که در سایت nuget.org ، بسته شما بر اساس id ذکر شده معرفی خواهد شد و آدرسی بر این اساس تشکیل میگردد. بنابراین از فاصله یا موارد مشکل ساز در این بین استفاده نکنید.
در مورد نحوهی ایجاد قدم به قدم یک پروژه جدید در سایت کدپلکس میتوان به این مطلب مراجعه نمود: (+)
ج) اکنون نوبت به تهیه بسته نهایی میرسد. برای این منظور دستور زیر را در خط فرمان صادر کنید:
NuGet.exe pack Package.nuspec
د) قبل از اینکه این فایل نهایی را در سایت nuget.org آپلود کنیم، میتوان مشخصات آنرا به صورت محلی نیز یکبار مرور کرد. برای این منظور در VS.NET به منوی Tools گزینهی Options مراجعه کرده و در قسمت package manager ، آدرس پوشه بسته مورد نظر را وارد کنید. برای مثال:
اکنون اگر کنسول پاورشل توضیح داده شده در قسمت قبل را باز نمائید، منبع جدید اضافه شده مشخص است یا میتوان توسط دستور ذیل از آن کوئری گرفت:
get-package -remote -filter silverlight
و یا اگر همانند توضیحات قبل به صفحهی دیالوگ add library package reference مراجعه کنیم، مشخصات کامل بسته به همراه منبع محلی باید قابل مشاهده باشند:
ه) پس از بررسی محلی بسته مورد نظر، اکنون نوبت به ارائه عمومی آن میباشد. برای این منظور ابتدا باید در سایت nuget.org ثبت نام کرد : (+). اگر آدرس ایمیل شما را نپذیرفت، از مرورگر IE استفاده کنید!
پس از ثبت نام تنها کافی است به قسمت contribute سایت مراجعه کرده و فایل بسته نهایی را در آنجا آپلود کرد. به این صورت بسته نهایی در سایت پدیدار خواهد شد :(+)
همچنین بلافاصله در قسمت گالری آنلاین صفحه add library package reference نیز قابل دسترسی خواهد بود.
در آینده جهت توزیع به روز رسانیهای جدید، همین مراحل باید تکرار شوند. البته در نظر داشته باشید که version ذکر شده در فایل Package.nuspec را باید حتما تغییر داد تا بستهها از یکدیگر متمایز شوند. امکان اتوماسیون این توزیع نیز وجود دارد. همان فایل nuget.exe ، امکان ارسال بسته نهایی را به سایت nuget.org نیز دارد:
nuget push name.nupkg key
اگر علاقمند به مشاهده جزئیات بیشتری از این پروسه هستید، میتوان به سایت رسمی آن مراجعه کرد: (+)
NuGet 2.0 منتشر شد
بسته MVC خودش حاوی Nuget هست ونمیدونم چرا نمیتونه آپدیتش کنه!
NetVips is a wrapper for the libvips image processing library. It's a bit like Magick.NET, but typically 8x faster. It's API-stable, supports around 300 image-processing operations, and a good range of image formats is supported.
NuGet package: https://www.nuget.org/packages/NetVips
There's a benchmark here: https://github.com/kleisauke/net-vips/tree/master/tests/NetVips.Benchmarks
Formatted docs, including a tutorial and full API: https://kleisauke.github.io/net-vips/
Blog post: https://jcupitt.github.io/libvips/2018/04/10/libvips-for-dot-net.html