Owin چیست ؟ قسمت اول
آغاز فصل سوم:
در فصل گذشته در مورد بسته بندی و توزیع اسمبلیها، بررسیهایی را انجام دادیم. در این نوع توزیع، فرض ما بر این بود که دسترسی به اسمبلیها، از طریق دایرکتوری خود اپلیکیشن میباشد؛ ولی برای اسمبلیهای عمومی، صحبتی به میان نیاوردیم. در این فصل، ما تمرکز خود را برای توزیع اسمبلیهای عمومی میگذاریم. اسمبلیهای عمومی این قابلیت را میدهند که از طریق چند اپلیکیشن قابل دسترسی باشند. سادهترین و قابل دسترسترین نمونهی این اسمبلیها، اسمبلیهای خود دات نت فریم ورک هستند؛ یا نمونهی دیگر، شرکتهای ثالثی مثل تلریک، که برای استفادهی دیگر برنامه نویسان اسمبلی میسازند.
مشکلی که در توزیع اسمبلیهای عمومی وجود دارد این است که شما باید این اطمینان را کسب کنید که اسمبلی شما، همیشه همان اسمبلی خواهد بود و تغییری در آن رخ نخواهد داد. فرض کنید که شما از یک اسمبلی که توسط شرکت تلریک تهیه شده است استفاده کردهاید و برنامهی شما به خوبی با آن کار میکند. ولی چه اتفاقی میافتد که اگر برنامهی دیگری بعد از شما نصب شود و از همان اسمبلی، منتها از نسخهی دیگر آن استفاده میکند؟ بله برنامهی شما احتمال زیادی دارد که در این حالت به مشکل بر بخورد یا اینکه شخص دیگری یک اسمبلی دیگری همنام اسمبلی و هم نسخهی اسمبلی شما تولید میکند. برای رفع این مشکلات مایکروسافت تمهیداتی را اندیشیده است که ما به آن میگوییم «اسمبلی با نام قوی Strong Name Assembly».
اسمبلیها به دو دسته تقسیم میشوند: اسمبلیهای با نام قوی و اسمبلی
هایی با نام ضعیف ( این مورد در مستندات مایکروسافت نیست و توسط نویسندهی کتاب، این
اصطلاح ایجاد شده است).
در قسمت دوم گفتیم که اسمبلیها از قسمتهایی چون جداول مانیفست، هدرها، متادیتاها و ... تشکیل میشوند. اسمبلیهای نام قوی هم به همین شکل هستند. فقط توسط جفت کلید عمومی و خصوصی محافظت و امضا میشوند که برای ناشر، یک کلید منحصر به فرد را ایجاد میکنند و به ناشر این اطمینان را میدهند که اگر جفت کلیدی را که در دست شما است، به کسی ندهید، هیچ کس دیگری نمیتواند اسمبلی را با مشخصات اسمبلی شما امضاء کند.
حال یک اسمبلی نام قوی، دارای چهار خصوصیت است: نام اسمبلی بدون پسوند، نگارش، فرهنگ (Culture) و کلید عمومی.
از آنجا که خود کلید عمومی بسیار بزرگ میباشد، ما برای استفادهی راحتتر، از توکن کلید عمومی استفاده میکنیم که طول کمتری دارد. توکن کلید عمومی، یک مقدار هش شده است که از کلید عمومی به دست میآید:
"MyTypes, Version=1.0.8123.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" "MyTypes, Version=1.0.8123.0, Culture="enUS", PublicKeyToken=b77a5c561934e089" "MyTypes, Version=2.0.1234.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" "MyTypes, Version=1.0.8123.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
استفاده از فضای نام
System.Reflection.AssemblyName
به شما اجازهی ساخت و دریافت اطلاعاتی را از اسمبلیها میدهد؛ هر نوع اطلاعاتی را که شامل 4 خصوصیت بالا میشود، به شما میدهد.
از آنجا که مطالب مربوطه به امضاء کردن اسمبلی، در سایت جاری موجود میباشند، این مباحث را میتوانید از طریق این مقاله "نام قوی" دنبال کنید تا در این باره گزافه گویی نکرده باشیم .
تصویر زیر توضیح بند بالا را نشان میدهد:
مختصری در مورد GAC
%SystemRoot%\Microsoft.NET\Assembly
هر اسمبلی را که توزیع میکنید، حتما حداقل به یک اسمبلی نام قوی ارجاع خواهد داشت؛ دلیل این گفته هم وجود فضای نام system.object در اسمبلی mscorlib است. برای همین، موقعیکه شما با csc، کامپایل میکنید، از سوئیچ reference استفاده میشود تا ارجاعی را به نام اسمبلی مورد نظر داشته باشد. اگر نام اسمبلی به طور کامل به همراه مسیر ذکر شود که مستقیما از همانجا فراخوانی میشود؛ در غیر این صورت مسیرهای زیر مورد بررسی قرار میگیرند:
- مسیر پوشهی کاری برنامه
- مسیر کامپایلر CSC
- هر مسیری که با سوئیچ lib به کامپایلر معرفی کرده باشید.
- هر مسیری که با متغیرهای Lib Environment مشخص شده باشند.
/reference:System.Drawing.dll
در ضمن اسمبلیهای موجود در مسیر کامپایلر به هیچ عنوان اهمیتی به نوع ماشین نمیدهند؛ چون متادیتاهای اسمبلی آنها اهمیت دارند نه کد IL آنها. کد IL فقط در زمان اجرا، برای ما اهمیت دارد و در زمان کامپایل، همان متادیتا کفایت میکند و در نهایت برنامه موقع اجرا، با توجه به نوع ماشین x86,x36,ARM، اسمبلی مورد نیاز خود را از طریق GAC فراهم میکند که هر یک از اسمبلیهای مخصوص هر ماشین، توسط GAC، در داخل زیر شاخههای مخصوص خود قرار گرفتهاند.
تمام مطالب فوق در مورد کش کردن خروجی اطلاعات پویا هستند. در مورد فایلهای ایستا میتوان از میان افزار static files به نحو ذیل استفاده کرد:
app.UseStaticFiles(new StaticFileOptions() { OnPrepareResponse = context => { context.Context.Response.Headers["Cache-Control"] = "private, max-age=43200"; context.Context.Response.Headers["Expires"] = DateTime.UtcNow.AddHours(12).ToString("R"); } });
نگاشت JSON به کلاسهای معادل آن
یا مثلا گوگل یک سری API خاص خودش را دارد و بعضی از اینها فقط خروجی JSON دارند: google data
CoffeeScript #1
مقدمه
CoffeeScript یک زبان برنامه نویسی برای تولید کدهای جاوااسکریپت است که Syntax آن الهام گرفته از Ruby و Python است و بسیاری از ویژگیهایش، از این دو زبان پیاده سازی شده است.سوالی که ممکن است برای هر کسی پیش بیاید این است که چرا باید از CoffeeScript استفاده کرد و یا چرا نوشتن CoffeeScript بهتر از نوشتن مستقیم جاوااسکریپت است؟
از جمله دلایلی که میشود عنوان کرد:
حجم کد کمتری نوشته میشود (تجربه شخصی من: تقریبا کدنویسی شما به یک سوم تا نصف تبدیل میشود)، بسیار مختصر است و پیاده سازی prototype aliases و classes به سادگی و با حداقل کدنویسی انجام میگیرد.
CoffeeScript زیرمجموعهای از جاوااسکریپت نیست، اگرچه از کتابخانههای خارجی جاوااسکریپت میتوان در کدهای CoffeeScript استفاده کرد، اما برای اینکار باید کدهای مورد نیاز را به CoffeeScript تبدیل کرد تا از خطای زمان کامپایل جلوگیری شود.
پیش نیاز نوشتن کد به زبان CoffeeScript، شناخت جاوااسکریپت است تا بتوان خطاهای زمان اجرا را اصلاح کرد.
CoffeeScript محدودیتی در مرورگر ندارد و میتوان در برنامههای جاوااسکریپتی تحت سرور مانند Node.js با کیفیت بالا نیز از آن استفاده کرد.
زمانی را که برای یادگیری CoffeeScript صرف میکنید در زمان نوشتن پروژه، نتیجهی آنرا متوجه خواهید شد.
راه اندازی اولیه
یکی از سادهترین راههای نوشتن CoffeeScript استفاده از نسخهی مرورگر این زبان است و برای اینکار باید وارد سایت CoffeeScript.Org شده و بر روی تب Try CoffeeScript کلیک کنید. این سایت از نسخهی مرورگر CoffeeScript Compiler استفاده میکند و هر کدی CoffeeScript ایی که در پنل سمت چپ سایت بنویسید، تبدیل به جاوااسکریپت میشود و در پنل راست سایت، نمایش داده میشود.
همچنین میتوانید با استفاده از پروژهی js2coffee کدهای جاوااسکریپت را به کدهای CoffeeScript تبدیل کنید.
در صورتیکه بخواهید از نسخهی درون مرورگری CoffeeScript Compiler استفاده کنید، باید یک تگ اسکریپت لینک به این اسکریپت و با اضافه کردن تگ اسکریپت با type coffeescript این کار را انجام دهید. برای نمونه:
<script src="http://jashkenas.github.com/coffee-script/extras/coffee-script.js" type="text/javascript" charset="utf-8"></script> <script type="text/coffeescript"> # Some CoffeeScript </script>
برای نصب باید آخرین نسخهی Node.js و (npm (Node Package Manager را نصب کرده باشید. برای نصب CoffeeScript با استفاده از npm از دستور زیر استفاده کنید.
npm install -g coffee-script
coffee --compile my-script.coffee
آشنایی با کتابخانه NHibernate Validator
پروژه جدیدی به پروژه NHibernate Contrib در سایت سورس فورج اضافه شده است به نام NHibernate Validator که از آدرس زیر قابل دریافت است:
این پروژه که توسط Dario Quintana توسعه یافته است، امکان اعتبار سنجی اطلاعات را پیش از افزوده شدن آنها به دیتابیس به دو صورت دستی و یا خودکار و یکپارچه با NHibernate فراهم میسازد؛ که امروز قصد بررسی آنرا داریم.
کامپایل پروژه اعتبار سنجی NHibernate
پس از دریافت آخرین نگارش موجود کتابخانه NHibernate Validator از سایت سورس فورج، فایل پروژه آنرا در VS.Net گشوده و یکبار آنرا کامپایل نمائید تا فایل اسمبلی NHibernate.Validator.dll حاصل گردد.
بررسی مدل برنامه
در این مدل ساده، تعدادی پزشک داریم و تعدادی بیمار. در سیستم ما هر بیمار تنها توسط یک پزشک مورد معاینه قرار خواهد گرفت. رابطه آنها را در کلاس دیاگرام زیر میتوان مشاهده نمود:
به این صورت پوشه دومین برنامه از کلاسهای زیر تشکیل خواهد شد:
namespace NHSample5.Domain
{
public class Patient
{
public virtual int Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
}
}
using System.Collections.Generic;
namespace NHSample5.Domain
{
public class Doctor
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Patient> Patients { get; set; }
public Doctor()
{
Patients = new List<Patient>();
}
}
}
ساختار کلی این پروژه را در شکل زیر مشاهده میکنید:
اطلاعات این برنامه بر مبنای NHRepository و NHSessionManager ایی است که در قسمتهای قبل توسعه دادیم و پیشنیاز ضروری مطالعه آن میباشند (سورس پیوست شده شامل نمونه تکمیل شده این موارد نیز هست). همچنین از قسمت ایجاد دیتابیس از روی مدل نیز صرفنظر میشود و همانند قسمتهای قبل است.
تعریف اعتبار سنجی دومین با کمک ویژگیها (attributes)
فرض کنید میخواهیم بر روی طول نام و نام خانوادگی بیمار محدودیت قرار داده و آنها را با کمک کتابخانه NHibernate Validator ، اعتبار سنجی کنیم. برای این منظور ابتدا فضای نام NHibernate.Validator.Constraints به کلاس بیمار اضافه شده و سپس با کمک ویژگیهایی که در این کتابخانه تعریف شدهاند میتوان قیود خود را به خواص کلاس تعریف شده اعمال نمود که نمونهای از آن را مشاهده مینمائید:
using NHibernate.Validator.Constraints;
namespace NHSample5.Domain
{
public class Patient
{
public virtual int Id { get; set; }
[Length(Min = 3, Max = 20,Message="طول نام باید بین 3 و 20 کاراکتر باشد")]
public virtual string FirstName { get; set; }
[Length(Min = 3, Max = 60, Message = "طول نام خانوادگی باید بین 3 و 60 کاراکتر باشد")]
public virtual string LastName { get; set; }
}
}
مثالی دیگر:
جهت اجباری کردن و همچنین اعمال Regular expressions برای اعتبار سنجی یک فیلد میتوان دو ویژگی زیر را به بالای آن فیلد مورد نظر افزود:
[NotNull]
[Pattern(Regex = "[A-Za-z0-9]+")]
تعریف اعتبار سنجی با کمک کلاس ValidationDef
راه دوم تعریف اعتبار سنجی، کمک گرفتن از کلاس ValidationDef این کتابخانه و استفاده از روش fluent configuration است. برای این منظور، پوشه جدیدی را به برنامه به نام Validation اضافه خواهیم کرد و سپس دو کلاس DoctorDef و PatientDef را به آن به صورت زیر خواهیم افزود:
using NHibernate.Validator.Cfg.Loquacious;
using NHSample5.Domain;
namespace NHSample5.Validation
{
public class DoctorDef : ValidationDef<Doctor>
{
public DoctorDef()
{
Define(x => x.Name).LengthBetween(3, 50);
Define(x => x.Patients).NotNullableAndNotEmpty();
}
}
}
using NHSample5.Domain;
using NHibernate.Validator.Cfg.Loquacious;
namespace NHSample5.Validation
{
public class PatientDef : ValidationDef<Patient>
{
public PatientDef()
{
Define(x => x.FirstName)
.LengthBetween(3, 20)
.WithMessage("طول نام باید بین 3 و 20 کاراکتر باشد");
Define(x => x.LastName)
.LengthBetween(3, 60)
.WithMessage("طول نام خانوادگی باید بین 3 و 60 کاراکتر باشد");
}
}
}
استفاده از قیودات تعریف شده به صورت دستی
میتوان از این کتابخانه اعتبار سنجی به صورت مستقیم نیز اضافه کرد. روش انجام آنرا در متد زیر مشاهده مینمائید.
/// <summary>
/// استفاده از اعتبار سنجی ویژه به صورت مستقیم
/// در صورت استفاده از ویژگیها
/// </summary>
static void WithoutConfiguringTheEngine()
{
//تعریف یک بیمار غیر معتبر
var patient1 = new Patient() { FirstName = "V", LastName = "N" };
var ve = new ValidatorEngine();
var invalidValues = ve.Validate(patient1);
if (invalidValues.Length == 0)
{
Console.WriteLine("patient1 is valid.");
}
else
{
Console.WriteLine("patient1 is NOT valid!");
//نمایش پیغامهای تعریف شده مربوط به هر فیلد
foreach (var invalidValue in invalidValues)
{
Console.WriteLine(
"{0}: {1}",
invalidValue.PropertyName,
invalidValue.Message);
}
}
//تعریف یک بیمار معتبر بر اساس قیودات اعمالی
var patient2 = new Patient() { FirstName = "وحید", LastName = "نصیری" };
if (ve.IsValid(patient2))
{
Console.WriteLine("patient2 is valid.");
}
else
{
Console.WriteLine("patient2 is NOT valid!");
}
}
در اینجا اگر سعی در اعتبار سنجی یک پزشک نمائیم، نتیجهای حاصل نخواهد شد زیرا هنگام استفاده از کلاس ValidationDef، باید نگاشت لازم به این قیودات را نیز دقیقا مشخص نمود تا مورد استفاده قرار گیرد که نحوهی انجام این عملیات را در متد زیر میتوان مشاهده نمود.
public static ValidatorEngine GetFluentlyConfiguredEngine()
{
var vtor = new ValidatorEngine();
var configuration = new FluentConfiguration();
configuration
.Register(
Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => t.Namespace.Equals("NHSample5.Validation"))
.ValidationDefinitions()
)
.SetDefaultValidatorMode(ValidatorMode.UseExternal);
vtor.Configure(configuration);
return vtor;
}
FluentConfiguration آن مجزا است از نمونه مشابه کتابخانه Fluent NHibernate و نباید با آن اشتباه گرفته شود (در فضای نام NHibernate.Validator.Cfg.Loquacious تعریف شده است).
در این متد کلاسهای قرار گرفته در پوشه Validation برنامه که دارای فضای نام NHSample5.Validation هستند، به عنوان کلاسهایی که باید اطلاعات لازم مربوط به اعتبار سنجی را از آنان دریافت کرد معرفی شدهاند.
همچنین ValidatorMode نیز به صورت External تعریف شده و منظور از External در اینجا هر چیزی بجز استفاده از روش بکارگیری attributes است (علاوه بر امکان تعریف این قیودات در یک پروژه class library مجزا و مشخص ساختن اسمبلی آن در اینجا).
اکنون جهت دسترسی به این موتور اعتبار سنجی تنظیم شده میتوان به صورت زیر عمل کرد:
/// <summary>
/// استفاده از اعتبار سنجی ویژه به صورت مستقیم
/// در صورت تعریف آنها با کمک
/// ValidationDef
/// </summary>
static void WithConfiguringTheEngine()
{
var ve2 = VeConfig.GetFluentlyConfiguredEngine();
var doctor1 = new Doctor() { Name = "S" };
if (ve2.IsValid(doctor1))
{
Console.WriteLine("doctor1 is valid.");
}
else
{
Console.WriteLine("doctor1 is NOT valid!");
}
var patient1 = new Patient() { FirstName = "وحید", LastName = "نصیری" };
if (ve2.IsValid(patient1))
{
Console.WriteLine("patient1 is valid.");
}
else
{
Console.WriteLine("patient1 is NOT valid!");
}
var doctor2 = new Doctor() { Name = "شمس", Patients = new List<Patient>() { patient1 } };
if (ve2.IsValid(doctor2))
{
Console.WriteLine("doctor2 is valid.");
}
else
{
Console.WriteLine("doctor2 is NOT valid!");
}
}
نکته مهم:
فراخوانی GetFluentlyConfiguredEngine نیز باید یکبار در طول برنامه صورت گرفته و سپس حاصل آن بارها مورد استفاده قرار گیرد. بنابراین نحوهی صحیح دسترسی به آن باید حتما از طریق الگوی Singleton که در قسمتهای قبل در مورد آن بحث شد، انجام شود.
استفاده از قیودات تعریف شده و سیستم اعتبار سنجی به صورت یکپارچه با NHibernate
کتابخانه NHibernate Validator زمانیکه با NHibernate یکپارچه گردد دو رخداد PreInsert و PreUpdate آنرا به صورت خودکار تحت نظر قرار داده و پیش از اینکه اطلاعات ثبت و یا به روز شوند، ابتدا کار اعتبار سنجی خود را انجام داده و اگر اعتبار سنجی مورد نظر با شکست مواجه شود، با ایجاد یک exception از ادامه برنامه جلوگیری میکند. در این حالت استثنای حاصل شده از نوع InvalidStateException خواهد بود.
برای انجام این مرحله یکپارچه سازی ابتدا متد BuildIntegratedFluentlyConfiguredEngine را به شکل زیر باید فراخوانی نمائیم:
/// <summary>
/// از این کانفیگ برای آغاز سشن فکتوری باید کمک گرفته شود
/// </summary>
/// <param name="nhConfiguration"></param>
public static void BuildIntegratedFluentlyConfiguredEngine(ref Configuration nhConfiguration)
{
var vtor = new ValidatorEngine();
var configuration = new FluentConfiguration();
configuration
.Register(
Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => t.Namespace.Equals("NHSample5.Validation"))
.ValidationDefinitions()
)
.SetDefaultValidatorMode(ValidatorMode.UseExternal)
.IntegrateWithNHibernate
.ApplyingDDLConstraints()
.And
.RegisteringListeners();
vtor.Configure(configuration);
//Registering of Listeners and DDL-applying here
ValidatorInitializer.Initialize(nhConfiguration, vtor);
}
SingletonCore()
{
Configuration cfg = DbConfig.GetConfig().BuildConfiguration();
VeConfig.BuildIntegratedFluentlyConfiguredEngine(ref cfg);
//با همان کانفیگ تنظیم شده برای اعتبار سنجی باید کار شروع شود
_sessionFactory = cfg.BuildSessionFactory();
}
از این لحظه به بعد، نیاز به فراخوانی متدهای Validate و یا IsValid نبوده و کار اعتبار سنجی به صورت خودکار و یکپارچه با NHibernate انجام میشود. لطفا به مثال زیر دقت بفرمائید:
/// <summary>
/// استفاده از اعتبار سنجی یکپارچه و خودکار
/// </summary>
static void tryToSaveInvalidPatient()
{
using (Repository<Patient> repo = new Repository<Patient>())
{
try
{
var patient1 = new Patient() { FirstName = "V", LastName = "N" };
repo.Save(patient1);
}
catch (InvalidStateException ex)
{
Console.WriteLine("Validation failed!");
foreach (var invalidValue in ex.GetInvalidValues())
Console.WriteLine(
"{0}: {1}",
invalidValue.PropertyName,
invalidValue.Message);
log4net.LogManager.GetLogger("NHibernate.SQL").Error(ex);
}
}
}
/// <summary>
/// استفاده از اعتبار سنجی یکپارچه و خودکار
/// </summary>
static void tryToSaveValidPatient()
{
using (Repository<Patient> repo = new Repository<Patient>())
{
var patient1 = new Patient() { FirstName = "Vahid", LastName = "Nasiri" };
repo.Save(patient1);
}
}
نکته:
اگر کار ساخت database schema را با کمک کانفیگ تنظیم شده توسط کتابخانه اعتبار سنجی آغاز کنیم، طول فیلدها دقیقا مطابق با حداکثر طول مشخص شده در قسمت تعاریف قیود هر یک از فیلدها تشکیل میگردد (حاصل از اعمال متد ApplyingDDLConstraints در متد BuildIntegratedFluentlyConfiguredEngine ذکر شده میباشد).
public static void CreateValidDb()
{
bool script = false;//آیا خروجی در کنسول هم نمایش داده شود
bool export = true;//آیا بر روی دیتابیس هم اجرا شود
bool dropTables = false;//آیا جداول موجود دراپ شوند
Configuration cfg = DbConfig.GetConfig().BuildConfiguration();
VeConfig.BuildIntegratedFluentlyConfiguredEngine(ref cfg);
//با همان کانفیگ تنظیم شده برای اعتبار سنجی باید کار شروع شود
new SchemaExport(cfg).Execute(script, export, dropTables);
}
دریافت سورس کامل قسمت دهم
FirstName
firstName
strFirstName lblFirstName
<Company>.<Technology|Produt|Project>[.<Feature>][.<SubNamespace>]
Microsoft.Reporting.WebForms Kara.Support.Manager.Enums Kara.CSS.HQ.WebUI.Configuration
PackageManager , PacakgeConfigGenerator Circle , Utility , Package
CreateConfig , classdata CManager , ClsPackage , Config_Creator , Config1389
CenterCollection , PackageCollection
public delegate void Logger (string log); public delegate void LoggingCallback (object sender, string reason);
AddEventArgs , EditEventArgs , DeleteEventArgs
Adding , Add , Added
public delegate void <EventName>EventHandler (object sender, <EventName>EventArgs e);
public event EventHandler <AddEventArgs> Adding;
DisplayNameAttribute , MessageTypeAttribute
IComponent (اسم) IConnectionProvider (موصوف) ICloneable (صفت)
public enum FileMode { Append, Read, … }
[Flag] public enum KeyModifiers { Alt = 1, Control = 2, Shift = 4 }
public enum OperationState { DoneState, FaultState, RollbackState }
AddDays , Save , DeleteRow , BindData , Close , Open
Radius , ReportType , DataSource , Mode , CurrentCenterId
public CenterCollection Centers { get; set; }
if (list.Contains(item)) if (regularExpression.Matches(text)) if (stream.CanSeek) if (context.Created) if (form.Enabled)
if (list.IsContains(item)) if (regularExpression.Match(text)) if (stream.Seekable) if (context.IsCreated) if (form.IsEnabled)
public Color Color { get; set; }
firstName , e , id , packageId , centerName , name
public static MyType operator +(MyType left, MyType right) public static bool operator ==(MyType left, MyType right)
public static MyType operator ++(MyType value)
public static MyType operator /(MyType dividend, MyType divisor)
public static MyType operator -(MyType d1, MyType d2) // incorrect!
Area , DataBinder , PublicCacheName
_centersList _firstName _currentCenter
parameterType , packageOperationTypeId
lblName (Label) txtHeader (TextBox) btnSave (Button)
ArgumentNullException , InvalidOperaionException
System.Data
<Company>.<Component>.dll <Company>.<Project|Product|Technology>.<Component>.dll
Microsoft.CSharp.dll , Kara.CSS.Manager.dll
public int IComparer<T> {…} public delegate bool Predicate<T> (T item)
public int ISessionChannel<TSession> {…} public delegate TOutput Converter<TInput, TOutput> (TInput from) public class Nullable<T> {…} public class List<T> {…}
ArgumentExceptionIllegalCharacters ArgumentExceptionInvalidName ArgumentExceptionFileNotFound
Pascal Casing |
camel Casing |
Wrong |
Callback |
callback |
CallBack |
BitFlag |
bitFlag |
Bitflag / bitflag |
Canceled |
canceled |
Cancelled |
DoNot |
doNot |
Donot / Don’t |
|
|
|
Endpoint |
endpoint |
EndPoint / endPoint |
FileName |
fileName |
Filename / filename |
Gridline |
gridline |
GridLine / gridLine |
Hashtable |
hashtable |
HashTable / hashTable |
Id |
id |
ID |
Indexes |
indexes |
Indices |
LogOff |
logOff |
Logoff / LogOut ! |
LogOn |
logOn |
Logon / LogIn ! |
SignOut |
signOut |
Signout / SignOff |
SignIn |
signIn |
Signin / SignOn |
Metadata |
metadata |
MetaData / metaData |
Multipanel |
multipanel |
MultiPanel / multiPanel |
Multiview |
multiview |
MultiView / multiView |
Namespace |
namespace |
NameSpace / nameSpace |
Ok |
ok |
OK |
Pi |
pi |
PI |
Placeholder |
placeholder |
PlaceHolder / placeHolder |
UserName |
username |
Username / username |
WhiteSpace |
whiteSpace |
Whitespace / whitespace |
Writable |
writable |
Writeable / writeable |
public class Color { … public static Color FromArgb(…) { … } }
Portable Class Library برای تولید Assembly مدیریت شده که قابیلت استفاده در اکثر تکنولوژیها نظیر (WP7(Windows Phone 7 و WPF و Silverlight و Windows Store App و حتی XBox را داراست استفاده میشود. این نوع پروژهها میزان استفاده مجدد از کدها رو به حداکثر ممکن میرسونه و در عوض تعداد پروژههای مورد نیاز رو به حداقل. مورد اصلی استفاده از اونها برای تولید Multi-Targeted Application هاست. برای مثال در تولید پروژههای تحت Windows که با تکنولوژی WPF پیاده سازی میشوند پروژه ViewModel و Model رو با این تکنولوژی پیاده سازی میکنند تا در آینده اگر نیاز بود قسمتی از پروژه با استفاده از Silverlight یا Windows Store App انجام بشه بتونیم Model , ViewModel نوشته شده رو به این پروژهها Reference بدیم. تا قبل از برای انجام این کار باید این دو بخش رو دوباره برای هر تکنولوژی بازنویسی میکردیم.
روش استفاده
زمانی که یک پروژه از نوع Portable Class Library رو ایجاد میکنیم باید حداقل 2 یا چند تا از Platformهای مورد نظر رو انتخاب کنیم. به صورت زیر :
بعد از انتخاب گزینه Portable Class Library و زدن کلید Enter فرم زیر ظاهر خواهد شد که در این قسمت باید Platformهای مورد نظر رو انتخاب کنیم.
در اینجا من 2 Platform رو انتخاب کردم. یکی Silverlight و Net 4.5. یعنی این Portable Class Library هم میتونه به پروژه Silverlight و هم به Class library .Net 4.5 رفرنس داده بشه.
حتما میپرسید چه طوری؟
در واقع Microsoft برای انجام این کار فقط یک سری از Referenceهای مشترک بین این 2 Platform رو به پروژه اضافه میکنه و همین موضوع باعث شده کار با این پروژهها نیاز به یکم مهارت داشته باشه.
برای مثال اگر قصد استفاده از تکنولوژی Async&Await رو دارید باید یکم به خودتون زحمت بدید و CTP مورد نظر رو نصب کنید.(حالا اگر از Net4 استفاده میکنید که باید از یک روش دیگه استفاده کنید که در یک مقاله جداگانه براتون توضیح خواهم داد).
به جدول زیر دقت کنید.
Xbox 360 | Windows Phone | Silverlight | Windows Store | .NET Framework | Feature |
√ | √ | √ | √ | √ | Core |
√ | √ | √ | √ | LINQ | |
Only 7.5 | √ | √ | √ | IQueryable | |
√ | √ | Only 4.5 | Dynamic keyword | ||
√ | √ | √ | Managed Extensibility Framework (MEF) | ||
√ | √ | √ | √ | Network Class Library (NCL) | |
√ | √ | √ | √ | Serialization | |
√ | √ | √ | √ | Windows Communication Foundation (WCF) | |
√ | √ | √ |
Only 4.5 | Model-View-View Model (MVVM) | |
√ | √ | Only 4.0.3 and 4.5 | Data annotations | ||
√ | √ | √ | √ | Only 4.0.3 and 4.5 | XLINQ |
در جدول بالا به صورت کامل مشخص شده که در هر پلاتفرم چه چیزی Support میشه. برای مثال Data Annotation فقط در Net4.3 , 4.5 قابل استفاده است.
اسمبلیهای زیر در یک Portable Class Library قابل استفاده هستند.
mscorlib.dll
System.dll
System.Core.dll
System.Xml.dll
System.ComponentModel.Composition.dll
System.Net.dll
System.Runtime.Serialization.dll
System.ServiceModel.dll
System.Xml.Serialization.dll
System.Windows.dll - From Silverlight
پیاده سازی یک مثال عملی
در این مثال قصد دارم یک کلاس برای مدیریت تاریخ شمسی درست کنم. مراحل زیر رو دنبال کنید
یک Portable Class Library به نام Common به پروژه اضافه کنید.
یک کلاس به نام PersianDate به برنامه اضافه کرده به صورت زیر
public class PersianDate<TCalendar> where TCalendar : System.Globalization.Calendar { public PersianDate() { this.CurentCalendar = System.Activator.CreateInstance<TCalendar>(); } public TCalendar CurentCalendar { get; private set; } public string GetDate() { return string.Format( "{0}/{1}/{2}", this.CurentCalendar.GetYear( DateTime.Today ).ToString( "####0000" ) , this.CurentCalendar.GetMonth( DateTime.Today ).ToString( "##00" ) , this.CurentCalendar.GetDayOfMonth( DateTime.Today ).ToString( "##00" ) ); } }
حالا یک پروژه از نوع Console Application به برنامه اضافه کنید و یک Reference به پروژه Common بدید و بعد کلاس زیر رو بنویسید.
public class CustomPersianDate { public CustomPersianDate() { } public static Common.PersianDate<System.Globalization.PersianCalendar> PersianCalendar { get { return _persianCalendar ?? ( _persianCalendar = new Common.PersianDate<System.Globalization.PersianCalendar>() ); } } private static Common.PersianDate<System.Globalization.PersianCalendar> _persianCalendar; }
حالا یک پروژه از نوع Silverlight به برنامه اضافه کنید و یک Reference به پروژه Common بدید و بعد کلاس بالا بدون تغییر بنویسید.
نمای کلی پروژه باید به صورت زیر باشد.
بعد پروژه ConsoleApplication رو به عنوان پروژه StartUp انتخاب کنید و فایل Program رو به صورت زیر تغییر بدید.
class Program { static void Main( string[] args ) { Console.WriteLine( "Today Is ?{0}", CustomPersianDate.PersianCalendar.GetDate() ); Console.ReadLine(); } }
خوب نتیجه به صورت زیر خواهد بود:
برای پروژه Silverlight هم نتیجه قطعا به همین صورت است.
همان طور که دید انتخاب نوع Calendar به خود Applicationها واگذار شد و شما میتونید هر نوع تقویم رو به عنوان TCalendar تعیین کنید.
امیدوارم شما هم مثل من به این تکنولوژی دلچسب علاقه پیدا کرده باشید.