مطالب
تنظیمات CORS در ASP.NET Core
برنامه‌های امروزی، ممکن است به چندین Web API مستقل، تبدیل شده و سپس برنامه‌هایی (Front-ends) جدای از آن‌ها برای کار با آن‌ها ایجاد شوند. بنابراین این وظیفه‌ی برنامه‌‌های Web API است که مطمئن شوند کلاینت‌ها قادر به تعامل با آن‌ها هستند. CORS استانداردی است که یک چنین امکانی را مهیا می‌کند.



CORS چیست؟

CORS و یا cross origin resource sharing، یک مکانیزم امنیتی است که در تمام مرورگرهای جدید جهت جلوگیری از ارسال اطلاعات یک وب سایت، به وب سایتی دیگر، درنظر گرفته شده‌است. درخواست دسترسی به یک منبع (Resource) مانند تصویر، داده و غیره، خارج از سرآغاز آن، یک درخواست cross-origin نامیده می‌شود. برای مدیریت یک چنین درخواست‌هایی، استانداردی به نام CORS طراحی شده‌است. می‌توان به آن مانند نگهبانی یک ساختمان نگاه کرد که تا مجوز خاصی به آن‌ها ارائه نشود، امکان دسترسی به منابع ساختمان را صادر نخواهند کرد.


Origin چیست؟

سرآغاز یک درخواست از سه قسمت تشکیل می‌شود:
- Protocol/Scheme مانند HTTP/HTTPS
- Host مانند نام دومین
- شماره پورت مانند 443 برای پروتکل HTTPS  یا پورت 80 برای HTTP که عموما هر دو مورد به علت پیش‌فرض بودن، ذکر نمی‌شوند

بنابراین URLای مانند https://www.dntips.ir یک Origin را مشخص می‌کند. در اینجا به تمام منابعی که از این سرآغاز شروع می‌شوند و سه قسمت یاد شده‌ی آن‌ها یکی است، same-origin گفته می‌شود.
در این حالت اگر منابعی به URLهایی مانند https://www.dntips.ir (پروتکل متفاوت) و یا https://github.com (با host متفاوت) اشاره کنند، به آن‌ها Different-Origin گفته خواهد شد.


سیاست امنیتی Same-Origin چیست؟

سیاست امنیتی Same-Origin که به صورت توکار در تمام مرورگرهای امروزی تعبیه شده‌است، مانع تعامل سرآغازهایی متفاوت، جهت جلوگیری از حملات امنیتی مانند Cross-Site Request Forgery یا CSRF می‌شود. این سیاست امنیتی بسیار محدود کننده‌است و برای مثال مانع این می‌شود که بتوان توسط کدهای JavaScript ای، درخواستی را به سرآغاز دیگری ارسال کرد؛ حتی اگر بدانیم درخواست رسیده از منبعی مورد اطمینان صادر شده‌است. برای مثال اگر سایت جاری یک درخواست Ajax ای را به https://anotherwebsite.com/api/users ارسال کند، چون قسمت host مربوط به origin آن‌ها یکی نیست، این عملیات توسط مرورگر غیرمجاز شمرده شده و مسدود می‌شود.


چگونه می‌توان از تنظیمات CORS، برای رفع محدودیت‌های سیاست‌های دسترسی Same-Origin استفاده کرد؟

استاندارد CORS تعدادی header ویژه را جهت تبادل اطلاعات بین سرور و مرورگر مشخص کرده‌است تا توسط آن‌ها بتوان منابع را بین سرآغازهای متفاوتی به اشتراک گذاشت. در این حالت ابتدا کلاینت درخواستی را به سمت سرور ارسال می‌کند. سپس سرور پاسخی را به همراه هدرهای ویژه‌ای که مشخص می‌کنند به چه منابعی و چگونه می‌توان دسترسی یافت، به سمت کلاینت ارسال خواهد کرد. اکثر این هدرها با Access-Control-Allow شروع می‌شوند:
• Access-Control-Allow-Origin
در آن لیست سرآغازهایی را که سرور مایل است منابع خود را با آن‌ها به اشتراک بگذارد، مشخص می‌شوند. در حالت توسعه‌ی برنامه می‌توان از مقدار * نیز برای آن استفاده کرد تا هر سرآغازی بتواند به منابع سرور دسترسی پیدا کند. اما از استفاده‌ی این مقدار سراسری و کلی، در حالت انتشار برنامه خودداری کنید.
• Access-Control-Allow-Headers
• Access-Control-Allow-Methods
• Access-Control-Allow-Credentials


درخواست‌های ویژه‌ی Pre-Flight

در بسیاری از موارد، مرورگر زمانیکه تشخیص می‌دهد درخواست صادر شده‌ی از طرف برنامه، قرار است به یک Origin دیگر ارسال شود، خودش یک درخواست ویژه را به نام Pre-Flight و از نوع OPTIONS به سمت سرور ارسال می‌کند. علت آن این است که سرورهای قدیمی، مفهوم CORS را درک نمی‌کنند و در برابر درخواست‌های ویژه‌ای مانند Delete که از سرور جاری صادر نشده باشند، مقاومت می‌کنند (صرفا درخواست‌های Same-Origin را پردازش می‌کنند). به همین جهت است که اگر به برگه‌ی network ابزارهای توسعه دهندگان مرورگر خود دقت کنید، درخواست‌های cross-origin به نظر دوبار ارسال شده‌اند. بار اول درخواستی که method آن، options است و در خواست دوم که درخواست اصلی است و برای مثال method آن put است. این درخواست اول، Pre-Flight Request نام دارد. هدف آن این است که بررسی کند آیا سرور مقصد، استاندارد CORS را متوجه می‌شود یا خیر و آیا اینقدر قدیمی است که صرفا درخواست‌های Same-Origin را پردازش می‌کند و مابقی را مسدود خواهد کرد. اگر سرور درخواست Pre-Flight را درک نکند، مرورگر درخواست اصلی را صادر نخواهد کرد.



البته درخواست‌های pre-flight بیشتر در حالت‌های زیر توسط مرورگر صادر می‌شوند:
- اگر متد اجرایی مدنظر، متدی بجز GET/POST/HEAD باشد.
- اگر content type درخواست‌های از نوع POST، چیزی بجز application/x-www-form-urlencoded, multipart/form-data و یا text/plain باشند.
- اگر درخواست، به همراه یک هدر سفارشی باشد نیز سبب صدور یک pre-flight request خواهد شد.

بنابراین در برنامه‌های SPA خود که اطلاعات را با فرمت JSON به سمت یک Web API ارسال می‌کنند (و Origin آن‌ها یکی نیست)، حتما شاهد درخواست‌های Pre-Flight نیز خواهید بود.


تنظیمات CORS در ASP.NET Core

اکنون که با مفهوم CORS آشنا شدیم، در ادامه به نحوه‌ی انجام تنظیمات آن در برنامه‌های ASP.NET Core خواهیم پرداخت.
تنظیمات ابتدایی CORS در فایل Startup.cs و متد ConfigureServices آن انجام می‌شوند:
public void ConfigureServices(IServiceCollection services) 
{ 
    // Add service and create Policy with options 
    services.AddCors(options => 
    { 
        options.AddPolicy("CorsPolicy", 
            builder => builder.AllowAnyOrigin() 
            .AllowAnyMethod() 
            .AllowAnyHeader() 
            .AllowCredentials() ); 
    }); 
     
    // Make sure MVC is added AFTER CORS 
    services.AddMvc(); 
}
ابتدا توسط متد AddCors، سرویس‌های مرتبط، به سیستم تزریق وابستگی‌های ASP.NET Core اضافه خواهند شد و سپس در قسمت تنظیمات آن می‌توان همان هدرهای Access-Control-Allow را که پیشتر در مورد آن‌ها بحث کردیم، تعریف و مقدار دهی کرد. برای مثال تنظیم AllowAnyOrigin، همان استفاده‌ی از مقدار * در هدر Access-Control-Allow-Origin تولیدی است. باید دقت داشت که تنظیمات این سرویس‌ها باید پیش از افزودن سرویس‌های MVC انجام شوند.
در اینجا CorsPolicy که به عنوان پارامتر مشخص شده‌است، نام این سیاست دسترسی سفارشی است و در قسمت‌های مختلف برنامه می‌توان ارجاعاتی را به این نام تعریف کرد.

و برای تعریف سرآغازی خاص و یا متدی مشخص، می‌توان به صورت زیر عمل کرد (ذکر صریح WithOrigins برای حالت توزیع برنامه مناسب است و از دیدگاه امنیتی، استفاده‌ی از AllowAnyOrigin کار صحیحی نیست ):
services.AddCors(options =>
{
    options.AddPolicy("AllowOrigin",
            builder => builder.WithOrigins("http://localhost:55294")
                              .WithMethods("GET", "POST", "HEAD"));
});

پس از تنظیم سیاست دسترسی مدنظر، اکنون نوبت به اعمال آن است. اینکار در متد Configure فایل Startup.cs انجام می‌شود:
public void Configure(IApplicationBuilder app) 
{ 
    // ... 
 
    app.UseCors("CorsPolicy"); 
     
    // ... 
     
    app.UseMvc(routes => 
    { 
        routes.MapRoute( 
            name: "default", 
            template: "{controller=Home}/{action=Index}/{id?}"); 
    }); 
}
در اینجا متد UseCors که میان‌افزار CORS را فعال می‌کند، باید پیش‌از میان‌افزار Mvc تعریف شود تا بتواند هدرها را اعمال کند. همچنین نامی که در اینجا به عنوان پارامتر آن استفاده شده، دقیقا به همان نامی که برای تنظیمات سیاست دسترسی درنظر گرفته شد، اشاره می‌کند.
متد app.UseCors، یک متد سراسری است و کل سیستم را داخل این سیاست دسترسی CORS قرار می‌دهد. اگر می‌خواهید صرفا به کنترلر خاصی این تنظیمات اعمال شوند، می‌توان از فیلتر EnableCors با ذکر نام سیاست دسترسی تعریف شده، استفاده کرد (در این حالت ذکر services.AddCors ضروری است و از ذکر app.UseCors صرفنظر می‌شود):
[EnableCors("CorsPolicy")]
public class MyApiController : Controller

و یا اگر می‌خواهید از app.UseCors سراسری استفاده کنید، اما آن‌را برای کنترلر و یا حتی اکشن متد خاصی غیرفعال نمائید، می‌توان از فیلتر [DisableCors] استفاده کرد.

چند نکته:
- به نام رشته‌ای سیاست دسترسی تعریف شده، دقت داشته باشید. اگر این نام را درست ذکر نکنید، هدری تولید نخواهد شد.
- میان‌افزار CORS، برای درخواست‌های same-origin نیز هدری را تولید نمی‌کند.


امکان تعریف سیاست‌های دسترسی بدون نام نیز وجود دارد

در هر دو روش فوق که یکی بر اساس app.UseCors سراسری و دیگری بر اساس فیلتر EnableCors اختصاصی کار می‌کنند، ذکر نام سیاست دسترسی options.AddPolicy ضروری است. اگر علاقه‌ای به ذکر این نام ندارید، می‌توان به طور کامل از تنظیم services.AddCors صرفنظر کرد (قسمت پارامتر و تنظیمات آن‌را ذکر نکرد) و متد app.UseCors را به صورت زیر تنظیم نمود که قابلیت داشتن تنظیمات خاص خود را نیز دارا است:
public void ConfigureServices(IServiceCollection services)
{
      services.AddCors();
      services.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
 
    app.UseCors(policyBuilder =>
    {
        string[] origins = new string[] { "http://localhost:2000", "http://localhost:2001" };
 
        policyBuilder
            .AllowAnyHeader()
            .AllowAnyMethod()
            .WithOrigins(origins);
    });
 
    app.UseMvc();
}

روش دیگر انجام اینکار، تعریف یک DefaultPolicy است:
public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddDefaultPolicy(
            builder =>
            {
            builder
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader();
            });
          options.AddPolicy("MyCORSPolicy",
            builder =>
            {
                builder.WithOrigins("http://localhost:49373")
                                    .AllowAnyHeader()
                                    .AllowAnyMethod();
            });
     });
    services.AddMvc().AddNewtonsoftJson();
}
در اینجا در متد AddCors می‌توان چندین AddPolicy نامدار را داشت، به همراه یک AddDefaultPolicy بدون نام. استفاده‌ی از سیاست نام‌دار تعریف شده، یا توسط متد سراسری app.UseCors("MyCORSPolicy") انجام می‌شود و یا توسط فیلتر [EnableCors("MyCORSPolicy")]. اما اگر فیلتر [EnableCors] را بدون ذکر نامی قید کنیم، از همان تنظیمات AddDefaultPolicy استفاده خواهد کرد.


خطاهای متداول حین کار با CORS

خطای کار با SignalR و ارسال اطلاعات اعتبارسنجی کاربر

Access to XMLHttpRequest at 'http://localhost:22135/chat/negotiate?jwt=<removed the jwt key>' 
from origin 'http://localhost:53150' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: 
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. 
The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
برای رفع این مشکل کافی است متد AllowCredentials نیز قید شود:
services.AddCors(options =>
{
     options.AddPolicy("AllowAllOrigins",
         builder =>
          {
              builder
                 .AllowAnyOrigin()
                 .AllowAnyHeader()
                 .AllowAnyMethod()
                 .AllowCredentials();
          });
    });

تمام اعتبارسنجی‌ها و اطلاعات کوکی‌ها در سمت سرور قابل دسترسی نیستند

CORS به صورت پیش‌فرض اطلاعات کوکی‌ها را به دومینی دیگر ارسال نمی‌کند. در این حالت اگر حتما نیاز به انجام اینکار است، باید در درخواست Ajax ای ارسالی، خاصیت withCredentials به true تنظیم شود. همچنین سمت سرور نیز هدر Access-Control-Allow-Credentials را تنظیم کند (همان متد AllowCredentials فوق). در اینجا Credentials به کوکی‌ها، هدرهای اعتبارسنجی (مانند هدرهای JWT) کاربران و یا مجوزهای TLS کلاینت‌ها اشاره می‌کند.
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.example.com/api/test');
xhr.withCredentials = true;

//In jQuery:
$.ajax({
  type: 'get',
  url: 'http://www.example.com/home',
  xhrFields: {
    withCredentials: true
}

//ES6 fetch API:
fetch(
   'http://remote-url.com/users',
   {
     'PUT',
     headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
     },
     mode: 'cors',
     credentials: 'include',
     body: JSON.stringify(body)
   }
)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((error) => console.error(error));

CORS حساس به حروف کوچک و بزرگ است

روش دیگر تنظیم فیلتر EnableCors را در اینجا مشاهده می‌کنید:
[EnableCors(origins: "http://MyWebsite.com", headers: "*", methods: "*")]
//is not the same as this:
[EnableCors(origins:"http://mywebsite.com", headers: "*", methods: "*")]
اگر بجای * دقیقا origins را مشخص کردید، بخاطر داشته باشید که این تنظیم به کوچکی و بزرگی حروف حساس است و در صورت اشتباهی (مانند ذکر MyWebSite بجای mywebsite متداول با حروف کوچک)، درخواست‌های رسیده مسدود خواهند شد. همچنین همانطور که ذکر شد، بین HTTP و HTTPS نیز تفاوت وجود دارد و origin این‌ها یکی درنظر گرفته نمی‌شود و حتی اگر تمام حروف را هم کوچک وارد کرده باشید، باز هم تنظیمات جداگانه‌ای را نیاز خواهند داشت.


در حالت بروز خطای مدیریت نشده‌ای در سمت سرور، ASP.NET Core هدرهای CORS را ارسال نمی‌کند
اطلاعات بیشتر 
نظرسنجی‌ها
آیا در پروژه‌ها از ابزار کرک شده استفاده میکنید؟
خیر؛ معتقد به copyright هستیم و به هیچ عنوان استفاده نمی‌کنیم.
خیر؛ نسخه‌ی اصلی یا تجاری را تهیه می‌کنیم.
بله؛ به کارفرما توصیه می‌کنیم از نسخه‌ی اصلی یا تجاری استفاده کند.
بله؛ تحریم هستیم و نمی‌توانیم خریداری کنیم.
بله؛ چون ناعادلانه تحریم هستیم.
نظری ندارم!
خیر؛ از نمونه‌های سورس باز استفاده می‌کنیم.
نظرات مطالب
معرفی Kendo UI
 آیا ارائه یک پروژه سورس باز با استفاده از این سری از کامپوننت‌های تلکریک کار درستی است؟
مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 22 - توزیع برنامه توسط IIS
روش کار برنامه‌های ASP.NET Core در IIS کاملا متفاوت است با تمام نگارش‌های پیشین ASP.NET؛ از این جهت که برنامه‌های ASP.NET Core در اصل یک برنامه‌ی متکی به خود از نوع Console می‌باشند. به همین جهت برای هاست شدن نیازی به IIS ندارند. این نوع برنامه‌ها به همراه یک self-hosted Web server ارائه می‌شوند (به نام Kestrel) و این وب سرور توکار است که تمام درخواست‌های رسیده را دریافت و پردازش می‌کند. هرچند در اینجا می‌توان از IIS صرفا به عنوان یک «front end proxy» استفاده کرد؛ از این جهت که Kestrel تنها یک وب سرور خام است و تمام امکانات و افزونه‌های مختلف IIS را شامل نمی‌شود.
بر روی ماشین‌های ویندوزی و ویندوزهای سرور، استفاده‌ی از IIS به عنوان پروکسی درخواست‌ها و ارسال آن‌ها به Kestrel، روش توصیه شده‌است؛ از این جهت که حداقل قابلیت‌هایی مانند «port 80/443 forwarding»، مدیریت طول عمر برنامه، مدیریت مجوزهای SLL آن و خیلی از موارد دیگر توسط Kestrel پشتیبانی نمی‌شود.


معماری پردازش نگارش‌های پیشین ASP.NET در IIS


در نگارش‌های پیشین ASP.NET، همه چیز داخل پروسه‌‌ای به نام w3wp.exe و یا IIS Worker Process پردازش می‌شود که در اصل چیزی نیست بجز همان IIS Application Pool. این AppPoolها، برنامه‌های ASP.NET شما را هاست می‌کنند و همچنین سبب وهله سازی و اجرای آن‌ها نیز خواهند شد.
در اینجا درایور http.sys ویندوز، درخواست‌های رسیده را دریافت کرده و سپس آن‌ها را به سمت سایت‌هایی نگاشت شده‌ی به AppPoolهای مشخص، هدایت می‌کند.


معماری پردازش برنامه‌های ASP.NET Core در IIS

روش اجرای برنامه‌های ASP.NET Core با نگارش‌های پیشین آن‌ها کاملا متفاوت هستند؛ از این جهت که داخل پروسه‌ی w3wp.exe اجرا نمی‌شوند. این برنامه‌ها در یک پروسه‌ی مجزای کنسول خارج از پروسه‌ی w3wp.exe اجرا می‌شوند و حاوی وب سرور توکاری به نام کسترل (Kestrel) هستند.


 این وب سرور، وب سروری است تماما دات نتی و به شدت برای پردازش تعداد بالای درخواست‌ها بهینه سازی شده‌است؛ تا جایی که کارآیی آن در این یک مورد چند 10 برابر IIS است. هرچند این وب سرور فوق العاده سریع است، اما «تنها» یک وب سرور خام است و به همراه سرویس‌های مدیریت وب، مانند IIS نیست.


در تصویر فوق مفهوم «پروکسی» بودن IIS را در حین پردازش برنامه‌های ASP.NET Core بهتر می‌توان درک کرد. ابتدا درخواست‌های رسیده به IIS می‌رسند و سپس IIS آن‌ها را به طرف Kestrel هدایت می‌کند.
برنامه‌های ASP.NET Core، برنامه‌های کنسول متکی به خودی هستند که توسط دستور خط فرمان dotnet اجرا می‌شوند. این اجرا توسط ماژولی ویژه به نام AspNetCoreModule در IIS انجام می‌شود.


همانطور که در تصویر نیز مشخص است، AspNetCoreModule یک ماژول بومی IIS است و هنوز برای اجرا نیاز به IIS Application Pool دارد؛ با این تفاوت که در تنظیم AppPoolهای برنامه‌های ASP.NET Core، باید NET CLR Version. را به No managed code تنظیم کرد.


اینکار از این جهت صورت می‌گیرد که IIS در اینجا تنها نقش یک پروکسی هدایت درخواست‌ها را به پروسه‌ی برنامه‌ی حاوی وب سرور Kestrel، دارد و کار آن وهله سازی NET Runtime. نیست. کار AspNetCoreModule این است که با اولین درخواست رسیده‌ی به برنامه‌ی شما، آن‌را بارگذاری کند. سپس درخواست‌های رسیده را دریافت و به سمت برنامه‌ی ASP.NET Core شما هدایت می‌کند (به این عملیات reverse proxy هم می‌گویند).


اگر دقت کرده باشید، برنامه‌های ASP.NET Core، هنوز دارای فایل web.config ایی با محتوای ذیل هستند:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*"
           modules="AspNetCoreModule" resourceType="Unspecified"/>
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%"
                arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false"
                stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
  </system.webServer>
</configuration>
توسط این تنظیمات است که AspNetCoreModule فایل‌های dll برنامه‌ی شما را یافته و سپس برنامه را به عنوان یک برنامه‌ی کنسول بارگذاری می‌کند (با توجه به اینکه حاوی کلاس Program و متد Main هستند).
یک نکته: در زمان publish برنامه، تنظیم و تبدیل مقادیر LAUNCHER_PATH و LAUNCHER_ARGS به معادل‌های اصلی آن‌ها صورت می‌گیرد (در ادامه مطلب بحث خواهد شد).


آیا واقعا هنوز نیازی به استفاده‌ی از IIS وجود دارد؟

هرچند می‌توان Kestrel را توسط یک IP و پورت مشخص، عمومی کرد و استفاده نمود، اما حداقل در ویندوز چنین توصیه‌ای نمی‌شود و بهتر است از IIS به عنوان یک front end proxy استفاده کرد؛ به این دلایل:
- اگر می‌خواهید چندین برنامه را بر روی یک وب سرور که از طریق پورت‌های 80 و 443 ارائه می‌شوند داشته باشید، نمی‌توانید از Kestrel  به صورت مستقیم استفاده کنید؛ زیرا از مفهوم host header routing که قابلیت ارائه‌ی چندین برنامه را از طریق پورت 80 و توسط یک IP میسر می‌کند، پشتیبانی نمی‌کند. برای اینکار نیاز به IIS و یا در حقیقت درایور http.sys ویندوز است.
- IIS خدمات قابل توجهی را به برنامه‌ی شما ارائه می‌کند. برای مثال با اولین درخواست رسیده، به صورت خودکار آن‌را اجرا و بارگذاری می‌کند؛ به همراه تمام مدیریت‌های پروسه‌ای که در اختیار برنامه‌های ASP.NET در طی سالیان سال قرار داشته‌است. برای مثال اگر پروسه‌ی برنامه‌ی شما در اثر استثنایی کرش کرد، دوباره با درخواست بعدی رسیده، حتما برنامه را بارگذاری و آماده‌ی خدمات دهی مجدد می‌کند.
- در اینجا می‌توان تنظیمات SSL را بر روی IIS انجام داد و سپس درخواست‌های معمولی را به Kestrel  ارسال کرد. به این ترتیب با یک مجوز می‌توان چندین برنامه‌ی Kestrel را مدیریت کرد.
- IISهای جدید به همراه ماژول‌های بومی بسیار بهینه و کم مصرفی برای مواردی مانند gzip compression of static content, static file caching, Url Rewriting هستند که با فعال سازی آن‌ها می‌توان از این قابلیت‌ها، در برنامه‌های ASP.NET Core نیز استفاده کرد.


نحوه‌ی توزیع برنامه‌های ASP.NET Core به IIS

روش اول: استفاده از دستور خط فرمان dotnet publish

برای این منظور به ریشه‌ی پروژه‌ی خود وارد شده و دستور dotnet publish را با توجه به پارامترهای ذیل اجرا کنید:
 dotnet publish --framework netcoreapp1.0 --output "c:\temp\mysite" --configuration Release
در اینجا برنامه کامپایل شده و همچنین مراحلی که در فایل project.json نیز ذکر شده‌اند، اعمال می‌شود. برای مثال در اینجا پوشه‌ها و فایل‌هایی که در قسمت include ذکر شده‌اند به خروجی کپی خواهند شد. همچین در قسمت scripts تمام مراحل ذکر شده مانند یکی کردن و فشرده سازی اسکریپت‌ها نیز انجام خواهد شد. قسمت postpublish تنها کاری را که انجام می‌دهد، ویرایش فایل web.config برنامه و تنظیم LAUNCHER_PATH و LAUNCHER_ARGS آن به مقادیر واقعی آن‌ها است.
{

    "publishOptions": {
        "include": [
            "wwwroot",
            "Features",
            "appsettings.json",
            "web.config"
        ]
    },
 
    "scripts": {
        "precompile": [
            "dotnet bundle"
        ],
        "prepublish": [
            //"bower install"
        ],
        "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
    }
}
و در نهایت اگر به پوشه‌ی output ذکر شده‌ی در فرمان فوق مراجعه کنید، این خروجی نهایی است که باید به صورت دستی به وب سرور خود برای اجرا انتقال دهید که به همراه تمام DLLهای مورد نیاز برای برنامه نیز هست.


پس از انتقال این فایل‌ها به سرور، مابقی مراحل آن مانند قبل است. یک Application جدید تعریف شده و سپس ابتدا مسیر آن مشخص می‌شود و نکته‌ی اصلی، انتخاب AppPool ایی است که پیشتر شرح داده شد:


برنامه‌های ASP.NET Core باید به AppPool ایی تنظیم شوند که NET CLR Version. آن‌ها No Managed Code است. همچنین بهتر است به ازای هر برنامه‌ی جدید یک AppPool مجزا را ایجاد کنید تا کرش یک برنامه تاثیر منفی را بر روی برنامه‌ی دیگری نگذارد.

روش دوم: استفاده از ابزار Publish خود ویژوال استودیو

اگر علاقمند هستید که روش خط فرمان فوق را توسط ابزار publish ویژوال استودیو انجام دهید، بر روی پروژه در solution explorer کلیک راست کرده و گزینه‌ی publish را انتخاب کنید. در صفحه‌ای که باز می‌شود، بر روی گزینه‌ی custom کلیک کرده و نامی را وارد کنید. از این نام پروفایل، جهت ساده سازی مراحل publish، در دفعات آتی فراخوانی آن استفاده می‌شود.


در صفحه‌ی بعدی اگر گزینه‌ی file system را انتخاب کنید، دقیقا همان مراحل روش اول تکرار می‌شوند:


سپس می‌توانید فریم ورک برنامه و نوع ارائه را مشخص کنید:


و در آخر کار، Publish به این پوشه‌ی مشخص شده که به صورت پیش فرض در ذیل پوشه‌ی bin برنامه‌است، صورت می‌گیرد.


روش عیب یابی راه اندازی اولیه‌ی برنامه‌های ASP.NET Core

در اولین سعی در اجرای برنامه‌ی ASP.NET Core بر روی IIS به این خطا رسیدم:


در event viewer ویندوز چیزی ثبت نشده بود. اولین کاری را که در این موارد می‌توان انجام داد به این صورت است. از طریق خط فرمان به پوشه‌ی publish برنامه وارد شوید (همان پوشه‌ای که توسط IIS عمومی شده‌است). سپس دستور dotnet prog.dll را صادر کنید. در اینجا prog.dll نام dll اصلی برنامه یا همان نام پروژه است:


همانطور که مشاهده می‌کنید، برنامه به دنبال پوشه‌ی bower_components ایی می‌گردد که کار publish آن انجام نشده‌است (این پوشه در تنظیمات آغازین برنامه عمومی شده‌است و در لیست include قسمت publishOptions فایل project.json فراموش شده‌است).

روش دوم، فعال سازی stdoutLogEnabled موجود در فایل وب کانفیگ، به true است. در اینجا web.config نهایی تولیدی توسط عملیات publish را مشاهده می‌کنید که در آن پارامترهای  processPath و arguments مقدار دهی شده‌اند (همان قسمت postpublish فایل project.json). در اینجا مقدار stdoutLogEnabled به صورت پیش فرض false است. اگر true شود، همان خروجی تصویر فوق را در پوشه‌ی logs خواهید یافت:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath="dotnet" arguments=".\Core1RtmEmptyTest.dll" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" />
  </system.webServer>
</configuration>
البته اگر کاربر منتسب به AppPool برنامه، دسترسی نوشتن در این پوشه را نداشته باشد، خطای ذیل را در event viewer ویندوز مشاهده خواهید کرد:
 Warning: Could not create stdoutLogFile \\?\D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest\bin\Release\PublishOutput\logs\stdout_10064_201672893654.log, ErrorCode = -2147024893.
همچنین پوشه‌ی logs را هم باید خودتان از پیش ایجاد کنید. به عبارتی کاربر منتسب به AppPool برنامه باید دسترسی نوشتن در پوشه‌ی logs واقع در ریشه‌ی برنامه را داشته باشد. این کاربر  IIS AppPool\DefaultAppPool نام دارد.



حداقل‌های یک هاست ویندوزی که می‌خواهد برنامه‌های ASP.NET Core را ارائه دهد

پس از نصب IIS، نیاز است ASP.NET Core Module نیز نصب گردد. برای این‌کار اگر بسته‌ی NET Core Windows Server Hosting. را نصب کنید، کافی است:
https://go.microsoft.com/fwlink/?LinkId=817246

این بسته به همراه NET Core Runtime, .NET Core Library. و ASP.NET Core Module است. همچنین همانطور که عنوان شد، برنامه‌های ASP.NET Core باید به AppPool ایی تنظیم شوند که NET CLR Version. آن‌ها No Managed Code است. این‌ها حداقل‌های راه اندازی یک برنامه‌ی ASP.NET Core بر روی سرورهای ویندوزی هستند.


هنوز فایل app_offline.htm نیز در اینجا معتبر است

یکی از خواص ASP.NET Core Module، پردازش فایل خاصی است به نام app_offline.htm. اگر این فایل را در ریشه‌ی سایت قرار دهید، برنامه پردازش تمام درخواست‌های رسیده را قطع خواهد کرد و سپس پروسه‌ی برنامه خاتمه می‌یابد. هر زمانیکه این فایل حذف شد، مجددا با درخواست بعدی رسیده، برنامه آماده‌ی پاسخگویی می‌شود.
اشتراک‌ها
موجودیت های مرتبط با مدیریت قابلیت ها و نسخه ها در یک سیستم License Management

اگر قصد راه اندازی سیستمی برای تولید مجوز استفاده از محصولات خود برای مشتریان خود را دارید، حداقل می‌توان موجودیت‌های موجود در این gist را در نظر گرفت و در نهایت در فایل License نهایی تولید شده برای مشتری خود با توجه به نسخه خریداری شده توسط او، قابلیت‌های نسخه مورد نظر نیز در فایل مذکور ثبت خواهند شد.

در راه حل ارائه شده علاوه بر اینکه امکان تنظیم یکسری قابلیت برای نسخه‌ها (Edition ها) وجود دارد، می‌توان برای مشتری خاصی قابلیت خاصی را به صورت مستقیم نیز در نظر گرفت.






موجودیت های مرتبط با مدیریت قابلیت ها و نسخه ها در یک سیستم License Management
نظرات مطالب
امن سازی برنامه‌های ASP.NET Core توسط IdentityServer 4x - قسمت اول - نیاز به تامین کننده‌ی هویت مرکزی
Your license for Duende IdentityServer only permits 5 number of clients. 
You have processed requests for 6. 
The clients used were: ["client6", "client2", "client5", "client4", "client3", "client1"].
نظرات اشتراک‌ها
دوراهی انتخاب NHibernate و Entityframework
استفاده از NH در مقابل EF Code first سورس باز اشتباه است؛ به دلایل زیر:
- توهم پشتیبانی از بانک‌های اطلاعاتی مختلف توسط NH . به شخصه با حداقل یک مورد نیم بند آن سروکار داشتم: SQL-CE. تقریبا بیشتر از نیمی از توانایی‌های این بانک اطلاعاتی در NH لحاظ نشده و حتی یک کوئری ساده از تاریخ تا تاریخ را توسط آن نمی‌توانید تهیه کنید. این مورد برعکس EF Code first است. کامل و بی‌نقص کار می‌کند. کلا تمام محصولات مایکروسافت به همین نحو هستند. اگر عنوان می‌کنند این محصول دو قابلیت دارد، واقعا این دو قابلیت، درست کار می‌کنند. نه اینکه عنوان کنند 100 قابلیت را ارائه می‌دهیم و فقط 10 تای آن کامل پیاده سازی شده باشند.
- تیم مدیریتی به شدت مغرور و ناراحت NH. باز هم برای این تیم ناراحت، جهت تکمیل نقایص کار با SQL-CE بیشتر از یکسال قبل وصله‌ای رو ارسال کردم. تا به امروز حتی یک پاسخ که آیا خوبه، بده ... ارسال نشده. با اکثر همکاری‌ها هم به همین نحو رفتار می‌کنند.
خلاصه حال و هوای یک پروژه سالم سورس باز را ندارد.
- پس از ارائه EF Code first این پروژه تقریبا غیرفعال شده: (^)
- نیم بند بودن پشتیبانی از LINQ. باز هم اگر تصور می‌کنید که راحت می‌تونید مثل EF از کوئری‌های LINQ در اینجا استفاده کنید، سخت در اشتباه هستید.
- دیر به روز شدن کتابخانه‌های جانبی آن. این مساله هم به مدیریت بد پروژه NH بر می‌گردد. شاید بیشتر از 10 مورد افزونه برای NH هست، مانند کش و اعتبار سنجی و غیره. اما ... صاحبان آن مشخص نیستند! امروز NH3 ارائه می‌شود، سه ماه بعد کتابخانه اعتبارسنجی متناظر با آن. تیم NH هم حاضر نشده تمام این‌ها رو کنار هم قرار بده و یک کار یکپارچه رو ارائه کنه. NH اعتبار خودش رو از این افزونه‌های موجود در NH Contrib کسب می‌کنه، اما حاضر نیستند مدیریت و نگهداری یکپارچه آن‌ها را قبول کنند.
- ناسازگاری با اکوسیستم دات نت. اگر از NH استفاده کنید مدام در حال جنگ با دات نت هستید. مثلا سیستم اعتبار سنجی EF با سیستم اعتبار سنجی سمت کلاینت و سرور MVC یکپارچه است. با NH اینطور نیست و از این نوع مثال‌ها زیاد است. همین مساله حجم کاری شما را چندبرابر می‌کند.
- طراحی زمخت NH در مقابل طراحی روان EF. برای مثال در EF Code first شما به ندرت نیاز خواهید داشت که نگاشت‌ها را تعریف یا حتی سفارشی سازی کنید. یک سری پیش فرض بسیار عالی در آن به صورت توکار (و نه به شکل افزونه) وجود دارد که حجم کاری شما را به شدت کاهش می‌دهند. در NH کتابخانه fluent nh سعی کرده که اینکار را انجام دهد اما جالب اینجا است که این کتابخانه از طرف تیم اصلی NH اصلا تحویل گرفته نشده و ... دست آخر هم یک روش دیگر را برای نوشتن نگاشت‌ها با کد تهیه کردند.
- مستندات NH کامل نیست. برای مثال شاید یک سری بلاگ‌های متفرقه را پیدا کنید که در مورد روش تهیه نگاشت‌ها با کد مطلب نوشته باشند ... نه توسط کسانی که این کتابخانه را تهیه کرده‌اند! این روند رو مقایسه کنید با وبلاگ EF مثلا : (^) این بلاگ تا این حد کامل است که مرجع بسیاری از مطالب آموزشی و کتاب‌های مرتبط با EF می‌باشد.
- سیستم migration موجود در EF Code first نسبت به نمونه NH بسیار کاملتر است؛ با قابلیت سفارشی سازی، مقایسه هش مدل‌ها با جداول جهت جلوگیری از تداخلات و اشتباهات، تولید اسکریپت آپدیت بانک اطلاعاتی و غیره.

یک زمانی بود دات نت ORM قابل ملاحظه‌ای نداشت. زمان دات نت2. در آن موقع NH حرف برای گفتن داشت اما ... نه الان.
مطالب
انتقال SVN به یک سیستم جدید

در راستای مهاجرت به ویندوز 7، کار نصب و راه اندازی SVN و کلاینت‌های آن باید مجددا انجام می‌شد. اگر برای بار اول است که به مبحث SVN برخورد می‌کنید، مطالعه این جزوه توصیه می‌شود. مطالب ذیل برای افرادی مفید است که قصد انتقال سیستم SVN موجود خود را به مکان و یا سیستم عامل دیگری در اسرع وقت دارند.

الف) دریافت و نصب Visual SVN server
یا می‌توان SVN خالص را از سایت آن دریافت کرد و یا جهت سهولت کار و همچنین دسترسی به یک کنسول مدیریتی می‌توان برنامه‌ی رایگان Visual SVN server را از آدرس زیر دریافت و نصب کرد:

پس از نصب، ابتدا باید یا کاربر جدیدی را جهت استفاده از منابع آن تعریف کرد و یا از نحوه‌ی اعتبار سنجی یکپارچه با ویندوز هم می‌توان استفاده کرد که من از این روش دوم استفاده می‌کنم (شکل زیر، کلیک راست بر روی نود اصلی visual SVN server و سپس انتخاب خواص و مراجعه به برگه‌ی اعتبار سنجی آن):



ب)دریافت و نصب TortoiseSVN

نصب آن نکته‌ی خاصی ندارد. اما یک سری نکته‌ی ریز پس از نصب آن بهتر است رعایت شود که در ادامه ذکر می‌شود:

ج) دریافت و نصب برنامه‌ی WinMerge
برنامه‌ی Diff پیش فرض TortoiseSVN آنچنان قوی نیست. به همین جهت می‌توان برنامه‌ی WinMerge را با آن یکپارچه کرد. برای این منظور ابتدا آن‌را دریافت نمائید:

اگر پس از نصب TortoiseSVN آن‌را نصب کنید، در حین نصب پیشنهاد یکپارچه سازی با TortoiseSVN را نیز می‌دهد. اگر ابتدا WinMerge را نصب کرده‌اید و سپس TortoiseSVN بر روی سیستم شما نصب شده، فقط کافی است مطابق شکل زیر ابتدا به قسمت Diff viewers آن مراجعه کرده و سپس با انتخاب گزینه‌ی external ، دستور خط فرمان زیر را وارد نمائید:

C:\Program Files (x86)\WinMerge\WinMergeU.exe -e -x -ub -dl %bname -dr %yname %base %mine



بدیهی است مسیر WinMergeU.exe مطابق مسیر نصب در سیستم شما باید تنظیم شود.

د) تنظیم مسیر تحت نظر قرار گرفتن سیستم
TortoiseSVN به صورت پیش فرض کل سیستم را جهت مشاهده‌ی تغییرات تحت نظر قرار می‌دهد که گاهی باعث کاهش کارآیی آن خواهد شد. برای رفع این مشکل می‌توان مسیرهایی را که پروژه‌های شما در آن قرار دارند را به آن معرفی نمود تا بار کلی سیستم کاهش یابد.



همانطور که در شکل نیز ملاحظه می‌کنید، Include path مقدار دهی شده است.

ه) مشخص سازی پسوندهایی که بهتر است از آن‌ها صرفنظر شود
به برگه‌ی general تنظیمات TortoiseSVN مراجعه کرده و در قسمت global ignore pattern آن، موارد زیر را وارد نمائید:



این موارد شامل پروژه‌های دات نت، دلفی ، VC و امثال آن است و همچنین یک سری فایل بایناری که عموما با پروژه‌های برنامه نویسی نیازی به ثبت نگارش آن‌ها نیست.

*.dcu *.~* dcu temp *.exe *.zip *.bkm *.ddp *.cfg *.dof *.dsk *.ini *.hlp *.gid *.bmp *.png *.gif ~* *.log bin debug release *.map *.chm *.bkf Thumbs.db *.mdb .obj *.elf *.stat *.ddp *.bpl *.map *.GID *.hlp *.opt *.dll *.raw *.BIN *.obj *.pdb *.scc Debug Release *.xml obj *.~* *.backup *.INI *.ArmLog *.KeyLog *.NanoLog *.Stats *.PreARM *.old *.drc *.*~ *.doc *.pdf *.bmp *.jpg *.MRW *.NEF *.ORF *.psd *.X3F __history *.local *.identcache *.bak Thumbs.db *.ldb *.dex *.rar DllDcu *.lck CVS cvs *.txt *.TXT *.jdbg *.HLP *.KWF *.xls *.cnt *.dsm *.dti *.tmp *.lnk *.cbk *.mes *.suo *.ncb *.user _ReSharper.* [Bb]in obj [Dd]ebug [Rr]elease *.aps *.eto


در همین برگه، اگر هنوز از VS2003 استفاده می‌کنید، تیک مربوط به استفاده از _svn بجای .svn را قرار دهید تا VS.Net با پوشه‌های مدیریتی ذکر شده مشکل پیدا نکند.

و) نصب افزونه‌های SVN سازگار با VS.Net
یا می‌توان از افزونه‌ی Visual SVN استفاده کرد (که رایگان نیست) و یا AnkhSVN که رایگان و سورس باز است.
ولی در کل یک مورد را بیشتر نصب نکنید. علت هم کند شدن VS.Net است به دلیل فعالیت‌های پشت صحنه‌ی هر کدام از این افزونه‌ها که زیاده روی در تعداد آن‌ها گاها باعث کرش هم می‌شود. بنابراین همان یک مورد کافی است.

ز) Import مخزن‌های قبلی
تا اینجا مقدمات کار فراهم شد. اکنون نوبت به import مخزن‌های بجا مانده از سیستم قبلی است. برای اینکار مطابق شکل زیر، گزینه‌ی import existing repositories را انتخاب کرده و مسیر مخزن‌های قبلی خود را باید معرفی نمود (به ازای هر کدام یکبار باید این عملیات صورت گیرد).



پس از انجام این مراحل یکبار باید سیستم reboot شود و اکنون همه چیز مثل قبل خواهد شد!


نکته:
اگر مسیر ریشه مخزن‌های جدید با مسیر آن‌ها در سیستم قبلی متفاوت است، هنگام commit کارهای خود با خطای زیر متوقف خواهید شد:
Commit failed (details follow): Unable to open an ra_local session to URL
Unable to open repository 'file:///C:/Repositories/tracking/trunk'




اشکالی ندارد! برای رفع آن باید از گزینه‌ی relocate مربوط به TortoiseSVN استفاده کرد.
بر روی پوشه کاری پروژه خود کلیک راست کرده، انتخاب گزینه‌ی TortoiseSVN و سپس انتخاب گزینه‌ی Relocate آن باید صورت گیرد. در اینجا می‌توان مسیر جدید ریشه اصلی مخزن را در سیستم جدید معرفی کرد.



مطالب
آشنایی با NuGet - قسمت دوم

قسمت قبل از دید یک مصرف کننده بود؛ این قسمت جهت توسعه‌ دهنده‌ها تهیه شده است. کسانی که قصد دارند تا بسته‌های 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
پس از چند لحظه فایل Silverlight.4.Persian.DatePicker.1.0.nupkg جهت ارائه عمومی تولید خواهد شد.

د) قبل از اینکه این فایل نهایی را در سایت 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
در اینجا key مخصوص به خود را می‌توان در صفحه‌ی http://nuget.org/Contribute/MyAccount مشاهده و استفاده نمود.

اگر علاقمند به مشاهده جزئیات بیشتری از این پروسه هستید، می‌توان به سایت رسمی آن مراجعه کرد: (+)