博客 (34)

直接运行项目启动程序(在发布目录中,以项目名称为文件名,扩展名为 .exe 的可执行程序)

启动后可在“Now listening on:”所在行看到访问入口 URL(如图中 http://localhost:5000)。

在同服浏览器中打开该地址,访问到报错页面,回到该命令行窗口可见“fail”异常的详细信息。

QQ截图20211003173208.png

xoyozo 4 年前
2,394

当 ASP.NET 发布一个新的小版本更新时(以 .NET 5.0.10 为例),生产环境服务器端可以直接下载安装 .NET 5.0.10 来自动替换 .NET 5.0.9。

倘若这时直接使用 VS 将 nuget 中版本为 5.0.9 的组件更新到 5.0.10 发布到服务器上的话,可能会发生错误:

HTTP Error 500.30 - ASP.NET Core app failed to start

这里我们可以在 nuget 回滚相关组件的版本至 5.0.9,等 VS 发现新的版本更新时,更新 VS 开发工具后,再更新 nuget 组件并进行发布即可。

着急的小伙伴可以直接前往 Microsoft .NET 网站下载安装包含 Runtime 5.0.10 的 SDK:

image.png

该情况同样发生在 ASP.NET Core 3.1 等大版本上。

若仍未生效,请重启服务器

----------------

后注:安装完成后重启服务器可避免以上烦恼!

xoyozo 4 年前
2,263

本文写于 2021 年 7 月。

WebBrowser 不能改用 Chrome 内核。

在 .NET Frameworks 和 .NET Core 年代,常用的第三方组件有:WebKit.NET、CefSharp 等。

而并未找到适用于 .NET 5 的成熟的 Chromium 内核的浏览器组件。

不过还是推荐一款微软官方出品的 WebView2,需要安装 Microsoft Edge Canary 才能正常运行。


xoyozo 4 年前
2,873

本文使用 Oracle 官方提供的 MySql.EntityFrameworkCore,如使用 Pomelo.EntityFrameworkCore.MySql 请移步

MySql.EntityFrameworkCore 是 MySql.Data.EntityFrameworkCore 的升级版


本文以 Visual Studio 2019、ASP.NET Core 5.0 开发环境为例。

  1. 新建 ASP.NET Core Web 应用程序。

  2. 安装 NuGet 包:

    MySql.EntityFrameworkCore

    Microsoft.EntityFrameworkCore.Design

    image.png

  3. 根据已有数据库创建数据模型。在 NuGet 的程序包管理(Package Manager)控制台中(PowerShell)执行命令:

    Scaffold-DbContext "server=数据库服务器;port=3306;user=数据库用户名;password=数据库密码;database=数据库名" MySql.EntityFrameworkCore -OutputDir Data -f

    .Net Core CLi:

    dotnet ef dbcontext scaffold "server=数据库服务器;port=3306;user=数据库用户名;password=数据库密码;database=数据库名" MySql.EntityFrameworkCore -o Data -f
  4. 搞定。


注:开发环境和生产环境都不需要安装 Connector/NET,只需要安装 ASP.NET Core。

补充:其它数据库提供程序请参考:https://docs.microsoft.com/zh-cn/ef/core/providers/

更多高级用法请参考官方文档


xoyozo 5 年前
4,916

获取表名:

using Microsoft.EntityFrameworkCore;
var entityType = _context.Model.FindEntityType(typeof(表实体));
var tableName = entityType.GetTableName();

获取字段名:

using Microsoft.EntityFrameworkCore;
var entityType = _context.Model.FindEntityType(typeof(表实体));
var dic = new Dictionary<string, string>();
foreach (var p in entityType.GetProperties())
{
    dic.Add(p.Name, p.GetColumnBaseName());
}


xoyozo 5 年前
5,021

报错:

HTTP Error 500.30 - ASP.NET Core app failed to start

Common solutions to this issue:

  • The app failed to start

  • The app started but then stopped

  • The app started but threw an exception during startup

Troubleshooting steps:

  • Check the system event log for error messages

  • Enable logging the application process' stdout messages

  • Attach a debugger to the application process and inspect

For more information visit: https://go.microsoft.com/fwlink/?LinkID=2028265


解决:

直接运行网站根目录的 .exe 启动文件可以找到答案。


一个常见的原因是:因 nuget 包升级(特别是需要服务器端安装组件的包)导致的发布后仍然是低版本的包,删除项目中的 /obj/ 目录重新发布即可。

xoyozo 5 年前
8,562

通过 nuget 安装 UEditorNetCore

从 UEditor 官网 下载最新的包 ueditorx_x_x_x-utf8-net.zip

解压包,并复制到项目的 wwwroot/lib 目录下,删除 net 目录。

根据 UEditorNetCore 官方的使用说明进行操作

步骤中,控制器 UEditorController 接替原 controller.ashx 的功能,用于统一处理上传逻辑

原 config.json 复制到项目根目录,用于配置上传相关设置(若更改文件名和路径在 services.AddUEditorService() 中处理)。

个人喜欢将 xxxPathFormat 值改为:upload/ueditor/{yyyy}{mm}{dd}/{time}{rand:6},方便日后迁移附件后进行批量替换。

记得配置 catcherLocalDomain 项。


上传相关的身份验证和授权控制请在 UEditorController 中处理,如:

public void Do()
{
    if (用户未登录) { throw new System.Exception("请登录后再试"); }
    _ue.DoAction(HttpContext);
}


如果图片仅仅上传到网站目录下,那么这样配置就结束了,如果要上传到阿里云 OSS 等第三方图床,那么继续往下看。


因 UEditorNetCore 虽然实现了上传到 FTP 和 OSS 的功能,但未提供配置相关的账号信息的途径,所以只能(1)重写 action,或(2)下载 github 的源代码,将核心项目加入到您的项目中进行修改。

重写 action 不方便后期维护,这里记录修改源码的方式。

将源码改造为可配置账号的上传到 OSS 的功能,具体步骤如下:

  1. 将 Consts.cs 从项目中排除。

  2. 打开 Handlers/UploadHandler.cs,找到 UploadConfig 类,将

    FtpUpload 改为 OssUpload,

    FtpAccount 改为 OssAccessKeyId,

    FtpPwd 改为 OssAccessKeySecret,

    FtpIp 改为 OssAccessEndpoint,

    再添加一个属性 OssBucketName。

  3. 打开 Handlers/UploadHandler.cs,找到 Process() 方法, 

    将 UploadConfig.FtpUpload 改为 UploadConfig.OssUpload,

    将 Consts.AliyunOssServer.* 改为 UploadConfig.Oss*。

  4. 打开 Handlers/CrawlerHandler.cs,找到 Fetch() 方法,

    将 Config.GetValue<bool>("catcherFtpUpload") 改为 Config.GetValue<bool>("OssUpload"),

    将 Consts.AliyunOssServer.* 改为 Config.GetString("Oss*")。

  5. 打开 UEditorActionCollection.cs,找到 UploadImageAction,将

    FtpUpload = Config.GetValue<bool>("imageFtpUpload"),
    FtpAccount = Consts.ImgFtpServer.account,
    FtpPwd = Consts.ImgFtpServer.pwd,
    FtpIp = Consts.ImgFtpServer.ip,

    替换为

    OssUpload = Config.GetValue<bool>("OssUpload"),
    OssAccessKeyId = Config.GetString("OssAccessKeyId"),
    OssAccessKeySecret = Config.GetString("OssAccessKeySecret"),
    OssAccessEndpoint = Config.GetString("OssAccessEndpoint"),
    OssBucketName = Config.GetString("OssBucketName"),

    其余 3 个 Action(UploadScrawlAction、UploadVideoAction、UploadFileAction)按同样的方式修改。

    在所有创建 UploadHandler 对象时补充添加 SaveAbsolutePath 属性。

  6. 打开 config.json,添加相关配置项(注:配置文件中的 *FtpUpload 全部废弃,统一由 OssUpload 决定)

    "OssUpload": true,
    "OssAccessEndpoint": "",
    "OssAccessKeyId": "",
    "OssAccessKeySecret": "",
    "OssBucketName": "",

    将 xxxUrlPrefix 的值改为 OSS 对应的 CDN 网址(以 / 结尾,如://cdn.xoyozo.net/)。


其它注意点:

  • 若使用 UEditorNetCore github 提供的源代码类库代替 nuget,且使用本地存储,那么需要将 Handlers 目录中与定义 savePath 相关的代码(查找  var savePath)替换成被注释的行

xoyozo 5 年前
6,681

纯真 IP 数据库官方下载地址:http://www.cz88.net/

下载安装纯真 IP,将 qqwry.dat 文件复制到项目下。(本文以放在 /App_Data/ 目录下为例)

在 qqwry.dat 上右键打开属性窗口,将“复制到输出目录”切换到“始终复制”或“如果较新则复制”。

通过 nuget 安装 QQWry,喜欢依赖注入方式的可以选择 QQWry.DependencyInjectio。

var config = new QQWryOptions
{
    DbPath = dbPath ?? (AppContext.BaseDirectory + @"App_Data\qqwry.dat")
};

var ipSearch = new QQWryIpSearch(config);

var ipl = ipSearch.GetIpLocation(ip);

return new IpLocation
{
    Ip = ipl.Ip,
    Country = ipl.Country?.Replace("CZ88.NET", "").Trim(),
    Area = ipl.Area?.Replace("CZ88.NET", "").Trim(),
};

github 开源地址:https://github.com/JadynWong/IP_qqwry


xoyozo 5 年前
3,994

本文使用 Oracle 官方提供的 MySql.Data.EntityFrameworkCore,如使用 Pomelo.EntityFrameworkCore.MySql 请移步

对比 MySql.Data.EntityFrameworkCore 与 Pomelo.EntityFrameworkCore.MySql

在 ASP.NET Core 5.0 中使用 MySql.EntityFrameworkCore


本文以 Visual Studio 2019、ASP.NET Core 3.1 开发环境为例。

  1. 新建 ASP.NET Core Web 应用程序。

  2. 安装 NuGet 包:

    MySql.Data.EntityFrameworkCore

    Microsoft.EntityFrameworkCore.Design

    image.png

    如果使用 EF Core 2.0 还需安装:Microsoft.EntityFrameworkCore.Tools

  3. 根据已有数据库创建数据模型。在 NuGet 的程序包管理(Package Manager)控制台中(PowerShell)执行命令:

    Scaffold-DbContext "server=数据库服务器;port=3306;user=数据库用户名;password=数据库密码;database=数据库名" MySql.Data.EntityFrameworkCore -OutputDir Data -f

    .Net Core CLi:

    dotnet ef dbcontext scaffold "server=数据库服务器;port=3306;user=数据库用户名;password=数据库密码;database=数据库名" MySql.Data.EntityFrameworkCore -o Data -f
  4. 搞定。


注:开发环境和生产环境都不需要安装 Connector/NET,只需要安装 ASP.NET Core。

补充:其它数据库提供程序请参考:https://docs.microsoft.com/zh-cn/ef/core/providers/

更多高级用法请参考官方文档

xoyozo 5 年前
3,859

image.png

Unify Template 提供三种文件上传样式(如上图),“Plain File Input”和“File input”使用传统 <form /> 提交,“Advanced File input”调用组件实现。


ASP.NET Core 实现传统 <form /> 提交(以“Plain File Input”为例):

<form class="g-brd-around g-brd-gray-light-v4 g-pa-30 g-mb-30" id="form_avatar_upload" asp-action="AvatarUpload" enctype="multipart/form-data" method="post">
    <!-- Plain File Input -->
    <div class="form-group mb-0">
        <p>Plain File Input</p>
        <label class="u-file-attach-v2 g-color-gray-dark-v5 mb-0">
            <input id="fileAttachment" name="Avatar" type="file" onchange="form_avatar_upload.submit()">
            <i class="icon-cloud-upload g-font-size-16 g-pos-rel g-top-2 g-mr-5"></i>
            <span class="js-value">Attach file</span>
        </label>
    </div>
    <!-- End Plain File Input -->
</form>
public class AvatarUploadModel
{
    public IFormFile Avatar { get; set; }
}

[HttpPost]
public IActionResult AvatarUpload(AvatarUploadModel Item)
{
    return RedirectToAction("");
}


ASP.NET Core 调用 HSFileAttachment 组件实现:

<div class="form-group mb-20">
    <label class="g-mb-10">上传作品文件(包)</label>
    <input class="js-file-attachment_project" type="file" name="" id="file_project">
    <div style="display: none;" id="file_project_tip">
        <div class="u-file-attach-v3 g-mb-15" id="file_project_tip_content">
            <h3 class="g-font-size-16 g-color-gray-dark-v2 mb-0">拖曳文件到此处或者 <span class="g-color-primary">浏览你的电脑</span></h3>
            <p class="g-font-size-14 g-color-gray-light-v2 mb-0">
                如果您的作品包含多个文件,请添加到压缩包再上传
            </p>
            <p class="g-font-size-14 g-color-gray-light-v2 mb-0">
                支持的文件格式:
                <code>zip</code>
                <code>rar</code>
                <code>7z</code>
                <code>psd</code>
                <code>ai</code>
                <code>cdr</code>
                <code>jpg</code>
                <code>png</code>
                <code>gif</code>
                <code>tif</code>
                <code>webp</code>
            </p>
            <p class="g-font-size-14 g-color-gray-light-v2 mb-0">文件(包)的大小不能超过 <span>@options.Value.MaxSizeOfSigleFile_MB</span> MB</p>
        </div>
    </div>
    <small class="form-control-feedback">请上传作品文件</small>
</div>

<!-- JS Implementing Plugins -->
<script src="//cdn.***.com/unify/unify-v2.6.2/html/assets/vendor/jquery.filer/js/jquery.filer.min.js"></script>
<!-- JS Unify -->
<script src="//cdn.***.com/unify/unify-v2.6.2/html/assets/js/helpers/hs.focus-state.js"></script>
<script src="//cdn.***.com/unify/unify-v2.6.2/html/assets/js/components/hs.file-attachement.js"></script>
<!-- JS Plugins Init. -->
<script>
    $(document).on('ready', function () {
        // initialization of forms
        $.HSCore.components.HSFileAttachment.init('.js-file-attachment_project', {
            changeInput: $('#file_project_tip').html(),
            uploadFile: {
                url: url_UploadFile,
                data: { type: 'project' },
                success: function (data, element) {
                    console.log(data);

                    if (!data.success) {
                        var parent = element.find(".u-progress-bar-v1").parent();
                        element.find(".u-progress-bar-v1").fadeOut("slow", function () {
                            $("<div class=\"text-error g-px-10\"><i class=\"fa fa-minus-circle\"></i> Error</div>").hide().appendTo(parent).fadeIn("slow");
                        });

                        alert(data.err_msg);
                    } else {
                        var parent = element.find(".u-progress-bar-v1").parent();
                        element.find(".u-progress-bar-v1").fadeOut("slow", function () {
                            $("<div class=\"text-success g-px-10\"><i class=\"fa fa-check-circle\"></i> Success</div>").hide().appendTo(parent).fadeIn("slow");
                        });

                        $('#file_project_tip_content').slideUp();

                        upload_project_id = data.id;
                    }
                }
            }
        });
        $.HSCore.helpers.HSFocusState.init();
    });
</script>
public IActionResult UploadFile([FromForm(Name = "[]")]IFormFile file, string type)
{
    return Ok(new { id = 1 });
}


xoyozo 5 年前
3,793