مدیریت محل اعمال Google analytics در ASP.NET MVC
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: سه دقیقه

ذخیره سازی اطلاعات بازدیدهای کاربران، در طول زمان حجم بالایی از بانک اطلاعاتی را به خود اختصاص خواهد داد؛ به علاوه کند شدن کوئری‌های مرتبط با آن، به همراه مصرف بالای منابع سیستم. به همین جهت اکثر سایت‌ها از Google analytics برای مدیریت جمع آوری بازدیدهای کاربران خود استفاده می‌کنند و این ابزار واقعا عالی و حرفه‌ای طراحی شده و پیاده سازی همانند آن شاید در حد یک پروژه‌ی‌ چندساله باشد.
اضافه کردن Google analytics به یک سایت، بسیار ساده است. در آن ثبت نام می‌کنید؛ سپس آدرس دومین خود را وارد کرده و یک قطعه کد جاوا اسکریپتی را دریافت خواهید کرد که باید به انتهای تمام صفحات سایت خود اضافه نمائید و ... همین.
اضافه کردن این کد در ASP.NET MVC می‌تواند در فایل layout یا همان master page سایت انجام شود تا به صورت خودکار به تمام صفحات اعمال گردد.

مشکل!
من نمی‌خواهم که صفحات غیرعمومی سایت نیز دارای کدهای Google analytics باشند و بی‌جهت Google به این‌جاها نیز سرکشی زاید کند! چکار باید کرد؟
احتمالا عنوان می‌کنید که باید یک if و else به همراه آرایه‌ای از نام‌ها و آدرس‌های صفحات غیرعمومی سایت تهیه کرد و بر این اساس کدهای Google analytics را در master page درج کرد یا خیر.
بله. این روش کار می‌کنه ولی بهینه نیست و همچنین نگهداری آن در طول زمان مشکل است. سایت توسعه خواهد یافت، صفحات غیرعمومی بیشتر خواهند شد و ممکن است در این بین فراموش شود که کدهای مرتبط به روز شوند.

روش بهتر:
آیا می‌توان در یک View مشخص کرد که فیلتر Authorize در اکشن متد متناظری که آن‌را رندر کرده است بکار گرفته شده است یا خیر؟
صفحات غیرعمومی سایت در ASP.NET MVC با فیلتر Authorize محافظت می‌شوند. این فیلتر را می‌توان به کل یک کنترلر اعمال کرد تا به تمام اکشن متدهای آن اعمال شود؛ یا فقط به یک اکشن متد خاص که Viewایی خاص را رندر می‌کند.

نحوه پیاده سازی تشخیص وجود فیلتر Authorize را در یک View رندر شده، در متد کمکی زیر می‌توان مشاهده کرد:
@helper IncludeGoogleAnalytics(WebViewPage page)
    {
        var controller = page.ViewContext.Controller;
        var controllerHasAuthorizeAttribute = controller.GetType().GetCustomAttributes(typeof(AuthorizeAttribute), true).Any();
        var currentActionName = page.ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();
        var actionHasAuthorizeAttribute = controller.GetType().GetMethods()
                                                    .Where(x => x.Name == currentActionName &&
                                                                x.GetCustomAttributes(typeof(AuthorizeAttribute), true).Any())                                                    
                                                    .Any();
        if (!controllerHasAuthorizeAttribute && !actionHasAuthorizeAttribute)
        {
            string trackingId = ConfigurationManager.AppSettings["GoogleAnalyticsID"];
    <script type="text/javascript">
        var _gaq = _gaq || [];
        _gaq.push(['_setAccount', '@trackingId']);
        _gaq.push(['_trackPageview']);
        (function () {
            var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
            ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
            var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
        })();    
    </script>
        }

  توضیحات:
این متد در فایلی به نام HtmlUtils قرار گرفته در پوشه app_code تعریف شده است و بکارگیری آن در یک فایل master page به نحو زیر خواهد بود:
@HtmlUtils.IncludeGoogleAnalytics(this)

در این متد به کمک خاصیت page.ViewContext.Controller می‌توان به کنترلری که در حال رندر کردن View جاری است دسترسی یافت. اکنون که به کنترلر دسترسی داریم، به کمک Reflection، ویژگی‌ها یا Attributes آن‌را یافته و بررسی می‌کنیم که آیا دارای AuthorizeAttribute است یا خیر. بر این اساس می‌توان تصمیم گرفت که آیا View در حال نمایش عمومی است یا خصوصی. اگر عمومی بود، کدهای اسکریپتی Google analytics به صورت خودکار به صفحه تزریق می‌شوند.
همچنین در اینجا فرض بر این است که Id منتسب به دومین جاری در کلیدی به نام GoogleAnalyticsID در فایل کانفیگ برنامه در قسمت app settings آن تعریف شده است.
 
  • #
    ‫۱۲ سال و ۴ ماه قبل، سه‌شنبه ۳۰ خرداد ۱۳۹۱، ساعت ۰۱:۳۴
    خیلی خوشحالم که مجددا شروع به نوشتن کردید.
    یه ایراد کوچیک درباره سایت جدید میخوام بگیرم. در سایت جدید دیگه نمیشه به راحتی به مطالب قبلی دسترسی داشت. در سایت قبل، گزینه‌های ارسال‌های قبلی و ارسال‌های جدیدتر وجود داشت که میشد به راحتی به ترتیب ارسال پست، سایت رو مرور کرد.
    در صورتی که این امکان گذاشته بشه، از مطالب بهتر میشه استفاده کرد
  • #
    ‫۱۲ سال و ۴ ماه قبل، سه‌شنبه ۳۰ خرداد ۱۳۹۱، ساعت ۰۱:۵۰
    ازتون تشکر میکنم.فقط احساس میکنم یه باگی تو این سیستم جدیدتون مربوط به تعداد نظرات هستش.به عنوان مثال همین مطلب تو صفحه اصلی سایت  0 نظر داره ولی داخل خود  پست که میشی میبنی 2 تا نظز داره.ولی بعد از چند دقیقه درست میشه.یا شایدم کش میشن.
    • #
      ‫۱۲ سال و ۴ ماه قبل، سه‌شنبه ۳۰ خرداد ۱۳۹۱، ساعت ۰۳:۰۶
      بله. از کش استفاده شده.
  • #
    ‫۱۲ سال و ۴ ماه قبل، سه‌شنبه ۳۰ خرداد ۱۳۹۱، ساعت ۰۲:۰۴
    سلام

    تبریک میگم وحید جان !
    خیلی خوشحالم باز میتونیم از مطالب خوبتون استفاده کنیم !

  • #
    ‫۱۲ سال و ۴ ماه قبل، سه‌شنبه ۳۰ خرداد ۱۳۹۱، ساعت ۰۳:۲۸

    سلام مهندس جان 

    از اینکه میتوونم اولین کار روزانه خودم را چک کردن سایتت قرار بدم خیلی خوشحالم

    ایکاش مانند گذشته فایل chm سایت رو نیز در اختیار مراجعه کننده‌ها برای استفاده آفلاین  قرار میدادی

    نکته دیگر آنکه تعداد برچسب‌های سایت خیلی کم است و این دسته بندی یافتن مطالب رو سخت میکنه

    و دیگر آنکه چند کاربره شدن سایت دامنه مطالب ارسالی رو بازتر کرده و ممکنه اولا سطح مطالب افت کنه و یا زیادی ‍پراکنده بشه اگر برای نویسندگان سایت راهبری هایی انجام بشه شاید مطالب هماهنگ‌تر و مفیدتر و مورد نیازتر بشن متشکرم

    • #
      ‫۱۲ سال و ۴ ماه قبل، سه‌شنبه ۳۰ خرداد ۱۳۹۱، ساعت ۰۳:۳۳
      سلام؛ ممنون. برچسب‌های سایت کم نیست. لیست کامل آن‌ها در اینجا قابل مشاهده است:
      https://www.dntips.ir/search/label 

  • #
    ‫۱۲ سال و ۴ ماه قبل، سه‌شنبه ۳۰ خرداد ۱۳۹۱، ساعت ۱۳:۲۳
    مبارک است
    هر روز بهتر از دیروز!
  • #
    ‫۱۲ سال و ۴ ماه قبل، چهارشنبه ۳۱ خرداد ۱۳۹۱، ساعت ۱۷:۰۹
    واقعا عالی
    عجب انرژیکی آقا وحید شما....
  • #
    ‫۱۲ سال و ۴ ماه قبل، پنجشنبه ۱ تیر ۱۳۹۱، ساعت ۰۱:۳۲
    جناب مهندس عزیز
    مثل اینکه چند روزی هست که google analytic  نیز ایران رو تحریم کرده چاره چیه؟جایگزین داره؟
    • #
      ‫۱۲ سال و ۴ ماه قبل، پنجشنبه ۱ تیر ۱۳۹۱، ساعت ۰۱:۵۸
      مثل بقیه سرویس‌های آن با V.P.N کار می‌کنه. شما فقط نیاز به یک tracking id دارید. ثبت سایت و دریافت آن کار جمعا یک تا دو دقیقه است.
  • #
    ‫۱۲ سال و ۴ ماه قبل، پنجشنبه ۱ تیر ۱۳۹۱، ساعت ۱۶:۳۴
    ممنون بابت مطلب خوبتون
  • #
    ‫۱۱ سال و ۲ ماه قبل، سه‌شنبه ۱ مرداد ۱۳۹۲، ساعت ۲۲:۴۶
    با سلام. امکان دارد در مورد نحوه استخراج اطلاعات از این سرویس و نمایش در سایت کمی راهنمایی کنید؟ باتشکر.
  • #
    ‫۱۰ سال و ۵ ماه قبل، سه‌شنبه ۲۳ اردیبهشت ۱۳۹۳، ساعت ۱۵:۴۹
    با تشکر.
    من دقیقاً روش بالا را استفاده کرده ام. در کلاینت خوب جواب می‌دهد ولی وقتی بر روی سرور آپلود میکنم ، نتیجه ای حاصل نمی‌شود.
    string username = ConfigurationManager.AppSettings["GoogleAnalyticsUsername"];
            string password = ConfigurationManager.AppSettings["GoogleAnalyticsPassword"];
            string profileId = ConfigurationManager.AppSettings["GoogleAnalyticsProfileId"];
            string yesterdayDate = DateTime.Today.AddDays(-1).ToString("yyyy-MM-dd");
    var service = new AnalyticsService("WebSiteAnalytics");
    
                    service.setUserCredentials(username, password);
                    var dataQuery = new DataQuery()
                    {
                        Ids = profileId,
                        Metrics = "ga:pageviews",
                        Sort = "ga:pageviews",
                    };
                    DataFeed dataFeed = null;
    
                    //--- total visit
                    dataQuery.GAStartDate = new DateTime(2012, 3, 1).ToString("yyyy-MM-dd");
                    dataQuery.GAEndDate = DateTime.Now.ToString("yyyy-MM-dd");
                    dataFeed = service.Query(dataQuery);
                    var totalEntry = (dataFeed.Entries == null || dataFeed.Entries.Count == 0) ? "0" :
                        (dataFeed.Entries[0] as DataEntry).Metrics[0].Value;
    
                    //--- yesterday visit
                    dataQuery.GAStartDate = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd");
                    dataQuery.GAEndDate = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd");
                    dataFeed = service.Query(dataQuery);
                    var yesterdayEntry = (dataFeed.Entries == null || dataFeed.Entries.Count == 0) ? "0" :
                        (dataFeed.Entries[0] as DataEntry).Metrics[0].Value;
    
                    //--- today visit
                    dataQuery.GAStartDate = DateTime.Now.ToString("yyyy-MM-dd");
                    dataQuery.GAEndDate = DateTime.Now.ToString("yyyy-MM-dd");
                    dataFeed = service.Query(dataQuery);
                    var todayEntry = (dataFeed.Entries == null || dataFeed.Entries.Count == 0) ? "0" :
                        (dataFeed.Entries[0] as DataEntry).Metrics[0].Value;
    
                    //--- last week visit
                    dataQuery.GAStartDate = DateTime.Now.AddDays(-7).ToString("yyyy-MM-dd");
                    dataQuery.GAEndDate = DateTime.Now.ToString("yyyy-MM-dd");
                    dataFeed = service.Query(dataQuery);
                    var lastWeekEntry = (dataFeed.Entries == null || dataFeed.Entries.Count == 0) ? "0" :
                        (dataFeed.Entries[0] as DataEntry).Metrics[0].Value;
    
                    //--- last month visit
                    dataQuery.GAStartDate = DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd");
                    dataQuery.GAEndDate = DateTime.Now.ToString("yyyy-MM-dd");
                    dataFeed = service.Query(dataQuery);
                    var lastMonthEntry = (dataFeed.Entries == null || dataFeed.Entries.Count == 0) ? "0" :
                        (dataFeed.Entries[0] as DataEntry).Metrics[0].Value;

    • #
      ‫۱۰ سال و ۵ ماه قبل، چهارشنبه ۲۴ اردیبهشت ۱۳۹۳، ساعت ۱۵:۵۰
      - این روش منسوخ شده‌است و مربوط است به پروتکل‌های قدیمی گوگل.
      - کار کردن با آن امن نیست چون باید اطلاعات حساس اکانت گوگل خود را در فایل کانفیگ برنامه قرار دهید.
      - برای کار با این نوع پروتکل‌ها، در بسیاری از اوقات گوگل نیاز دارد تا شما توسط مرورگر سیستم جاری (در اینجا سرور وب)، یکبار به اکانت خود لاگین کنید.
      - ga:pageviews با visits ارتباطی ندارد. فقط به این معنا است که صفحات سایت شما چندبار مشاهده شده‌اند و نه به معنای اینکه چندنفر آن‌هارا مشاهده کرده‌اند.
      روش بهتر در اینجا
  • #
    ‫۱۰ سال و ۴ ماه قبل، چهارشنبه ۷ خرداد ۱۳۹۳، ساعت ۱۴:۰۱
    با سلام و درود؛  یک سوال ؟ برای بدست آوردن کاربران Unique از session استفاده میکنیم و اما گوگل با استفاده از کدهای جاواسکریپت چطور میتونه کاربران  unique را بدست بیاره ؟!
    و یک سوال دیگه اگه راهنمایی کنید ممنون میشم.
    من یک آمارگیر برای سایتم نوشتم که یک مشکل با کاربرانی داره که با موبایل یا تبلت از سایت دیدن میکنند
    و با هر بار بازدید چند بار session اجرا میشه ! یعنی با یک بازدید به جای اینکه یک عدد به کاربران unique  اضافه بشه چند عدد اضافه میشه ! که مشکل برای کاربرانی که از طریق ویندوز سایت را مشاهده میکنند وجود نداره.
    • #
      ‫۱۰ سال و ۴ ماه قبل، چهارشنبه ۷ خرداد ۱۳۹۳، ساعت ۱۴:۰۸
      در Google Analytics (نه راه حل‌های شخصی):
      تعداد بار مراجعه کاربران: «sessions»
      کاربران منحصربفرد مراجعه کننده به سایت: «users» 
      تفاوت بین ga:sessions و ga:users در Google Analytics  
      - آنالیز محتوای کوکی‌ها utma و utmz  + بررسی IP کاربر و تهیه یک چکیده از user-agent مرورگر و خیلی از مسایل ریز دیگر او برای تشخیص منحصربفرد بودن کاربر و نه فقط اینکه سشنی شروع شده، بنابراین کاربر جدید است.
  • #
    ‫۹ سال و ۷ ماه قبل، پنجشنبه ۱۴ اسفند ۱۳۹۳، ساعت ۰۴:۴۹
    سلام؛ میخواستم بدونم در صورتیکه قصد داشته باشیم آنالیز ترافیک بازدید سایت رو بدون استفاده از سرویس‌های مختلف (PersianStat, Google Analytic)، در وب سایت خودمون پیاده سازی کنیم چه روش هایی پیشنهاد میکنین؟

    وب سایت بر پایه MVC 5 ساخته شده. روشی که خودم در نظر دارم، یک جدول در بانک اطلاعاتی هست که شامل یک سری فیلد مانند IP و User-Agent و تاریخ و ساعت و ...

    به ازای هر کاربر یک رکورد اضافه بشه در دیتابیس. ولی به صورتی باشه که فقط یکبار اضافه بشه در یک مدت زمان محدود. یعنی به ازای هر Request که از یک کاربر مشخص ارسال میشه نیاد پشته سر هم هی رکورد درج کنه و به قول معروف با Refresh کردن هی رکورد ثبت بشه توی دیتابیس.

    Session_Start در فایل Global گزینه‌ی خوبی هست برای اینکار ولی در وب سایت از Session استفاده نمیکنم و غیر فعالش کردم در وب کانفیگ، بنابراین جوابگو نیست.
    ممنون میشم اگر بتونید راهنمایی کنید.
    • #
      ‫۹ سال و ۷ ماه قبل، پنجشنبه ۱۴ اسفند ۱۳۹۳، ساعت ۰۵:۰۱
      - از رخداد  Application_BeginRequest باید استفاده کنید.
      - همچنین اگر سرور متعلق به خودتان است، روش لاگ‌های IIS، امکاناتی مشابه google analytics را در اختیار شما قرار می‌دهد (^ و ^ و ^).