.Generate(data => { fileName = HttpUtility.UrlEncode(fileName, Encoding.UTF8); data.FlushInBrowser(fileName, FlushType.Inline); }); // creating an in-memory PDF file
EF Code First #7
اکثر خدمات گوگل دارای API هم هستند و به این ترتیب با استفاده از برنامه نویسی نیز میتوان به آنها دسترسی پیدا کرد. برای نمونه API دسترسی به Blogger در اینجا توضیح داده شده است. برای کار با این امکانات یا میتوان چرخ را از نو اختراع کرد یا از کتابخانههای مرتبطی همانند Gdata API for .NET استفاده نمود. برای دات نت فریم ورک، از آدرس http://code.google.com/p/google-gdata/ میتوان آخرین کتابخانههای کار با GData یا Google Data API را دریافت کرد. برای نمونه فایل Google_Data_API_Setup_1.9.0.0.msi فعلی آن حدود 28 مگ حجم دارد و به درد کسانی میخورد که علاقمند هستند تا تمام امکانات موجود آنرا بررسی کنند. راه سادهتری هم برای دسترسی به این کتابخانهها وجود دارد؛ میتوان از NuGet استفاده کرد.
به این ترتیب به سادگی و سرعت هرچه تمامتر فایل 200 کیلوبایتی Google.GData.Client.dll دریافت شده و ارجاعی نیز به آن اضافه خواهد شد. همین حد جهت کار با بلاگر کافی است.
برای نمونه قطعه کد زیر کار ارسال یک مطلب جدید به وبلاگ بلاگری شما را انجام خواهد داد:
using System;
using System.Collections.Generic;
using Google.GData.Client;
namespace BloggerAutoPoster
{
public class BloggerAutoPoster
{
public string UserName { set; get; }
public string Password { set; get; }
public string PostTitle { set; get; }
public IList<string> PostTags { set; get; }
public string PostBody { set; get; }
public string BlogUrl { set; get; }
public bool PostAsDraft { set; get; }
public bool PostNewEntry()
{
var service = new Service("blogger", "blogger-example")
{
Credentials = new GDataCredentials(UserName, Password)
};
var newPost = constructNewEntry();
var result = service.Insert(new Uri(BlogUrl), newPost);
return result != null;
}
private AtomEntry constructNewEntry()
{
var newPost = new AtomEntry
{
Title = { Text = PostTitle },
Content = new AtomContent
{
Content = string.Format(@"<div xmlns=""http://www.w3.org/1999/xhtml"">{0}</div>", PostBody),
Type = "xhtml"
},
IsDraft = PostAsDraft
};
foreach (var tag in PostTags)
{
newPost.Categories.Add(
new AtomCategory
{
Term = tag,
Scheme = "http://www.blogger.com/atom/ns#"
});
}
return newPost;
}
}
}
مثالی از استفاده آن هم به صورت زیر میباشد:
new BloggerAutoPoster
{
BlogUrl = "https://www.blogger.com/feeds/number/posts/default",
UserName = "name@gmail.com",
Password = "pass",
PostTitle = "بررسی ارسل خودکار-3",
PostTags = new List<string> { "بررسی ارسال خودکار" },
PostBody = "تست میشود123",
PostAsDraft = false
}.PostNewEntry();
نام کاربری و کلمه عبور آن، همان مشخصات وارد شدن به اکانت جیمیل شما است. اگر میخواهید مطلب ارسالی بلافاصله در سایت ظاهر نشود PostAsDraft را true کنید. همچنین BlogUrl آن، همانطور که ملاحظه میکنید فرمت خاصی دارد. جهت یافتن آن میتوان از قطعه کد زیر کمک گرفت:
using System;
using System.Collections.Generic;
using System.Linq;
using Google.GData.Client;
namespace BloggerAutoPoster
{
public class BlogInfo
{
public string Title { set; get; }
public string Url { set; get; }
}
public class BloggerInfo
{
public static IList<BlogInfo> FindMyBlogsUrls(string username, string password)
{
var result = new List<BlogInfo>();
var service = new Service("blogger", "blogger-example")
{
Credentials = new GDataCredentials(username, password)
};
var query = new FeedQuery { Uri = new Uri("https://www.blogger.com/feeds/default/blogs") };
var feed = service.Query(query);
if (feed == null)
throw new NotSupportedException("You don't have any blogs!");
foreach (var entry in feed.Entries)
{
result.AddRange(entry.Links.Where(t => t.Rel.Equals("http://schemas.google.com/g/2005#post"))
.Select(t => new BlogInfo
{
Url = new Uri(t.HRef.ToString()).AbsoluteUri,
Title = entry.Title.Text
}));
}
return result;
}
}
}
توسط کد فوق، آدرس ویژه و عنوان تمام بلاگهای ثبت شدهی بلاگری شما بازگشت داده میشود.
سشن چیست؟
شیء سشن، مجموعهای از اشیاء serialized مرتبط با جلسهی کاری جاری یک کاربر است. این اشیاء عموما در حافظهی محلی سرور ذخیره میشوند؛ اما امکان ذخیره سازی توزیع شدهی آنها در بانکهای اطلاعاتی نیز پیش بینی شدهاست.
عموما استفادهی از اشیاء سشن توصیه نمیشوند. از این جهت که این نوع اشیاء بسیار شبیه هستند به متغیرهای سراسری و وجود این نوع متغیرها اساسا ضعف طراحی شیءگرا به حساب میآیند. اما با توجه به ماهیت stateless بودن برنامههای وب، به این معنا که با پایان رندر یک صفحه، تمام اشیاء مرتبط با آنها نیز در سمت سرور تخریب میشوند، نیاز است برای یک سری از دادههای عمومی کاربر، راه حلی را پیدا کرد تا بتوان از اطلاعات آنها استفادهی مجدد کرد. برای مثال نگهداری رشتهی اتصالی بانک اطلاعاتی که کاربر در حین لاگین به سیستم آنرا انتخاب کردهاست (اگر برنامه به ازای هر سال از یک بانک اطلاعاتی مجزا استفاده میکند) و یا زمانیکه کاربری captcha را پر میکند و مقدار آنرا به سمت سرور ارسال میکند، نیاز است مقدار ارسالی او را با مقدار ابتدایی captcha مقایسه کرد. یک چنین اطلاعاتی نباید با پایان رندر صفحه تخریب شوند و نیاز است تا زمانیکه جلسهی کاری کاربر به پایان نرسیدهاست، در دسترس باشند. به همین جهت است که مفهومی را به نام «اشیاء سشن» طراحی کردهاند.
درکل خارج از این موارد بهتر است از سشن استفاده نکنید و در جای جای برنامهی خود ردپای آنرا باقی نگذارید و به خاطر داشته باشید:
متغیر سشن = متغیر سراسری = ضعف طراحی شیءگرا
توصیهی به استفادهی از روشهای سبک وزنتر
سشنها تنها روش به اشتراک گذاری اطلاعات نیستند. اگر میخواهید اطلاعاتی را در بین میان افزارهای برنامه در طی یک درخواست به اشتراک بگذارید، شاید سشن هم یک راه حل باشد؛ اما راه حلی سنگین وزن. راه حل بهتر برای این موارد، استفادهی از HttpContext.Items است. HttpContext.Items نیز همانند سشن، یک key/value store است؛ اما طول عمر آن محدود است به طول عمر درخواست جاری و در تمام میان افزارهای برنامه در دسترس است.
برای مثال در یک میان افزار آنرا تنظیم میکنید:
app.Use(async (context, next) => { context.Items["isVerified"] = true; await next.Invoke(); });
app.Run(async (context) => { await context.Response.WriteAsync("Verified request? " + context.Items["isVerified"]); });
فعال سازی سشنها در ASP.NET Core
ASP.NET Core یک choose-what-you-need framework است. به این معنا که تا زمانیکه قابلیتی را به صورت صریح فعال سازی نکرده باشید، در دسترس نخواهد بود. همین مساله در نهایت به کاهش مصرف منابع این نوع برنامهها و همچنین طراحی ماژولار سیستم ختم میشوند. برای مثال در نگارشهای قبلی ASP.NET (تمام نگارشها)، سشنها به صورت پیش فرض فعال هستند، مگر آنکه HTTP Module آنرا در فایل web.config حذف کنید؛ اما در اینجا برعکس است.
اگر تنها در موارد خاصی که ذکر شد، نیاز به استفادهی از متغیرهای سشن را داشتید، روش فعال سازی آن به صورت ذیل است:
الف) نصب بستهی نیوگت Microsoft.AspNetCore.Session
برای این منظور وابستگی ذیل را به فایل project.json اضافه کنید:
{ "dependencies": { //same as before "Microsoft.AspNetCore.Session": "1.0.0" } }
برای این کار به کلاس آغازین برنامه مراجعه کرده و ابتدا سرویس سشنها را فعال کنید:
public void ConfigureServices(IServiceCollection services) { services.AddSession();
public void Configure(IApplicationBuilder app) { app.UseSession();
app.UseSession(options: new SessionOptions { IdleTimeout = TimeSpan.FromMinutes(30), CookieName = ".MyApplication" });
روش استفادهی از سشنها
در مثال ذیل نحوهی ذخیره سازی اطلاعات را در شیء سشن جلسهی جاری یک کاربر، ملاحظه میکنید:
public ActionResult TestSession() { this.HttpContext.Session.Set("key-1", BitConverter.GetBytes(DateTime.Now.Ticks)); this.HttpContext.Session.SetInt32("key-2", 1); this.HttpContext.Session.SetString("key-3", "DNT"); return Content("OK!"); }
public IActionResult Index() { byte[] key1 = this.HttpContext.Session.Get("key-1"); long key1Value = BitConverter.ToInt64(key1, 0); int? key2Value = this.HttpContext.Session.GetInt32("key-2"); string key3Value = this.HttpContext.Session.GetString("key-3"); return Content("OK!"); }
حالت Set آن آرایهای از بایتها را دریافت میکند و میتوان برای حالت serialization اشیاء، مفید باشد.
دقیقا معادل همین سه متد، متدهای Get، GetInt32 و GetString برای بازیابی مقادیر سشن طراحی شدهاند و باید دقت داشت که خروجیهای اینها میتوانند نال نیز باشند. به همین جهت خروجی GetInt32 آن نال پذیر است.
توسعهی متدهای پیش فرض کار با سشنها
سه متد یاد شدهی کار با سشنها در ASP.NET Core هرچند ضروری هستند، اما کافی نیستند. برای توسعهی آنها میتوان متدهای الحاقی را تدارک دید که نمونهای از آنها را ذیل مشاهده میکنید:
using System; using Microsoft.AspNetCore.Http; using Newtonsoft.Json; namespace Core1RtmEmptyTest.StartupCustomizations { public static class SessionExts { public static void SetDateTime(this ISession collection, string key, DateTime value) { collection.Set(key, BitConverter.GetBytes(value.Ticks)); } public static DateTime? GetDateTime(this ISession collection, string key) { var data = collection.Get(key); if (data == null) { return null; } var dateInt = BitConverter.ToInt64(data, 0); return new DateTime(dateInt); } public static void SetObject(this ISession session, string key, object value) { var stringValue = JsonConvert.SerializeObject(value); session.SetString(key, stringValue); } public static T GetObject<T>(this ISession session, string key) { var stringValue = session.GetString(key); return JsonConvert.DeserializeObject<T>(stringValue); } } }
و یا جهت کار با اشیاء پیچیدهتر میتوان از کتابخانهی JSON.NET استفاده کرد. به عبارتی در این نگارش از ASP.NET، کار سریالایز و دیسریالایز اشیاء، به برنامه نویس واگذار شدهاست و اینکه در پشت صحنه از چه کتابخانهای میخواهید استفاده کنید، در اختیار خودتان است.
البته باید دقت داشت که در اینجا وابستگی JSON.NET به صورت خودکار در دسترس است. از این جهت که بسیاری از وابستگیهای ASP.NET Core مانند مورد ذیل، به JSON.NET وابستهاند و نصب آنها به معنای نصب خودکار JSON.NET نیز هست:
{ "dependencies": { //same as before "Microsoft.Extensions.Configuration.Json": "1.0.0" } }
یک مطلب تکمیلی
در اینجا نیز امکان ذخیره سازی سشنها در بانک اطلاعاتی بجای حافظهی فرار سرور درنظر گرفته شدهاست و برای این حالت، بانکهای اطلاعاتی NoSQL ویژهای به نام key/value stores مانند بانک اطلاعاتی فوق سریع Redis پیشنهاد میشود؛ هرچند امکان کار با SQL Server نیز در اینجا وجود دارد، اما برای کش سرورهای مبتنی بر key/value ها، بانک اطلاعاتی Redis، انتخاب اول است.
Managing Application State
بدین منظور فریم ورک ASP.NET Web API کتابخانه ای برای تولید خودکار صفحات راهنما در زمان اجرا (run-time) فراهم کرده است.
ایجاد صفحات راهنمای API
برای شروع ابتدا ابزار ASP.NET and Web Tools 2012.2 Update را نصب کنید. اگر از ویژوال استودیو 2013 استفاده میکنید این ابزار بصورت خودکار نصب شده است. این ابزار صفحات راهنما را به قالب پروژههای ASP.NET Web API اضافه میکند.
یک پروژه جدید از نوع ASP.NET MVC Application بسازید و قالب Web API را برای آن انتخاب کنید. این قالب پروژه کنترلری بنام ValuesController را بصورت خودکار برای شما ایجاد میکند. همچنین صفحات راهنمای API هم برای شما ساخته میشوند. تمام کد مربوط به صفحات راهنما در قسمت Areas قرار دارند.
اگر اپلیکیشن را اجرا کنید خواهید دید که صفحه اصلی لینکی به صفحه راهنمای API دارد. از صفحه اصلی، مسیر تقریبی Help/ خواهد بود.
این لینک شما را به یک صفحه خلاصه (summary) هدایت میکند.
نمای این صفحه در مسیر Areas/HelpPage/Views/Help/Index.cshtml قرار دارد. میتوانید این نما را ویرایش کنید و مثلا قالب، عنوان، استایلها و دیگر موارد را تغییر دهید.
بخش اصلی این صفحه متشکل از جدولی است که APIها را بر اساس کنترلر طبقه بندی میکند. مقادیر این جدول بصورت خودکار و توسط اینترفیس IApiExplorer تولید میشوند. در ادامه مقاله بیشتر درباره این اینترفیس صحبت خواهیم کرد. اگر کنترلر جدیدی به API خود اضافه کنید، این جدول بصورت خودکار در زمان اجرا بروز رسانی خواهد شد.
ستون "API" متد HTTP و آدرس نسبی را لیست میکند. ستون "Documentation" مستندات هر API را نمایش میدهد. مقادیر این ستون در ابتدا تنها placeholder-text است. در ادامه مقاله خواهید دید چگونه میتوان از توضیحات XML برای تولید مستندات استفاده کرد.
هر API لینکی به یک صفحه جزئیات دارد، که در آن اطلاعات بیشتری درباره آن قابل مشاهده است. معمولا مثالی از بدنههای درخواست و پاسخ هم ارائه میشود.
افزودن صفحات راهنما به پروژه ای قدیمی
می توانید با استفاده از NuGet Package Manager صفحات راهنمای خود را به پروژههای قدیمی هم اضافه کنید. این گزینه مخصوصا هنگامی مفید است که با پروژه ای کار میکنید که قالب آن Web API نیست.
از منوی Tools گزینههای Library Package Manager, Package Manager Console را انتخاب کنید. در پنجره Package Manager Console فرمان زیر را وارد کنید.
Install-Package Microsoft.AspNet.WebApi.HelpPage
@Html.ActionLink("API", "Index", "Help", new { area = "" }, null)
همانطور که مشاهده میکنید مسیر نسبی صفحات راهنما "Help/" میباشد. همچنین اطمینان حاصل کنید که ناحیهها (Areas) بدرستی رجیستر میشوند. فایل Global.asax را باز کنید و کد زیر را در صورتی که وجود ندارد اضافه کنید.
protected void Application_Start() { // Add this code, if not present. AreaRegistration.RegisterAllAreas(); // ... }
افزودن مستندات API
بصورت پیش فرض صفحات راهنما از placeholder-text برای مستندات استفاده میکنند. میتوانید برای ساختن مستندات از توضیحات XML استفاده کنید. برای فعال سازی این قابلیت فایل Areas/HelpPage/App_Start/HelpPageConfig.cs را باز کنید و خط زیر را از حالت کامنت درآورید:
config.SetDocumentationProvider(new XmlDocumentationProvider( HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")));
زیر قسمت Output گزینه XML documentation file را تیک بزنید و در فیلد روبروی آن مقدار "App_Data/XmlDocument.xml" را وارد کنید.
حال کنترلر ValuesController را از مسیر Controllers/ValuesController.cs/ باز کنید و یک سری توضیحات XML به متدهای آن اضافه کنید. بعنوان مثال:
/// <summary> /// Gets some very important data from the server. /// </summary> public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } /// <summary> /// Looks up some data by ID. /// </summary> /// <param name="id">The ID of the data.</param> public string Get(int id) { return "value"; }
اپلیکیشن را مجددا اجرا کنید و به صفحات راهنما بروید. حالا مستندات API شما باید تولید شده و نمایش داده شوند.
صفحات راهنما مستندات شما را در زمان اجرا از توضیحات XML استخراج میکنند. دقت کنید که هنگام توزیع اپلیکیشن، فایل XML را هم منتشر کنید.
توضیحات تکمیلی
صفحات راهنما توسط کلاس ApiExplorer تولید میشوند، که جزئی از فریم ورک ASP.NET Web API است. به ازای هر API این کلاس یک ApiDescription دارد که توضیحات لازم را در بر میگیرد. در اینجا منظور از "API" ترکیبی از متدهای HTTP و مسیرهای نسبی است. بعنوان مثال لیست زیر تعدادی API را نمایش میدهد:
- GET /api/products
- {GET /api/products/{id
- POST /api/products
اگر اکشنهای کنترلر از متدهای متعددی پشتیبانی کنند، ApiExplorer هر متد را بعنوان یک API مجزا در نظر خواهد گرفت. برای مخفی کردن یک API از ApiExplorer کافی است خاصیت ApiExplorerSettings را به اکشن مورد نظر اضافه کنید و مقدار خاصیت IgnoreApi آن را به true تنظیم نمایید.
[ApiExplorerSettings(IgnoreApi=true)] public HttpResponseMessage Get(int id) { }
همچنین میتوانید این خاصیت را به کنترلرها اضافه کنید تا تمام کنترلر از ApiExplorer مخفی شود.
کلاس ApiExplorer متن مستندات را توسط اینترفیس IDocumentationProvider دریافت میکند. کد مربوطه در مسیر Areas/HelpPage/XmlDocumentation.cs/ قرار دارد. همانطور که گفته شد مقادیر مورد نظر از توضیحات XML استخراج میشوند. نکته جالب آنکه میتوانید با پیاده سازی این اینترفیس مستندات خود را از منبع دیگری استخراج کنید. برای اینکار باید متد الحاقی SetDocumentationProvider را هم فراخوانی کنید، که در HelpPageConfigurationExtensions تعریف شده است.
کلاس ApiExplorer بصورت خودکار اینترفیس IDocumentationProvider را فراخوانی میکند تا مستندات APIها را دریافت کند. سپس مقادیر دریافت شده را در خاصیت Documentation ذخیره میکند. این خاصیت روی آبجکتهای ApiDescription و ApiParameterDescription تعریف شده است.
مطالعه بیشتر
در حال حاضر این کتابخانه از مفاهیم زیر پشتیبانی میکند:
- تبدیل کلاس به جدول با پشتیبانی از خصوصیت Table
- تبدیل پراپرتیها به ستون با پشتیبانی از خصوصیت هایی چون Column,Key,MaxLength,Required,Notmapped,DatabaseGenerated,Index
- پشتیبانی از primarykey و کلیدهای ترکیبی
- کلید خارجی و روابط یک به چند و پشتیبانی از cascade on delete
- فیلد غیر نال
برای شروع ابتدا کتابخانه مورد نظر را از Nuget با دستور زیر دریافت کنید:
Install-Package SQLite.CodeFirst
solution من شامل سه پروژه است یکی برای مدلها که شامل کلاسهای زیر برای تهیه یک دفترچه تلفن ساده است:
Person
public class Person { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public virtual ICollection<PhoneBook> Numbers { get; set; } }
PhoneBook
public class PhoneBook { public int Id { get; set; } public string Field{ get; set; } public string Number { get; set; } public virtual Person Person { get; set; } }
پروژه بعدی به نام سرویس که جهت پیاده سازی کلاسهای EF است و دیگری هم یک پروژهی WPF جهت تست برنامه.
در پروژهی سرویس ما یک کلاس به نام Context داریم که مفاهیم مربوط به پیاده سازی Context در آن انجام شده است:
public class Context:DbContext { public Context():base("constr") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); var initializer = new InitialDb(modelBuilder); Database.SetInitializer(initializer); } public DbSet<PhoneBook> PhoneBook { get; set; } public DbSet<Person> Persons { get; set; } }
اول اینکه در سطر اول متد بازنویسی شده onModelCreating، قرارداد مربوط به نامگذاری جداول را حذف میکنیم چرا که در صورت نبودن این خط، اسامی که کلاس sqllite برای آن در نظر خواهد گرفت با اسامی که برای انجام عملیات CURD استفاده میشوند متفاوت خواهد بود. برای مثال برای Person جدولی به اسم People خواهد ساخت ولی برای درج، آن را در جدول Person انجام میدهد که به خاطر نبودن جدول با خطای چنین جدولی موجود نیست روبرو میشویم.
نکتهی دوم اینکه در همین کلاس Context ما یک پیاده سازی جدید بر روی کلاس InitialDb داشته ایم که در زیر نمونه کد آن را میبینید:
public class InitialDb:SQLite.CodeFirst.SqliteCreateDatabaseIfNotExists<Context> { public InitialDb(DbModelBuilder modelBuilder) : base(modelBuilder) { } protected override void Seed(Context context) { var person = new Person() { FirstName = "ali", LastName = "yeganeh", Numbers = new List<PhoneBook>() { new PhoneBook() { Field = "Work", Number = "031551234" }, new PhoneBook() { Field = "Mobile", Number = "09123456789" }, new PhoneBook() { Field = "Home", Number = "031554321" } } }; context.Persons.Add(person); base.Seed(context); } }
سپس در پروژهی اصلی WPF در فایل AppConfig رشته اتصالی مورد نظر را وارد نمایید:
<connectionStrings> <add name="constr" connectionString="data source=.\phonebook.sqlite;foreign keys=true" providerName="System.Data.SQLite" /> </connectionStrings>
خطا:
The ADO.NET provider with invariant name 'System.Data.SQLite' is either not registered in the machine or application config file, or could not be loaded
قسمتی از فایل app.config:
<entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> <parameters> <parameter value="mssqllocaldb" /> </parameters> </defaultConnectionFactory> <providers> <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" /> </providers> </entityFramework> <system.data> <DbProviderFactories> <remove invariant="System.Data.SQLite.EF6" /> <remove invariant="System.Data.SQLite" /> <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /> </DbProviderFactories> </system.data>
کد Load پروژه WPF:
public MainWindow() { InitializeComponent(); var context=new Context(); var list= context.Persons.ToList(); var s = ""; foreach (var person in list) { s += person.FirstName + " " + person.LastName + " has these numbers:" + Environment.NewLine; foreach (var number in person.Numbers) { s += number.Field + " : " + number.Number + Environment.NewLine; } s += Environment.NewLine; } MessageBox.Show(s); }
دانلود مثال
الف) به قسمت application pools در IIS Manager مراجعه کرده و گزینهی add application pool را انتخاب کنید. سپس یک نمونهی جدید را برای مثال به نام no-managed ایجاد کنید که net clr version. آن به گزینهی no managed code اشاره میکند.
ب) پس از publish برنامه مطابق مطلب فوق (برای مثال با اجرای دستور dotnet publish -c Release) و معرفی مسیر پوشهی publish به IIS (برای مثال به عنوان یک Application جدید ذیل default web site با کلیک راست بر روی default web site و انتخاب گزینهی Add application)، این application pool جدید را به برنامهی خود در IIS نسبت دهید. برای اینکار basic settings سایت را باز کرده و بر روی دکمهی select که در کنار نام application pool هست، کلیک کرده و گزینهی no-managed قسمت الف را انتخاب کنید.
نکته 1: برنامههای blazor wasm، یا standalone هستند و یا hosted. مورد standalone یعنی کاری به Web API ندارد و به خودی خود، به صورت یک سایت استاتیک قابل مشاهدهاست. حالت hosted یعنی به همراه web api هم هست و توسط دستور برای مثال «dotnet new blazorwasm -o BlazorIIS --hosted --no-https» ایجاد میشود که به همراه سه پوشهی کلاینت، سرور و shared است. برای توزیع حالت متکی به خود، فقط محتویات پوشهی publish، به عنوان مسیر برنامه، در IIS معرفی خواهند شد. در حالت hosted، مسیر اصلی، پوشهی publish مربوط به پروژهی سرور است؛ یعنی: Server\bin\Release\net5.0\publish. در این حالت پوشهی Client\bin\Release\net5.0\publish باید به داخل همین پوشهی publish سرور کپی شود. یعنی پوشهی publish پروژهی client باید به درون پوشهی publish پروژهی server کپی شود تا با هم یک برنامهی قابل توزیع توسط IIS را تشکیل دهند.
ج) اکنون اگر برنامه را برای مثال با مسیر فرضی جدید http://localhost/blazortest اجرا کنید، خطای 500.19 را دریافت میکنید. علت آنرا در مطلب «بررسی خطاهای ممکن در حین راه اندازی اولیه برنامههای ASP.NET Core در IIS» بررسی کردهایم. باید IIS URL Rewrite ماژول را نصب کرد؛ تا این مشکل برطرف شود. همچنین دلیل دیگر مشاهدهی این خطا، عدم نصب بستهی هاستینگ متناظر با شماره نگارش NET. مورد استفادهاست (اگر برنامهی شما از نوع hosted است و web api هم دارد).
د) پس از آن باز هم برنامه اجرا نمیشود! اگر در خطاها دقت کنید، به دنبال اسکریپتهایی شروع شده از مسیر localhost است و نه از پوشهی جدید blazortest. برای رفع این مشکل باید فایل publish\wwwroot\index.html را مطابق نکتهی base-URL که کمی بالاتر ذکر شد، ویرایش کرد تا blazor بداند که فایلها، در چه مسیری قرار دارند (و در ریشهی سایت واقع نشدهاند):
<head> <base href="/blazortest/" />
- الگوهای ابتدایی برای برنامه نویسی دات نت | www.dotnetdev.info
- امنیت Android مبتنی بر هسته لینوکس، آنچنان هم تعریفی ندارد | www.winbeta.net
- معرفی StimulReport نسخه Silverlight با ساپورت RightToLeft | www.nikamooz.com
- Wintellect's Power Collections for .NET | powercollections.codeplex.com
- DFA/NFA for .NET | github.com
- Doom 3 GPL source code | github.com
- Visual Studio Achievements | channel9.msdn.com
- امکان یکپارچگی Atmel AVR Studio 5 با ویژوال استودیو | channel9.msdn.com
- شروع به کار با MongoDB | net.tutsplus.com
- طرح Visual Studio Achievements و توجه به کیفیت کدهای ارائه شده | hadihariri.com
- کتابی رایگان در مورد Razor View Engine | www.kunal-chowdhury.com
- لیستی از کتابخانههای رایگان مفید مرتبط با دات نت فریم ورک | stackoverflow.com
- مقایسهای بین Silverlight و HTML5 | channel9.msdn.com