b站視頻:2022年C#進(jìn)階教程-C#應(yīng)該學(xué)到什么程度(針對(duì)編程思維)
前提
UI框架:WinForm(基于.net framework 4.6.1)、MaterialSkin.2(v2.3.0.0)
//第一步 NuGet下載MaterialSkin.2
// 第二步
// 初始化MaterialSkinManager
MaterialSkinManager materialSkinManager = MaterialSkinManager.Instance;
//將此設(shè)置為false,以禁用對(duì)非材質(zhì)蒙皮組件的背景色強(qiáng)制
//這必須在AddFormToManager()之前設(shè)置
materialSkinManager.EnforceBackcolorOnAllComponents = true;
//MaterialSkinManager 屬性
materialSkinManager.AddFormToManage(this);
materialSkinManager.Theme = MaterialSkinManager.Themes.LIGHT;
materialSkinManager.ColorScheme = new ColorScheme(Primary.Teal400, Primary.Teal200, Primary.Teal400, Accent.DeepOrange100, TextShade.WHITE);
ps:如果你想使用wpf到達(dá)類似界面效果可以參考。
https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit
章節(jié)
1.程序員福音-定時(shí)提醒(C#版)
會(huì)使用自定義控件
ps:等到后面學(xué)習(xí)ef6的時(shí)候 我們把數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)里面 以便打開(kāi)時(shí)能查詢到我們?cè)O(shè)置的任務(wù)
2.C#使用Apose.PDF給Pdf文件添加自定義水印
依賴:Aspose.Pdf (v10.0.0.0)
官網(wǎng):https://docs.aspose.com/pdf/net/
Stream LStream = new MemoryStream(Convert.FromBase64String(ConfigurationManager.AppSettings.Get("aposeLicense")));
new Aspose.Pdf.License().SetLicense(LStream);
ps:僅支持10.0.0.0版本以上
破解版秘鑰許可:
PExpY2Vuc2U+DQogIDxEYXRhPg0KICAgIDxMaWNlbnNlZFRvPkFzcG9zZSBTY290bGFuZCBUZWFtPC9MaWNlbnNlZFRvPg0KICAgIDxFbWFpbFRvPmJpbGx5Lmx1bmRpZUBhc3Bvc2UuY29tPC9FbWFpbFRvPg0KICAgIDxMaWNlbnNlVHlwZT5EZXZlbG9wZXIgT0VNPC9MaWNlbnNlVHlwZT4NCiAgICA8TGljZW5zZU5vdGU+TGltaXRlZCB0byAxIGRldmVsb3BlciwgdW5saW1pdGVkIHBoeXNpY2FsIGxvY2F0aW9uczwvTGljZW5zZU5vdGU+DQogICAgPE9yZGVySUQ+MTQwNDA4MDUyMzI0PC9PcmRlcklEPg0KICAgIDxVc2VySUQ+OTQyMzY8L1VzZXJJRD4NCiAgICA8T0VNPlRoaXMgaXMgYSByZWRpc3RyaWJ1dGFibGUgbGljZW5zZTwvT0VNPg0KICAgIDxQcm9kdWN0cz4NCiAgICAgIDxQcm9kdWN0PkFzcG9zZS5Ub3RhbCBmb3IgLk5FVDwvUHJvZHVjdD4NCiAgICA8L1Byb2R1Y3RzPg0KICAgIDxFZGl0aW9uVHlwZT5FbnRlcnByaXNlPC9FZGl0aW9uVHlwZT4NCiAgICA8U2VyaWFsTnVtYmVyPjlhNTk1NDdjLTQxZjAtNDI4Yi1iYTcyLTdjNDM2OGYxNTFkNzwvU2VyaWFsTnVtYmVyPg0KICAgIDxTdWJzY3JpcHRpb25FeHBpcnk+MjAxNTEyMzE8L1N1YnNjcmlwdGlvbkV4cGlyeT4NCiAgICA8TGljZW5zZVZlcnNpb24+My4wPC9MaWNlbnNlVmVyc2lvbj4NCiAgICA8TGljZW5zZUluc3RydWN0aW9ucz5odHRwOi8vd3d3LmFzcG9zZS5jb20vY29ycG9yYXRlL3B1cmNoYXNlL2xpY2Vuc2UtaW5zdHJ1Y3Rpb25zLmFzcHg8L0xpY2Vuc2VJbnN0cnVjdGlvbnM+DQogIDwvRGF0YT4NCiAgPFNpZ25hdHVyZT5GTzNQSHNibGdEdDhGNTlzTVQxbDFhbXlpOXFrMlY2RThkUWtJUDdMZFRKU3hEaWJORUZ1MXpPaW5RYnFGZkt2L3J1dHR2Y3hvUk9rYzF0VWUwRHRPNmNQMVpmNkowVmVtZ1NZOGkvTFpFQ1RHc3pScUpWUVJaME1vVm5CaHVQQUprNWVsaTdmaFZjRjhoV2QzRTRYUTNMemZtSkN1YWoyTkV0ZVJpNUhyZmc9PC9TaWduYXR1cmU+DQo8L0xpY2Vuc2U+
3.C#實(shí)現(xiàn)文件分片上傳,前端winform+后端.net core api
簡(jiǎn)述分片上傳
所謂分片上傳,也就是把文件分成一小片,形成多個(gè)文件,上傳后服務(wù)器將文件組成一個(gè)完整的文件,當(dāng)然此時(shí)需要校驗(yàn)文件的hashcode保證上傳與組成的文件是同一個(gè)文件
.net core 3.1 關(guān)于文件上傳:
https://learn.microsoft.com/zh-cn/aspnet/core/mvc/models/file-uploads?view=aspnetcore-3.1#upload-large-files-with-streaming
public static string UploadFileHttpRequest(string url,byte[] fileBytes, string fileName, string name = "files"
, Dictionary<string,string> paramDict=null)
{
using (HttpClient client = new HttpClient())
{
try
{
var content = new MultipartFormDataContent();
if (paramDict != null)
{
foreach (var item in paramDict)
{
content.Add(new StringContent(item.Value), item.Key);
}
}
// 上傳文件類型
content.Add(new ByteArrayContent(fileBytes), name, fileName);
string result = client.PostAsync(url, content).Result.Content.ReadAsStringAsync().Result;
return result;
}
catch (Exception ex)
{
return ex.Message;
}
}
}
/// <summary>
/// 分片上傳(未記錄文件hash碼)
/// </summary>
/// <param name="url">上傳url</param>
/// <param name="filePath">文件位置</param>
/// <param name="sectionLen">每片長(zhǎng)度(按M為單位)</param>
/// <param name="name">文件后端接收映射的key值</param>
/// <param name="paramDict">相關(guān)參數(shù)</param>
/// <returns></returns>
public static string UploadSectionFile(string url, string filePath, int sectionLen = 5, string name = "file"
, Dictionary<string, string> paramDict = null)
{
FileInfo file = new FileInfo(filePath);
string result=null;
int partLen = 1024 * 1024 * sectionLen;//5M
long total = file.Length % partLen == 0 ? file.Length / partLen : file.Length / partLen + 1;
byte[] sends = new byte[partLen];
int restLen = (int)(file.Length % partLen);
int position = 0;
using (FileStream fileStream = file.OpenRead())
{
for (int i = 0; i < total; i++)
{
if (i == total-1 && restLen > 0)
{
sends = new byte[restLen];
partLen = restLen;
}
fileStream.Read(sends, 0, partLen);
paramDict = paramDict??new Dictionary<string, string>();
if (paramDict.ContainsKey("position"))
{
paramDict.Remove("position");
}
paramDict.Add("position", position + "");//記錄文件位置
result = UploadFileHttpRequest(url, sends, file.Name, name, paramDict);
position += partLen;//位置
}
}
return result;
}
/// <summary>
/// 分片上傳
/// </summary>
/// <returns></returns>
[HttpPost("partUpload")]
public async Task<IActionResult> OnPostPartUploadAsync(IFormFile file,[FromForm]long position)
{
if (file?.Length > 0)
{
long size = file.Length;
string filePath = Path.Combine(@"F:\", file.FileName);//可以修改保存路徑
using (var stream = System.IO.File.Open(filePath, FileMode.OpenOrCreate))
{
stream.Seek(position, SeekOrigin.Begin);
byte[] reads = new byte[1024];
using (var inputStream = file.OpenReadStream())
{
int readV;
while ((readV = inputStream.Read(reads)) > 0)
{
await stream.WriteAsync(reads, 0, readV);
}
}
}
return Ok(new { msg = "上傳成功", position, size });
}
return Ok(new { msg = "沒(méi)有文件需要上傳", count = 0 });
}
4.winform的數(shù)據(jù)綁定
//方式一
xxControl.DataBindings.Add(binding);
//方式二
xxControl.DataBindings.Add(propName,dataSource,memberName);
5.EF6框架(EntityFramework)
需要三張表: t_user_info t_book_info t_borrow_info
5.1 官方地址
源碼地址: https://github.com/dotnet/ef6/tree/main/src
文檔地址: https://learn.microsoft.com/zh-cn/ef/ef6/
5.2 相關(guān)集成(配置文件+代碼層面)
本地 SQL Server數(shù)據(jù)庫(kù)鏈接:
Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=C:\Users\CNC\Desktop\MusicDBContext.mdf;Initial Catalog=MusicDBContext;Integrated Security=True
Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=FileApplication.MyDbContext;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False
-
第一步 NuGet安裝核心依賴項(xiàng)
**第一種:輕便型**NuGet安裝 EntityFramework(v6.2.0)、MySQL.Data.Entities(v6.8.3)
<connectionStrings>
<add name="mysqlCon" connectionString="server=127.0.0.1;port=3306;user=root;password=123456; database=book_manage;Charset=utf8" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<entityFramework>
<!--MySql.Data.MySqlClient部分安裝后需要自己配置,而System.Data.SqlClient是安裝依賴后自己生成的-->
<providers>
<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6" />
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<!--安裝依賴后自動(dòng)生成的-->
<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=6.8.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
第二種: 方便型
(僅安裝MySql.Data.EntityFramework,缺點(diǎn)是安裝的關(guān)聯(lián)依賴很多,見(jiàn)下圖)
直接NuGet安裝MySql.Data.EntityFramework(v8.0.30)它會(huì)把關(guān)聯(lián)的依賴項(xiàng)加入 如MySql.Data.DLL(8.0.30) + EntityFramework .DLL (v6.2.0)+EntityFramework.SqlServer.DLL (v6.2.0)
- [圖片上傳失敗...(image-136f33-1668222314579)]
<connectionStrings>
<!--mysql 連接信息-->
<add name="mysqlCon" connectionString="server=127.0.0.1;user id=root;password=123456;database=smart-parking;sslmode=none;charset=utf8" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<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.30.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
- 第二步
建立實(shí)體 DbContext里面具體數(shù)據(jù)集
5.3 相關(guān)特性(注解)
約束注解:
組件模型注解:
5.4 日志打印
自定義 DatabaseLogFormatter
通過(guò)創(chuàng)建一個(gè)派生自 DatabaseLogFormatter 并適當(dāng)替代方法的新類,可以更改記錄的內(nèi)容及其格式。 最常見(jiàn)的替代方法是:
- LogCommand - 替代此選項(xiàng)可更改命令在執(zhí)行前的記錄方式。 默認(rèn)情況下,LogCommand 會(huì)針對(duì)每個(gè)參數(shù)調(diào)用 LogParameter;可選擇在替代中執(zhí)行相同的操作或以不同的方式處理參數(shù)。
- LogResult - 替代此選項(xiàng)可更改執(zhí)行命令結(jié)果的記錄方式。
- LogParameter - 替代此選項(xiàng)可更改參數(shù)記錄的格式和內(nèi)容。
例如,假設(shè)我們只想在每個(gè)命令發(fā)送到數(shù)據(jù)庫(kù)之前記錄一行。 可通過(guò)兩個(gè)替代來(lái)完成:
- 替代 LogCommand 以格式化和寫(xiě)入單行 SQL
- 替代 LogResult,不執(zhí)行任何操作。
代碼將如下所示:
public class OneLineFormatter : DatabaseLogFormatter
{
public OneLineFormatter(DbContext context, Action<string> writeAction)
: base(context, writeAction)
{
}
public override void LogCommand<TResult>(
DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
{
Write(string.Format(
"Context '{0}' , Executing Command:\r\n '{1}'{2}",
Context.GetType().Name,
command.CommandText.Replace(Environment.NewLine, ""),
Environment.NewLine));
}
public override void LogResult<TResult>(
DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext)
{
}
}
若要記錄輸出,只需調(diào)用 Write 方法,該方法會(huì)將輸出發(fā)送到配置的寫(xiě)入委托。
(請(qǐng)注意,此代碼會(huì)簡(jiǎn)單刪除換行符,就像示例一樣。它可能無(wú)法很好地查看復(fù)雜的 SQL.)
設(shè)置 DatabaseLogFormatter
創(chuàng)建一個(gè)新的 DatabaseLogFormatter 類后,需要向 EF 注冊(cè)該類。 使用基于代碼的配置完成此操作。 簡(jiǎn)而言之,這意味著在與 DbContext 類相同的程序集中創(chuàng)建一個(gè)派生自 DbConfiguration 的新類,然后在這個(gè)新類的構(gòu)造函數(shù)中調(diào)用 SetDatabaseLogFormatter。 例如:
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetDatabaseLogFormatter(
(context, writeAction) => new OneLineFormatter(context, writeAction));
}
}
5.5 CRUD+事務(wù)
5.5.1 封裝的DbSet
//單個(gè)新增
//將給定實(shí)體以“已添加”狀態(tài)添加到集的基礎(chǔ)上下文中,這樣一來(lái),當(dāng)調(diào)用 SaveChanges 時(shí),會(huì)將該實(shí)體插入到數(shù)據(jù)庫(kù)中。
DataSet.Add(Object);
//多個(gè)新增
//將給定的實(shí)體集合添加到該集的上下文中,并將每個(gè)實(shí)體放入“添加”狀態(tài),以便調(diào)用 SaveChanges 時(shí),該實(shí)體將插入數(shù)據(jù)庫(kù)。
DataSet.AddRange(IEnumerable)
//將在此上下文中所做的所有更改保存到基礎(chǔ)數(shù)據(jù)庫(kù)。
DbContext.SaveChanges()
//擴(kuò)展方法
//需要引入命名空間: System.Data.Entity.Migrations
DataSet.AddOrUpdate(TEntity);
//將在此上下文中所做的所有更改保存到基礎(chǔ)數(shù)據(jù)庫(kù)。
DbContext.SaveChanges(TEntity[]);
//單個(gè)刪除
//將給定實(shí)體標(biāo)記為“已刪除”,這樣一來(lái),當(dāng)調(diào)用 SaveChanges 時(shí),將從數(shù)據(jù)庫(kù)中刪除該實(shí)體。 請(qǐng)注意,在調(diào)用此方法之前,該實(shí)體必須以另一種狀態(tài)存在于該上下文中。
DataSet.Remove(Object)
//多個(gè)刪除
//從設(shè)置的上下文中刪除給定的實(shí)體集合,并將每個(gè)實(shí)體放入 Deleted 狀態(tài),以便調(diào)用 SaveChanges 時(shí),將從數(shù)據(jù)庫(kù)中刪除該實(shí)體。
DataSet.RemoveRange(IEnumerable)
//將在此上下文中所做的所有更改保存到基礎(chǔ)數(shù)據(jù)庫(kù)。
DbContext.SaveChanges()
//方式一
//創(chuàng)建一個(gè)原始 SQL 查詢,該查詢將返回此集中的實(shí)體。
DataSet.SqlQuery(String, Object[]);
示例:SqlQuery ("SELECT * FROM dbo.表名 WHERE Author = @author", new SqlParameter ("@author", userSuppliedAuthor) ) ;
//方式二
DataSet.Find(Object[]);
5.5.2 原生SQL
DataSet.SqlQuery("dbo.表名");//sql不帶參數(shù)
DataSet.SqlQuery("dbo.表名",參數(shù)數(shù)組);//sql帶參數(shù)
DataSet.ExecuteSqlCommand(新增/修改/刪除語(yǔ)句, Object[]);
//object[] 對(duì)應(yīng)的類型=>new SqlParameter ("@author", userSuppliedAuthor)
5.5.3 自動(dòng)檢測(cè)更改
//如果跟蹤上下文中的大量實(shí)體,并且在循環(huán)中多次調(diào)用其中某個(gè)方法,則可關(guān)閉在循環(huán)期間的更改檢測(cè)來(lái)獲得顯著的性能改進(jìn)。 例如:
using (var context = new DbContext())
{
try
{
context.Configuration.AutoDetectChangesEnabled = false;
// 在循環(huán)中進(jìn)行多次調(diào)用(Add方法)
foreach (var blog in aLotOfBlogs)
{
context.Blogs.Add(blog);
}
}
finally
{
context.Configuration.AutoDetectChangesEnabled = true;
}
}
//不要忘記在循環(huán)后重新啟用更改檢測(cè) - 我們使用了 try/finally 來(lái)確保始終重新啟用更改,即使循環(huán)中的代碼引發(fā)異常。
//禁用和重新啟用的替代方法是,使自動(dòng)檢測(cè)更改一直保持關(guān)閉狀態(tài),并且顯式調(diào)用context.ChangeTracker.DetectChanges或努力使用更改跟蹤代理。 這兩個(gè)都是高級(jí)選項(xiàng),可以輕松地在應(yīng)用程序中引入細(xì)微 bug,因此請(qǐng)謹(jǐn)慎使用它們。
//如果需要在上下文中添加或刪除多個(gè)對(duì)象,請(qǐng)考慮使用 DbSet.AddRange 和 DbSet.RemoveRange。 此方法僅在添加或刪除操作完成后自動(dòng)檢測(cè)更改一次。
5.5.4 使用事務(wù):
從 EF6 開(kāi)始,框架現(xiàn)在提供:
- Database.BeginTransaction():一種更簡(jiǎn)單的方法,讓用戶在現(xiàn)有的 DbContext 中自己?jiǎn)?dòng)和完成事務(wù) - 允許在同一事務(wù)中合并多個(gè)操作,因此所有已提交或所有回滾都為一個(gè)事務(wù)。 它還允許用戶更輕松地指定事務(wù)的隔離級(jí)別。
- Database.UseTransaction():它允許 DbContext 使用在實(shí)體框架外部啟動(dòng)的事務(wù)。
5.5.4 處理并發(fā)沖突
方案一:通過(guò) Reload(數(shù)據(jù)庫(kù)優(yōu)先)解決樂(lè)觀并發(fā)異常
方案二:在客戶端優(yōu)先時(shí)解決樂(lè)觀并發(fā)異常
方案三:自定義樂(lè)觀并發(fā)異常的解決方案
方案四:使用對(duì)象自定義樂(lè)觀并發(fā)異常的解決方案
5.6 拓展(關(guān)于遷移)
選項(xiàng)一:使用現(xiàn)有架構(gòu)作為起點(diǎn)
Code First 遷移使用存儲(chǔ)在最近遷移中的模型快照來(lái)檢測(cè)模型的更改(可以在團(tuán)隊(duì)環(huán)境中的 Code First 遷移中找到關(guān)于此的詳細(xì)信息)。 由于我們將假設(shè)數(shù)據(jù)庫(kù)已擁有當(dāng)前模型的架構(gòu),因此我們將生成一個(gè)空(無(wú)操作)遷移,該遷移將當(dāng)前模型作為快照。
- 在包管理器控制臺(tái)中運(yùn)行 Add-Migration InitialCreate –IgnoreChanges 命令。 這將創(chuàng)建一個(gè)以當(dāng)前模型作為快照的空遷移。
- 在包管理器控制臺(tái)運(yùn)行 Update-Database 命令。 這會(huì)將 InitialCreate 遷移應(yīng)用到數(shù)據(jù)庫(kù)。 由于實(shí)際遷移不包含任何更改,因此它只會(huì)向 __MigrationsHistory 表添加一行,指示已應(yīng)用此遷移。
- [圖片上傳失敗...(image-48a274-1668222314579)]
選項(xiàng)二:使用空數(shù)據(jù)庫(kù)作為起點(diǎn)
在這個(gè)場(chǎng)景中,我們需要遷移能夠從頭開(kāi)始創(chuàng)建整個(gè)數(shù)據(jù)庫(kù),包括本地?cái)?shù)據(jù)庫(kù)中已存在的表。 我們將生成一個(gè) InitialCreate 遷移,其中包含用于創(chuàng)建現(xiàn)有架構(gòu)的邏輯。 然后,我們將使現(xiàn)有數(shù)據(jù)庫(kù)看起來(lái)就像已應(yīng)用此遷移一樣。
- 在包管理器控制臺(tái)中運(yùn)行 Add-Migration InitialCreate 命令。 這將創(chuàng)建一個(gè)遷移以創(chuàng)建現(xiàn)有架構(gòu)。
[圖片上傳失敗...(image-104fb8-1668222314579)]
[圖片上傳失敗...(image-3cd56e-1668222314579)]
- 注釋掉新創(chuàng)建遷移的 Up 方法中的所有代碼。 這樣便可以將遷移“應(yīng)用”到本地?cái)?shù)據(jù)庫(kù),而無(wú)需嘗試重新創(chuàng)建所有已經(jīng)存在的表等。
- 在包管理器控制臺(tái)運(yùn)行 Update-Database 命令。 這會(huì)將 InitialCreate 遷移應(yīng)用到數(shù)據(jù)庫(kù)。 由于實(shí)際遷移不包含任何更改(因?yàn)橐褧簳r(shí)將其注釋掉),因此它只會(huì)向 __MigrationsHistory 表添加一行,指示已應(yīng)用此遷移。
[圖片上傳失敗...(image-40a36-1668222314579)]
[圖片上傳失敗...(image-dfa547-1668222314579)]
- 取消注釋 Up 方法中的代碼。 這意味著,當(dāng)此遷移應(yīng)用于將來(lái)的數(shù)據(jù)庫(kù)時(shí),本地?cái)?shù)據(jù)庫(kù)中已經(jīng)存在的架構(gòu)將由遷移創(chuàng)建。
EF6: 創(chuàng)建 mysql 遷移文件報(bào)錯(cuò)
未為提供程序“MySql.Data.MySqlClient”找到任何 MigrationSqlGenerator。請(qǐng)?jiān)谀繕?biāo)遷移配置類中使用 SetSqlGenerator 方法以注冊(cè)其他 SQL 生成器。
[圖片上傳失敗...(image-d44b9e-1668222314579)]
解決:
添加特性:
[DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]
關(guān)于注解的詳細(xì)使用:
https://learn.microsoft.com/zh-cn/ef/ef6/modeling/code-first/data-annotations
關(guān)于Mysql(EF6的支持):
https://dev.mysql.com/doc/connector-net/en/connector-net-entityframework60.html