Так что я немного поиграл с этим, основываясь на комментариях здесь. Я придумал счетчик в простом поле. В моем приложении есть фрагменты кода со свойством Views.
Когда просматривается фрагмент, метод отфильтровывает (белый список) только то, что должно быть браузерами:
public bool LogSnippetView(string snippetId, string ipAddress, string userAgent)
{
if (string.IsNullOrEmpty(userAgent))
return false;
userAgent = userAgent.ToLower();
if (!(userAgent.Contains("mozilla") || !userAgent.StartsWith("safari") ||
!userAgent.StartsWith("blackberry") || !userAgent.StartsWith("t-mobile") ||
!userAgent.StartsWith("htc") || !userAgent.StartsWith("opera")))
return false;
this.Context.LogSnippetClick(snippetId, IpAddress);
}
Затем хранимая процедура использует отдельную таблицу для временного хранения последних представлений, в которых хранятся идентификатор фрагмента, введенная дата и адрес IP. Каждое представление записывается в журнал, и, когда появляется новое представление, проверяется, получал ли тот же IP-адрес доступ к этому фрагменту за последние 2 минуты. если так, то ничего не регистрируется.
Если это новое представление, представление регистрируется (снова SnippetId, IP, Entered), и фактическое поле Views обновляется в таблице Snippets.
Если это не новое представление, таблица очищается с помощью любых зарегистрированных представлений, которые старше 4 минут. Это должно привести к минимальному количеству записей в таблице просмотра журнала в любое время.
Вот хранимый процесс:
ALTER PROCEDURE [dbo].[LogSnippetClick]
-- Add the parameters for the stored procedure here
@SnippetId AS VARCHAR(MAX),
@IpAddress AS VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
-- check if don't allow updating if this ip address has already
-- clicked on this snippet in the last 2 minutes
select Id from SnippetClicks
WHERE snippetId = @SnippetId AND ipaddress = @IpAddress AND
DATEDIFF(minute, Entered, GETDATE() ) < 2
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO SnippetClicks
(SnippetId,IpAddress,Entered) VALUES
(@SnippetId,@IpAddress,GETDATE())
UPDATE CodeSnippets SET VIEWS = VIEWS + 1
WHERE id = @SnippetId
END
ELSE
BEGIN
-- clean up
DELETE FROM SnippetClicks WHERE DATEDIFF(minute,Entered,GETDATE()) > 4
END
END
Кажется, это работает довольно хорошо. Как уже упоминалось, это не идеально, но похоже, что оно достаточно хорошо при первоначальном тестировании.