很多人会直接用静态类做内存缓存,包括我自己之前也是这样做,但这样内存的生命周期及GC机制得不到保障,特别是对于多线程的控制,静态类都是无能为力。

另外就是 MemoryCache,很多人都习惯用他的 MemoryCache.TryGetValue 来实现自动缓存,这对于小项目及访问量不大的项目是可行的,但如果对于大项目,这样会导致访问很慢,因为是被动式的去拉取数据,有没有一种更好的方式呢,好在net core 提供了 BackgroundService 及 IHostedService,两者类似,可以完美的解决我们的需求,这里我就举例说一下使用 IHostedService 来实现主动式缓存网站首页的全部数据,以实现最快速的首页访问。

新建逻辑处理服务类:

public class DbServices : IHostedService, IDisposable
{
    CancellationToken cancelToken;
    HomeData? datas;
    Task? mainTask;
    private ILogger logger;

    public DbServices(ILogger logger)
    {
        this.logger=logger;
    }

    public HomeData? GetHomeData()
    {
        return datas;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        cancelToken = cancellationToken;
        mainTask = Task.Factory.StartNew(HomeDataWork, cancellationToken);
        return Task.CompletedTask;
    }
    private async void HomeDataWork()
    {
        DateTime last = DateTime.Now.AddMinutes(-2);
        while (!cancelToken.IsCancellationRequested)
        {
            int sec = 30000 - (int)(DateTime.Now - last).TotalMilliseconds;
            if (sec > 0)
                await Task.Delay(sec);
            last = DateTime.Now;
            HomeData? _data = .....;//实现获取数据
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        mainTask?.Dispose();
    }
}

Program.cs 中:

builder.Services.AddSingleton<DbServices>();
builder.Services.AddHostedService<DbServices>(provider => provider.GetService<DbServices>());

大功造成,该服务会在后台主动更新内存数据,首页可以直接无任何延迟直接获取数据:

DbServices? service = MyHttpContext.Current?.RequestServices.GetService(typeof(DbServices)) as DbServices;
HomeData = service?.GetHomeData(Langs.Instance.LangCode) ?? new();

直接编辑 xxx.csproj 项目文件:

<PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <!--不打包视图文件-->
    <RazorCompileOnBuild>false</RazorCompileOnBuild>
    <RazorCompileOnPublish>false</RazorCompileOnPublish>
    <!--防止生成很多语言资源包-->
    <SatelliteResourceLanguages>zh-Hans;vi</SatelliteResourceLanguages>
</PropertyGroup>

Program.cs 中:

var serviceProvider = builder.Services.BuildServiceProvider();
var logger = serviceProvider.GetService<ILogger<MyServices>>();
builder.Services.AddSingleton(typeof(ILogger), logger);

这样就会将 ILogger 注入到相关类中,可以直接通过构造函数来获取了:

private ILogger logger;
public void MyServices(ILogger logger)
{
    this.logger = logger;
    ...
}

安装一个完整的 Ruby 开发环境:

sudo apt-get install ruby-full build-essential zlib1g-dev
echo '# Install Ruby Gems to ~/gems' >> ~/.bashrc
echo 'export GEM_HOME="$HOME/gems"' >> ~/.bashrc
echo 'export PATH="$HOME/gems/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

安装 jekyll

gem install jekyll bundler

创建项目示例:

jekyll new myblog
cd myblog
bundle exec jekyll serve

好了,打开浏览器,浏览网址:http://localhost:4000 看看吧

如果下载了项目,到项目下,修改配置文件 _config.yml
主要是 baseurl 及 url 前者表示项目路径,留空为根路径;后者是web服务侦听的协议、地址及端口
修改完后,下载依赖项:

bundle install

生成静态内容:

bundle exec jekyll build

后台运行服务:

bundle exec jekyll serve --detach

在使用正则前,需要启用系统高级选项的OLE自动化功能,启用过程如下:

exec sp_configure 'show advanced options',1
reconfigure
exec sp_configure 'Ole Automation Procedures',1
reconfigure

安全起见,使用完后记得关闭该高级功能:

exec sp_configure 'Ole Automation Procedures',0
reconfigure
exec sp_configure 'show advanced options',0
reconfigure

搜索 Function:

ALTER FUNCTION [dbo].[RegexMatch]
(
    @matchstring VARCHAR(4000),
    @pattern VARCHAR(200)
)
RETURNS BIT
AS BEGIN
    DECLARE @handle int, @result bit
    exec sp_oacreate 'vbscript.regexp', @handle output
    exec sp_oasetproperty @handle, 'pattern',@pattern
    exec sp_oasetproperty @handle, 'global', 'true'
    exec sp_oasetproperty @handle, 'ignorecase', 0
    exec sp_oamethod @handle, 'test', @result output,@matchstring
    exec sp_oadestroy @handle
    return @result
END

使用:

select dbo.RegexMatch(N'abc12345',N'\d{5}')

替换Function

CREATE FUNCTION [dbo].[RegReplace]
(
    @matchstring VARCHAR(4000),
    @pattern VARCHAR(200),
    @replace VARCHAR(200)
)
RETURNS VARCHAR(4000)
AS BEGIN
    DECLARE @handle int, @result VARCHAR(4000)
    exec sp_oacreate 'vbscript.regexp', @handle output
    exec sp_oasetproperty @handle, 'pattern',@pattern
    exec sp_oasetproperty @handle, 'global', 1 --全局替换
    exec sp_oasetproperty @handle, 'ignorecase', 1 --忽略大小写
    exec sp_oamethod @handle, 'Replace', @result output,@matchstring,@replace
    exec sp_oadestroy @handle
    return @result
END

使用:

select dbo.RegReplace('hello 123','\d{2}','world')