博客 (168)

编译器错误消息: CS0012: The type '***' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.

错误CS0012类型“***”在未引用的程序集中定义。必须添加对程序集“netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51”的引用。

解决方法:

打开 Web.config,在 <system.web /> 的 <compilation /> 中添加 <assemblies><add>,如:

<compilation debug="true" targetFramework="4.8">
  <assemblies>
    <add assembly="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"/>
  </assemblies>
</compilation>

缺少其它 assembly 的参照上面添加。

xoyozo 5 年前
6,107

对于不同场景下 WebP 的使用,我们总结了一些解决方案,如下:

 1、若使用场景是浏览器,可以:

JavaScript 能力检测,对支持 WebP 的用户输出 WebP 图片(https://developers.google.com/speed/webp/faq#how_can_i_detect_browser_support_for_webp

使用 WebP 支持插件:WebPJS:http://webpjs.appspot.com,下载 webpjs-0.0.2.min.js


 2、若使用场景是 App,可以:

Android 4.0 以下 WebP 解析库(https://github.com/alexey-pelykh/webp-android-backport

iOS WebP 解析库(https://github.com/carsonmcdonald/WebP-iOS-example


 3、转换工具:

智图(http://zhitu.tencent.com

iSparta(http://isparta.github.io/



阿里云 OSS 格式转换:https://help.aliyun.com/document_detail/44703.html

腾讯云数据万象格式转换:https://cloud.tencent.com/document/product/460/36543

七牛:https://developer.qiniu.com/dora/api/1279/basic-processing-images-imageview2


x
转自 xiangzhihong 5 年前
4,629

本教程教你如何升级 ASP.NET 项目中的 MySql.Data 和服务器安装的 Connector/NET 版本至 8.0.18。


使用 MySQL Application Configuration 升级 MySql.Data

双击打开 .edmx 文件后,解决方案资源管理器上会有 MySQL Application Configuration 的图标。(如果没有,点开“从数据库更新模型”一下即可)

image.png

勾选“Use MySQL with Entity Framework”,安装完成。

image.png

完成后发现,Nuget 中会自动安装或升级下面两个组件:

MySql.Data  8.0.18

MySql.Data.EntityFramework  8.0.18

并且在 Web.config 中会自动添加以下节点:

<system.data>
  <DbProviderFactories>
    <remove invariant="MySql.Data.MySqlClient" />
    <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=8.0.18, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
  </DbProviderFactories>
</system.data>

这段代码使 MySql.Data 8.0.18 的项目能够兼容运行在 Connector/NET 6.10.x 环境中。方便我们挨个升级服务器上的项目。


8.0.18 已经不再需要 MySql.Data.Entity 组件了,可以从 Nuget 中手动卸载。

xoyozo 5 年前
5,543

在数据库连接字符串可设置是否将 tinyint(1) 映射为 bool,否则为 sbyte:

TreatTinyAsBoolean=false/true

tinyint(1) 一般用于表示 bool 型字段,存储内容为 0 或 1,但有时候也用来存储其它数字。

以 Discuz! 的表 pre_forum_post 为例,字段 first 和 invisible 都是 tinyint(1),但 first 只储存 0 和 1,invisible 却有 -1、-5 之类的值。

因此我们一般设置 TreatTinyAsBoolean=false,程序中 first 与 invisible 均以 sbyte 处理。


设置 TreatTinyAsBoolean=true 后,EF 或 EF Core 自动将该类型映射为 bool,方便在程序中作进一步处理。

一旦设置 TreatTinyAsBoolean=true,那么所有查询结果中 tinyint(1) 字段的返回值永远只有 1 和 0(即 True/False),即使真实值为 -1,也返回 1。

因为我们必须在确保所有的 tinyint(1) 类型字段都仅表示布尔值是才设置 TreatTinyAsBoolean=true。

一旦部分 tinyint(1) 类型字段用于存放 0 和 1 以外的数,那么就应该设置 TreatTinyAsBoolean=false。


在数据库优先的项目中,以 TreatTinyAsBoolean=false 生成数据模型后,可将明确为布尔类型的字段改为 bool。列出 MySQL 数据库中所有表所有字段中类型为 tinyint(1) 的字段值


以 .edmx 为例:

在项目中搜索该字段名,在搜索结果中找到 .edmx 文件中的两处。

.edmx 文件中的注释已经表明其包含 SSDL、CSDL、C-S mapping 三块内容,

在 SSDL content 下方找到该字段:

<Property Name="字段名" Type="tinyint" Nullable="***" />

改为

<Property Name="字段名" Type="bool" Nullable="***" />


在 CSDL content 下方找到该属性:

<Property Name="属性名" Type="SByte" Nullable="***" />

改为

<Property Name="属性名" Type="Boolean" Nullable="***" />

在解决方案管理器中展开 .edmx ->库名.tt -> 表名.cs 文件,

将模型类中的属性

public sbyte invisible { get; set; }

改为

public bool invisible { get; set; }

或 sbyte? 改为 bool?。


在 EF Core 中,直接打开对应数据表的 .cs 文件,更改属性类型即可。


相关报错:

错误: 指定的成员映射无效。类型中的成员的类型“Edm.SByte[Nullable=False,DefaultValue=]”与类型中的成员的“MySql.bool[Nullable=False,DefaultValue=]”不兼容。

InvalidOperationException: The property '***' is of type 'sbyte' which is not supported by the current database provider. Either change the property CLR type, or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

尝试先连接一次能解决此问题(概率),非常的莫名其妙:

using Data.Discuz.db_bbs2021Context dbd = new();
var conn = dbd.Database.GetDbConnection();
conn.Open();
conn.Close();


参考:

https://mysqlconnector.net/connection-options/

https://stackoverflow.com/questions/6656511/treat-tiny-as-boolean-and-entity-framework-4


2023年1月注:本文适用于 Pomelo.EntityFrameworkCore.MySql 6.0,升级到 7.0 后会出现:

System.InvalidOperationException:“The 'sbyte' property could not be mapped to the database type 'tinyint(1)' because the database provider does not support mapping 'sbyte' properties to 'tinyint(1)' columns. Consider mapping to a different database type or converting the property value to a type supported by the database using a value converter. See https://aka.ms/efcore-docs-value-converters for more information. Alternately, exclude the property from the model using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.”

解决方法:https://xoyozo.net/Blog/Details/the-sbyte-property-could-not-be-mapped-to-the-database-type-tinyint-1

xoyozo 5 年前
6,592

Nuget 安装:X.PagedList.Mvc.Core


控制器:

using X.PagedList;

public IActionResult Index(int page = 1)
{
    ……
    return View(q.ToPagedList(page, size));
}


视图:

@using X.PagedList
@using X.PagedList.Mvc.Core
@model IPagedList<xxx>

@Html.PagedListPager(Model, page => Url.Action("Index", new { page }))


自定义(options 默认值):

@Html.PagedListPager(
    Model, 
    page => Url.Action("Index", new { page }), 
    new X.PagedList.Mvc.Common.PagedListRenderOptionsBase
    {
        HtmlEncoder = HtmlEncoder.get_Default(),
        DisplayLinkToFirstPage = PagedListDisplayMode.IfNeeded,
        DisplayLinkToLastPage = PagedListDisplayMode.IfNeeded,
        DisplayLinkToPreviousPage = PagedListDisplayMode.IfNeeded,
        DisplayLinkToNextPage = PagedListDisplayMode.IfNeeded,
        DisplayLinkToIndividualPages = true,
        DisplayPageCountAndCurrentLocation = false, // 显示总页数和当前页码
        MaximumPageNumbersToDisplay = 10, // 最多显示页码数
        DisplayEllipsesWhenNotShowingAllPageNumbers = true,
        EllipsesFormat = "&#8230;",
        LinkToFirstPageFormat = "<<",
        LinkToPreviousPageFormat = "<",
        LinkToIndividualPageFormat = "{0}",
        LinkToNextPageFormat = ">",
        LinkToLastPageFormat = ">>",
        PageCountAndCurrentLocationFormat = "Page {0} of {1}.",
        ItemSliceAndTotalFormat = "Showing items {0} through {1} of {2}.",
        FunctionToDisplayEachPageNumber = null,
        ClassToApplyToFirstListItemInPager = null,
        ClassToApplyToLastListItemInPager = null,
        ContainerDivClasses = new string[1]
        {
            "pagination-container"
        },
        UlElementClasses = new string[1]
        {
            "pagination"
        },
        LiElementClasses = Enumerable.Empty<string>(),
        PageClasses = Enumerable.Empty<string>(),
        UlElementattributes = null,
        ActiveLiElementClass = "active",
        EllipsesElementClass = "PagedList-ellipses",
        PreviousElementClass = "PagedList-skipToPrevious",
        NextElementClass = "PagedList-skipToNext",
    })


保留地址栏参数:

@{ 
    string query = Context.Request.QueryString.Value;
}
@Html.PagedListPager(Model, page => Regex.IsMatch(query, @"[?&]page=\d+")
    ? Regex.Replace(query, @"([?&])page=\d+", $"$1page={page}")
    : (query.StartsWith("?") ? $"{query}&page={page}" : $"{query}?page={page}"),
    new X.PagedList.Web.Common.PagedListRenderOptionsBase
    {
        DisplayPageCountAndCurrentLocation = true,
        MaximumPageNumbersToDisplay = 5,
    })

这里从查询字符串中判断并替换 page 值,如果有更简单的方法敬请告知。比如 Webdiyer 的分页组件会自动携带所有参数。


更多使用方式参官方文档:https://github.com/dncuug/X.PagedList


附应用于 Unify Template(一款基于 Bootstrap 的 HTML 模板)中的配置:

<style>
    .u-pagination-v1-1--active .u-pagination-v1-1 { color: #fff; border-color: #72c02c; }
    .PagedList-pageCountAndLocation { float: right !important; }
</style>
@{
    string query = Context.Request.QueryString.Value;
}
@Html.PagedListPager(Model, page => Regex.IsMatch(query, @"[?&]page=\d+")
    ? Regex.Replace(query, @"([?&])page=\d+", $"$1page={page}")
    : (query.StartsWith("?") ? $"{query}&page={page}" : $"{query}?page={page}"),
    new X.PagedList.Web.Common.PagedListRenderOptionsBase
    {
        DisplayPageCountAndCurrentLocation = true,
        MaximumPageNumbersToDisplay = 5,
        UlElementClasses = new string[] { "list-inline" },
        LiElementClasses = new string[] { "list-inline-item" },
        PageClasses = new string[] { "u-pagination-v1__item", "u-pagination-v1-1", "g-pa-7-14" },
        ActiveLiElementClass = "u-pagination-v1-1--active",
        EllipsesElementClass = "g-pa-7-14",
    })


xoyozo 5 年前
9,661

安装 Nuget 包:

BuildBundlerMinifier


项目根目录创建绑定配置文件:bundleconfig.json

示例:

[
  {
    "outputFileName": "wwwroot/css/site.min.css",
    "inputFiles": [
      "wwwroot/css/site.css",
      "wwwroot/css/custom.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/site.min.js",
    "inputFiles": [
      "wwwroot/js/site.js"
    ],
    "minify": {
      "enabled": true,
      "renameLocals": true
    },
    "sourceMap": false
  }
]

配置文件中所有路径都相对于项目根目录(而非静态文件根目录 wwwroot),因此配置的路径都要以“wwwroot”开头。

outputFileName 是压缩合并后的文件,inputFiles 是被压缩合并的原始文件集合。

对于 js 配置部分,minify.enabled 配置是否缩小,renameLocals 配置是否修改变量名,sourceMap 配置是否生成 map 映射文件。


引用示例:

<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />

asp-append-version 表示是否在引用路径添加版本参数,可实现在文件有修改时及时在客户端浏览器中生效。


* 注意:有时候“生成”不一定生效,“重新生成”肯定会生效。


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

xoyozo 5 年前
6,062

ASP.NET Core 缓存 Caching 提供了包括但不限于以下几种存储方式:

内存缓存:https://xoyozo.net/Blog/Details/aspnetcore-memory-cache

SQL Server 缓存:https://xoyozo.net/Blog/Details/aspnetcore-sql-cache

Redis 缓存:https://xoyozo.net/Blog/Details/aspnetcore-redis-cache

MySQL 缓存:https://xoyozo.net/Blog/Details/aspnetcore-mysql-cache


Nuget 安装:Microsoft.Extensions.Caching.SqlServer

执行 .NET Core CLI 命令,在数据库中创建表“TestCache”

dotnet sql-cache create "数据库连接字符串" dbo TestCache

若提示

找不到 "dotnet sql-cache" 命令,请运行以下命令进行安装

则运行

dotnet tool install --global dotnet-sql-cache

表和索引创建成功提示:

Table and index were created successfully.

表结构:

image.png

在 Startup.cs 文件的方法 ConfigureServices() 中添加:

services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = "数据库连接字符串";
    options.SchemaName = "dbo";
    options.TableName = "TestCache";
});

在控制器中注入 IDistributedCache:

public class TestController : Controller
{
    private readonly IDistributedCache cache;

    public TestController(IDistributedCache cache)
    {
        this.cache = cache;
    }

    public IActionResult Index()
    {
        string k = "count";
        int v = Convert.ToInt32(cache.GetString(k));
        v++;
        cache.SetString(k, v.ToString());
        return Content(v.ToString());
    }
}

结果:

image.png

更多用法详见官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/distributed?view=aspnetcore-3.0


若要实现将 Session 保存至 SQL Server 中,参此文:https://xoyozo.net/Blog/Details/aspnetcore-session-sql

xoyozo 5 年前
6,181

ASP.NET Core 缓存 Caching 提供了包括但不限于以下几种存储方式:

内存缓存:https://xoyozo.net/Blog/Details/aspnetcore-memory-cache

SQL Server 缓存:https://xoyozo.net/Blog/Details/aspnetcore-sql-cache

Redis 缓存:https://xoyozo.net/Blog/Details/aspnetcore-redis-cache

MySQL 缓存:https://xoyozo.net/Blog/Details/aspnetcore-mysql-cache


Nuget 安装:Microsoft.Extensions.Caching.StackExchangeRedis

在 Startup.cs 文件的方法 ConfigureServices() 中添加:

services.AddStackExchangeRedisCache(options =>
{
    // 连接字符串
    options.Configuration = "192.168.111.134,password=aW1HAyupRKmiZn3Q";
    // 键名前缀
    options.InstanceName = "xoyozo_";
});

在控制器中注入 IDistributedCache:

public class TestController : Controller
{
    private readonly IDistributedCache cache;

    public TestController(IDistributedCache cache)
    {
        this.cache = cache;
    }

    public IActionResult Index()
    {
        string k = "count";
        int v = Convert.ToInt32(cache.GetString(k));
        v++;
        cache.SetString(k, v.ToString());
        return Content(v.ToString());
    }
}

结果:

image.png

更多用法详见官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/distributed?view=aspnetcore-3.0


注:.NET 6 已不支持 Redis on Windows 3.0。


经过以上配置,Session 也会保存到 Redis 中,键名是 前缀_Guid 格式。

关于 Session,参此文:https://xoyozo.net/Blog/Details/aspnetcore-session-redis

xoyozo 5 年前
5,691

ASP.NET Core 缓存 Caching 提供了包括但不限于以下几种存储方式:

内存缓存:https://xoyozo.net/Blog/Details/aspnetcore-memory-cache

SQL Server 缓存:https://xoyozo.net/Blog/Details/aspnetcore-sql-cache

Redis 缓存:https://xoyozo.net/Blog/Details/aspnetcore-redis-cache

MySQL 缓存:https://xoyozo.net/Blog/Details/aspnetcore-mysql-cache


本文介绍内存缓存

Memory Caching

1.新建一个 ASP.NET Core 项目,选择 Web 应用程序,将身份验证 改为 不进行身份验证。

2.添加引用

Install-Package Microsoft.Extensions.Caching.Memory

3.使用

在 Startup.cs 中 ConfigureServices

public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
    // Add framework services.
    services.AddMvc();
}

然后在

public class HomeController : Controller
{
    private IMemoryCache _memoryCache;
    public HomeController(IMemoryCache memoryCache)
    {
        _memoryCache = memoryCache;
    }

    public IActionResult Index()
    {
        string cacheKey = "key";
        string result;
        if (!_memoryCache.TryGetValue(cacheKey, out result))
        {
            result = $"LineZero{DateTime.Now}";
            _memoryCache.Set(cacheKey, result);
        }
        ViewBag.Cache = result;
        return View();
    }
}

这里是简单使用,直接设置缓存。

我们还可以加上过期时间,以及移除缓存,还可以在移除时回掉方法。

过期时间支持相对和绝对。

下面是详细的各种用法。

public IActionResult Index()
{
    string cacheKey = "key";
    string result;
    if (!_memoryCache.TryGetValue(cacheKey, out result))
    {
        result = $"LineZero{DateTime.Now}";
        _memoryCache.Set(cacheKey, result);
        //设置相对过期时间2分钟
        _memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
            .SetSlidingExpiration(TimeSpan.FromMinutes(2)));
        //设置绝对过期时间2分钟
        _memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
            .SetAbsoluteExpiration(TimeSpan.FromMinutes(2)));
        //移除缓存
        _memoryCache.Remove(cacheKey);
        //缓存优先级 (程序压力大时,会根据优先级自动回收)
        _memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
            .SetPriority(CacheItemPriority.NeverRemove));
        //缓存回调 10秒过期会回调
        _memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
            .SetAbsoluteExpiration(TimeSpan.FromSeconds(10))
            .RegisterPostEvictionCallback((key, value, reason, substate) =>
            {
                Console.WriteLine($"键{key}值{value}改变,因为{reason}");
            }));
        //缓存回调 根据Token过期
        var cts = new CancellationTokenSource();
        _memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
            .AddExpirationToken(new CancellationChangeToken(cts.Token))
            .RegisterPostEvictionCallback((key, value, reason, substate) =>
            {
                Console.WriteLine($"键{key}值{value}改变,因为{reason}");
            }));
        cts.Cancel();
    }
    ViewBag.Cache = result;
    return View();
}


Distributed Cache Tag Helper

在 ASP.NET Core MVC 中有一个 Distributed Cache 我们可以使用。

我们直接在页面上增加 distributed-cache 标签即可。

<distributed-cache name="mycache" expires-after="TimeSpan.FromSeconds(10)">
    <p>缓存项10秒过期-LineZero</p>
    @DateTime.Now
</distributed-cache>
<distributed-cache name="mycachenew" expires-sliding="TimeSpan.FromSeconds(10)">
    <p>缓存项有人访问就不会过期,无人访问10秒过期-LineZero</p>
    @DateTime.Now
</distributed-cache>

这样就能缓存标签内的内容。


L
转自 LineZero 5 年前
7,490

image.png

使用 myssl.com 检测证书状态,显示握手失败(No FS No SNI):

image.png

发现 XP 上的 IE6 和 IE8 均无法访问该站点,原因是 XP 不支持 FS,不支持 SNI。

可以尝试在 IIS 的站点的“绑定”中更改“需要服务器名称指示”来实现正常访问。

步骤参阅:https://xoyozo.net/Blog/Details/wxpay-notify-url-https

当然,前提是服务器上必须已启用相关的协议版本和加密方式(按需启用),建议使用 IISCrypto

image.png

xoyozo 5 年前
7,013