主頁 > .NET開發 > net core天馬行空系列-各大資料庫快速批量插入資料方法匯總

net core天馬行空系列-各大資料庫快速批量插入資料方法匯總

2022-07-28 16:22:48 .NET開發

1.前言

hi,大家好,我是三合,我是怎么想起寫一篇關于資料庫快速批量插入的博客的呢?事情起源于我們作業中的一個需求,簡單來說,就是有一個定時任務,從資料庫里獲取大量資料,在應用層面經過處理后再把結果批量插入回到資料庫里,這個任務每十分鐘執行一次,但是有的時候資料量太大,回圈插入資料庫的時候會超時,導致任務失敗,所以這個時候我就開始研究怎么快速批量插入資料庫,因為我們用的資料庫是Oracle,所以我首先研究了Oracle的快速批量插入,后面我一想那其他型別的資料庫肯定也有這樣的需求,于是我在找了很多資料,并且反復實驗后,終于完美解決了mysql,sqlServer以及Oracle的快速批量插入,sqlite自身不支持,所以沒有sqlite,特地整理成這篇文章,分享給大家,

2.測驗前準備

添加一個具有絕大多數型別屬性的物體類,用來完整測驗批量插入效果,該物體類用于mysql和sqlserver的測驗,

public class NullableTable
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public int Id { get; set; }
    [Description("Int2")]
    public int? Int2 { get; set; }
    [Description("Long2")]
    public long? Long2 { get; set; }

    public float? Float2 { get; set; }
    public double? Double2 { get; set; }

    public decimal? Decimal2 { get; set; }

    [DecimalPrecision(20,4)]
    public decimal? Decimal3 { get; set; }

    public Guid? Guid2 { get; set; }

    public short? Short2 { get; set; }

    public DateTime? DateTime2 { get; set; }

    public bool? Bool2 { get; set; }

    public TimeSpan? TimeSpan2 { get; set; }

    public byte? Byte2 { get; set; }


    [StringLength(100)]
    public string String2 { get; set; }
    public string String3 { get; set; }

    public Enum2? Enum2 { get; set; }

    [Column("TestInt3")]
    [Description("Int2")]
    public int? Int3 { get; set; }
}

 public enum Enum2
    {
        x,
        y
    }

因為oracle資料庫我們習慣于表名和欄位名大寫,所以oracle的測驗物體類定義如下:

[Table("NULLABLETABLE")]
[Description("NullableTable")]
public class NullableTable
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    [Column("ID")]
    public int Id { get; set; }
    [Description("Int2")]
    [Column("INT2")]
    public int? Int2 { get; set; }
    [Description("Long2")]
    [Column("LONG2")]
    public long? Long2 { get; set; }
    [Column("FLOAT2")]
    public float? Float2 { get; set; }
    [Column("DOUBLE2")]
    public double? Double2 { get; set; }
    [Column("DECIMAL2")]
    public decimal? Decimal2 { get; set; }
    [Column("DECIMAL3")]
    [DecimalPrecision(20,4)]
    public decimal? Decimal3 { get; set; }
    [Column("GUID2")]
    public Guid? Guid2 { get; set; }
    [Column("SHORT2")]
    public short? Short2 { get; set; }
    [Column("DATETIME2")]
    public DateTime? DateTime2 { get; set; }
    [Column("BOOL2")]
    public bool? Bool2 { get; set; }
    [Column("TIMESPAN2")]
    public TimeSpan? TimeSpan2 { get; set; }
    [Column("BYTE2")]
    public byte? Byte2 { get; set; }

    [Column("STRING2")]
    [StringLength(100)]
    public string String2 { get; set; }
    [Column("STRING3")]
    public string String3 { get; set; }
    [Column("ENUM2")]
    public Enum2? Enum2 { get; set; }

    [Column("TESTINT3")]
    [Description("Int2")]
    public int? Int3 { get; set; }
}

實驗我們采用的是code first,先利用SummerBoot框架的可用于依賴注入的,資料庫表和c#物體類互相轉換的介面實作功能從物體類生成相應的資料庫表,本次實驗批量插入2w條資料來對比時間,定義一個串列,用回圈的方式給這個串列添加2w條資料,

var nullableTableList3 = new List<NullableTable>();
var now = DateTime.Now;
for (int i = 0; i < 20000; i++)
{
    var a = new NullableTable()
    {
        Int2 = 2,
        Bool2 = true,
        Byte2 = 1,
        DateTime2 = now,
        Decimal2 = 1m,
        Decimal3 = 1.1m,
        Double2 = 1.1,
        Float2 = (float)1.1,
        Guid2 = Guid.NewGuid(),
        Id = 0,
        Short2 = 1,
        TimeSpan2 = TimeSpan.FromHours(1),
        String2 = "sb",
        String3 = "sb",
        Long2 = 2,
        Enum2 = Model.Enum2.y,
        Int3 = 4
    };
    nullableTableList3.Add(a);
}

資料庫驅動上的選擇是這樣的,sqlserver采用微軟官方驅動System.Data.SqlClient,oracle采用官方驅動Oracle.ManagedDataAccess.Core,mysql采用社區驅動MySqlConnector(為啥mysql不采用官方的驅動呢?因為官方的驅動封裝的太差了,社區的驅動支持列名映射,同時專案里官方驅動和社區驅動可以共存),
同時快速批量插入均支持異步同步,這里僅演示同步,異步的實作基本一樣,

3.sqlserver快速批量插入

sqlserver官方提供的批量插入方式是SqlBulkCopy,引數為一個dataTable物件,原生的批量插入代碼如下,采用StopWatch類進行計時,測驗前都會用DELETE from NullableTable 陳述句清空表,測驗里回圈跑5次,獲取總時間后除以5獲取平均值,合計插入10w條資料,

var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 5; i++)
{
  using (var dbConnection = new SqlConnection(connectionString))
  {
      dbConnection.Open();

      SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(dbConnection, SqlBulkCopyOptions.KeepIdentity,
          null);
      sqlBulkCopy.BatchSize = 20000;
      sqlBulkCopy.DestinationTableName = "NullableTable";
      //針對列名做一下映射
      sqlBulkCopy.ColumnMappings.Add("Int2", "Int2");
      sqlBulkCopy.ColumnMappings.Add("Bool2", "Bool2");
      sqlBulkCopy.ColumnMappings.Add("Byte2", "Byte2");
      sqlBulkCopy.ColumnMappings.Add("DateTime2", "DateTime2");
      sqlBulkCopy.ColumnMappings.Add("Decimal2", "Decimal2");
      sqlBulkCopy.ColumnMappings.Add("Decimal3", "Decimal3");
      sqlBulkCopy.ColumnMappings.Add("Double2", "Double2");
      sqlBulkCopy.ColumnMappings.Add("Float2", "Float2");
      sqlBulkCopy.ColumnMappings.Add("Guid2", "Guid2");
      sqlBulkCopy.ColumnMappings.Add("Short2", "Short2");
      sqlBulkCopy.ColumnMappings.Add("TimeSpan2", "TimeSpan2");

      sqlBulkCopy.ColumnMappings.Add("String2", "String2");
      sqlBulkCopy.ColumnMappings.Add("String3", "String3");
      sqlBulkCopy.ColumnMappings.Add("Long2", "Long2");
      sqlBulkCopy.ColumnMappings.Add("Enum2", "Enum2");
      sqlBulkCopy.ColumnMappings.Add("Int3", "TestInt3");
      //將物體類串列轉換成dataTable
      var table = nullableTableList3.ToDataTable();
      sqlBulkCopy.WriteToServer(table);
  }

}
sw.Stop();            
var totalTime= sw.ElapsedMilliseconds;
var avgValue = https://www.cnblogs.com/hezp/archive/2022/07/28/totalTime / 5;

實驗結果如下,sql server中:
采用快速批量插入10w條資料,時間合計1858毫秒,平均插入2w條資料僅需371毫秒,
采用insert into陳述句,回圈插入10w條資料,時間合計457606毫秒,平均插入2w條資料需91521毫秒,

4.物體類串列轉dataTable的擴展方法

這里有一個物體類串列轉dataTable的擴展方法,采用的是運算式樹+構建委托的方式,性能不錯,大家可以參考,代碼實作如下,

public static ConcurrentDictionary<string, object> CacheDictionary = new ConcurrentDictionary<string, object>();
/// <summary>
/// 構建一個object資料轉換成一維陣列資料的委托
/// </summary>
/// <param name="objType"></param>
/// <param name="propertyInfos"></param>
/// <returns></returns>
public static Func<T, object[]> BuildObjectGetValuesDelegate<T>(List<PropertyInfo> propertyInfos) where T : class
{
    var objParameter = Expression.Parameter(typeof(T), "model");
    var selectExpressions = propertyInfos.Select(it => BuildObjectGetValueExpression(objParameter, it));
    var arrayExpression = Expression.NewArrayInit(typeof(object), selectExpressions);
    var result = Expression.Lambda<Func<T, object[]>>(arrayExpression, objParameter).Compile();
    return result;
}


/// <summary>
/// 構建物件獲取單個值得
/// </summary>
/// <param name="modelExpression"></param>
/// <param name="propertyInfo"></param>
/// <returns></returns>
public static Expression BuildObjectGetValueExpression(ParameterExpression modelExpression, PropertyInfo propertyInfo)
{
    var propertyExpression = Expression.Property(modelExpression, propertyInfo);
    var convertExpression = Expression.Convert(propertyExpression, typeof(object));
    return convertExpression;
}

public static DataTable ToDataTable<T>(this IEnumerable<T> source, List<PropertyInfo> propertyInfos = null,bool useColumnAttribute=false) where T : class
{
    var table = new DataTable("template");
    if (propertyInfos == null || propertyInfos.Count == 0)
    {
        propertyInfos = typeof(T).GetProperties().Where(it => it.CanRead).ToList();
    }
    foreach (var propertyInfo in propertyInfos)
    {
        var columnName=useColumnAttribute?(propertyInfo.GetCustomAttribute<ColumnAttribute>()?.Name?? propertyInfo.Name) : propertyInfo.Name;
        table.Columns.Add(columnName, ChangeType(propertyInfo.PropertyType));
    }

    Func<T, object[]> func;
    var key = typeof(T).FullName + propertyInfos.Select(it => it.Name).ToList().StringJoin();
    if (CacheDictionary.TryGetValue(key, out var cacheFunc))
    {
        func = (Func<T, object[]>)cacheFunc;
    }
    else
    {
        func = BuildObjectGetValuesDelegate<T>(propertyInfos);
        CacheDictionary.TryAdd(key, func);
    }

    foreach (var model in source)
    {
        var rowData = https://www.cnblogs.com/hezp/archive/2022/07/28/func(model);
        table.Rows.Add(rowData);
    }

    return table;
}

private static Type ChangeType(Type type)
{
    if (type.IsNullable())
    {
        type = Nullable.GetUnderlyingType(type);
    }

    return type;
}

5.oracle快速批量插入

oracle官方提供的批量插入方式是ArrayBindCount,即陣列批量插入,原生的批量插入代碼如下,計時方式與sqlserver相同

var total = 20000;
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 5; i++)
{
    var connection = new OracleConnection(connectionString);
    connection.Open();
    int?[] Int2 = new int?[total];
    bool[] Bool2 = new bool[total];
    byte[] Byte2 = new byte[total];
    DateTime[] DateTime2 = new DateTime[total];
    decimal?[] Decimal2 = new decimal?[total];
    decimal[] Decimal3 = new decimal[total];
    double[] Double2 = new double[total];
    float[] Float2 = new float[total];
    Guid?[] Guid2 = new Guid?[total];
    short[] Short2 = new short[total];
    TimeSpan[] TimeSpan2 = new TimeSpan[total];
    string[] String2 = new string[total];
    string[] String3 = new string[total];
    long[] Long2 = new long[total];
    Enum2[] Enum2 = new Enum2[total];

    for (int j = 0; j < total; j++)
    {
        Int2[j] = 2;
        Bool2[j] = true;
        Byte2[j] = 1;
        DateTime2[j] = now;
        Decimal2[j] = 1m;
        Decimal3[j] = 1.1m;
        Double2[j] = 1.1;
        Float2[j] = (float) 1.1;
        Guid2[j] = Guid.NewGuid();
        Short2[j] = 1;
        TimeSpan2[j] = TimeSpan.FromHours(1);
        String2[j] = "sb";
        String3[j] = "sb";
        Long2[j] = 2;
        Enum2[j] = Model.Enum2.y;
    }

    var c = (int) Model.Enum2.y;
    OracleParameter pInt2 = new OracleParameter();
    pInt2.OracleDbType = OracleDbType.Int32;
    pInt2.Value = https://www.cnblogs.com/hezp/archive/2022/07/28/Int2;

    OracleParameter pBool2 = new OracleParameter();
    pBool2.OracleDbType = OracleDbType.Byte;
    pBool2.Value = Bool2;

    OracleParameter pByte2 = new OracleParameter();
    pByte2.OracleDbType = OracleDbType.Byte;
    pByte2.Value = Byte2;

    OracleParameter pDateTime2 = new OracleParameter();
    pDateTime2.OracleDbType = OracleDbType.TimeStamp;
    pDateTime2.Value = DateTime2;

    OracleParameter pDecimal2 = new OracleParameter();
    pDecimal2.OracleDbType = OracleDbType.Decimal;
    pDecimal2.Value = Decimal2;

    OracleParameter pDecimal3 = new OracleParameter();
    pDecimal3.OracleDbType = OracleDbType.Decimal;
    pDecimal3.Value = Decimal3;

    OracleParameter pDouble2 = new OracleParameter();
    pDouble2.OracleDbType = OracleDbType.Double;
    pDouble2.Value = Double2;

    OracleParameter pFloat2 = new OracleParameter();
    pFloat2.OracleDbType = OracleDbType.BinaryFloat;
    pFloat2.Value = Float2;


    OracleParameter pGuid2 = new OracleParameter();
    pGuid2.OracleDbType = OracleDbType.Raw;
    pGuid2.Value = Guid2;

    OracleParameter pShort2 = new OracleParameter();
    pShort2.OracleDbType = OracleDbType.Int16;
    pShort2.Value = Short2;

    OracleParameter pTimeSpan2 = new OracleParameter();
    pTimeSpan2.OracleDbType = OracleDbType.IntervalDS;
    pTimeSpan2.Value = TimeSpan2;

    OracleParameter pString2 = new OracleParameter();
    pString2.OracleDbType = OracleDbType.Varchar2;
    pString2.Value = String2;

    OracleParameter pString3 = new OracleParameter();
    pString3.OracleDbType = OracleDbType.Varchar2;
    pString3.Value = String3;


    OracleParameter pLong2 = new OracleParameter();
    pLong2.OracleDbType = OracleDbType.Long;
    pLong2.Value = Long2;

    OracleParameter pEnum2 = new OracleParameter();
    pEnum2.OracleDbType = OracleDbType.Byte;
    pEnum2.Value = Enum2;
    // create command and set properties
    OracleCommand cmd = connection.CreateCommand();
    cmd.CommandText ="INSERT INTO NULLABLETABLE (INT2, LONG2, FLOAT2, DOUBLE2, DECIMAL2, DECIMAL3, GUID2, SHORT2, DATETIME2, BOOL2, TIMESPAN2, BYTE2, STRING2, STRING3,ENUM2) VALUES(:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15)";
    cmd.ArrayBindCount = total;
    cmd.Parameters.Add(pInt2);
    cmd.Parameters.Add(pLong2);
    cmd.Parameters.Add(pFloat2);
    cmd.Parameters.Add(pDouble2);
    cmd.Parameters.Add(pDecimal2);
    cmd.Parameters.Add(pDecimal3);
    cmd.Parameters.Add(pGuid2);
    cmd.Parameters.Add(pShort2);
    cmd.Parameters.Add(pDateTime2);
    cmd.Parameters.Add(pBool2);
    cmd.Parameters.Add(pTimeSpan2);
    cmd.Parameters.Add(pByte2);
    cmd.Parameters.Add(pString2);
    cmd.Parameters.Add(pString3);
    cmd.Parameters.Add(pEnum2);
    cmd.ExecuteNonQuery();
}
sw.Stop();

var totalTime = sw.ElapsedMilliseconds;
var avgValue = https://www.cnblogs.com/hezp/archive/2022/07/28/totalTime / 5;

實驗結果如下,oracle中:
采用快速批量插入10w條資料,時間合計2323毫秒,平均插入2w條資料僅需464毫秒,
采用insert into陳述句,回圈插入10w條資料,時間合計462837毫秒,平均插入2w條資料僅需92567毫秒,

6.mysql快速批量插入

mysql社區驅動MySqlConnector提供的批量插入方式是SqlBulkCopy,基于mysql自身的檔案上傳機制進行批量插入,引數為一個dataTable物件,原生的批量插入代碼如下,計時方式與sqlserver相同,同時,mysql的連接字串里要添加";AllowLoadLocalInfile=true",即連接字串的形式應該是"Server= ;Database=;User ID=;Password=;AllowLoadLocalInfile=true",同時在mysql資料庫上執行"set global local_infile=1"開啟批量上傳

var sw = new Stopwatch();
sw.Start();
for (int j = 0; j < 5; j++)
{
    using (var dbConnection = new MySqlConnection(connectionString))
    {
        dbConnection.Open();

        MySqlBulkCopy sqlBulkCopy = new MySqlBulkCopy(dbConnection, null);
        sqlBulkCopy.DestinationTableName = "NullableTable";
        var propertys = typeof(NullableTable).GetProperties()
            .Where(it => it.CanRead && it.GetCustomAttribute<NotMappedAttribute>() == null).ToList();

        for (int i = 0; i < propertys.Count; i++)
        {
            var property = propertys[i];
            var columnName = property.GetCustomAttribute<ColumnAttribute>()?.Name ?? property.Name;

            if (property.PropertyType.GetUnderlyingType() == typeof(Guid))
            {
                sqlBulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(i, "@tmp",
                    $"{columnName} =unhex(@tmp)"));
            }
            else
            {
                sqlBulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(i, columnName));
            }
        }

        var table = nullableTableList3.ToDataTable();

        SbUtil.ReplaceDataTableColumnType<Guid, byte[]>(table, guid1 => guid1.ToByteArray());
        var c = sqlBulkCopy.WriteToServer(table);
    }
}

sw.Stop();

var totalTime = sw.ElapsedMilliseconds;
var avgValue = https://www.cnblogs.com/hezp/archive/2022/07/28/totalTime / 5;

實驗結果如下,mysql中:
采用快速批量插入10w條資料,時間合計2350毫秒,平均插入2w條資料僅需470毫秒,
采用insert into陳述句,回圈插入10w條資料,時間合計414700毫秒,平均插入2w條資料需82940毫秒,

在mysql中c#的guid對應的mysql欄位型別為varbinary(16),所以table里的guid要轉換為位元組陣列,否則插入資料庫后,guid的值就會變成亂碼,位元組陣列傳遞到mysql服務端后利用unhex函式進行決議,即可正常保存guid型別, 將table里guid的值轉為位元組陣列的方法-SbUtil.ReplaceDataTableColumnType的代碼實作如下:

/// <summary>
/// 替換dataTable里的列型別
/// </summary>
/// <param name="dt"></param>
public  static void ReplaceDataTableColumnType<OldType,NewType>(DataTable dt,Func<OldType, NewType> replaceFunc)
{
    var needUpdateColumnIndexList = new List<int>();
    var needUpdateColumnNameList = new List<string>();
    
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        var column = dt.Columns[i];
        if (column.DataType.GetUnderlyingType() == typeof(OldType))
        {
            needUpdateColumnIndexList.Add(i);
            needUpdateColumnNameList.Add(column.ColumnName);
          
        }
    }

    if (needUpdateColumnIndexList.Count == 0)
    {
        return;
    }

    var nameMapping = new Dictionary<string, string>();
    for (int i = 0; i < needUpdateColumnIndexList.Count; i++)
    {
        var oldColumnName = needUpdateColumnNameList[i];
        var newColumnName = Guid.NewGuid().ToString("N");
        nameMapping.Add(newColumnName, oldColumnName);
      
        dt.Columns.Add(newColumnName, typeof(byte[])).SetOrdinal(needUpdateColumnIndexList[i]);
        for (int j = 0; j < dt.Rows.Count; j++)
        {
            var c = (dt.Rows[j][oldColumnName]);
            dt.Rows[j][newColumnName] = replaceFunc((OldType)(dt.Rows[j][oldColumnName]));
        }
        dt.Columns.Remove(oldColumnName);
    }
    
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        var columnName = dt.Columns[i].ColumnName;
        if (nameMapping.ContainsKey(columnName))
        {
            dt.Columns[i].ColumnName = nameMapping[columnName];
        }
    }

}

7.SummerBoot對各資料庫快速批量插入的封裝

基于以上各種資料庫對于快速批量插入的原生寫法過于復雜難記,SummerBoot對其進行了封裝,在宣告式編程的理念下,封裝后僅需3步即可快速批量插入,這里以sqlserver舉例,

7.1在StartUp.cs中添加summerBoot的服務支持

services.AddSummerBoot();
services.AddSummerBootRepository(it =>
{
    it.DbConnectionType = typeof(SqlConnection);
    it.ConnectionString = connectionString;
});

7.2添加倉儲介面

[AutoRepository]
public interface INullableTableRepository : IBaseRepository<NullableTable>
{
    
}

7.3注入倉儲介面后直接呼叫FastBatchInsert方法

var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 5; i++)
{
    nullableTableRepository.FastBatchInsert(nullableTableList3);
}
sw.Stop();
  
var totalTime= sw.ElapsedMilliseconds;
var avgValue = https://www.cnblogs.com/hezp/archive/2022/07/28/totalTime / 5;

實驗結果如下,sql server中:
采用SummerBoot統一封裝后快速批量插入10w條資料,時間合計3926(原生快速批量寫法1858)毫秒,平均插入2w條資料僅需785(原生快速批量寫法371)毫秒,從對比可以看出,經過SummerBoot封裝后,快速批量插入所花費的時間有所增加,但是對于這么大資料量而言,這點多消耗的時間和節省的開發量對比,不值一提,

寫在最后

SummerBoot是一款宣告式編程框架,專注于”做什么”而不是”如何去做”,更多用法,可參考SummerBoot檔案,也可以加入QQ群:799648362反饋建議,同時各位看官,如果你覺得這篇文章還不錯的話,請幫忙一鍵三連哦(推薦+關注+github star)

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/500485.html

標籤:.NET技术

上一篇:net core天馬行空系列-各大資料庫快速批量插入資料方法匯總

下一篇:SkiaSharp 之 WPF 自繪 拖曳小球(案例版)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more