所以我根据这里的 cmets 玩了一下。我想出的是在一个简单的领域计算一个计数器。在我的应用中,我有带有 Views 属性的代码 sn-p 实体。
当查看一个 sn-p 时,一个方法过滤掉(白名单)应该是浏览器:
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);
}
然后存储过程使用一个单独的表来临时保存最新的视图,其中存储了 sn-p Id、输入的日期和 IP 地址。每个视图都被记录下来,当一个新视图出现时,它会检查相同的 IP 地址是否在过去 2 分钟内访问了这个 sn-p。如果是这样,则不会记录任何内容。
如果是新视图,则会记录该视图(同样是 SnippetId、IP、Entered),并在 Snippets 表上更新实际的 Views 字段。
如果它不是一个新视图,则该表会被清理,并记录任何超过 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
这似乎运作良好。正如其他人提到的那样,这并不完美,但在初始测试中看起来已经足够了。