主頁 > .NET開發 > .NET ORM 倉儲層必備的功能介紹之 FreeSql Repository 實作篇

.NET ORM 倉儲層必備的功能介紹之 FreeSql Repository 實作篇

2022-05-07 06:07:35 .NET開發

寫在開頭

2018年11月的某一天,頭腦發熱開啟了 FreeSql 開源專案之旅,時間一晃已經四年多,當初從舒服區走向一個巨大的坑,回頭一看后背一涼,四年時間從無到有,經歷了數不清的日夜奮戰(有人問我花了多長時間投入,答案:全職x2 + 前兩年無休息,以及后面兩年的持續投入),今天 FreeSql 已經很強大,感謝第一期、第二期、第N期持續提出建議的網友,

FreeSql 現如今已經是一個穩定的版本,主要體現:

  • API 已經確定,不會輕易推翻重作調整,堅持十年不變的原則,讓使用者真真正正的不再關心 ORM 使用問題;
  • 單元測驗覆寫面廣,6336+ 個單元測驗,小版本更新升級無須考慮修東墻、補西墻的問題;
  • 經歷四年時間的生產考驗,nuget下載量已超過900K+,平均每日750+;

感嘆:有些人說 .Net 陷入 orm 怪圈,動手的沒幾個,指點江山的一堆,.Net orm 真的如他們所講的簡單嗎?


專案介紹

FreeSql 是 .Net ORM,能支持 .NetFramework4.0+、.NetCore、Xamarin、MAUI、Blazor、以及還有說不出來的運行平臺,因為代碼綠色無依賴,支持新平臺非常簡單,目前單元測驗數量:6336+,Nuget下載數量:900K+,QQ群:4336577(已滿)、8578575(在線)、52508226(在線)

溫馨提醒:以下內容無商吹成份,FreeSql 不打誑語

為什么要重復造輪子?

FreeSql 主要優勢在于易用性上,基本是開箱即用,在不同資料庫之間切換兼容性比較好,作者花了大量的時間精力在這個專案,肯請您花半小時了解下專案,謝謝,FreeSql 整體的功能特性如下:

  • 支持 CodeFirst 對比結構變化遷移;
  • 支持 DbFirst 從資料庫匯入物體類;
  • 支持 豐富的運算式函式,自定義決議;
  • 支持 批量添加、批量更新、BulkCopy;
  • 支持 導航屬性,貪婪加載、延時加載、級聯保存;
  • 支持 讀寫分離、分表分庫,租戶設計;
  • 支持 MySql/SqlServer/PostgreSQL/Oracle/Sqlite/Firebird/達夢/神通/人大金倉/翰高/MsAccess Ado.net 實作包,以及 Odbc 的專門實作包;

5500+個單元測驗作為基調,支持10多數資料庫,我們提供了通用Odbc理論上支持所有資料庫,目前已知有群友使用 FreeSql 操作華為高斯、mycat、tidb 等資料庫,安裝時只需要選擇對應的資料庫實作包:

dotnet add packages FreeSql.Provider.MySql

FreeSql.Repository 是 FreeSql 專案的延申擴展類別庫,支持 .NETFramework4.0+、.NETCore2.0+、.NET5+、Xamarin 平臺,

FreeSql.Repository 除了 CRUD 還有很多實用性功能,不防耐下心花10分鐘看完,


01 安裝

環境1:.NET Core 或 .NET 5.0+

dotnet add package FreeSql.Repository

環境2、.NET Framework

Install-Package FreeSql.DbContext
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
    .UseConnectionString(FreeSql.DataType.Sqlite, connectionString)
    .UseAutoSyncStructure(true) //自動遷移物體的結構到資料庫
    .UseNoneCommandParameter(true)
    .UseMonitorCommand(cmd => Console.WriteLine(cmd.CommandText))
    .Build(); //請務必定義成 Singleton 單例模式

02 使用方法

方法1、IFreeSql 的擴展方法;

var curd = fsql.GetRepository<Topic>();

注意:Repository 物件多執行緒不安全,因此不應在多個執行緒上同時對其執行作業,

  • fsql.GetRepository 方法回傳新倉儲實體
  • 不支持從不同的執行緒同時使用同一倉儲實體

以下為了方便測驗代碼演示,我們都使用方法1,fsql.GetRepository 創建新倉儲實體


方法2、繼承實作;

public class TopicRepository: BaseRepository<Topic, int> {
    public TopicRepository(IFreeSql fsql) : base(fsql, null, null) {}

    //在這里增加 CURD 以外的方法
}

方法3、依賴注入;

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IFreeSql>(Fsql);
    services.AddFreeRepository(null, this.GetType().Assembly);
}

//在控制器使用
public TopicController(IBaseRepository<Topic> repo) {
}

03 添加資料

repo.Insert 插入資料,適配了各資料庫優化執行 ExecuteAffrows/ExecuteIdentity/ExecuteInserted

1、如果表有自增列,插入資料后應該要回傳 id,

var repo = fsql.GetRepository<Topic>();
repo.Insert(topic);

內部會將插入后的自增值填充給 topic.Id

2、批量插入

var repo = fsql.GetRepository<Topic>();
var topics = new [] { new Topic { ... }, new Topic { ... } };
repo.Insert(topics);

3、插入資料庫時間

使用 [Column(ServerTime = DateTimeKind.Utc)] 特性,插入資料時,使用適配好的每種資料庫內容,如 getutcdate()

4、插入特殊型別

使用 [Column(RereadSql = "{0}.STAsText()", RewriteSql = "geography::STGeomFromText({0},4236)")] 特性,插入和讀取時特別處理

5、插入時忽略

使用 [Column(CanInsert = false)] 特性


04 更新資料

1、只更新變化的屬性

var repo = fsql.GetRepository<Topic>();
var item = repo.Where(a => a.Id == 1).First();  //此時快照 item

item.Name = "newtitle";
repo.Update(item); //對比快照時的變化
//UPDATE `Topic` SET `Title` = 'newtitle'
//WHERE (`Id` = 1)

2、手工管理狀態

var repo = fsql.GetRepository<Topic>();
var item = new Topic { Id = 1 };
repo.Attach(item); //此時快照 item

item.Title = "newtitle";
repo.Update(item); //對比快照時的變化
//UPDATE `Topic` SET `Title` = 'newtitle'
//WHERE (`Id` = 1)

3、直接使用 repo.UpdateDiy,它是 IFreeSql 提供的原生 IUpdate 物件,功能更豐富


05 級聯保存資料

實踐發現,N對1 不適合做級聯保存,保存 Topic 的時候把 Type 資訊也保存?我個人認為自下向上保存的功能太不可控了,FreeSql 目前不支持自下向上保存,因此下面我們只講 OneToOne/OneToMany/ManyToMany 級聯保存,至于 ManyToOne 級聯保存使用手工處理,更加安全可控,

功能1:SaveMany 手工保存

完整保存,對比表已存在的資料,計算出添加、修改、洗掉執行,

遞回保存導航屬性不安全,不可控,并非技術問題,而是出于安全考慮,提供了手工完整保存的方式,

var repo = fsql.GetRepository<Type>();
var type = new Type
{
    name = "c#",
    Topics = new List<Topic>(new[]
    {
        new Topic { ... }
    })
};
repo.Insert(type);
repo.SaveMany(type, "Topics"); //手工完整保存 Topics
  • SaveMany 僅支持 OneToMany、ManyToMany 導航屬性
  • 只保存 Topics,不向下遞回追朔
  • 當 Topics 為 Empty 時,洗掉 type 存在的 Topics 所有表資料,確認?
  • ManyToMany 機制為,完整對比保存中間表,外部表只追加不更新

如:

  • 本表 Topic
  • 外部表 Tag
  • 中間表 TopicTag

功能2:EnableCascadeSave 倉儲級聯保存

DbContext/Repository EnableCascadeSave 可實作保存物件的時候,遞回追朔其 OneToOne/OneToMany/ManyToMany 導航屬性也一并保存,本檔案說明機制防止誤用,

1、OneToOne 級聯保存

v3.2.606+ 支持,并且支持級聯洗掉功能(檔案請向下瀏覽)

2、OneToMany 追加或更新子表,不洗掉子表已存在的資料

var repo = fsql.GetRepository<Type>();
repo.DbContextOptions.EnableCascadeSave = true; //需要手工開啟
repo.Insert(type);
  • 不洗掉 Topics 子表已存在的資料,確認?
  • 當 Topics 屬性為 Empty 時,不做任何操作,確認?
  • 保存 Topics 的時候,還會保存 Topics[0-..] 的下級集合屬性,向下18層,確認?

向下18層的意思,比如【型別】表,下面有集合屬性【文章】,【文章】下面有集合屬性【評論】,

保存【型別】表物件的時候,他會向下檢索出集合屬性【文章】,然后如果【文章】被保存的時候,再繼續向下檢索出集合屬性【評論】,一起做 InsertOrUpdate 操作,

3、ManyToMany 完整對比保存中間表,追加外部表

完整對比保存中間表,對比【多對多】中間表已存在的資料,計算出添加、修改、洗掉執行,

追加外部表,只追加不更新,

  • 本表 Topic
  • 外部表 Tag
  • 中間表 TopicTag

06 洗掉資料

var repo = fsql.GetRepository<Topic>();
repo.Delete(new Topic { Id = 1 }); //有多載方法 repo.Delete(Topic[])

var repo2 = fsql.GetRepository<Topic, int>(); //int 是主鍵型別,相比 repo 物件多了 Delete(int) 方法
repo2.Delete(1);

07 級聯洗掉資料

第一種:基于【物件】級聯洗掉

比如使用過 Include/IncludeMany 查詢的物件,可以使用此方法級聯洗掉它們,

var repo = fsql.GetRepository<Group>();
repo.DbContextOptions.EnableCascadeSave = true; //關鍵設定
repo.Insert(new UserGroup
{
    GroupName = "group01",
    Users = new List<User>
    {
        new User { Username = "admin01", Password = "pwd01", UserExt = new UserExt { Remark = "用戶備注01" } },
        new User { Username = "admin02", Password = "pwd02", UserExt = new UserExt { Remark = "用戶備注02" } },
        new User { Username = "admin03", Password = "pwd03", UserExt = new UserExt { Remark = "用戶備注03" } },
    }
}); //級聯添加測驗資料
//INSERT INTO "usergroup"("groupname") VALUES('group01') RETURNING "id"
//INSERT INTO "user"("username", "password", "groupid") VALUES('admin01', 'pwd01', 1), ('admin02', 'pwd02', 1), ('admin03', 'pwd03', 1) RETURNING "id" as "Id", "username" as "Username", "password" as "Password", "groupid" as "GroupId"
//INSERT INTO "userext"("userid", "remark") VALUES(3, '用戶備注01'), (4, '用戶備注02'), (5, '用戶備注03')

var groups = repo.Select
    .IncludeMany(a => a.Users, 
        then => then.Include(b => b.UserExt))
    .ToList();
repo.Delete(groups); //級聯洗掉,遞回向下遍歷 group OneToOne/OneToMany/ManyToMany 導航屬性
//DELETE FROM "userext" WHERE ("userid" IN (3,4,5))
//DELETE FROM "user" WHERE ("id" IN (3,4,5))
//DELETE FROM "usergroup" WHERE ("id" = 1)

第二種:基于【資料庫】級聯洗掉,不依賴資料庫外鍵

根據設定的導航屬性,遞回洗掉 OneToOne/OneToMany/ManyToMany 對應資料,并回傳已洗掉的資料,此功能不依賴資料庫外鍵

var repo = fsql.GetRepository<Group>();
var ret = repo.DeleteCascadeByDatabase(a => a.Id == 1);
//SELECT a."id", a."username", a."password", a."groupid" FROM "user" a WHERE (a."groupid" = 1)
//SELECT a."userid", a."remark" FROM "userext" a WHERE (a."userid" IN (3,4,5))
//DELETE FROM "userext" WHERE ("userid" IN (3,4,5))
//DELETE FROM "user" WHERE ("id" IN (3,4,5))
//DELETE FROM "usergroup" WHERE ("id" = 1)

//ret   Count = 7	System.Collections.Generic.List<object>
//  [0]	{UserExt}	object {UserExt}
//  [1]	{UserExt}	object {UserExt}
//  [2]	{UserExt}	object {UserExt}
//  [3]	{User}	    object {User}
//  [4]	{User}	    object {User}
//  [5]	{User}  	object {User}
//  [6]	{UserGroup}	object {UserGroup}

public class Group
{
    [Column(IsIdentity = true)]
    public int Id { get; set; }
    public string GroupName { get; set; }

    [Navigate(nameof(User.GroupId))]
    public List<User> Users { get; set; }
}
public class User
{
    [Column(IsIdentity = true)]
    public int Id { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public int GroupId { get; set; }

    [Navigate(nameof(Id))]
    public UserExt UserExt { get; set; }
}
public class UserExt
{
    [Column(IsPrimary = true)]
    public int UserId { get; set; }
    public string Remark { get; set; }

    [Navigate(nameof(UserId))]
    public User User { get; set; }
}

08 添加或修改資料

var repo = fsql.GetRepository<Topic>();
repo.InsertOrUpdate(item);

如果內部的狀態管理存在資料,則更新,

如果內部的狀態管理不存在資料,則查詢資料庫,判斷是否存在,

存在則更新,不存在則插入

缺點:不支持批量操作

提醒:IFreeSql 也定義了 InsertOrUpdate 方法,兩者實作機制不同,它利用了資料庫特性:

Database Features Database Features
MySql on duplicate key update 達夢 merge into
PostgreSQL on conflict do update 人大金倉 on conflict do update
SqlServer merge into 神通 merge into
Oracle merge into 南大通用 merge into
Sqlite replace into MsAccess 不支持
Firebird merge into
fsql.InsertOrUpdate<T>()
  .SetSource(items) //需要操作的資料
  //.IfExistsDoNothing() //如果資料存在,啥事也不干(相當于只有不存在資料時才插入)
  .ExecuteAffrows();

09 批量編輯資料

var repo = fsql.GetRepository<BeginEdit01>();
var cts = new[] {
    new BeginEdit01 { Name = "分類1" },
    new BeginEdit01 { Name = "分類1_1" },
    new BeginEdit01 { Name = "分類1_2" },
    new BeginEdit01 { Name = "分類1_3" },
    new BeginEdit01 { Name = "分類2" },
    new BeginEdit01 { Name = "分類2_1" },
    new BeginEdit01 { Name = "分類2_2" }
}.ToList();
repo.Insert(cts);

repo.BeginEdit(cts); //開始對 cts 進行編輯

cts.Add(new BeginEdit01 { Name = "分類2_3" });
cts[0].Name = "123123";
cts.RemoveAt(1);

var affrows = repo.EndEdit(); //完成編輯
Assert.Equal(3, affrows);
class BeginEdit01
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

上面的代碼 EndEdit 方法執行的時候產生 3 條 SQL 如下:

INSERT INTO "BeginEdit01"("Id", "Name") VALUES('5f26bf07-6ac3-cbe8-00da-7dd74818c3a6', '分類2_3')

UPDATE "BeginEdit01" SET "Name" = '123123' 
WHERE ("Id" = '5f26bf00-6ac3-cbe8-00da-7dd01be76e26')

DELETE FROM "BeginEdit01" WHERE ("Id" = '5f26bf00-6ac3-cbe8-00da-7dd11bcf54dc')

場景:winform 加載表資料后,一頓添加、修改、洗掉操作之后,點擊【保存】

提醒:該操作只對變數 cts 有效,不是針對全表對比更新,


10 弱型別 CRUD

var repo = fsql.GetRepository<object>();
repo.AsType(typeof(Topic));

var item = (object)new Topic { Title = "object title" };
repo.Insert(item);

11 無引數化命令

支持引數化、無引數化命令執行,有一些特定的資料庫,使用無引數化命令執行效率更高哦,并且除錯起來更直觀,

var repo = fsql.GetRepository<object>();
repo.DbContextOptions.NoneParameter = true;

12 作業單元(事務)

UnitOfWork 可將多個倉儲放在一個單元管理執行,最終通用 Commit 執行所有操作,內部采用了資料庫事務,

方法1:隨時創建使用

using (var uow = fsql.CreateUnitOfWork())
{
  var typeRepo = fsql.GetRepository<Type>();
  var topicRepo = fsql.GetRepository<Topic>();
  typeRepo.UnitOfWork = uow;
  topicRepo.UnitOfWork = uow;

  typeRepo.Insert(new Type());
  topicRepo.Insert(new Topic());

  uow.Orm.Insert(new Topic()).ExecuteAffrows();
  //uow.Orm 和 fsql 都是 IFreeSql
  //uow.Orm CRUD 與 uow 是一個事務
  //fsql CRUD 與 uow 不在一個事務

  uow.Commit();
}

方法2:使用 AOP + UnitOfWorkManager 實作多種事務傳播

本段內容引導,如何在 asp.net core 專案中使用特性(注解) 的方式管理事務,

UnitOfWorkManager 支持六種傳播方式(propagation),意味著跨方法的事務非常方便,并且支持同步異步:

  • Requierd:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中,默認的選擇,
  • Supports:支持當前事務,如果沒有當前事務,就以非事務方法執行,
  • Mandatory:使用當前事務,如果沒有當前事務,就拋出例外,
  • NotSupported:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起,
  • Never:以非事務方式執行操作,如果當前事務存在則拋出例外,
  • Nested:以嵌套事務方式執行,

第一步:配置 Startup.cs 注入

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IFreeSql>(fsql);
    services.AddScoped<UnitOfWorkManager>();
    services.AddFreeRepository(null, typeof(Startup).Assembly);
}
UnitOfWorkManager 成員 說明
IUnitOfWork Current 回傳當前的作業單元
void Binding(repository) 將倉儲的事務交給它管理
IUnitOfWork Begin(propagation, isolationLevel) 創建作業單元

第二步:定義事務特性

[AttributeUsage(AttributeTargets.Method)]
public class TransactionalAttribute : Attribute
{
    /// <summary>
    /// 事務傳播方式
    /// </summary>
    public Propagation Propagation { get; set; } = Propagation.Requierd;
    /// <summary>
    /// 事務隔離級別
    /// </summary>
    public IsolationLevel? IsolationLevel { get; set; }
}

第三步:引入動態代理庫

在 Before 從容器中獲取 UnitOfWorkManager,呼叫它的 var uow = Begin(attr.Propagation, attr.IsolationLevel) 方法

在 After 呼叫 Before 中的 uow.Commit 或者 Rollback 方法,最后呼叫 uow.Dispose

提醒:動態代理,一定注意處理好異步 await,否則會出現事務例外的問題

第四步:在 Controller 或者 Service 中使用事務特性

public class TopicService
{
    IBaseRepository<Topic> _repoTopic;
    IBaseRepository<Detail> _repoDetail;

    public TopicService(IBaseRepository<Topic> repoTopic, IBaseRepository<Detail> repoDetail)
    {
        _repoTopic = repoTopic;
        _repoDetail = repoDetail;
    }

    [Transactional]
    public virtual void Test1()
    {
        //這里 _repoTopic、_repoDetail 所有 CRUD 操作都是一個作業單元
        this.Test2();
    }

    [Transactional(Propagation = Propagation.Nested)]
    public virtual void Test2() //嵌套事務,新的(不使用 Test1 的事務)
    {
        //這里 _repoTopic、_repoDetail 所有 CRUD 操作都是一個作業單元
    }
}

是不是進方法就開事務呢?

不一定是真實事務,有可能是虛的,就是一個假的 unitofwork(不帶事務)

也有可能是延用上一次的事務

也有可能是新開事務,具體要看傳播模式

示例專案:https://github.com/dotnetcore/FreeSql/tree/master/Examples/aspnetcore_transaction

Autofac 動態代理參考專案:

  • https://github.com/luoyunchong/lin-cms-dotnetcore
  • https://github.com/luoyunchong/dotnetcore-examples/tree/master/ORM/FreeSql/OvOv.FreeSql.AutoFac.DynamicProxy
  • AOP + FreeSql 跨方法異步事務 https://www.cnblogs.com/igeekfan/p/aop-freesql-autofac.html

13 手工分表

FreeSql 原生用法、FreeSql.Repository 倉儲用法 都提供了 AsTable 方法對分表進行 CRUD 操作,例如:

var repo = fsql.GetRepository<Log>();
repo.AsTable(oldname => $"{oldname}_201903"); //對 Log_201903 表 CRUD

repo.Insert(new Log { ... });

跨庫,但是在同一個資料庫服務器下,也可以使用 AsTable(oldname => $"db2.dbo.{oldname}")

//跨表查詢
var sql = fsql.Select<User>()
    .AsTable((type, oldname) => "table_1")
    .AsTable((type, oldname) => "table_2")
    .ToSql(a => a.Id);

//select * from (SELECT a."Id" as1 FROM "table_1" a) ftb 
//UNION ALL
//select * from (SELECT a."Id" as1 FROM "table_2" a) ftb 

分表總結:

  • 分表、相同服務器跨庫 可以使用 AsTable 進行 CRUD;
  • AsTable CodeFirst 會自動創建不存在的分表;
  • 不可在分表分庫的物體型別中使用《延時加載》;

v3.2.500 按時間自動分表方案:https://github.com/dotnetcore/FreeSql/discussions/1066


寫在最后

FreeSql 他是免費自由的 ORM,也可以說是寶藏 ORM,更多檔案請前往 github wiki 查看,

FreeSql 已經步入第四個年頭,期待少年的你十年后還能歸來在此貼回復,兌現當初吹過十年不變的承諾,

多的不說了,希望民間的開源力量越來越強大,

希望作者的努力能打動到你,請求正在使用的、善良的您能動一動小手指,把文章轉發一下,讓更多人知道 .NET 有這樣一個好用的 ORM 存在,謝謝!!

FreeSql 使用最寬松的開源協議 MIT https://github.com/dotnetcore/FreeSql ,完全可以商用,檔案齊全,甚至拿去賣錢也可以,QQ群:4336577(已滿)、8578575(在線)、52508226(在線)

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

標籤:.NET技术

上一篇:使用Visual Studio 2022開發前端

下一篇:C#Delegate和Control中Invoke和BeginInvoke區別

標籤雲
其他(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