博客 (96)

使用 Linq 语法调用数据库时,需要包含导航属性(外键表数据)会用到 Include 方法,但是如果引用的程序集搞错了,就不会有数据输出,应该:

using Microsoft.EntityFrameworkCore;

而不是

using System.Data.Entity;

xoyozo 1 个月前
153

早前记录过在 CentOS 中部署 ASP.NET Core 网站,现在宝塔面板已经直接支持创建 .NET 网站了,再次记录一下。


本文环境:VS2022、.NET 9、宝塔面板v11。


一、在 VS 中创建一个 .NET 9 网站,项目名称例:WebApplication1

发布选项:

image.png

关于“生成单个文件”选项,若勾选,发布后的项目启动文件不带后缀名(.dll),尝试在宝塔面板 v11.0.0 中无法顺利启动。


二、在 Linux 服务器上创建目录:/www/wwwroot/WebApplication1/

将发布后的文件上传到这个目录上,最终的文件结构如下:

image.png


三、进入宝塔面板,在 网站-Net项目 中安装 .Net环境管理,这里以 9.0.201 为例:

image.png


四、添加项目

项目名称:随意

运行路径:项目所在目录,本例中为:

/www/wwwroot/WebApplication1

启动命令:使用 dotnet 命令,dotnet 命令可以不使用全路径(/www/server/dotnet/9.0.201/dotnet),第一个参数是项目启动文件,--urls 是反向代理的服务器和端口。服务器名可以是*也可以是localhost。例:

dotnet WebApplication1.dll --urls=http://*:5000

项目端口:与启动命令中的端口号一致

开机启动:一般会勾选

启动用户:尽量用 www,最小权限原则。

image.png

正常情况下,网站已启动,如果未启动,检查配置,根据报错内容排查问题。


五、配置网站

添加域名、SSL 证书等。


友情提示:

  • 网站版本更新重新发布后,需要手动重启网站才能生效,习惯于发布到 IIS(会自动生效)的同学要特别注意。

  • 新手尽量以空项目或默认项目来部署,避免因特殊原因导致一系列其它问题。

  • nginx 反向代理并不会转发所有 Header,需要手动配置。

xoyozo 3 个月前
6,421

AsNoTracking 设置未追踪查询

var customers = dbContext.Customers.AsNoTracking().ToList();

这对于只读查询非常有用,因为它可以减少内存使用并提高性能,因为它不需要维护实体的更改跟踪信息。

何时需要 AsNoTracking()?


ExecuteDelete 和 ExecuteUpdate 批量操作

context.Logs.Where(c => c.Time < new DateTime(2000, 1, 1)).ExecuteDelete();

从 EF Core 7 开始,ExecuteDelete 和 ExecuteUpdate 是官方原生支持的批量操作方法。直接操作数据库,不需要调用 SaveChanges():不加载实体到内存,减少内存消耗和网络往返。

若需要分页删除和大批量插入,或在高频、大规模场景,推荐使用 Zack.EFCore.Batch

context.Logs.Where(c => c.Time < new DateTime(2000, 1, 1)).DeleteRangeAsync(batchSize: 1000);


考虑用 Union 代替 OR

// Where 后行数多时(如分页前)用 OR
var q = db.dt_crm__contract.AsNoTracking();
q = q.Where(c => c.dt_crm__customer.SalesmanId == uid || myIns.Contains(c.IndustryId));

// 用于合并的 q1、q2 的行数少时用 Union
var q1 = db.dt_crm__contract.AsNoTracking().Where(c => c.dt_crm__customer.SalesmanId == uid);
var q2 = db.dt_crm__contract.AsNoTracking().Where(c => myIns.Contains(c.IndustryId));
var q = q1.Union(q2);


“ToDictionary + Count”之前先 Select

// 不推荐
var dic = q.GroupBy(c => c.Date)
    .ToDictionary(k => k.Key, v => v.Count());
// 推荐
var dic = q.GroupBy(c => c.Date)
    .Select(g => new { g.Key, Count = g.Count() })
    .ToDictionary(k => k.Key, v => v.Count);



xoyozo 6 个月前
907
方法/工具发布时间所属框架命名空间/依赖项
编码标准空格处理严格性适用场景现代项目支持(.NET 6+)
HttpUtility.UrlEncode2002.NET Framework 1.0+System.Web(需引用 DLL)x-www-form-urlencoded+宽松传统 ASP.NET WebForms
Server.UrlEncode2002.NET Framework 1.0+System.Web(ASP.NET 页面内)x-www-form-urlencoded+宽松ASP.NET WebForms 页面内编码
Uri.EscapeDataString2005.NET Framework 2.0+System(核心库)RFC 3986%20严格构造 URI 组件(路径、查询参数)✔️
WebUtility.UrlEncode2012.NET Framework 4.5+System.Net(跨平台)x-www-form-urlencoded+宽松非 Web 环境或兼容旧代码✔️
UrlEncoder.Default.Encode2016.NET Core 1.0+System.Text.Encodings.WebRFC 3986%20严格现代应用,严格 URI 编码✔️

关键选择原则

  • 兼容旧代码 → HttpUtility.UrlEncode 或 WebUtility.UrlEncode。

  • 严格 URI 规范 → Uri.EscapeDataString 或 UrlEncoder。

  • ASP.NET Core → UrlEncoder。

  • 非 Web 或跨平台 → 弃用 System.Web,选择 System.Net 或 System.Text.Encodings.Web 中的方法。


xoyozo 7 个月前
902

打开 .csproj 项目文件,在 <PropertyGroup> 标签内添加:

<Version>
  1.0.$([System.Math]::Floor($([System.DateTime]::Now.Subtract($([System.DateTime]::Parse('2000-01-01T00:00:00Z'))).TotalDays))).$([MSBuild]::Divide($([System.Math]::Floor($([System.DateTime]::Now.TimeOfDay.TotalSeconds))), 2))
</Version>

最终生成的版本号示例: 1.0.9238.28518

其中,Major 与 Minor 是固定的,Build 是2000年1月1日至今的天数,Revision 是今天的秒数 / 2 所得的值。(为了防止数值超过 65535)


程序中获取版本号:

var version = Assembly.GetExecutingAssembly().GetName().Version!; // 当前类库
var version = Assembly.GetEntryAssembly()?.GetName().Version!; // 入口项目


从版本号获取发布时间:

DateTime versionTime = new DateTime(2000, 1, 1).AddDays(version.Build).AddSeconds(version.Revision * 2);


查看 .NET Framework 实现自动版本号的方法


xoyozo 8 个月前
825
  1. 在解决方案资源管理器中找到 Properties/AssemblyInfo.cs 文件。该文件存放程序集版本信息。

  2. 修改版本号格式

    将以下代码片段中的 AssemblyVersion 改为使用星号通配符(建议保留主版本和次版本号):

    [assembly: AssemblyVersion("1.0.*")]  // 自动生成构建号和修订号
    // [assembly: AssemblyFileVersion("1.0.0.0")] // 注释或删除此行
  3. 关闭确定性构建

    用文本编辑器打开 .csproj 项目文件,在 <PropertyGroup> 标签内添加:

    <Deterministic>false</Deterministic>

    此设置允许 MSBuild 生成动态版本号。

最终生成的版本号示例: 1.0.9238.28518

其中,Major 与 Minor 是固定的,Build 是2000年1月1日至今的天数,Revision 是今天的秒数 / 2 所得的值。(为了防止数值超过 65535)


程序中获取版本号:

var version = Assembly.GetExecutingAssembly().GetName().Version;


从版本号获取发布时间:

DateTime versionTime = new DateTime(2000, 1, 1).AddDays(version.Build).AddSeconds(version.Revision * 2);


查看 .NET Core / .NET 5+ 实现自动版本号的方法


xoyozo 8 个月前
650

前几天实现了在 nginx 中使用 lua 实现远程鉴权,今天想试试在 IIS 中能不能实现相同的功能。查询资料发现需要使用 URL 重写和 HTTP 请求模块,没有深究。干脆使用 ASP.NET 中间件来实现吧。

在 StratUp.cs 的 Configure 方法中,或 Program.cs 文件中添加以下代码:

// 远程鉴权
app.Use(async (context, next) =>
{
    var ip = context.Connection.RemoteIpAddress!.ToString();
    var ua = context.Request.Headers.UserAgent.ToString();
    var host = context.Request.Host.Host;
    var uri = new Uri(context.Request.GetDisplayUrl()).PathAndQuery;

    var client = new HttpClient();
    client.Timeout = TimeSpan.FromSeconds(1); // 设置超时时间

    try
    {
        var requestUrl = "https://鉴权地址/";

        var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrl);
        requestMessage.Headers.Add("X-Real-IP", ip);
        requestMessage.Headers.Add("User-Agent", ua);
        requestMessage.Headers.Add("X-Forwarded-Host", host);
        requestMessage.Headers.Add("X-Forwarded-Uri", uri);

        // 发送请求
        var response = await client.SendAsync(requestMessage);

        // 检查响应状态码
        if (response.StatusCode == HttpStatusCode.Forbidden)
        {
            // 如果返回403,则拒绝访问
            context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
            await context.Response.WriteAsync("Access Denied");
        }
        else
        {
            // 如果返回其他状态码,则继续执行管道中的下一个中间件
            await next();
        }
    }
    catch (TaskCanceledException ex) when (ex.CancellationToken.IsCancellationRequested)
    {
        // 如果请求超时(任务被取消),则继续执行管道中的下一个中间件
        await next();
    }
    catch
    {
        // 如果遇到错误,则继续执行管道中的下一个中间件
        await next();
    }
});

代码很简单,使用 HttpClient 发送请求,若返回 403 则拒绝访问,其它情况继续执行业务逻辑,超时或报错的情况按需修改即可。

若鉴权接口在私网中,建议将鉴权接口域名和私网 IP 添加到 hosts 文件中。

xoyozo 11 个月前
1,046
引擎连接方式
mysqlimysqli_connect("域名或IP:端口", "用户名", '密码', "数据库名")
Scaffold-DbContextScaffold-DbContext "server=域名或IP;port=端口;uid=用户名;pwd=密码;database=数据库名;" Pomelo.EntityFrameworkCore.MySql -OutputDir 模型路径 -Force

如果端口配置不正确,会报错:

Unable to connect to any of the specified MySQL hosts.

xoyozo 1 年前
669

POST

$.post('AjaxCases', {
    following: true,
    success: null,
    page: 1,
}, function (response) {
    console.log(response.data)
}, 'json').fail(function (xhr, status, error) {
    console.log(xhr.responseText);
});
[HttpPost]
public IActionResult AjaxCases([FromForm] AjaxCasesRequestModel req)
{
    bool? following = req.following;
    bool? success = req.success;
    int page = req.page;
}

提示:只能传输对象(Object),不能传输数组(Array)。


相关:axios 请求 .NET Core / .NET 5 / .NET 6

xoyozo 1 年前
1,532
CorelDRAW 版本“另存为”支持的最低版本
CorelDRAW 2023(版本 24.315.0 (X5)
CorelDRAW 2022(版本 24.015.0 (X5)
CorelDRAW 2021(版本 23.015.0 (X5)
CorelDRAW 2020(版本 22.011.0
CorelDRAW 2019(版本 21.0)11.0
CorelDRAW 2018(版本 20.0
11.0
CorelDRAW 2017(版本 19.0
11.0
CorelDRAW X8(版本 18.011.0
CorelDRAW X7(版本 17.011.0
CorelDRAW X6(版本 16.07.0
CorelDRAW X5(版本 15.07.0
CorelDRAW X4(版本 14.0
7.0
CorelDRAW X3(版本 13.07.0


xoyozo 2 年前
1,798