مطالب
نحوه ایجاد یک نقشه‌ی سایت پویا با استفاده از قابلیت Reflection
طبق این استاندارد قالب نقشه‌ی سایت به فرم زیر می‌باشد:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
   <url>
      <loc>http://www.example.com/</loc>
      <lastmod>2005-01-01</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
   </url>
</urlset>

که یک فایل XML متشکل از یک تگ urlset  است و این تگ نیز حاوی یک یا چند تگ url می‌باشد. با توجه به تعاریف بالا به یک چنین کلاسی خواهیم رسید: 

public enum ChangeFreq
        {
            Always,
            Hourly,
            Daily,
            Weekly,
            Monthly,
            Yearly,
            Never
        }

        [XmlElement("loc")]
        public string Url { get; set; }

        [XmlElement("lastmod")]
        public DateTime? LastModified { get; set; }
        public bool ShouldSerializeLastModified()
        {
            return LastModified.HasValue;
        }

        [XmlElement("changefreq")]
        public ChangeFreq? ChangeFrequency { get; set; }
        public bool ShouldSerializeChangeFrequency()
        {
            return ChangeFrequency.HasValue;
        }
        [XmlElement("priority")]
        public float? Priority { get; set; }
        public bool ShouldSerializePriority()
        {
            return Priority.HasValue;
        }
    }

دقت داشته باشید که چون پروپرتی‌های LastModified ، ChangeFrequency و Priority از نوع Nullable تعریف شده‌اند، پس باید کاری کنیم در صورتیکه این پروپرتی‌ها نال بودند سریالیز نشوند. بدین منظور از تابع ShouldSerialize[MemberName] استفاده می‌شود. این تابع  جزئی از دات نت است. کافی است بعد از ShouldSerialize نام پروپرتی را ذکر کنید. حال به کلاس دیگری نیاز داریم تا لیستی از کلاس فوق را دربر داشته باشد. 

[XmlRoot("urlset",Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
    public class SiteMp
    {
        private readonly List<Location> _locations;

        public SiteMp()
        {
            _locations = new List<Location>();
        }

        [XmlElement("url")]
        public List<Location> Locations
        {
            get { return _locations; }
            set
            {
                foreach (var location in value)
                {
                    Add(location);
                }
            } 
            
        }

        public void Add(Location location)
        {
            _locations.Add(location);
        }
    }

حال برای پردازش کلاس بالا لازم است ActionResultی را طراحی کنیم تا خروجی Response را به فرمت XML پردازش کند:

public class XmlResult : ActionResult
    {
        private readonly object _objectToSerialize;

        public XmlResult(object objectToSerialize)
        {
            _objectToSerialize = objectToSerialize;
        }
        public override void ExecuteResult(ControllerContext context)
        {
            if (_objectToSerialize == null)
               return;
             context.HttpContext.Response.Clear();
             var xmlSerializer = new XmlSerializer(_objectToSerialize.GetType());
             context.HttpContext.Response.ContentType = "text/xml";
             xmlSerializer.Serialize(context.HttpContext.Response.Output, _objectToSerialize);            
        }
    }

و در آخر یک کنترلر ساخته و به صورت زیر از آن استفاده می‌کنیم: 

public class SiteMapController : Controller
    {
        // GET: SiteMap
        public ActionResult Index()
        {
            SiteMp siteMap = new SiteMp();
            siteMap.Add(new Location
            {
                Url = Request.Url.GetLeftPart(UriPartial.Authority) + "/Home/Index"
            });
            siteMap.Add(new Location
            {
                Url = Request.Url.GetLeftPart(UriPartial.Authority) + "/Home/NewRequest",
                ChangeFrequency = Location.ChangeFreq.Always,
                LastModified = DateTime.UtcNow,
                Priority = 0.5f
            });
            siteMap.Add(new Location
            {
                Url = Request.Url.GetLeftPart(UriPartial.Authority) + "/Home/FindRequest",
                ChangeFrequency = Location.ChangeFreq.Always,
                LastModified = DateTime.UtcNow,
                Priority = 0.5f
            });
            siteMap.Add(new Location
            {
                Url = Request.Url.GetLeftPart(UriPartial.Authority) + "/ContactUs/Index",
                ChangeFrequency = Location.ChangeFreq.Daily,
                LastModified = DateTime.UtcNow,
                Priority = 0.5f
            });
            return new XmlResult(siteMap);
        }

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

public class ControllerScanner
    {
       public static List<string> ScanAllControllers(HttpRequestBase requestBase)
        {
            Assembly asm = Assembly.GetAssembly(typeof(MvcApplication));

            var controllerActionlist = asm.GetTypes()
                .Where(type => typeof (Controller).IsAssignableFrom(type))
                .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
                .Where((returnType => returnType.ReturnType == (typeof(ViewResult)) || returnType.ReturnType==(typeof(ActionResult))))
                .Select(
                    x =>
                        new
                        {
                            Controller = x.DeclaringType.Name,
                            Action = x.Name,
                            ReturnType = x.ReturnType.Name

                        })
                .OrderBy(x => x.Controller).ThenBy(x => x.Action).Distinct().ToList();

            if (requestBase.Url == null)
                return null;

            var url = requestBase.Url.GetLeftPart(UriPartial.Authority);
            return controllerActionlist.Select(controller => $"{url}/{controller.Controller}/{controller.Action}").ToList();
        }
    }

حال از کلاس بالا در کنترلر SiteMap به صورت زیر استفاده می‌کنیم :

public class SiteMapController : Controller
    {
        // GET: SiteMap
        public ActionResult Index()
        {
            var siteMap = new SiteMap();
            var controllers = ControllerScanner.ScanAllControllers(Request);
            foreach (var controller in controllers)
            {
                siteMap.Add(new Location
                {
                    Url = controller,
                    ChangeFrequency = Location.ChangeFreq.Always,
                    LastModified = DateTime.UtcNow,
                    Priority = 0.5f
                });
            }
            return new XmlResult(siteMap);
        }        
    }

در آخر نیز سطر زیر را به سیستم مسیریابی اضافه نمایید تا در صورت درخواست فایل sitemap.xml  اکشن Index از کنترلر SiteMap فراخوانی شود.

 routes.MapRoute(
                "SiteMap", // Route name
                "sitemap.xml", // URL with parameters
                new { controller = "Sitemap", action = "Index", name = UrlParameter.Optional, area = "" }
            );


مطالب
ایجاد نقشه سایت (Site Map) داینامیک
همان طور که می‌دانید نقشه‌ی سایت علاوه بر استفاده از MetaTag‌ها و Url Routing‌ها و ... یکی از نکات اصلی برای سایت شماست که در نتایج گوگل برای جستجو کنندگان نمایش داده شود .

در این مقاله من قصد دارم که به شما چگونگی ایجاد و کار با یک SiteMap  داینامیک را آموزش دهم .
منظور از SiteMap داینامیک این است که به ازای هر مطلبی که شما در سایت تان ایجاد ، ویرایش یا حذف می‌کنید چنانچه دارای صفحه ای در سایت باشد SiteMap تغییر می‌کند .

ساختار یک SiteMap به صورت زیر است :

<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
<loc>Url Page 1</loc>
<lastmod>2014-02-20</lastmod>
<changefreq>always</changefreq>
<priority>1</priority>
  </url>
  <url>
<loc>Url Page 2</loc>
<lastmod>2014-02-20</lastmod>
<changefreq>always</changefreq>
<priority>1</priority>
  </url>
</urlset>
به ازای هر مطلبی که به سایتتان اضافه می‌کنید چنانچه آن مطلب جهت نمایش دارای Url باشد ، باید یک تگ Url  به SiteMap اضافه شود.
تگ loc موجود در تگ url آدرس صفحه را مشخص می‌کند .
تگ lastmod تاریخ اضافه کردن یا آخرین ویرایش را نمایش می‌دهد .
تگ changefreq که دوره‌ی بروز رسانی صفحه را مشخص می‌کند .
تگ priority الویت صفحه را مشخص می‌کند .

که من در کد نویسی تگ changefreq  را always  و تگ priority را  1 قرار دادم.

در فایل ضمیمه یک کلاس به اسم updateSiteMap.cs وجود دارد که تابع آن شامل دو پارامتر ورودی مانند زیر است :

public void UpdateSiteMap(string Addr,string NewOpr)
پارامتر Addr که آدرس صفحه ای است که شما می‌خواهید به SiteMap اضافه شود .
پارامتر NewOpr که می‌تواند شامل یکی از سه مقدار زیر باشد  :add ، edit ، delete

اگر پارامتر NewOpr دارای مقدار add باشد یعنی مقدار موجود در پارامتر Addr را بهSiteMap اضافه کن . یعنی یک تگ url  یه SiteMap اضافه کن .
اگر پارامتر NewOpr دارای مقدار edit باشد یعنی مقدار موجود در تگ <lastmod> را ویرایش کن . یعنی تاریخ آخرین بروزرسانی تغییر می‌کند .
اگر پارامتر NewOpr دارای مقدار delete باشد یعنی تگ url ایی که محتوای تگ loc آن برابر است با مقدار موجود در پارامتر Addr را از SiteMap حذف کن.

این بخش از کد موجود در فایل ضمیمه uupdateSiteMaop.cs  قسمت edit و delete  نقشه‌ی سایت را انجام می‌دهد .
 if (NewOpr != "add")
{
XmlElement xmlElement = xmlDoc.DocumentElement;
if (xmlElement.ChildNodes != null)
{
  foreach (XmlElement myElement in xmlDoc.DocumentElement)
  {
if (myElement.ChildNodes[0].InnerText == Addr)
{
  if (NewOpr != "delete")
myElement.ChildNodes[1].InnerText = DateTime.Now.ToString("yyyy-MM-dd");
  else
myElement.ParentNode.RemoveChild(myElement);
break;
}
  }
}
}

و بخش else دستور بالا قسمت Add  را انجام می‌دهد .یعنی کدهای زیر:
 else
{
string ns="http://www.sitemaps.org/schemas/sitemap/0.9";
XmlNode url = xmlDoc.CreateNode(XmlNodeType.Element, "url",ns );
XmlNode loc = xmlDoc.CreateNode(XmlNodeType.Element, "loc", ns);
XmlNode lastmod = xmlDoc.CreateNode(XmlNodeType.Element, "lastmod", ns);
XmlNode changefreq = xmlDoc.CreateNode(XmlNodeType.Element, "changefreq", ns);
XmlNode priority = xmlDoc.CreateNode(XmlNodeType.Element, "priority", ns);
loc.InnerText = Addr;
lastmod.InnerText = DateTime.Now.ToString("yyyy-MM-dd");
changefreq.InnerText = "always";
priority.InnerText = "1";
url.AppendChild(loc);
url.AppendChild(lastmod);
url.AppendChild(changefreq);
url.AppendChild(priority);
xmlDoc.DocumentElement.AppendChild(url);
}
اگر اطلاعاتی را به جدول اضافه می‌کنید و می‌خواهید Url صفحه‌ی مربوط به آن اطلاعات برای شما در SiteMap اضافه شود  بعد از ذخیره شدن اطلاعات در جدول بلافاصله کد زیر را اضافه می‌کنید :
//
Add Info In Table
//
updateSiteMap updateSiteMap = new updateSiteMap();
updateSiteMap.UpdateSiteMap("Url Page", "add");

برای قسمت ویرایش هم پس از آنکه اطلاعات را ویرایش کردید چنانچه برای آن اطلاعات صفحه ای را در SiteMap درج کرده اید کد زیر را می‌نویسید :
 updateSiteMap updateSiteMap = new updateSiteMap();
updateSiteMap.UpdateSiteMap("Url Page", "edit");

برای قسمت حذف هم اگر شما اطلاعاتی را از جدول حذف می‌کنید چنانچه برای آن اطلاعات صفحه ای در SiteMap درج کرده اید کد زیر را می‌نویسید :
  updateSiteMap updateSiteMap = new updateSiteMap();
updateSiteMap.UpdateSiteMap("Url Page", "delete");

موفق باشید .


 
Files.zip
مطالب
نگارش نهایی MBUnit 3 ارائه شد

MBUnit که یکی دیگر از فریم ورک‌های آزمایش واحد یا unit testing دات نت به شمار می‌رود، نگارش 3 بتا آن از سال 2007 شروع شده و اخیرا نگارش نهایی 3 آن ارائه گردیده است.


جهت مشاهده‌ی جزئیات آخرین تغییرات اعمال شده در نگارش جدید آن، MbUnit v3.0.6 Update 1 می‌توان به وبلاگ یکی از اعضای اصلی تیم مراجعه نمود.

Added support for TestDriven.Net category filters.
Added support for more powerful inclusion/exclusion test filter expressions.
Fixed ReSharper v3.1, v4.0 and v4.1 hangs.
Increased NCover v1.5.8 timeout.
Adopted new assembly version numbering scheme

MBUnit از جهات بسیاری از NUnit پیشرفته‌تر است برای مثال در هنگام انجام آزمایشات واحد بر روی یک دیتابیس، به صورت خودکار امکان حذف رکوردهای آزمایشی را داشته و کار به حالت اول بازگردان وضعیت دیتابیس را انجام می‌دهد.
همچنین نگارش 3 آن کار یکپارچه شدن با ReSharper را هم انجام می‌دهد که پیشتر به صورت پیش فرض مهیا نبود و این مورد یکی از دلایل مهم استفاده گسترده از NUnit به شمار می‌رفت.

پ.ن.
برای دریافت آن باید به گوگل‌کد مراجعه کرد که احتمالا با مشکلاتی همراه خواهد بود. نگارش نهایی آن تا این تاریخ را از اینجا دریافت کنید.

مطالب
مدیریت فایلهای یک پروژه نرم افزاری با استفاده از Subversion
کتابچه‌ای را درباره‌ی کار با SVN تهیه کرده‌ام که از آدرس زیر قابل دریافت است:
دریافت فایل

خلاصه‌ای از مقدمه کتاب:
آیا شما هم جزو آن دسته از برنامه نویسانی هستید که هنوز به ازای هر نگارش از برنامه، سورس‌کدهای خود را فشرده کرده و آنها را بر اساس تاریخ آرشیو می‌کنند؟ آیا می‌توانید گزارشی مقایسه‌ای را از تغییرات انجام شده در سورس کدهای دو نگارش اخیر برنامه خود ارائه دهید؟ آیا می‌دانید فایلی را که هم اکنون بر روی آن مشغول به کار هستید در نگارش قبلی آن چه وضعیتی داشته و مقایسه آن با فایل فعلی شامل چه موارد و تغییراتی خواهد شد؟ آیا امکان بازگشت سریع و تبدیل سورس کدهای جاری برنامه را به سه نگارش قبل که از نظر شما پایدارتر هستند، بدون اضطراب و تشنج عصبی و با سرعت هرچه تمام‌تر و بدون خطا دارید؟ آیا می‌دانید بر روی یک فایل ویژه پروژه چه کسانی کار کرده‌اند و چه تغییراتی را اعمال نموده‌اند؟ آیا می‌توانید در یک تیم برنامه نویسی در کنار سایر برنامه‌نویس‌ها بر روی یک پروژه واحد کار کنید و به‌سادگی تداخلات رخ داده را مرتفع و یا آخرین تغییرات انجام شده را ادغام نمائید؟ آیا می‌توانید همواره آخرین نگارش تائید شده پروژه را به سرعت و با دقت تمام به افراد تیم نرم افزاری خود تحویل دهید؟ آیا مکان مجتمعی را جهت نگهداری سورس‌کدهای پروژه‌های مختلف، در سازمان خود دارید؟

مطالب
EF Code First #1

در ادامه بحث ASP.NET MVC می‌شود به ابزاری به نام MVC Scaffolding اشاره کرد. کار این ابزار که توسط یکی از اعضای تیم ASP.NET MVC به نام استیو اندرسون تهیه شده، تولید کدهای اولیه یک برنامه کامل ASP.NET MVC از روی مدل‌های شما می‌باشد. حجم بالایی از کدهای تکراری آغازین برنامه را می‌شود توسط این ابزار تولید و بعد سفارشی کرد. MVC Scaffolding حتی قابلیت تولید کد بر اساس الگوی Repository و یا نوشتن Unit tests مرتبط را نیز دارد. بدیهی است این ابزار جای یک برنامه نویس را نمی‌تواند پر کند اما کدهای آغازین یک سری کارهای متداول و تکراری را به خوبی می‌تواند پیاده سازی و ارائه دهد. زیر ساخت این ابزار، علاوه بر ASP.NET MVC، آشنایی با Entity framework code first است.
در طی سری ASP.NET MVC که در این سایت تا به اینجا مطالعه کردید من به شدت سعی کردم از ابزارگرایی پرهیز کنم. چون شخصی که نمی‌داند مسیریابی چیست، اطلاعات چگونه به یک کنترلر منتقل یا به یک View ارسال می‌شوند، قراردادهای پیش فرض فریم ورک چیست یا زیر ساخت امنیتی یا فیلترهای ASP.NET MVC کدامند، چطور می‌تواند از ابزار پیشرفته Code generator ایی استفاده کند، یا حتی در ادامه کدهای تولیدی آن‌را سفارشی سازی کند؟ بنابراین برای استفاده از این ابزار و درک کدهای تولیدی آن، نیاز به یک پیشنیاز دیگر هم وجود دارد: «Entity framework code first»
امسال دو کتاب خوب در این زمینه منتشر شده‌اند به نام‌های:
Programming Entity Framework: DbContext, ISBN: 978-1-449-31296-1
Programming Entity Framework: Code First, ISBN: 978-1-449-31294-7
که هر دو به صورت اختصاصی به مقوله EF Code first پرداخته‌اند.


در طی روزهای بعدی EF Code first را با هم مرور خواهیم کرد و البته این مرور مستقل است از نوع فناوری میزبان آن؛ می‌خواهد یک برنامه کنسول باشد یا WPF یا یک سرویس ویندوز NT و یا ... یک برنامه وب.
البته از دیدگاه مایکروسافت، M در MVC به معنای EF Code first است. به همین جهت MVC3 به صورت پیش فرض ارجاعی را به اسمبلی‌های آن دارد و یا حتی به روز رسانی که برای آن ارائه داده نیز در جهت تکمیل همین بحث است.


مروری سریع بر تاریخچه Entity framework code first

ویژوال استودیو 2010 و دات نت 4، به همراه EF 4.0 ارائه شدند. با این نگارش امکان استفاده از حالت‌های طراحی database first و model first مهیا است. پس از آن، به روز رسانی‌های EF خارج از نوبت و به صورت منظم، هر از چندگاهی ارائه می‌شوند و در زمان نگارش این مطلب، آخرین نگارش پایدار در دسترس آن 4.3.1 می‌باشد. از زمان EF 4.1 به بعد، نوع جدیدی از مدل سازی به نام Code first به این فریم ورک اضافه شد و در نگارش‌های بعدی آن، مباحث DB migration جهت ساده سازی تطابق اطلاعات مدل‌ها با بانک اطلاعاتی، اضافه گردیدند. در روش Code first، کار با طراحی کلاس‌ها که در اینجا مدل داده‌ها نامیده می‌شوند، شروع گردیده و سپس بر اساس این اطلاعات، تولید یک بانک اطلاعاتی جدید و یا استفاده از نمونه‌ای موجود میسر می‌گردد.
پیشتر در روش database first ابتدا یک بانک اطلاعاتی موجود، مهندسی معکوس می‌شد و از روی آن فایل XML ایی با پسوند EDMX تولید می‌گشت. سپس به کمک entity data model designer ویژوال استودیو، این فایل نمایش داده شده و یا امکان اعمال تغییرات بر روی آن میسر می‌شد. همچنین در روش دیگری به نام model first نیز کار از entity data model designer جهت طراحی موجودیت‌ها آغاز می‌گشت.
اما با روش Code first دیگر در ابتدای امر مدل فیزیکی و یک بانک اطلاعاتی وجود خارجی ندارد. در اینجا EF تعاریف کلاس‌های شما را بررسی کرده و بر اساس آن، اطلاعات نگاشت‌های خواص کلاس‌ها به جداول و فیلدهای بانک اطلاعاتی را تشکیل می‌دهد. البته عموما تعاریف ساده کلاس‌ها بر این منظور کافی نیستند. به همین جهت از یک سری متادیتا به نام ویژگی‌ها یا اصطلاحا data annotations مهیا در فضای نام System.ComponentModel.DataAnnotations برای افزودن اطلاعات لازم مانند نام فیلدها، جداول و یا تعاریف روابط ویژه نیز استفاده می‌گردد. به علاوه در روش Code first یک API جدید به نام Fluent API نیز جهت تعاریف این ویژگی‌ها و روابط، با کدنویسی مستقیم نیز درنظر گرفته شده است. نهایتا از این اطلاعات جهت نگاشت کلاس‌ها به بانک اطلاعاتی و یا برای تولید ساختار یک بانک اطلاعاتی خالی جدید نیز می‌توان کمک گرفت.



مزایای EF Code first

- مطلوب برنامه نویس‌ها! : برنامه نویس‌هایی که مدتی تجربه کار با ابزارهای طراح را داشته باشند به خوبی می‌دانند این نوع ابزارها عموما demo-ware هستند. چندجا کلیک می‌کنید، دوبار Next، سه بار OK و ... به نظر می‌رسد کار تمام شده. اما واقعیت این است که عمری را باید صرف نگهداری و یا پیاده سازی جزئیاتی کرد که انجام آن‌ها با کدنویسی مستقیم بسیار سریعتر، ساده‌تر و با کنترل بیشتری قابل انجام است.
- سرعت: برای کار با EF Code first نیازی نیست در ابتدای کار بانک اطلاعاتی خاصی وجود داشته باشد. کلا‌س‌های خود را طراحی و شروع به کدنویسی کنید.
- سادگی: در اینجا دیگر از فایل‌های EDMX خبری نیست و نیازی نیست مرتبا آن‌ها را به روز کرده یا نگهداری کرد. تمام کارها را با کدنویسی و کنترل بیشتری می‌توان انجام داد. به علاوه کنترل کاملی بر روی کد نهایی تهیه شده نیز وجود دارد و توسط ابزارهای تولید کد، ایجاد نمی‌شوند.
- طراحی بهتر بانک اطلاعاتی نهایی: اگر طرح دقیقی از مدل‌های برنامه داشته باشیم، می‌توان آن‌ها را به المان‌های کوچک و مشخصی، تقسیم و refactor کرد. همین مساله در نهایت مباحث database normalization را به نحوی مطلوب و با سرعت بیشتری میسر می‌کند.
- امکان استفاده مجدد از طراحی کلاس‌های انجام شده در سایر ORMهای دیگر. چون طراحی مدل‌های برنامه به بانک اطلاعاتی خاصی گره نمی‌خورند و همچنین الزاما هم قرار نیست جزئیات کاری EF در آن‌ها لحاظ شود، این کلاس‌ها در صورت نیاز در سایر پروژه‌ها نیز به سادگی قابل استفاده هستند.
- ردیابی ساده‌تر تغییرات: روش اصولی کار با پروژه‌های نرم افزاری همواره شامل استفاده از یک ابزار سورس کنترل مانند SVN، Git، مرکوریال و امثال آن است. به این ترتیب ردیابی تغییرات انجام شده به سادگی توسط این ابزارها میسر می‌شوند.
- ساده‌تر شدن طراحی‌های پیچیده‌تر: برای مثال پیاده سازی ارث بری،‌ ایجاد کلاس‌های خود ارجاع دهنده و امثال آن با کدنویسی ساده‌تر است.


دریافت آخرین نگارش EF


برای دریافت و نصب آخرین نگارش EF نیاز است از NuGet استفاده شود و این مزایا را به همراه دارد:
به کمک NuGet امکان با خبر شدن از به روز رسانی جدید صورت گرفته به صورت خودکار درنظر گرفته شده است و همچنین کار دریافت بسته‌های مرتبط و به روز رسانی ارجاعات نیز در این حالت خودکار است. به علاوه توسط NuGet امکان دسترسی به کتابخانه‌هایی که مثلا در گوگل‌کد قرار دارند و به صورت معمول امکان دریافت آن‌ها برای ما میسر نیست، نیز بدون مشکل فراهم است (برای نمونه ELMAH، که اصل آن از گوگل‌کد قابل دریافت است؛ اما بسته نیوگت آن نیز در دسترس می‌باشد).
پس از نصب NuGet، تنها کافی است بر روی گره References در Solution explorer ویژوال استودیو، کلیک راست کرده و به کمک NuGet آخرین نگارش EF را نصب کرد. در گالری آنلاین آن، عموما EF اولین گزینه است (به علت تعداد بالای دریافت آن).
حین استفاده از NuGet جهت نصب Ef، ابتدا ارجاعاتی به اسمبلی‌های زیر به برنامه اضافه خواهند شد:
System.ComponentModel.DataAnnotations.dll
System.Data.Entity.dll
EntityFramework.dll
بدیهی است بدون استفاده از NuGet، تمام این کارها را باید دستی انجام داد.
سپس در پوشه‌ای به نام packages، فایل‌های مرتبط با EF قرار خواهند گرفت که شامل اسمبلی آن به همراه ابزارهای DB Migration است. همچنین فایل packages.config که شامل تعاریف اسمبلی‌های نصب شده است به پروژه اضافه می‌شود. NuGet به کمک این فایل و شماره نگارش درج شده در آن، شما را از به روز رسانی‌های بعدی مطلع خواهد ساخت:

<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EntityFramework" version="4.3.1" />
</packages>

همچنین اگر به فایل app.config یا web.config برنامه نیز مراجعه کنید، یک سری تنظیمات ابتدایی اتصال به بانک اطلاعاتی در آن ذکر شده است:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</configSections>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
<parameters>
<parameter value="Data Source=(localdb)\v11.0; Integrated Security=True; MultipleActiveResultSets=True" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
</configuration>

همانطور که ملاحظه می‌کنید بانک اطلاعاتی پیش فرضی که در اینجا ذکر شده است، LocalDB می‌باشد. این بانک اطلاعاتی را از این آدرس‌ نیز می‌توانید دریافت کنید.

البته ضرورتی هم به استفاده از آن نیست و از سایر نگارش‌های SQL Server نیز می‌توان استفاده کرد ولی خوب ... مزیت استفاده از آن برای کاربر نهایی این است که «نیازی به یک مهندس برای نصب، راه اندازی و نگهداری ندارد». تنها مشکل آن این است که از ویندوز XP پشتیبانی نمی‌کند. البته SQL Server CE 4.0 این محدودیت را ندارد.
ضمن اینکه باید درنظر داشت EF به فناوری میزبان خاصی گره نخورده است و مثال‌هایی که در اینجا بررسی می‌شوند صرفا تعدادی برنامه کنسول معمولی هستند و نکات عنوان شده در آن‌ها در تمام فناوری‌های میزبان موجود به یک نحو کاربرد دارند.


قراردادهای پیش فرض EF Code first

عنوان شد که اطلاعات کلاس‌های ساده تشکیل دهنده مدل‌های برنامه، برای تعریف جداول و فیلدهای یک بانک اطلاعات و همچنین مشخص سازی روابط بین آن‌ها کافی نیستند و مرسوم است برای پر کردن این خلاء از یک سری متادیتا و یا Fluent API مهیا نیز استفاده گردد. اما در EF Code first یک سری قرار داد توکار نیز وجود دارند که مطلع بودن از آن‌ها سبب خواهد شد تا حجم کدنویسی و تنظیمات جانبی این فریم ورک به حداقل برسند. برای نمونه مدل‌های معروف بلاگ و مطالب آن‌را درنظر بگیرید:

namespace EF_Sample01.Models
{
public class Post
{
public int Id { set; get; }
public string Title { set; get; }
public string Content { set; get; }
public virtual Blog Blog { set; get; }
}
}

using System.Collections.Generic;

namespace EF_Sample01.Models
{
public class Blog
{
public int Id { set; get; }
public string Title { set; get; }
public string AuthorName { set; get; }
public IList<Post> Posts { set; get; }
}
}


یکی از قراردادهای EF Code first این است که کلاس‌های مدل شما را جهت یافتن خاصیتی به نام Id یا ClassId مانند BlogId، جستجو می‌کند و از آن به عنوان primary key و فیلد identity جدول بانک اطلاعاتی استفاده خواهد کرد.
همچنین در کلاس Blog، خاصیت لیستی از Posts و در کلاس Post خاصیت virtual ایی به نام Blog وجود دارند. به این ترتیب روابط بین دو کلاس و ایجاد کلید خارجی متناظر با آن‌را به صورت خودکار انجام خواهد داد.
نهایتا از این اطلاعات جهت تشکیل database schema یا ساختار بانک اطلاعاتی استفاده می‌گردد.
اگر به فضاهای نام دو کلاس فوق دقت کرده باشید، به کلمه Models ختم شده‌اند. به این معنا که در پوشه‌ای به همین نام در پروژه جاری قرار دارند. یا مرسوم است کلاس‌های مدل را در یک پروژه class library مجزا به نام DomainClasses نیز قرار دهند. این پروژه نیازی به ارجاعات اسمبلی‌های EF ندارد و تنها به اسمبلی System.ComponentModel.DataAnnotations.dll نیاز خواهد داشت.


EF Code first چگونه کلاس‌های مورد نظر را انتخاب می‌کند؟

ممکن است ده‌ها و صدها کلاس در یک پروژه وجود داشته باشند. EF Code first چگونه از بین این کلاس‌ها تشخیص خواهد داد که باید از کدامیک استفاده کند؟ اینجا است که مفهوم جدیدی به نام DbContext معرفی شده است. برای تعریف آن یک کلاس دیگر را به پروژه برای مثال به نام Context اضافه کنید. همچنین مرسوم است که این کلاس را در پروژه class library دیگری به نام DataLayer اضافه می‌کنند. این پروژه نیاز به ارجاعی به اسمبلی‌های EF خواهد داشت. در ادامه کلاس جدید اضافه شده باید از کلاس DbContext مشتق شود:

using System.Data.Entity;
using EF_Sample01.Models;

namespace EF_Sample01
{
public class Context : DbContext
{
public DbSet<Blog> Blogs { set; get; }
public DbSet<Post> Posts { set; get; }
}
}

سپس در اینجا به کمک نوع جنریکی به نام DbSet، کلاس‌های دومین برنامه را معرفی می‌کنیم. به این ترتیب، EF Code first ابتدا به دنبال کلاسی مشتق شده از DbContext خواهد گشت. پس از یافتن آن‌، خواصی از نوع DbSet را بررسی کرده و نوع‌های متناظر با آن‌را به عنوان کلاس‌های دومین درنظر می‌گیرد و از سایر کلاس‌های برنامه صرفنظر خواهد کرد. این کل کاری است که باید انجام شود.
اگر دقت کرده باشید، نام کلاس‌های موجودیت‌ها، مفرد هستند و نام خواص تعریف شده به کمک DbSet‌، جمع می‌باشند که نهایتا متناظر خواهند بود با نام جداول بانک اطلاعاتی تشکیل شده.


تشکیل خودکار بانک اطلاعاتی و افزودن اطلاعات به جداول

تا اینجا بدون تهیه یک بانک اطلاعاتی نیز می‌توان از کلاس Context تهیه شده استفاده کرد و کار کدنویسی را آغاز نمود. بدیهی است جهت اجرای نهایی کدها، نیاز به یک بانک اطلاعاتی خواهد بود. اگر تنظیمات پیش فرض فایل کانفیگ برنامه را تغییر ندهیم، از همان defaultConnectionFactory یاده شده استفاده خواهد کرد. در این حالت نام بانک اطلاعاتی به صورت خودکار تنظیم شده و مساوی «EF_Sample01.Context» خواهد بود.
برای سفارشی سازی آن نیاز است فایل app.config یا web.config برنامه را اندکی ویرایش نمود:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
...
</configSections>
<connectionStrings>
<clear/>
<add name="Context"
connectionString="Data Source=(local);Initial Catalog=testdb2012;Integrated Security = true"
providerName="System.Data.SqlClient"
/>
</connectionStrings>
...
</configuration>

در اینجا به بانک اطلاعاتی testdb2012 در وهله پیش فرض SQL Server نصب شده، اشاره شده است. فقط باید دقت داشت که تگ configSections باید در ابتدای فایل قرار گیرد و مابقی تنظیمات پس از آن.
یا اگر علاقمند باشید که از SQL Server CE استفاده کنید، تنظیمات رشته اتصالی را به نحو زیر مقدار دهی نمائید:

<connectionStrings> 
              <add name="MyContextName"
                         connectionString="Data Source=|DataDirectory|\Store.sdf"
                         providerName="System.Data.SqlServerCe.4.0" />
</connectionStrings>

در هر دو حالت، name باید به نام کلاس مشتق شده از DbContext اشاره کند که در مثال جاری همان Context است.
یا اگر علاقمند بودید که این قرارداد توکار را تغییر داده و نام رشته اتصالی را با کدنویسی تعیین کنید، می‌توان به نحو زیر عمل کرد:

public class Context : DbContext
{
    public Context()
      : base("ConnectionStringName")
    {
    }


البته ضرورتی ندارد این بانک اطلاعاتی از پیش موجود باشد. در اولین بار اجرای کدهای زیر، به صورت خودکار بانک اطلاعاتی و جداول Blogs و Posts و روابط بین آن‌ها تشکیل می‌گردد:

using EF_Sample01.Models;

namespace EF_Sample01
{
class Program
{
static void Main(string[] args)
{
using (var db = new Context())
{
db.Blogs.Add(new Blog { AuthorName = "Vahid", Title = ".NET Tips" });
db.SaveChanges();
}
}
}
}


در این تصویر چند نکته حائز اهمیت هستند:
الف) نام پیش فرض بانک اطلاعاتی که به آن اشاره شد (اگر تنظیمات رشته اتصالی قید نگردد).
ب) تشکیل خودکار primary key از روی خواصی به نام Id
ج) تشکیل خودکار روابط بین جداول و ایجاد کلید خارجی (به کمک خاصیت virtual تعریف شده)
د) تشکیل جدول سیستمی به نام dbo.__MigrationHistory که از آن برای نگهداری سابقه به روز رسانی‌های ساختار جداول کمک گرفته خواهد شد.
ه) نوع و طول فیلدهای متنی، nvarchar از نوع max است.

تمام این‌ها بر اساس پیش فرض‌ها و قراردادهای توکار EF Code first انجام شده است.

در کدهای تعریف شده نیز، ابتدا یک وهله از شیء Context ایجاد شده و سپس به کمک آن می‌توان به جدول Blogs اطلاعاتی را افزود و در آخر ذخیره نمود. استفاده از using هم دراینجا نباید فراموش شود، زیرا اگر استثنایی در این بین رخ دهد، کار پاکسازی منابع و بستن اتصال گشوده شده به بانک اطلاعاتی به صورت خودکار انجام خواهد شد.
در ادامه اگر بخواهیم مطلبی را به Blog ثبت شده اضافه کنیم، خواهیم داشت:

using EF_Sample01.Models;

namespace EF_Sample01
{
class Program
{
static void Main(string[] args)
{
//addBlog();
addPost();
}

private static void addPost()
{
using (var db = new Context())
{
var blog = db.Blogs.Find(1);
db.Posts.Add(new Post
{
Blog = blog,
Content = "data",
Title = "EF"
});
db.SaveChanges();
}
}

private static void addBlog()
{
using (var db = new Context())
{
db.Blogs.Add(new Blog { AuthorName = "Vahid", Title = ".NET Tips" });
db.SaveChanges();
}
}
}
}

متد db.Blogs.Find، بر اساس primary key بلاگ ثبت شده، یک وهله از آن‌را یافته و سپس از آن جهت تشکیل شیء Post و افزودن آن به جدول Posts استفاده می‌شود. متد Find ابتدا Contxet جاری را جهت یافتن شیءایی با id مساوی یک جستجو می‌کند (اصطلاحا به آن first level cache هم گفته می‌شود). اگر موفق به یافتن آن شد، بدون صدور کوئری اضافه‌ای به بانک اطلاعاتی از اطلاعات همان شیء استفاده خواهد کرد. در غیراینصورت نیاز خواهد داشت تا ابتدا کوئری لازم را به بانک اطلاعاتی ارسال کرده و اطلاعات شیء Blog متناظر با id=1 را دریافت کند. همچنین اگر نیاز داشتیم تا تنها با سطح اول کش کار کنیم، در EF Code first می‌توان از خاصیتی به نام Local نیز استفاده کرد. برای مثال خاصیت db.Blogs.Local بیانگر اطلاعات موجود در سطح اول کش می‌باشد.
نهایتا کوئری Insert تولید شده توسط آن به شکل زیر خواهد بود (لاگ شده توسط برنامه SQL Server Profiler):

exec sp_executesql N'insert [dbo].[Posts]([Title], [Content], [Blog_Id])
values (@0, @1, @2)
select [Id]
from [dbo].[Posts]
where @@ROWCOUNT > 0 and [Id] = scope_identity()',
N'@0 nvarchar(max) ,@1 nvarchar(max) ,@2 int',
@0=N'EF',
@1=N'data',
@2=1


این نوع کوئرهای پارامتری چندین مزیت مهم را به همراه دارند:
الف) به صورت خودکار تشکیل می‌شوند. تمام کوئری‌های پشت صحنه EF پارامتری هستند و نیازی نیست مرتبا مزایای این امر را گوشزد کرد و باز هم عده‌ای با جمع زدن رشته‌ها نسبت به نوشتن کوئری‌های نا امن SQL اقدام کنند.
ب) کوئرهای پارامتری در مقابل حملات تزریق اس کیوال مقاوم هستند.
ج) SQL Server با کوئری‌های پارامتری همانند رویه‌های ذخیره شده رفتار می‌کند. یعنی query execution plan محاسبه شده آن‌ها را کش خواهد کرد. همین امر سبب بالا رفتن کارآیی برنامه در فراخوانی‌های بعدی می‌گردد. الگوی کلی مشخص است. فقط پارامترهای آن تغییر می‌کنند.
د) مصرف حافظه SQL Server کاهش می‌یابد. چون SQL Server مجبور نیست به ازای هر کوئری اصطلاحا Ad Hoc رسیده یکبار execution plan متفاوت آن‌ها را محاسبه و سپس کش کند. این مورد مشکل مهم تمام برنامه‌هایی است که از کوئری‌های پارامتری استفاده نمی‌کنند؛ تا حدی که گاهی تصور می‌کنند شاید SQL Server دچار نشتی حافظه شده، اما مشکل جای دیگری است.


مشکل! ساختار بانک اطلاعاتی تشکیل شده مطلوب کار ما نیست.

تا همینجا با حداقل کدنویسی و تنظیمات مرتبط با آن، پیشرفت خوبی داشته‌ایم؛ اما نتیجه حاصل آنچنان مطلوب نیست و نیاز به سفارشی سازی دارد. برای مثال طول فیلدها را نیاز داریم به مقدار دیگری تنظیم کنیم، تعدادی از فیلدها باید به صورت not null تعریف شوند یا نام پیش فرض بانک اطلاعاتی باید مشخص گردد و مواردی از این دست. با این موارد در قسمت‌های بعدی بیشتر آشنا خواهیم شد.
نظرات نظرسنجی‌ها
روزانه چقدر کافئین مصرف می‌کنید؟
تا دو سال پیش روزی سه وعده هر بار سه چهار فنجان چای مصرف می‌کردم. بعد چند جا خوندم که یکی از دلایل زود عصبی شدن و احساس کمبود انرژی مصرف زیاد چای است.

الان روزی یک وعده، دو یا سه فنجان چای سبز مصرف می‌کنم معمولا عصرها یا آخر شب. احساس کمبود انرژی کمتری دارم. البته همزمان با این تغییر، هفته‌ای یک‌بار هم استخر میرم. مصرف لبنیات پاستوریزه رو هم قطع کردم، لبنیات محلی مصرف می‌کنم (مخصوصا کره و شیر). قبلا افت قند و احساس کمبود انرژی زیادی داشتم. الان خیلی کم شده.
مطالب
تنظیمات مورد نیاز جهت شروع به کار با C# 9.0
ویژگی‌های جدید C# 9.0، به همراه NET 5. ارائه می‌شوند. بنابراین جهت راه اندازی پروژه‌ای که قرار است بر این مبنا تهیه شود، نیاز است مراحل زیر را طی کنید:
- آخرین نگارش NET 5 SDK. را از اینجا دریافت و نصب کنید (حتما SDK باشد و نه runtime).
- اگر می‌خواهید با ویژوال استودیو کار کنید، نیاز است حداقل نگارش 16.7 یا بالاتر را نصب کرده باشید. به همین جهت پیش از ادامه‌ی بحث، از منوی Help، گزینه‌ی Check For Updates را انتخاب کرده و حتما آخرین به روز رسانی‌های موجود را نصب کنید. بنابراین برای کار با C# 9.0 توسط VS، حتما باید آخرین نگارش 2019 آن، به همراه تمام به روز رسانی‌های ممکن بر روی سیستم شما نصب باشند؛ در غیراینصورت امکان کار با آن‌را حداقل توسط VS نخواهید داشت.
- در زمان نگارش این مطلب چون هنوز نگارش نهایی NET 5 SDK. ارائه نشده‌است، نیاز است به منوی Tools در ویژوال استودیو مراجعه کرده و با انتخاب «Preview Features» آن، گزینه‌ی «Use previews of the .NET Core SDK» را فعال کنید. پس از آن، یکبار هم نیاز است VS را بسته و راه اندازی مجدد نمائید.

پس از نصب پیشنیازهای لازم، اکنون فایل csproj را به صورت زیر ویرایش کنید:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <LangVersion>9.0</LangVersion>
  </PropertyGroup>
</Project>
در اینجا TargetFramework حتما باید net5.0 باشد و اگر هنوز نگارش نهایی SDK آن در دسترس نیست، تنظیم گزینه‌ی LangVersion هم ضروری است. پس از ارائه‌ی نگارش نهایی SDK، می‌توان ویژگی LangVersion را حذف کرد؛ چون به صورت خودکار به آخرین نگارش موجود تنظیم می‌شود.


تنظیمات مورد نیاز C# 9.0 در پروژه‌های کتابخانه‌ای

در این نوع پروژه‌ها، علاوه بر نصب پیشنیازهای یاد شده، نیاز است TargetFramework را به حداقل netstandard2.1 تنظیم کرد (و یا حتی net5.0 هم در اینجا کار می‌کند):
<TargetFramework>netstandard2.1</TargetFramework>
<LangVersion>9</LangVersion>


تنظیمات مورد نیاز C# 9.0 در VSCode

برای کار با VSCode، تنها کافی است آخرین نگارش SDK و آخرین نگارش افزونه‌ی #C آن‌را نصب کنید و TargetFramework و LangVersion را همانطور که عنوان شد، تنظیم نمائید. این روش ساده‌ترین و کم حجم‌ترین روش کار با C# 9.0 است.


تنظیمات مورد نیاز C# 9.0 در Rider

اگر می‌خواهید برای کار با C# 9.0 از محصولات Jetbrains استفاده کنید، نیاز است حداقل نگارش 2020.3 آن‌ها را نصب کنید که در این زمان هنوز در مرحله‌ی پیش‌نمایش (ReSharper 2020.3 EAP or Rider 2020.3 EAP) به سر می‌برند.


من از چه روشی استفاده می‌کنم؟!

VS کامل بر روی سیستم من نصب نیست؛ هیچ نگارشی از آن! عمده‌ی کارهای من توسط VS Code و افزونه‌ی #C آن انجام می‌شوند و هر از چندگاهی، یکبار هم توسط Rider چون به همراه ReSharper توکار است، کنترل کیفیت می‌شوند (در حد بررسی گزارش‌های ReSharper آن). البته افزونه‌ی Roslynator برای VS Code هم موجود است و بسیاری از قابلیت‌های ReSharper را در VSCode نیز مهیا می‌کند.
مطالب
معرفی سرویس‌های ارائه شده توسط شرکت‌های گوگل، آمازون و مایکروسافت در قالب رایانش ابری - قسمت اول

رایانش ابری مفهوم نسبتا جدیدی در عرصه‌ی فناوری اطلاعات است و در حال گسترش می­‌باشد. به طور خلاصه رایانش ابری به همه چیز اعم از برنامه کاربردی( Application )، سکو ی ( Platform ) توسعه نرم افزار، سخت افزار و زیرساخت، به عنوان سرویس نگاه می‌کند. زیرساخت های موجود در مراکز داده( Data Center ) به انضمام  نرم‌افزارهایی که در آن قرار دارند، مجموعه‌ه­ایی را تشکیل می­‌دهند که ابر نامیده می­‌شود. به عبارت ساده­‌تر رایانش ابری یعنی استفاده­ اشتراکی از برنامه­‌ها و منابع یک محیط شبکه­‌ای برای انجام یک کار، بدون این که مالکیت، مدیریت منابع شبکه و سخت­ افزار و برنامه­‌ها، برای استفاده کننده مهم باشد. در رایانش ابری منابع کامپیوترها، برای انجام یک کار استفاده می‌شوند و داده­‌های مربوط به پردازش، در هیچ کدام از کامپیوترهای شخصی ذخیره نمی­‌شوند، بلکه در جای دیگری در داخل همان منابع شبکه، ذخیره می­‌شوند تا در زمان و مکان دیگری قابل دسترسی باشند.

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

 سرویس­‌های رایانش ابری گوگل، در زیر دو چتر قرار دارند. گروه اول شامل مجموعه گسترده­ای از برنامه­‌های محبوب گوگل مانند Google Doc ،   Google Health ، Google Mail ، Google Earth هستند که با کلیک بر روی گزینه More و Even More که در بالای صفحه اصلی گوگل قرار دارند، می­توان به آن­ها دسترسی پیدا کرد.

دومین محصول مبتنی بر ابر گوگل، ابزار توسعه PaaS گوگل است. این سکو در سال 2008 برای توسعه برنامه‌­های تحت وب، با استفاده از زیرساخت گوگل به نام موتور Google App  معرفی شد. هدف از آن قادر ساختن توسعه دهندگان برای ساخت و استقرار برنامه­‌های وب بدون نگرانی از زیرساختی است که برنامه بر رویش اجرا می­شود. برنامه­‌های این موتور، با زبان­های سطح بالا به ویژه جاوا و پایتون و در چارچوب GAE نوشته می­‌شوند. گوگل به منظور گسترش این نوع برنامه­‌ها یک سطح رایگان مشخص از سرویس را ارائه می­دهد و زمانی که برنامه از سطح مشخصی از بار پردازشی، ذخیره­‌سازی و پهنای باند شبکه فراتر رفت، آنگاه شارژها بر مبنای میزان استفاده محاسبه می­شود.

برنامه­‌های GAE را باید به گونه­‌ای نوشت که با زیرساخت گوگل وفق یابند. این مسئله، باعث محدودیت برنامه­‌های قابل اجرا در GAE  می­گردد و علاوه بر آن، انتقال برنامه‌­ها به سکوی GAE و یا انتقال از این سکو به سایر سکو­های موجود دشوار می­شود.

از میان سرویس های ابری رایگان ارائه شده از سوی گوگل، به معرفی سرویس آنالیز گوگل بسنده کرده و تمرکز اصلی بر روی سکوی توسعه نرم‌افزاری این شرکت ( GAE ) می‌باشد.


Google Analytics

به اختصار GA نامیده می­شود و یک ابزار آماری است که تعداد و انواع بازدیدکنندگان وب­‌سایت و نحوه استفاده از وب­‌سایت را اندازه­‌گیری می­کند. این محصول بر روی بسته تحلیلی Urchin 5 که گوگل در سال 2006 آن را خریداری نمود، ساخته شده است. این سرویس رایگان عرضه می­شود و فرآیند تحلیل را با استفاده از یک قطعه کد جاوا اسکریپت به نام Google Analytics Tracking Code با پیاده‌سازی در تگ صفحه وب انجام می­‌شود.

این کد با اولین بارگذاری صفحه در سیستم­ کاربران، به جمع آوری اطلاعات مورد نیاز پرداخته و برای پردازش به سرورهای GA باز پس می­فرستد. این کد با کمک Cookie مرورگر اطلاعات مورد نیاز را جمع آوری می­نماید.

سرویس Google Analytics


آشنایی با Google App Engine

GAE یک سکو به عنوان سرویس می­باشد و مبتنی بر ابر گوگل است و بر روی زیر ساخت­ گوگل مستقر شده است. 

این سرویس توسعه دهندگان را قادر می­سازد تا برنامه‌­های وب ایجاد کرده و بر روی سرور­های گوگل مستقر سازند و گوگل مدیریت زیرساخت را بر عهده گیرد و اعمالی مانند نظارت، برطرف کردن اشکالات احتمالی، خوشه بندی، مدیریت وهله‌سازی ماشین‌های مجازی و غیره را انجام دهد. برای اجرای یک برنامه در GAE ابتدا باید استانداردهای سکوی گوگل رعایت شود. این استانداردها دامنه برنامه­‌هایی که قابل اجرا می­باشند را بسیار محدود می‌­نماید و قابلیت حمل آن­ها را کاهش می­دهد.

محدودیت­‌هایی که این سکو ایجاد می­‌کند، با خود مزایایی را به همراه می­‌آورد که در زیر به آن­ها اشاره می­گردد:

  • وب سرویس­های پویا بر مبنای استانداردهای رایج
  • توسعه خودکار و توازن بار بین ماشین‌های وهله‌سازی شده که مورد استفاده وب سرویس است.
  • اعتبارسنجی با استفاده از API موجود در گوگل.
  • فضای ذخیره سازی ماندگار با قابلیت جستجو، مرتب سازی و مدیریت تراکنش.
  • صف کاری و زمان بندی کاری
  • محیط توسعه سمت مشتری( توسعه دهندگان ) برای شبیه سازی GAE در سیستم محلی.
  • پشتیبانی از محیط اجرا جاوا و پایتون.

هنگامی که یک برنامه در GAE مستقر گردید، با استفاده از نام دامنه دلخواه یا با استفاده از آدرس تجاری Google Apps قابل دستیابی است. موتور Google Apps در حال حاضر برنامه­‌هایی که در جاوا و پایتون نوشته شده است را پشتیبانی می­کند و علاوه بر آن از زبان­های ماشین مجازی جاوا و چندین چارچوب تحت وب پایتون که WSGI و CGI را پشتیبانی می­کنند نیز با محیط GAE سازگاری دارند.

برنامه­‌هایی که در GAE اجرا می­شوند از سیستم عامل مستقل هستند یا به گفته گوگل بر روی   Sand Box  اجرا می­شوند. این ویژگی GAE را قادر می­سازد، سیستم را بهینه کند تا تقاضاهای وب، با بار ترافیکی فعلی منطبق شوند. همچنین برنامه­‌ها را قادر می­سازد با امنیت بالاتری کار کنند، زیرا تنها می­توانند به کامپیوترهایی متصل شوند که آدرس‌های مشخصی دارند و سرویس­ها را با استفاده از پروتکل Http و یا Https از پورت­های شناخته شده پاسخ دهند. از طرف دیگر برنامه‌­ها نیز به این میزان محدود شده که تنها فایل­ها را بخوانند. آن‌ها حق نوشتن فایل به صورت مستقیم بر روی سیستم­ها را ندارند و برای دستیابی به داده، باید از ذخیره داده در Cache یا سرویس ماندگار دیگری استفاده نمایند.

GAE یک سیستم انبار داده توزیع شده دارد که از پرس و جوها و تراکنش­ها پشتیبانی می­نماید. این انبار داده غیر رابطه­‌ای است، اما اشیاء داده یا موجودیت­‌هایی که خصوصیات لازم را دارند، ذخیره می­‌نماید. به همین علت در پرس و جوها می­توان از فیلتر نوع موجودیت بهره برد و آن­ها را به ترتیب خصوصیات مرتب نمود.

در نهایت توجه به مدل قیمت‌گذاری گوگل قابل توجه است. گوگل برای تشویق توسعه دهندگان در نوشتن برنامه با استفاده از GAE ، استقرار و توسعه برنامه را تا میزان مشخصی از منابع رایگان کرده است و با عبور از مقدار رایگان باید هزینه را به ازای مصرف پرداخت نمود. بر اساس جدول ارائه شده در سایت شرکت گوگل به ازای تجاوز از میزان مصرف رایگان، سیستم هزینه گذاری بر اساس تعرفه‌های زیر، اقدام به محاسبه حق شارژ می‌نماید و بدیهی است برای آگاهی از آخرین تعرفه‌ها و کسب اطلاعات بیشتر، مراجعه به  صفحه سایت شرکت گوگل  توصیه می‌شود:

  • مبلغ به ازای هر یک ساعت استفاده از CPU معادل 0.08 دلار
  • داده ذخیره شده به ازای هر گیگابایت در ماه معادل 0.18 دلار
  • پهنای باند خروجی به ازای هر گیگابایت معادل 0.12 دلار
  • پهنای باند ورودی رایگان
  • هزینه دریافت هر ایمیل معادل 0.0001 دلار 

به منظور ذخیره اطلاعات در منبع داده پایدار، از API استفاده می­گردد که به ازای تعداد تراکنش­هایی که تبادل می­گردد، هزینه پرداخت می­شود. از آنجایی که بنا به تعداد تبادلات و نوع حافظه پایداری که استفاده می­گردد، هزینه متغیر است، خواننده محترم برای رویت لیست مذکور به منبع ذکر شده، ارجاع داده می­شود.


  منبع سهمیه 
سهمیه پیش فرض رایگان به ازای هر برنامه   
  مصرف  CPU 
  28 ساعت به ازای هر برنامه در روز 
  منبع ذخیره پایدار داده 
1 گیگابایت به ازای هر برنامه در ماه
  پهنای باند ورودی 
  1 گیگابایت به ازای هر برنامه در روز 
  پهنای باند خروجی 
  1 گیگابایت به ازای هر برنامه در روز 
  تراکنش با منبع داده  Datastore 
  50 هزار تراکنش برای خواندن و نوشتن به ازای هر برنامه در ماه 
  تراکنش با منبع داده  Blobstore 
  5 گیگابایت به ازای هر برنامه در روز 
  ایمیل دریافتی 
  100 دریافت به ازای هر برنامه در روز 

نظرات مطالب
پردازش داده‌های جغرافیایی به کمک SQL Server و Entity framework
باید نزدیک‌ترین آدرس‌ها را یافت:
var searchLocation = DbGeography.FromText(String.Format("POINT({0} {1})", longitude, latitude));
var nearbyLocations = 
    (from location in _context.GeoLocations
     where  // (Additional filtering criteria here...)
     select new 
     {
         LocationID = location.ID,
         // ... 
         Distance = searchLocation.Distance(
             DbGeography.FromText("POINT(" + location.Longitude + " " + location.Latitude + ")"))
     })
    .OrderBy(location => location.Distance)
    .ToList();