каков наилучший способ фиксировать просмотры страниц для каждого пользователя в asp.net-mvc

#c# #asp.net-mvc #pageviews

#c# #asp.net-mvc #просмотры страниц

Вопрос:

каков наилучший способ фиксировать просмотры страниц каждым пользователем без снижения производительности сайта. Я вижу, что stackoverflow показывает просмотры страниц повсюду. Выполняют ли они вставку в базу данных каждый раз, когда я нажимаю на страницу?

В asp.net-mvc есть ли какой-либо рекомендуемый способ отслеживать просмотр страниц для каждого пользователя (на моем сайте есть экран входа в систему), чтобы я мог просматривать, какие страницы посещают люди и как часто

Комментарии:

1. Какая версия asp.net вы используете mvc?

Ответ №1:

Во-первых .. если вас действительно волнует, как клиенты используют мой сайт, то вы, скорее всего, захотите заглянуть в Google Analytics или аналогичный сервис.

Но если вам нужна быстрая и грязная запись о просмотре страницы, и вы используете ASP.Net MVC 3 тогда, как упоминал Крис Фулстоу, вам захочется использовать сочетание глобальных фильтров действий и кэширования. Вот пример.

 PageViewAttribute.cs 

    public class PageViewAttribute : ActionFilterAttribute
{
    private static readonly TimeSpan pageViewDumpToDatabaseTimeSpan = new TimeSpan(0, 0, 10);

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var calledMethod = string.Format("{0} -> {1}",
                                         filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
                                         filterContext.ActionDescriptor.ActionName);

        var cacheKey = string.Format("PV-{0}", calledMethod);

        var cachedResult = HttpRuntime.Cache[cacheKey];

        if(cachedResult == null)
        {
            HttpRuntime.Cache.Insert(cacheKey, new PageViewValue(), null, DateTime.Now.Add(pageViewDumpToDatabaseTimeSpan) , Cache.NoSlidingExpiration, CacheItemPriority.Default,
                                  onRemove);
        }
        else
        {
            var currentValue = (PageViewValue) cachedResu<

            currentValue.Value  ;
        }
    }

    private static void onRemove(string key, object value, CacheItemRemovedReason reason)
    {
        if (!key.StartsWith("PV-"))
        {
            return;
        }

        // write out the value to the database
    }

    // Used to get around weird cache behavior with value types
    public class PageViewValue
    {
        public PageViewValue()
        {
            Value = 1;
        }

        public int Value { get; set; }
    }
}
  

И в вашем Global.asax.cs

 public class MvcApplication : HttpApplication 
{
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new PageViewAttribute());
        }
}
  

Для pre-ASP.Net ТОЛЬКО на MVC 3 вам придется вручную применять один и тот же атрибут ко всем вашим действиям.

 [PageView]
public ActionResult CallOne()
{
}

[PageView]
public ActionResult CallTwo()
{
}
  

Комментарии:

1. @ShaneC — спасибо за ваш ответ. .единственная проблема в том, что я нигде не вижу, чтобы вы сохраняли это

2. Понятия не имею, как настроена ваша база данных .. эта часть, мой друг, зависит от вас 🙂 смотрите в onRemove, где говорится // записать значение в базу данных

3. @ShaneC — когда вызывается OnRemove? При любой загрузке одной страницы?

4. Нет, он вызывается только по истечении срока действия кэша. Он передается в кэш. Вставить вызов в качестве обратного вызова при удалении.

5. @usr — вас не волнует остальное (например, запросы контента)

Ответ №2:

Вероятно, лучшим способом был бы глобальный фильтр действий, который перехватывает запросы ко всем действиям на всех контроллерах, затем увеличивает счетчик в базе данных для текущего пользователя и страницы. Чтобы не слишком сильно нагружать базу данных, вы могли бы кэшировать эти значения и аннулировать их каждые несколько минут, в зависимости от объема трафика, с которым вы имеете дело.

Комментарии:

1. можете ли вы более подробно объяснить, как вы будете кэшировать значения и аннулировать их каждые несколько минут?

2. Проверьте System.Web.Caching. Класс кэша — msdn.microsoft.com/en-us/library/system.web.caching.cache.aspx — это позволит вам кэшировать значения в памяти и устанавливать дату истечения срока действия.

3. Фильтр действий — неправильный выбор. Вы не будете получать все запросы, только запросы MVC.

4. @usr не думаете, что мы хотим отслеживать все запросы здесь? Просто просмотры страниц, которые можно разумно считать действиями контроллера MVC.

Ответ №3:

Мы используем Piwik с открытым исходным кодом:http://piwik.org /, который настроен на собственном сервере. Одна строка Javascript на странице _Layout вызывает Piwik после загрузки страницы (поместите JS в конце) и вообще не влияет на производительность загрузки страницы.

В дополнение к простым подсчетам, вы получите массу информации о том, откуда приходят ваши пользователи, браузере, разрешениях экрана, установленных плагинах. Кроме того, вы можете отслеживать конверсии и использовать тот же инструмент для отслеживания маркетинговых кампаний и т.д.

<soapbox>

Я не могу представить ситуацию, когда вам было бы лучше реализовать это в MVC или в вашем веб-приложении в целом. Этот материал просто не относится к вашему веб-приложению и является мета-проблемой, которую следует выделить. Этот подход позволил нам отслеживать аналитику для всех наших приложений (32 из них: mvc 2/3, webforms, php …) унифицированным образом.

Если вы действительно не хотите использовать другой инструмент для этой цели, я бы рекомендовал подключиться к вашему журналу IIS и получить оттуда свою статистику. Опять же, чтобы извлечь из этого реальную пользу для принятия решений, вам нужно установить на него хороший анализатор. Я рекомендую Splunk:http://www.splunk.com

</soapbox>

Комментарии:

1. Есть аргумент в пользу размещения JavaScript для этого типа анализа ближе к верхней части вашей страницы, поскольку он сможет регистрировать запросы на заброшенные страницы или очень быстрые запросы страниц — например, если я нажму на «Продукты» и до завершения загрузки страницы я найду ссылку на «Камеры» и нажму на нее — скрипт внизу страницы фактически не будет регистрировать мое посещение страницы «Продукты».

2. @Sohnee: Согласен. У Piwik также есть способ отслеживать просмотры путем встраивания изображения в 1 пиксель. Если производительность Javascript становится проблемой, это было бы несколько менее мощной альтернативой.

3. @xameeramir Да, но наша веб-команда сочла, что Google Analytics лучше, поэтому мы находимся в процессе переключения. Плюс мы не фанаты PHP.

Ответ №4:

Я хотел опубликовать обновленную версию ответа Шейна для тех, кто заинтересован. Некоторые вещи, которые следует учитывать:

  1. Вы должны настроить атрибут action как сервис при оформлении своих методов, используя синтаксис, подобный следующему :

    [ServiceFilter(typeof(PageViewAttribute))]

  2. Насколько я могу судить, HttpRuntime.Кэш.В .NET Core нет функции Insert, поэтому я использовал простую реализацию IMemoryCache (возможно, вам потребуется добавить эту строку в свой startup.cs, чтобы использовать интерфейс):

    Услуги.AddMemoryCache ();

  3. Поскольку мы внедряем IMemoryCache в класс, который не является контроллером, нам нужно зарегистрировать наш атрибут как сервис в startup.cs, вот так:

    Услуги.AddScoped<[PageViewAttribute]>(); — без скобок!

  4. Любой объект, который вы возвращаете при создании CacheKey, будет присвоен параметру ‘value’ метода OnRemove.

Ниже приведен код.

 public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var controllerActionDescriptor = filterContext.ActionDescriptor as ControllerActionDescriptor;

        var arguments = filterContext.ActionArguments;
        ActionId = arguments["id"].ToString();

        var calledMethod = string.Format("{0} -> {1}",
                                         controllerActionDescriptor.ControllerName,
                                         controllerActionDescriptor.ActionName);

        var cacheKey = string.Format("PV-{0}", calledMethod);

        var cachedResult = _memoryCache.Get(cacheKey);

        if (cachedResult == null)
        {
            //Get cacheKey if found, if not create cache key with following settings
            _memoryCache.GetOrCreate(cacheKey, cacheKey =>
            {
                cacheKey.AbsoluteExpirationRelativeToNow
                              = pageViewDumpToDatabaseTimeSpan;
                cacheKey.SetValue(1);
                cacheKey.RegisterPostEvictionCallback(onRemove);
                return cacheKey.Value;
            });
        }
        else
        {
            _memoryCache.Get(cacheKey);
        }
    }

    //Called when Memory entry is removed
    private void onRemove(object key, object value, EvictionReason reason, object state)
    {
        if (!key.ToString().StartsWith("PV-"))
        {
            return;
        }

        // write out the value to the database
        SaveToDataBase(key.ToString(), (int)value);

    }
  

В качестве ориентира это было сделано для приложения .NET Core 5 MVC.

С уважением.