头像

.Net 中Json序列化实体时忽略部分属性

接口对接中,返回的实体想要部分字段不被序列化返回。以前的做法是新建一个类做深拷贝,后来发现这方法不是很友好。

找了个不错的方法如下:

using Newtonsoft.Json;
namespace Actuator.Contacts
{
[JsonObject(MemberSerialization.OptIn)]
class ZJ
{
[JsonProperty]
public string seqid; //Varchar(50) 每条记录的时间戳标识,精确到毫秒
[JsonProperty]
public string code; //Varchar(200)设备号(终端 SN 号)
[JsonProperty]
public string pileCode;// Varchar(50) 桩编号由施工现场定义,一般为桩号

[JsonProperty]
public int isResultData = 1; // Int 是否为施工结果数据 1是,0否

[JsonIgnoreAttribute]
public int KeyId { get; set; }

}
}

附带解释
JsonObjectAttribute
这个标签的成员序列化标志指定成员序列化是opt-in(要序列化的成员必须带有JsonProperty或DataMember标签)还是opt-out(默认所有的都会序列化,但通过JsonIgnoreAttribute标签可以忽略序列化。opt-out是json.net默认的)。

JsonPropertyAttribute
允许被序列化的成员自定义名字。这个标签同时标示出:在成员序列化设置为opt-in的时候,成员会被序列化。

JsonIgnoreAttribute
忽略域或属性的序列化

JsonConverterAttribute
用于指派转换对象的JsonSerializer。
这个标签可以修饰类或类成员。用于修饰类时,通过此标签指派的JsonConverter会被设置为序列化类的默认方式。用于修饰属性或域成员时,被指派的JsonConverter会序列化它们的值

[XmlIgnore]
忽略xml 序列化

头像

‘OFFSET’ 附近有语法错误。 在 FETCH 语句中选项 NEXT 的用法无效。

原因:可能因为本地开发环境的数据库版本高于服务器版本,导致 EF 生成了错误的 SQL 语句

解决:找到 EF 对应生成的 edmx 文件,选中右键-打开方式-使用 XML 文本编辑器 打开编辑,找到“ProviderManifestToken”这一属性, EF 此属性值为 2012,而服务器中是 2008 版本的SQLServer数据库,所以将此属性值修改为 2008 即可。

头像

C# AES加密与慕课的JAVA AES对称加解密代码分享

以下是C#版本代码:

///<summary>

    /// DES加密、解密帮助类

    /// </summary>

    ///

    public class MoocAESEncrypt

    {

        private static char[] BcdLookup = { ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’ };

        

        #region AES加密

        /// <summary>

        /// AES加密

        /// </summary>

        /// <param name=”toEncrypt“>要加密的内容</param>

        /// <param name=”strKey“>密钥(16或者32位)</param>

        /// <returns>Base64转码后的密文</returns>

        public static string Encrypt(string toEncrypt, string strKey)

        {

            byte[] keyArray = HexStrToBytes(strKey);

            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

            RijndaelManaged rDel = new RijndaelManaged();//using System.Security.Cryptography;    

            rDel.Key = keyArray;

            rDel.Mode = CipherMode.ECB;//using System.Security.Cryptography;    

            rDel.Padding = PaddingMode.PKCS7;//using System.Security.Cryptography;                

            ICryptoTransform cTransform = rDel.CreateEncryptor();//using System.Security.Cryptography;    

            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            return BytesToHexStr(resultArray);                                          //返回十六进制数据; 

        }

        #endregion AES加密

        #region AES解密

        /// <summary>

        /// AES解密

        /// </summary>

        /// <param name=”toDecrypt“>要解密的内容</param>

        /// <param name=”strKey“>密钥(16或者32位)</param>

        /// <returns>解密后的明文</returns>

        public static string Decrypt(string toDecrypt, string strKey)

        {

            byte[] keyArray = HexStrToBytes(strKey);

            byte[] toEncryptArray = HexStrToBytes(toDecrypt);                   //16进制to byte[];

            RijndaelManaged rDel = new RijndaelManaged();

            rDel.Key = keyArray;

            rDel.Mode = CipherMode.ECB;

            rDel.Padding = PaddingMode.PKCS7;

            ICryptoTransform cTransform = rDel.CreateDecryptor();

            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            return UTF8Encoding.UTF8.GetString(resultArray);

        }

        #endregion AES解密

        

        #region 转码

        /**

         * 将16进制字符串还原为字节数组.

         */

        public static byte[] HexStrToBytes(string s)

        {

            byte[] bytes;

            bytes = new byte[s.Length / 2];

            for (int i = 0; i < bytes.Length; i++)

            {

                bytes[i] = (byte)Convert.ToInt32(s.Substring(2 * i,2),16);

            }

            return bytes;

        }

        /**

         * 将字节数组转换为16进制字符串的形式.

         */

        public static string BytesToHexStr(byte[] bcd)

        {

            StringBuilder s = new StringBuilder(bcd.Length * 2);

            for (int i = 0; i < bcd.Length; i++)

            {

                s.Append(BcdLookup[(bcd[i] >> 4) & 0x0f]);

                s.Append(BcdLookup[bcd[i] & 0x0f]);

            }

            return s.ToString();

        }

        #endregion

    }

头像

在Visual Studio 2019中修改项目名的方法

1.需求场景

场景一:开始创建项目时,瞎起了一个名字,等后面开发了一部分功能后突然想改名。

场景二:想从一个老项目的基础上开发一个新项目。

2.操作步骤

2.1 重命名解决方案

【解决方案】右键选择【重命名】,将OldSlnName重命名为NewSlnName

2.2 重命名项目名

【项目(OldProject)】右键选择【重命名】,将OldProject重命名为NewProject

2.3 修改程序集名称及命名空间

【项目(NewProject)】右键选择【属性】

2.4 全局替换项目名

在整个解决方案下搜索【旧项目名(OldProject)】,将其替换为【新项目名(NewProject)】

2.5 修改项目文件夹名称

关闭Visual Studio;

在文件管理器中找到项目文件夹,将【旧项目文件夹名(OldProject)】修改为【新项目文件夹名(NewProject)】

2.6 修改.sln文件

在项目文件夹下找到对应.sln文件,用文本编辑器打开;

将文件中的旧项目名称修改为新项目名称

修改完毕。

头像

ASP.Net Core 运行错误 Http Error 502.5 解决办法

这个一般是本地的.NET Core SDK版本不统一报错造成的。

解决思路

首先你要去找你的IIS报错日志,得到的错误代码 ErrorCode = '0x80004005 : 8000808c.是这个的话,那就可以通过我说的办法来解决了。

第一种

通过直接修改web.config 的文件。

web配置
 <aspNetCore processPath="dotnet" arguments=".\LTM.School.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />

processPath="dotnet"改成你安装的.NET CORE SDK路径,一般默认在”C:\Program Files\dotnet\dotnet.exe”路径下,替换下就可以解决了。这种一般是常规加临时解决方案,不稳定。

第二种

下载对应版本的SDK地址:https://www.microsoft.com/net/download/archives

img_bceee70c5a52bbd3a7ba6547fa8345dd.png

找到对应的大版本,然后里面有具体的版本信息。但是有个问题,你如果已经装了高版本的SDK,是无法安装低版本的SDK的,所以也不推荐这个办法。

 

在错误页面提供的连接中,找到个升级运行时的页面,下载文件“DotNetCore.1.0.4_1.1.1-WindowsHosting.exe” ,安装完成之后,重启 IIS7 站点,运行成功。

以上所述解决办法是:

在“https://www.microsoft.com/net/download/core#/runtime”页面下载文件“DotNetCore.1.0.4_1.1.1-WindowsHosting.exe”,安装后就可以了。

如果不是上面的问题的话,那就是更新程序没完全更新,可以尝试将发布后的文件除配置文件和root下的文件之外 全部覆盖。

 

头像

在C#中生成与PHP一样的MD5 Hash Code

最近在对一个现有的系统进行C#改造,该系统以前是用PHP做的,后台的管理员登陆用的是MD5加密算法。在PHP中,要对一个字符串进行MD5加密非常简单,一行代码即可:

md5("Something you want to encrypt.")

直接调用md5()方法,然后将要进行MD5加密的字符串传进去,就可以得到返回的hash code。在C#中应该也会有对应的算法吧!对吗?我首先尝试了下面的代码,结果得到的hash code和PHP不一样。

public static string MD5(string stringToHash)
{
    return FormsAuthentication.HashPasswordForStoringInConfigFile(stringToHash, "md5");
}

所以,我们不得不借用C#的MD5CryptoServiceProvider对象自己写代码进行转换。

1. 实例化MD5CryptoServiceProvider对象

2. 将字符串转换成byte数组

3. 使用MD5CryptoServiceProvider对象的ComputeHash()方法将byte数组进行加密,返回转换后的byte数组

4. 在讲byte数组转换成字符串之前,还需要对其进行遍历并做如下转换:

myByte.ToString("x2").ToLower()

然后,你才能得到和PHP中一样的MD5 hash code。为什么在.NET中要这么麻烦,或许这也是为什么那么多的开发人员仍然热衷于PHP开发的理由之一,每一门编程语言都有它自身的魅力,也都有它存在的意义!

基于上面的讨论,完整的代码如下:

public static string MD5ForPHP(string stringToHash)
{
    var md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
    byte[] emailBytes = Encoding.UTF8.GetBytes(stringToHash.ToLower());
    byte[] hashedEmailBytes = md5.ComputeHash(emailBytes);
    StringBuilder sb = new StringBuilder();
    foreach (var b in hashedEmailBytes)
    {
        sb.Append(b.ToString("x2").ToLower());
    }
    return sb.ToString();
}

或者,你也可以把上面的方法写成一个C#扩展方法,只需要修改方法签名即可。

public static string MD5ForPHP(this String, string stringToHash)
{
    // Your code here.
}

PHP程序和C#程序在许多方面都会涉及到格式之间的转换,如果运行PHP的服务器是UNIX类型的,则还会存在日期格式之间的转换。下面的两个方法展示了如何将UNIX时间转换成C# DateTime以及如何将C# DateTime转换成UNIX时间。

public static DateTime UnixTimeStampToDateTime(long unixTimeStamp)
{
    // Unix timestamp is seconds past epoch
    DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
    return dtDateTime.AddSeconds(unixTimeStamp);
}

public static long DateTimeToUnixTimeStamp(DateTime datetime)
{
    TimeSpan span = (datetime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc));
    return (long)span.TotalSeconds;
}
头像

无法序列化会话状态。在“StateServer”或“SQLServer”模式下,ASP.NET 将序列化

开发asp.net应用时,修改web.config中的SessionState节点。

<sessionState mode=“StateServer” stateConnectionString=“tcpip=127.0.0.1:42424″ sqlConnectionString=“data source=127.0.0.1;Trusted_Connection=yes” cookieless=“false” timeout=“120”/>

<sessionState mode=“InProc” stateConnectionString=“tcpip=127.0.0.1:42424″ sqlConnectionString=“data source=127.0.0.1;Trusted_Connection=yes” cookieless=“false” timeout=“120”/>

InProc模式
优点:获取session状态的速度快,session状态直接存储在iis的进程中。
缺点:易丢失,经常需要重新登录

StateServer模式
优点:session状态单独存储在一个进程中,不会因为iis或者应用的重启而丢失状态
缺点:获取session状态的速度比InProc慢一些,毕竟是两个不同的进程。

在开发的时候,对应用有一点修改,就会导致应用的重启,这时候如果使用InProc模式
,那么每次都需要重新登录,比较浪费时间.建议使用StateServer模式。并在iis里面设置超时时间长一些。

注:使用StateServer模式的时候
1、要开启“ASP.NET State Service”服务(设为“自动”)

2、如果stateConnectionString的值不是127.0.0.1或者localhost等代表本地地址的值,需要修改注册表:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state \Parameters 节点 → 将 AllowRemoteConnection 的键值设置成“1”(1 为允许远程电脑的连接,0 代表禁止)→ 设置 Port (端口号)

3、session中存储非序列化的对象,如果违反会抛出  无法序列化会话状态。在“StateServer”或“SQLServer”模式下,ASP.NET 将序列化会话状态对象,因此不允许使用无法序列化的对象或 MarshalByRef 对象。如果自定义会话状态存储在“Custom”模式下执行了类似的序列化,则适用同样的限制。这样的异常。如果向session存储自定义的对象,那么该对象的类上一定要加上[Serializable]注释。

头像

entity framework 实现按照距离排序

纯SQL语句实现方法:

SELECT
    es_name,
    es_lon,
    es_lat,
    ROUND(
        6378.138 * 2 * ASIN(
            SQRT(
                POW(
                    SIN(
                        (
                            30.611842 * PI() / 180 - es_lat * PI() / 180
                        ) / 2
                    ),
                    2
                ) + COS(30.611842 * PI() / 180) * COS(es_lat * PI() / 180) * POW(
                    SIN(
                        (
                            104.074666 * PI() / 180 - es_lon * PI() / 180
                        ) / 2
                    ),
                    2
                )
            )
        ) * 1000
    ) AS distance_um
FROM
    c_ershuai
ORDER BY
    distance_um ASC

 

 

但是我比较习惯使用 entity framework,于是我就想着能不能用 entity framework 实现按照距离排序。

 

以下是我采用的方案

首先定义一个接口,用来表示具有经纬度信息的实体。

    /// <summary>
    /// 具有经纬度
    /// </summary>
    public interface IHasLngAndLat
    {
        /// <summary>
        /// 经度
        /// </summary>
        double Lng { get; set; }
        /// <summary>
        /// 纬度
        /// </summary>
        double Lat { get; set; }
    }

然后创建泛型类,用来包装计算的距离。

    /// <summary>
    /// 带距离的数据
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public class DataWithDistance<TEntity>
    {
        /// <summary>
        /// 距离(km)
        /// </summary>
        public double Distance { get; set; }
        /// <summary>
        /// 实体数据
        /// </summary>
        public TEntity Entity { get; set; }
    }

最后编写根据距离排序的扩展方法

注意:这个方法是采用的 SqlFunctions 类,所以仅支持SqlServer数据库,如果是其它数据库,需要将 SqlFunctions 更换成对应的类

    /// <summary>
    /// IQueryable扩展类
    /// </summary>
    public static class QueryableExtension
    {
        /// <summary>
        /// 根据距离排序
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="queryable"></param>
        /// <param name="lng">经度</param>
        /// <param name="lat">纬度</param>
        /// <returns></returns>
        public static IQueryable<DataWithDistance<TEntity>> OrderByDistance<TEntity>(this IQueryable<TEntity> queryable, double lng, double lat) where TEntity : class, IHasLngAndLat
        {
            var rtn = from q in queryable
                      let radLat1 = lat * Math.PI / 180.0
                      let radLat2 = q.Lat * Math.PI / 180.0
                      let a = radLat1 - radLat2
                      let b = lng * Math.PI / 180.0 - q.Lng * Math.PI / 180.0
                      let s = 2 * SqlFunctions.Asin(SqlFunctions.SquareRoot(Math.Pow((double)SqlFunctions.Sin(a / 2), 2) +
               SqlFunctions.Cos(radLat1) * SqlFunctions.Cos(radLat2) * Math.Pow((double)SqlFunctions.Sin(b / 2), 2))) * 6378.137
                      let d = Math.Round((double)s * 10000) / 10000
                      orderby d
                      select new DataWithDistance<TEntity> { Entity = q, Distance = d };

            return rtn;
        }
    }

以上就完成了 entity framework 按照距离排序的功能。

 

接下来我们用它来写一个小小的demo

首先创建一个商店实体类,具有经纬度字段,实现了  IHasLngAndLat 接口。

    /// <summary>
    /// 商店实体
    /// </summary>
    public class Shop : IHasLngAndLat
    {
        /// <summary>
        /// 主键
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// 商店名称
        /// </summary>
        [Required]
        [StringLength(64)]
        public string ShopName { get; set; }
        /// <summary>
        /// 经度
        /// </summary>
        public double Lng { get; set; }
        /// <summary>
        /// 纬度
        /// </summary>
        public double Lat { get; set; }
    }

然后创建EF上下文类

    /// <summary>
    /// EF上下文
    /// </summary>
    public class DemoDbContext : DbContext
    {
        public DemoDbContext()
            : base("name=DemoDbContext")
        {
        }
        public virtual DbSet<Shop> Shop { get; set; }
    }

最后我们分页查询商店,并按照距离由近到远排序

            #region 入参
            double user_lng = 113.46, user_lat = 22.27;  //用户经纬度
            int pageIndex = 3; //当前页码
            int pageSize = 10; //每页条数
            #endregion

            using (DemoDbContext context = new DemoDbContext())
            {
                var queryable = context.Shop.AsNoTracking().AsQueryable();
                IQueryable<DataWithDistance<Shop>> sort_queryable = queryable.OrderByDistance(user_lng, user_lat);  //按照用户的距离从近到远排序
                List<DataWithDistance<Shop>> data = sort_queryable.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();   //分页并执行sql查询获取数据

                //TODO:将查到的数据映射成DTO对象,并返回给客户端
            }

好了,entity framework 实现按照距离排序 也就全部完成了。

头像

VS如何去掉browserLinkSignalR

在使用vs开发时查看源代码可以发现最下面有以下代码,此段代码会一直请求网络,感觉不爽的可以这样去掉:

<!-- Visual Studio Browser Link -->
<script type="application/json" id="__browserLink_initializationData">
   {"appName":"Firefox","requestId":"861452d477c64fd590b602a9f006c089"}
</script>
<script type="text/JavaScript" src="http://localhost:2988/5825625854525662255/browserLink" async="async"></script>
<!-- End Browser Link -->

方法如下:

去掉“启用浏览器链接”前面的勾。