大規模で包括的な.NETヘルパークラスライブラリ - Masuit.Tools

大規模で包括的な.NETヘルパークラスライブラリ - Masuit.Tools

よく使われる操作クラスを含み、多くは静的クラスです

最終更新 2023/03/11 14:58
懒得勤快
読了目安 30 分
カテゴリ
.NET
タグ
.NET C#
  • リポジトリリンク:https://github.com/ldqk/Masuit.Tools

LICENSE nuget nuget codeSize language

よく使う操作クラスをまとめたものです。ほとんどが static クラスで、暗号化・復号、リフレクション操作、重み付きランダム選択アルゴリズム、分散型ショートID、式ツリー、LINQ 拡張、ファイル圧縮、マルチスレッドダウンロードとFTPクライアント、ハードウェア情報、文字列拡張メソッド、日時拡張操作、中国旧暦、大容量ファイルコピー、画像トリミング、認証コード、レジューム機能、コレクション拡張、Excel エクスポートなど、よく使う機能をひとまとめにしています。多機能でありながら、コード量は 2MB 以下!

公式チュートリアル

Masuit Tools

プロジェクト開発モード:日々のコード蓄積+ネット収集
⭐⭐⭐ このプロジェクトが気に入ったら、Star、Fork、Follow の三連をお願いします ♂ ⭐⭐⭐
このプロジェクトに関して、わからないことや使用中に問題が発生した場合は、直接 issue を立てるか、私にプライベートメッセージを送ってください。完全無料の技術サポートを提供します。ただし、無料でのサポートを受け取るのが気が引けて、適度に寄付したいという場合は、それも歓迎します!🤣🤣🤣

本プロジェクトはJetBrainsのサポートを受けています!

Star トレンド

ご注意:

本オープンソースプロジェクト、または本プロジェクトもしくは本プロジェクトのコードを含むプロジェクトを利用している企業が、労働法に違反した(違法な人員削減、時間外労働、児童労働などを含むがこれに限らない)ために何らかの訴訟で敗訴した場合、発覚次第、本プロジェクトの作者は本プロジェクトの使用料(会社の工商登記情報の引受金額の2~5倍を本プロジェクトのライセンス料として)を請求する権利を有します。または、本プロジェクトのソースコードを含む一切の使用を許可しないものとします!いかなる性質のアウトソーシング会社996会社が本クラスライブラリを使用する場合は、作者に連絡して商用ライセンスを取得してください。その他の企業や個人は自由に使用していただいて構いません。996 は人を使うのではなく、人を廃人にします。8時間労働制によってこそ、自己研鑽の時間が生まれ、将来競争力が身につきます。反対 996、みんなの責任です!

推奨開発環境

OS:Windows 10 1903 以降
開発ツール:VisualStudio2019 v16.5 以降
SDK:.NET Core 2.1.0 以降のすべてのバージョン

パッケージのインストール

基本機能パッケージ

.NET Framework 版のパッケージはビルド環境の異常により正常に公開・更新できませんので、現在は一旦更新を停止しています。

.NET Framework ≥ 4.6.1

PM> Install-Package Masuit.Tools.Net

.NET Standard ≥ 2.1 もしくは基本機能のみで良い場合

汎用プロジェクトにはこちらを推奨

PM> Install-Package Masuit.Tools.Abstraction

.NET Core ≥ 2.1

.NET Core プロジェクトにはこちらを推奨

PM> Install-Package Masuit.Tools.Core

.NET Framework 4.5 特別版

注意:これは .NET Framework 4.5 専用バージョンです。4.6.1 や .NET Core 版と比較して、Redis、HTML、ファイル圧縮、ASP.NET 拡張、ハードウェア監視、Session 拡張などの一部機能が削除されています。プロジェクトのバージョンが 4.5 より高い場合は、必ず上記のバージョンのパッケージを使用して、完全な機能をお楽しみください!

PM> Install-Package Masuit.Tools.Net45

追加パッケージ

Masuit.Tools.AspNetCore

AspNetCore プロジェクトにはこちらを推奨

ASP.NET Core Web 専用パッケージ。Masuit.Tools.Core の全機能に加え、ASP.NET Core Web 機能の追加サポートを含みます。

Masuit.Tools.Excel

Excel インポート・エクスポート専用の独立パッケージ

Masuit.Tools.NoSQL.MongoDBClient

MongoDB 操作用のラッパークラス独立パッケージ

ツールライブラリの構成登録

ツールライブラリは外部設定セクションを必要とします。.NET Framework プロジェクトでは web.config/app.config の AppSettings セクションに、.NET Core プロジェクトでは appsettings.json に設定します。

  1. EmailDomainWhiteList:メール検証に使用するホワイトリストドメイン。カンマ区切り。各要素は正規表現に対応。未設定の場合はメール検証ホワイトリストは無効。例:"^\\w{1,5}@qq.com,^\\w{1,5}@163.com,^\\w{1,5}@gmail.com,^\\w{1,5}@outlook.com"

  2. EmailDomainBlockList:メール検証に使用するブラックリストドメイン。カンマ区切り。各要素は正規表現に対応。ブラックリストはホワイトリストより優先。未設定の場合はメール検証ブラックリストは無効。

public Startup(IConfiguration configuration)
{
    configuration.AddToMasuitTools(); // 呼び出さない場合、デフォルトでappsettings.jsonを自動ロード
}

機能サンプルコード

オンライン体験

https://replit.com/@ldqk/MasuitToolsDemo?v=1#main.cs

1. 文字列がメール、電話番号、URL、IPアドレス、ID番号などかどうかを検証

var (isMatch, match) = "337845818@qq.com".MatchEmail(); // appsettings.jsonにEmailDomainWhiteListとEmailDomainBlockListを追加してメールドメインのホワイト/ブラックリストを設定可能。カンマ区切り。例:"EmailDomainBlockList": "^\\w{1,5}@qq.com,^\\w{1,5}@163.com,^\\w{1,5}@gmail.com,^\\w{1,5}@outlook.com"
bool isInetAddress = "114.114.114.114".MatchInetAddress();
bool isUrl = "http://ldqk.org/20/history".MatchUrl();
bool isPhoneNumber = "15205201520".MatchPhoneNumber();
bool isIdentifyCard = "312000199502230660".MatchIdentifyCard(); // 中国本土のID番号を検証
bool isCNPatentNumber = "200410018477.9".MatchCNPatentNumber(); // 中国特許出願番号または特許番号を検証(チェックデジットの有無、チェックデジット前の"."の有無を問わない)。番号の前にCN、ZLなどの接頭辞は不要。

2. ハードウェア監視(Windows のみ対応、一部関数は物理マシンのみ)

float load = SystemInfo.CpuLoad;// CPU使用率を取得
long physicalMemory = SystemInfo.PhysicalMemory;// 物理メモリ総数を取得
long memoryAvailable = SystemInfo.MemoryAvailable;// 物理メモリ可用率を取得
double freePhysicalMemory = SystemInfo.GetFreePhysicalMemory();// 利用可能な物理メモリを取得
double temperature = SystemInfo.GetCPUTemperature();// CPU温度を取得
int cpuCount = SystemInfo.GetCpuCount();// CPUコア数を取得
var ipAddress = SystemInfo.GetLocalIPs();// ローカルIPアドレスをすべて取得
string localUsedIp = SystemInfo.GetLocalUsedIP();// 現在使用中のIPアドレスを取得
IList<string> macAddress = SystemInfo.GetMacAddress();// 全ネットワークカードのMACアドレスを取得
string osVersion = Windows.GetOsVersion();// OSバージョンを取得
RamInfo ramInfo = SystemInfo.GetRamInfo();// メモリ情報を取得
var cpuSN=SystemInfo.GetCpuInfo()[0].SerialNumber; // CPUシリアル番号
var driveSN=SystemInfo.GetDiskInfo()[0].SerialNumber; // ハードディスクシリアル番号

// 簡単な方法
var cpuInfos = CpuInfo.Locals; // CPU情報を簡単に取得
var ramInfo = RamInfo.Local; // メモリ情報を簡単に取得
var diskInfos = DiskInfo.Locals; // ハードディスク情報を簡単に取得
var biosInfo = BiosInfo.Local; // マザーボード情報を簡単に取得

3. HTML の XSS 対策処理:

string html = @"<link href='/Content/font-awesome/css' rel='stylesheet'/>
        <!--[if IE 7]>
        <link href='/Content/font-awesome-ie7.min.css' rel='stylesheet'/>
        <![endif]-->
        <script src='/Scripts/modernizr'></script>
        <div id='searchBox' role='search'>
        <form action='/packages' method='get'>
        <span class='user-actions'><a href='/users/account/LogOff'>ログアウト</a></span>
        <input name='q' id='searchBoxInput'/>
        <input id='searchBoxSubmit' type='submit' value='送信' />
        </form>
        </div>";
string s = html.HtmlSantinizerStandard();// クレンジング後:<div><span><a href="/users/account/LogOff">ログアウト</a></span></div>

4. Windows メモリ整理:

各種システム最適化ソフトウェアのアクセラレータボールのような機能

Windows.ClearMemorySilent();

5. 任意基数変換

ショートID、ショートハッシュ、ランダム文字列などの生成に使用。純粋な数学演算。

NumberFormater nf = new NumberFormater(36);// 2-62進数の変換を内蔵
//NumberFormater nf = new NumberFormater("0123456789abcdefghijklmnopqrstuvwxyz");// カスタム基数文字、認証コード生成などに使用可能
string s36 = nf.ToString(12345678);
long num = nf.FromString("7clzi");
Console.WriteLine("12345678の36進数は:" + s36); // 7clzi
Console.WriteLine("36進数の7clziは:" + num); // 12345678
var s = new NumberFormater(62).ToString(new Random().Next(100000, int.MaxValue)); // 乱数と組み合わせてランダム文字列生成
// 拡張メソッド形式
var bin=12345678.ToBase(36);// 10進数→36進数:7clzi
var num="7clzi".FromBase(36);// 36進数→10進数:12345678
// 巨大数の基数変換
var num = "e6186159d38cd50e0463a55e596336bd".FromBaseBig(16); // 巨大数の16進数→10進数
Console.WriteLine(num); // 10進数:305849028665645097422198928560410015421
Console.WriteLine(num.ToBase(64)); // 64進数:3C665pQUPl3whzFlVpoPqZ、22桁
Console.WriteLine(num.ToBase(36)); // 36進数:dmed4dkd5bhcg4qdktklun0zh、25桁
Console.WriteLine(num.ToBase(7)); // 7進数:2600240311641665565300424545154525131265221035、46桁
Console.WriteLine(num.ToBase(12)); // 12進数:5217744842749978a756b22135b16a5998a5、36桁
Console.WriteLine(num.ToBase(41)); // 41進数:opzeBda2aytcEeudEquuesbk、24桁

6. ナノ秒精度のタイマー

HiPerfTimer timer = HiPerfTimer.StartNew();
for (int i = 0; i < 100000; i++)
{
    //todo
}
timer.Stop();
Console.WriteLine("forループ100000回の実行時間:"+timer.Duration+"s");
double time = HiPerfTimer.Execute(() =>
{
    for (int i = 0; i < 100000; i++)
    {
        //todo
    }
});
Console.WriteLine("forループ100000回の実行時間:"+time+"s");

7. 分散型一意順序ショートID(Snowflake ID)

var sf = SnowFlake.GetInstance();
string token = sf.GetUniqueId();// rcofqodori0w
string shortId = sf.GetUniqueShortId(8);// qodw9728
var set = new HashSet<string>();
double time = HiPerfTimer.Execute(() =>
{
    for (int i = 0; i < 1000000; i++)
    {
        set.Add(SnowFlake.GetInstance().GetUniqueId());
    }
});
Console.WriteLine(set.Count == 1000000); //True
Console.WriteLine("100万個のID生成時間:" + time + "s"); //2.6891495s

8. 旧暦変換

ChineseCalendar.CustomHolidays.Add(DateTime.Parse("2018-12-31"),"元旦");// カスタム祝日
ChineseCalendar today = new ChineseCalendar(DateTime.Parse("2018-12-31"));
Console.WriteLine(today.ChineseDateString);// 二零一八年十一月廿五
Console.WriteLine(today.AnimalString);// 生肖:狗
Console.WriteLine(today.GanZhiDateString);// 干支:戊戌年甲子月丁酉日
Console.WriteLine(today.DateHoliday);// グレゴリオ暦に基づく祝日を取得
...

9. LINQ 式ツリー拡張

Expression<Func<string, bool>> where1 = s => s.StartsWith("a");
Expression<Func<string, bool>> where2 = s => s.Length > 10;
Func<string, bool> func = where1.And(where2)
    .AndIf(!string.IsNullOrEmpty(name),s=>s==name)
    .Compile(); // And と AndIf を選択可能、条件を満たす場合のみ And を実行
bool b=func("abcd12345678");//true
Expression<Func<string, bool>> where1 = s => s.StartsWith("a");
Expression<Func<string, bool>> where2 = s => s.Length > 10;
Func<string, bool> func = where1
    .Or(where2)
    .OrIf(!string.IsNullOrEmpty(name),s=>s==name)
    .Compile(); // Or と OrIf を選択可能、条件を満たす場合のみ Or を実行
bool b=func("abc");// true
queryable.WhereIf(!string.IsNullOrEmpty(name),e=>e.Name==name)
    .WhereIf(()=> age.HasValue,e=>e.Age>=age); // IQueryable の WhereIf 拡張関数、条件を満たす場合のみ Where を実行

10. テンプレートエンジン

var tmp = new Template("{{name}}、こんにちは!");
tmp.Set("name", "万金油");
string s = tmp.Render();// 万金油、こんにちは!
var tmp = new Template("{{one}},{{two}},{{three}}");
string s = tmp.Set("one", "1").Set("two", "2").Set("three", "3").Render();// 1,2,3
var tmp = new Template("{{name}}、{{greet}}!");
tmp.Set("name", "万金油");
string s = tmp.Render();// throw テンプレート変数「{{greet}}」が使用されていません

11. List を DataTable に変換

var list = new List<MyClass>()
{
    new MyClass()
    {
        Name = "张三",
        Age = 22
    },
    new MyClass()
    {
        Name = "李四",
        Age = 21
    },
    new MyClass()
    {
        Name = "王五",
        Age = 28
    }
};
var table = list.Select(c => new{姓名=c.Name,年龄=c.Age}).ToDataTable();// 自動で列「姓名」「年龄」が設定される

12. ファイル圧縮・解凍

.NET Framework

MemoryStream ms = SevenZipCompressor.ZipStream(new List<string>()
{
    @"D:\1.txt",
    "http://ww3.sinaimg.cn/large/87c01ec7gy1fsq6rywto2j20je0d3td0.jpg",
});// メモリストリームに圧縮
SevenZipCompressor.Zip(new List<string>()
{
    @"D:\1.txt",
    "http://ww3.sinaimg.cn/large/87c01ec7gy1fsq6rywto2j20je0d3td0.jpg",
}, zip);// zipに圧縮
SevenZipCompressor.UnRar(@"D:\Download\test.rar", @"D:\Download\");// rar解凍
SevenZipCompressor.Decompress(@"D:\Download\test.tar", @"D:\Download\");// 自動認識して解凍
SevenZipCompressor.Decompress(@"D:\Download\test.7z", @"D:\Download\");

ASP.NET Core

Startup.cs

services.AddSevenZipCompressor();

コンストラクタインジェクション ISevenZipCompressor

private readonly ISevenZipCompressor _sevenZipCompressor;
public Test(ISevenZipCompressor sevenZipCompressor)
{
    _sevenZipCompressor = sevenZipCompressor;
}

使用方法は .NET Framework 版と同じ

13. 簡易ログコンポーネント(ダメ元で使える)

LogManager.LogDirectory=AppDomain.CurrentDomain.BaseDirectory+"/logs";
LogManager.Event+=info =>
{
    //todo: イベント処理を登録
};
LogManager.Info("メッセージを記録");
LogManager.Error(new Exception("例外メッセージ"));

14. FTP クライアント

FtpClient ftpClient = FtpClient.GetAnonymousClient("192.168.2.2");// 匿名アクセスクライアントを作成
//FtpClient ftpClient = FtpClient.GetClient("192.168.2.3","admin","123456");// ユーザー名/パスワード付きクライアントを作成
ftpClient.Delete("/1.txt");// ファイル削除
ftpClient.Download("/test/2.txt","D:\\test\\2.txt");// ファイルダウンロード
ftpClient.UploadFile("/test/22.txt","D:\\test\\22.txt",(sum, progress) =>
{
    Console.WriteLine("アップロード済み:"+progress*1.0/sum);
});// ファイルアップロード&進捗監視
List<string> files = ftpClient.GetFiles("/");// FTPサーバーのファイル一覧を取得
...

15. マルチスレッドバックグラウンドダウンロード

var mtd = new MultiThreadDownloader("https://attachments-cdn.shimo.im/yXwC4kphjVQu06rH/KeyShot_Pro_7.3.37.7z",Environment.GetEnvironmentVariable("temp"),"E:\\Downloads\\KeyShot_Pro_7.3.37.7z",8);
mtd.Configure(req =>
 {
     req.Referer = "https://masuit.com";
     req.Headers.Add("Origin", "https://baidu.com");
});
mtd.TotalProgressChanged+=(sender, e) =>
{
    var downloader = sender as MultiThreadDownloader;
    Console.WriteLine("ダウンロード進捗:"+downloader.TotalProgress+"%");
    Console.WriteLine("ダウンロード速度:"+downloader.TotalSpeedInBytes/1024/1024+"MBps");
};
mtd.FileMergeProgressChanged+=(sender, e) =>
{
    Console.WriteLine("ダウンロード完了");
};
mtd.FileMergedComplete+=(sender,e)=>{
    Console.WriteLine("ファイル結合完了");
};
mtd.Start();// ダウンロード開始
//mtd.Pause(); // 一時停止
//mtd.Resume(); // 再開

16. 暗号化・復号 / ハッシュ

var enc="123456".MDString();// MD5
var enc="123456".MDString("abc");// MD5 ソルト付き
var enc="123456".MDString2();// MD5 2回
var enc="123456".MDString2("abc");// MD5 2回ソルト付き
var enc="123456".MDString3();// MD5 3回
var enc="123456".MDString3("abc");// MD5 3回ソルト付き

string aes = "123456".AESEncrypt();// AES暗号化→暗号文
string s = aes.AESDecrypt(); // AES復号→平文
string aes = "123456".AESEncrypt("abc");// AES鍵暗号化→暗号文
string s = aes.AESDecrypt("abc"); // AES鍵復号→平文

string enc = "123456".DesEncrypt();// DES暗号化→暗号文
string s = enc.DesDecrypt(); //DES復号→平文
string enc = "123456".DesEncrypt("abcdefgh");// DES鍵暗号化→暗号文
string s = enc.DesDecrypt("abcdefgh"); //DES鍵復号→平文

RsaKey rsaKey = RsaCrypt.GenerateRsaKeys();// RSA鍵ペア生成
string encrypt = "123456".RSAEncrypt(rsaKey.PublicKey);// 公開鍵暗号化
string s = encrypt.RSADecrypt(rsaKey.PrivateKey);// 秘密鍵復号

string s = "123".Crc32();// CRC32ダイジェスト生成
string s = "123".Crc64();// CRC64ダイジェスト生成
string s = "123".SHA256();// SHA256ダイジェスト生成

string pub="hello,world!";
string hidden="ldqk";
var str = pub.InjectZeroWidthString(hidden); // 拡張関数:"ldqk"をゼロ幅文字列として"hello,world!"に隠す
var str = ZeroWidthCodec.Encrypt(pub,hidden); // クラスメソッド:"ldqk"をゼロ幅文字列として"hello,world!"に隠す
var dec = str.DecodeZeroWidthString(); // 拡張関数:隠し文字列"ldqk"を復号
var dec = ZeroWidthCodec.Decrypt(str); // クラスメソッド:隠し文字列"ldqk"を復号
var enc = hidden.EncodeToZeroWidthText(); // 拡張関数:文字列をゼロ幅文字列にエンコード
var enc = ZeroWidthCodec.Encode(); // クラスメソッド:文字列をゼロ幅文字列にエンコード

17. エンティティ検証

public class MyClass
{
    [IsEmail] // appsettings.json に EmailDomainWhiteList を追加してメールドメインホワイトリストを設定可能、カンマ区切り
    public string Email { get; set; }

    [IsPhone]
    public string PhoneNumber { get; set; }

    [IsIPAddress]
    public string IP { get; set; }

    [MinValue(0, ErrorMessage = "年齢の最小値は0歳"), MaxValue(100, ErrorMessage = "年齢の最大値は100歳")]
    public int Age { get; set; }

    [ComplexPassword]// パスワード複雑度検証
    public string Password { get; set; }

    [EnumOf] // 有効な列挙値かどうか検証
    public MyEnum MyEnum { get; set; }

    [MinItemsCount(1)] // コレクション要素の最小数1
    public List<string> Strs { get; set; }
}

18. HTML 操作

List<string> srcs = "html".MatchImgSrcs().ToList();// HTML文字列内の全てのimgタグのsrc属性を取得
var imgTags = "html".MatchImgTags();// HTML文字列内の全てのimgタグを取得
var str="html".RemoveHtmlTag(); // HTMLタグ除去
...

19. DateTime 拡張

double milliseconds = DateTime.Now.GetTotalMilliseconds();// ミリ秒タイムスタンプ
double microseconds = DateTime.Now.GetTotalMicroseconds();// マイクロ秒タイムスタンプ
double nanoseconds = DateTime.Now.GetTotalNanoseconds();// ナノ秒タイムスタンプ
double seconds = DateTime.Now.GetTotalSeconds();// 秒タイムスタンプ
double minutes = DateTime.Now.GetTotalMinutes();// 分タイムスタンプ
...

20. IP アドレスと URL

bool inRange = "192.168.2.2".IpAddressInRange("192.168.1.1","192.168.3.255");// IPが範囲内か判定
bool isPrivateIp = "172.16.23.25".IsPrivateIP();// プライベートIPか判定
bool isExternalAddress = "http://baidu.com".IsExternalAddress();// 外部URLか判定

// 以下は baiduAK の設定が必要
string isp = "114.114.114.114".GetISP(); // ISP情報を取得
PhysicsAddress physicsAddress = "114.114.114.114".GetPhysicsAddressInfo().Result;// 詳細地理情報オブジェクト取得
Tuple<string, List<string>> ipAddressInfo = "114.114.114.114".GetIPAddressInfo().Result;// 詳細地理情報コレクション取得

21. 要素の重複除去

var list = new List<MyClass>()
{
    new MyClass()
    {
        Email = "1@1.cn"
    },
    new MyClass()
    {
        Email = "1@1.cn"
    },
    new MyClass()
    {
        Email = "1@1.cn"
    }
};
List<MyClass> classes = list.DistinctBy(c => c.Email).ToList();
Console.WriteLine(classes.Count==1);//True

22. 列挙型拡張

public enum MyEnum
{
    [Display(Name = "読む")]
    [Description("読む")]
    Read,

    [Display(Name = "書く")]
    [Description("書く")]
    Write
}
Dictionary<int, string> dic1 = typeof(MyEnum).GetDictionary();// 列挙値と文字列表現の辞書マッピングを取得
var dic2 = typeof(MyEnum).GetDescriptionAndValue();// 文字列表現と列挙値の辞書マッピングを取得
string desc = MyEnum.Read.GetDescription();// Descriptionラベルを取得
string display = MyEnum.Read.GetDisplay();// DisplayラベルのName属性を取得
var value = typeof(MyEnum).GetValue("Read");// 文字列表現に対応する列挙値を取得
string enumString = 0.ToEnumString(typeof(MyEnum));// 列挙値に対応する文字列表現を取得

23. 固定長キューと ConcurrentHashSet の実装

.NET5 以降では、フレームワーク標準の Channel を使用することを推奨

LimitedQueue<string> queue = new LimitedQueue<string>(32);// 容量32の固定長キュー
ConcurrentLimitedQueue<string> queue = new ConcurrentLimitedQueue<string>(32);// 容量32のスレッドセーフ固定長キュー
var set = new ConcurrentHashSet<string>(); // 使い方は hashset と同じ

24. リフレクション操作

MyClass myClass = new MyClass();
PropertyInfo[] properties = myClass.GetProperties();// プロパティ一覧を取得
myClass.SetProperty("Email","1@1.cn");// オブジェクトに値を設定
myClass.DeepClone(); // オブジェクトのディープコピー(ネストあり)

25. スレッド内ユニークオブジェクトの取得

CallContext<T>.SetData("db",dbContext);// スレッド内ユニークオブジェクトを設定
CallContext<T>.GetData("db");// スレッド内ユニークオブジェクトを取得

26. メール送信

new Email()
{
    SmtpServer = "smtp.masuit.com",// SMTPサーバー
    SmtpPort = 25, // SMTPサーバーポート
    EnableSsl = true,// SSL使用
    Username = "admin@masuit.com",// メールユーザー名
    Password = "123456",// メールパスワード
    Tos = "10000@qq.com,10001@qq.com", // 受信者
    Subject = "テストメール",// メール件名
    Body = "こんにちは",// メール本文
}.SendAsync(s =>
{
    Console.WriteLine(s);// 送信成功後のコールバック
});// 非同期送信

27. 画像の簡易処理

ImageUtilities.CompressImage(@"F:\src\1.jpg", @"F:\dest\2.jpg");// ロスレス圧縮

"base64".SaveDataUriAsImageFile();// Base64を画像として保存

Image image = Image.FromFile(@"D:\1.jpg");
image.MakeThumbnail(@"D:\2.jpg", 120, 80, ThumbnailCutMode.LockWidth);// サムネイル生成

Bitmap bmp = new Bitmap(@"D:\1.jpg");
Bitmap newBmp = bmp.BWPic(bmp.Width, bmp.Height);// 白黒変換
Bitmap newBmp = bmp.CutAndResize(new Rectangle(0, 0, 1600, 900), 160, 90);// 切り抜き&リサイズ
bmp.RevPicLR(bmp.Width, bmp.Height);// 左右反転
bmp.RevPicUD(bmp.Width, bmp.Height);// 上下反転

var marker=ImageWatermarker(stream);
stream=maker.AddWatermark("透かし文字","フォントファイル",フォントサイズ,color,透かし位置,マージン); // 画像に透かしを追加
stream=maker.AddWatermark(透かし画像,透かし位置,マージン,フォントサイズ,フォント); // 画像に透かしを追加

// 画像類似度比較
var hasher = new ImageHasher();
var hash1 = hasher.DifferenceHash256("画像1"); // 差分ハッシュアルゴリズムで256ビットハッシュを計算
var hash2 = hasher.DifferenceHash256("画像2"); // 差分ハッシュアルゴリズムで256ビットハッシュを計算
//var hash1 = hasher.AverageHash64("画像1"); // 平均値アルゴリズムで64ビットハッシュを計算
//var hash2 = hasher.AverageHash64("画像2"); // 平均値アルゴリズムで64ビットハッシュを計算
//var hash1 = hasher.DctHash("画像1"); // DCTアルゴリズムで64ビットハッシュを計算
//var hash2 = hasher.DctHash("画像2"); // DCTアルゴリズムで64ビットハッシュを計算
//var hash1 = hasher.MedianHash64("画像1"); // 中央値アルゴリズムで64ビットハッシュを計算
//var hash2 = hasher.MedianHash64("画像2"); // 中央値アルゴリズムで64ビットハッシュを計算
var sim=ImageHasher.Compare(hash1,hash2); // 画像の類似度、範囲:[0,1]

var imageFormat=stream.GetImageType(); // 画像の実際のフォーマットを取得

28. 乱数

Random rnd = new Random();
int num = rnd.StrictNext();// 真の乱数を生成
double gauss = rnd.NextGauss(20,5);// 正規分布に従う乱数を生成
var s = new NumberFormater(62).ToString(new Random().Next(100000, int.MaxValue));// ランダム文字列を生成

29. 重み付き選択機能

var data=new List<WeightedItem<string>>()
{
     new WeightedItem<string>("A", 1),
     new WeightedItem<string>("B", 3),
     new WeightedItem<string>("C", 4),
     new WeightedItem<string>("D", 4),
};
var item=data.WeightedItem();// 重みに従って1要素を選択
var list=data.WeightedItems(2);// 重みに従って2要素を選択
var selector = new WeightedSelector<string>(new List<WeightedItem<string>>()
{
    new WeightedItem<string>("A", 1),
    new WeightedItem<string>("B", 3),
    new WeightedItem<string>("C", 4),
    new WeightedItem<string>("D", 4),
});
var item = selector.Select();// 重みに従って1要素を選択
var list = selector.SelectMultiple(3);// 重みに従って3要素を選択

30. EF Core の AddOrUpdate メソッドサポート

/// <summary>
/// Idで記事エンティティを追加または更新
/// </summary>
public override Post SavePost(Post t)
{
    DataContext.Set<Post>().AddOrUpdate(t => t.Id, t);
    return t;
}

31. 機密情報マスキング

"13123456789".Mask(); // 131****5678
"admin@masuit.com".MaskEmail(); // a****n@masuit.com

32. コレクション拡張

var list = new List<string>()
{
    "1","3","3","3"
};
list.AddRangeIf(s => s.Length > 1, "1", "11"); // 追加される要素の中で長さ>1のものをlistに追加
list.AddRangeIfNotContains("1", "11"); // 追加される要素の中でlistに含まれないものを追加
list.RemoveWhere(s => s.Length<1); // 長さ<1の要素を削除
list.InsertAfter(0, "2"); // 最初の要素の後ろに挿入
list.InsertAfter(s => s == "1", "2"); // 要素"1"の後ろに挿入
var dic = list.ToDictionarySafety(s => s); // 安全に辞書に変換、キー重複時は1つのキーのみ追加
var dic = list.ToConcurrentDictionary(s => s); // 並行辞書に変換、キー重複時は1つのキーのみ追加
var dic = list.ToDictionarySafety(s => s, s => s.GetHashCode()); // 安全に辞書に変換、キー重複時は1つのキーのみ追加
dic.AddOrUpdate("4", 4); // キーと値の追加または更新
dic.AddOrUpdate(new Dictionary<string, int>()
{
    ["5"] = 5,["55"]=555
}); // 一括追加または更新
dic.AddOrUpdate("5", 6, (s, i) => 66); // 追加の場合は値6、更新の場合は66
dic.AddOrUpdate("5", 6, 666); // 追加の場合は値6、更新の場合は666
dic.GetOrAdd("7",77); // 辞書から取得または追加
dic.GetOrAdd("7",()=>77); // 辞書から取得または追加
dic.AsConcurrentDictionary(); // 通常の辞書を並行辞書に変換
var table=list.ToDataTable(); // DataTableに変換
table.AddIdentityColumn(); // DataTableに自動採番列を追加
table.HasRows(); // DataTableに行があるか確認
table.ToList<T>(); // DataTableをListに変換
var set = list.ToHashSet(s=>s.Name);// HashSetに変換
var cts = new CancellationTokenSource(100); // キャンセルトークン
await list.ForeachAsync(async i=>{
    await Task.Delay(100);
    Console.WriteLine(i);
},cts.Token); // 非同期foreach

await list.ForAsync(async (item,index)=>{
    await Task.Delay(100);
    Console.WriteLine(item+"_"+index);
},cts.Token); // 非同期for、インデックス付き
await list.SelectAsync(async i=>{
    await Task.Delay(100);
    return i*10;
}); // 非同期Select
await list.SelectAsync(async (item,index)=>{
    await Task.Delay(100);
    return item*10;
}); // 非同期Select、インデックス付き
string s=list.Join(",");// 文字列コレクションをカンマ区切りの単一文字列に結合
var max=list.MaxOrDefault(); // 最大値を取得、コレクションが空でもエラーにならない
var max=list.MaxOrDefault(selector); // 最大値を取得、コレクションが空でもエラーにならない
var max=list.MaxOrDefault(selector,default); // 最大値を取得、コレクションが空でもエラーにならない
var max=list.MinOrDefault(); // 最小値を取得、コレクションが空でもエラーにならない
var max=list.MinOrDefault(selector); // 最小値を取得、コレクションが空でもエラーにならない
var max=list.MinOrDefault(selector,default); // 最小値を取得、コレクションが空でもエラーにならない
var stdDev=list.Select(s=>s.ConvertTo<int>()).StandardDeviation(); // 標準偏差

var pages=queryable.ToPagedList(1,10); // ページネーションクエリ
var pages=await queryable.ToPagedListAsync(1,10); // ページネーションクエリ(非同期)

var nums=Enumerable.Range(1, 10).ExceptBy(Enumerable.Range(5, 10), i => i); // フィールド指定で差集合
var nums=Enumerable.Range(1, 10).IntersectBy(Enumerable.Range(5, 10), i => i); // フィールド指定で積集合
var nums=Enumerable.Range(1, 10).SequenceEqual(Enumerable.Range(5, 10), i => i); // シーケンスの等価判定
var nums=Enumerable.Range(1, 10).OrderByRandom(); // ランダムソート

// 複数コレクションの積集合
var list=new List<List<MyClass>>(){
    new List<MyClass>(){
        new MyClass(){Name="aa",Age=11},
        new MyClass(){Name="bb",Age=12},
        new MyClass(){Name="cc",Age=13},
    },
    new List<MyClass>(){
        new MyClass(){Name="bb",Age=12},
        new MyClass(){Name="cc",Age=13},
        new MyClass(){Name="dd",Age=14},
    },
    new List<MyClass>(){
        new MyClass(){Name="cc",Age=13},
        new MyClass(){Name="dd",Age=14},
        new MyClass(){Name="ee",Age=15},
    },
};
var sect=list.IntersectAll(m=>m.Name); // new MyClass(){Name="cc",Age=13}

var list=new List<List<int>>(){
    new(){1,2,3},
    new(){2,3,4},
    new(){3,4,5}
};
var sect=list.IntersectAll();// [3]

// コレクション要素のインデックス位置変更
list.ChangeIndex(item,3); // 要素itemのインデックスを3番目に変更
list.ChangeIndex(t=>t.Id=="123",2); // idが123の要素のインデックスを2番目に変更

33. MIME タイプ

var mimeMapper = new MimeMapper();
var ext = mimeMapper.GetExtensionFromMime("image/jpeg"); // .jpg
var mime = mimeMapper.GetMimeFromExtension(".jpg"); // image/jpeg

34. 日時拡張

DateTime.Now.GetTotalSeconds(); // 1970-01-01 00:00:00 からの秒数
DateTime.Now.GetTotalMilliseconds(); // 1970-01-01 00:00:00 からのミリ秒数
DateTime.Now.GetTotalMicroseconds(); // 1970-01-01 00:00:00 からのマイクロ秒数
DateTime.Now.GetTotalNanoseconds(); // 1970-01-01 00:00:00 からのナノ秒数
var indate=DateTime.Parse("2020-8-3").In(DateTime.Parse("2020-8-2"),DateTime.Parse("2020-8-4"));//true
DateTime time="2021-1-1 8:00:00".ToDateTime(); // 文字列からDateTimeに変換

// 時間範囲計算ツール
var range = new DateTimeRange(DateTime.Parse("2020-8-3"), DateTime.Parse("2020-8-5"));
range.Union(DateTime.Parse("2020-8-4"), DateTime.Parse("2020-8-6")); // 2つの時間範囲を結合、結果:2020-8-3~2020-8-6
range.In(DateTime.Parse("2020-8-3"), DateTime.Parse("2020-8-6"));// 指定範囲内か判定、true
var (intersected,range2) = range.Intersect(DateTime.Parse("2020-8-4"), DateTime.Parse("2020-8-6"));// 2つの範囲が交差するか、(true,2020-8-3~2020-8-4)
range.Contains(DateTime.Parse("2020-8-3"), DateTime.Parse("2020-8-4"));// 指定範囲を含むか、true
...

35. ストリーム関連

stream.SaveAsMemoryStream(); // 任意のストリームをメモリストリームに変換
stream.ToArray(); // 任意のストリームをバイト配列に変換
stream.ToArrayAsync(); // 任意のストリームを非同期でバイト配列に変換
stream.ShuffleCode(); // ストリームの末尾にランダムな空バイトを追加(重要データでは注意、破損の可能性あり)

// プール化メモリストリーム、MemorySteam と同じ使い方
using var ms=PooledMemoryStream();

// 大容量メモリストリーム、最大1TB対応。データストリームが2GBを超える場合に推奨。MemorySteam と同じ使い方
using var ms=LargeMemoryStream();

// ファイルストリームの高速コピー
FileStream fs = new FileStream(@"D:\boot.vmdk", FileMode.OpenOrCreate, FileAccess.ReadWrite);
{
        //fs.CopyToFile(@"D:\1.bak");// 同期大容量ファイルコピー
        fs.CopyToFileAsync(@"D:\1.bak");// 非同期大容量ファイルコピー
        string md5 = fs.GetFileMD5Async().Result;// 非同期でファイルのMD5を取得
        string sha1 = fs.GetFileSha1();// 非同期でファイルのSHA1を取得
}
memoryStream.SaveFile("filename"); // メモリストリームをファイルに保存

36. 数値変換

1.2345678901.Digits8(); // 小数を8桁に丸める
1.23.ConvertTo<int>(); // 小数→int
1.23.ConvertTo<T>(); // 小数→T基本型
bool b=1.23.TryConvertTo<T>(out result); // 小数→T基本型(試行)
var num=1.2345.ToDecimal(2); // decimalに変換し小数点以下2桁を保持

37. INI ファイル操作(Windows のみ)

INIFile ini=new INIFile("filename.ini");
ini.IniWriteValue(section,key,value); // 値の書き込み
ini.IniReadValue(section,key); // 値の読み取り
ini.ClearAllSection(); // 全セクションをクリア
ini.ClearSection(section); // セクションをクリア

38. レーダーチャート計算エンジン

用途:2つのポリゴンの類似度計算、ユーザープロファイリングなど

var points=RadarChartEngine.ComputeIntersection(chart1,chart2); // 2つのポリゴンの交差領域を取得
points.ComputeArea(); // ポリゴン面積を計算

39. ツリー構造の実装

基本インターフェースクラス:
ITreeChildren:Children プロパティを持つインターフェース
ITreeParent:Parent プロパティを持つインターフェース
ITree:ITreeParent と ITreeChildren を継承し、Name プロパティを追加

関連拡張メソッド:

trees.Filter(func); // ツリーコレクションからフィルタリング
trees.Flatten(); // データを平坦化
tree.AllChildren(); // すべての子を取得
tree.AllParent(); // すべての親を取得
tree.IsRoot(); // ルートノードか判定
tree.IsLeaf(); // リーフノードか判定
tree.Level(); // 深さ/階層
tree.Path(); // フルパス

var tree=list.ToTree(c => c.Id, c => c.Pid);// ITreeParent<T>, ITreeChildren<T> を継承したコレクションをツリー構造に変換
var tree=list.ToTreeGeneral(c => c.Id, c => c.Pid);// 一般的なコレクションをツリー構造に変換

40. 簡単な Excel エクスポート

追加パッケージが必要:Masuit.Tools.Excel

var stream=list.Select(item=>new{
    姓名=item.Name,
    年龄=item.Age,
    item.Gender,
    Avatar=Image.FromStream(filestream) // 画像列
}).ToDataTable().ToExcel("Sheet1"); // カスタム列名でエクスポート
var stream=list.ToDataTable("Sheet1").ToExcel("ファイルパスワード");

いくつかのルール:

  1. 画像列は Stream、Bitmap、IEnumerable、IEnumerable、IDictionary<string,Stream>、IDictionary<string,MemoryStream>、IDictionary<string,Bitmap> をサポート。
  2. IDictionary 型の画像列の場合、キーは画像のハイパーリンクの完全なURL。
  3. デフォルトではフィールド名が列名としてエクスポートされる。
  4. list が具象型の場合、各フィールドの Description 属性を最初に検索し、Description 属性があればそれを列名として表示。
  5. ToExcel メソッドは DataTable、List、Dictionary<string, DataTable> を直接サポート。

41. EFCore エンティティ比較機能

指定エンティティの変更を取得

var changes=dbContext.GetChanges<Post>();// 変更フィールド情報を取得
var added=dbContext.GetAdded<Post>();// 追加されたエンティティフィールド情報を取得
var removed=dbContext.GetRemoved<Post>();// 削除されたエンティティフィールド情報を取得
var allchanges=dbContext.GetAllChanges<Post>();// 追加・削除・変更のエンティティフィールド情報を取得

全エンティティの変更を取得

var changes=dbContext.GetChanges();// 変更フィールド情報を取得
var added=dbContext.GetAdded();// 追加されたエンティティフィールド情報を取得
var removed=dbContext.GetRemoved();// 削除されたエンティティフィールド情報を取得
var allchanges=dbContext.GetAllChanges();// 追加・削除・変更のエンティティフィールド情報を取得

比較情報には、プロパティ情報、旧値、新値、エンティティ情報、キー情報、変更状態などが含まれます。

42. 任意の型でのメソッドチェーンサポート

a.Next(func1).Next(func2).Next(func3);
"123".Next(s=>s.ToInt32()).Next(x=>x*2).Next(x=>Math.Log(x));

43. Newtonsoft.Json の逆シリアル化のみ許可するコントラクトリゾルバー

DeserializeOnlyContractResolver

このリゾルバーは、DeserializeOnlyJsonPropertyAttribute でマークされたクラスプロパティに対して、逆シリアル化時に有効になり、シリアル化時には無視されます。

public class ClassDto
    {
        [DeserializeOnlyJsonProperty]
        public string MyProperty { get; set; }

        public int Num { get; set; }
    }

    JsonConvert.SerializeObject(new MyClass(),new JsonSerializerSettings()
    {
        ContractResolver = new DeserializeOnlyContractResolver() // DeserializeOnlyContractResolver を使用する設定
    });

WebAPI でグローバルに使用する場合:

        // Startup.ConfigureServices 内
        services.AddMvc().AddNewtonsoftJson(options =>
             {
                 var resolver = new DeserializeOnlyContractResolver();
                 resolver.NamingStrategy = new CamelCaseNamingStrategy();
                 options.SerializerSettings.ContractResolver = resolver;
             });

FallbackJsonPropertyResolver

このリゾルバーは、特定のプロパティに複数のエイリアスを設定し、逆シリアル化時に複数のエイリアスキーでのバインディングをサポートします。公式の JsonProperty エイリアス属性が単一のエイリアスしか設定できない欠点を補います。

    public class ClassDto
    {
        [FallbackJsonProperty("MyProperty","a","b")]
        public string MyProperty { get; set; }

        public int Num { get; set; }
    }

    JsonConvert.SerializeObject(new MyClass(),new JsonSerializerSettings()
    {
        ContractResolver = new FallbackJsonPropertyResolver() // FallbackJsonPropertyResolver を使用する設定
    });

CompositeContractResolver

このリゾルバーは、DeserializeOnlyContractResolver と FallbackJsonPropertyResolver の統合版です。

44. ASP.NET Core Action で queryString、フォーム、JSON リクエストタイプを同時にサポートするモデルバインダー BodyOrDefaultModelBinder

使い方:

パッケージを導入:Masuit.Tools.AspNetCore

PM> Install-Package Masuit.Tools.AspNetCore

Startup の設定:

    services.AddMvc(options =>
        {
             options.ModelBinderProviders.InsertBodyOrDefaultBinding();
        })

Action のパラメータモデルの前に [FromBodyOrDefault] 属性を付けます。省略も可能です。サンプルコード:

        [HttpGet("query"),HttpPost("query")]
        public IActionResult Query([FromBodyOrDefault]QueryModel query)
        {
            return Ok(...);
        }

        [HttpGet("query"),HttpPost("query")]
        public IActionResult Query([FromBodyOrDefault]int id,[FromBodyOrDefault]string name)
        {
            return Ok(...);
        }

45. 文字列 SimHash 類似度アルゴリズム

var dis="12345678".HammingDistance("1234567");
var dis=new SimHash("12345678").HammingDistance(new SimHash("1234567"));

46. 実際のファイルタイプ検出

// 複数の方法、お好きなものを
var detector=new FileInfo(filepath).DetectFiletype();
//var detector=File.OpenRead(filepath).DetectFiletype();
//var detector=FileSignatureDetector.DetectFiletype(filepath);
detector.Precondition;// 基本ファイルタイプ
detector.Extension;// 実際の拡張子
detector.MimeType;// MimeType
detector.FormatCategories;// フォーマットカテゴリ

デフォルトでサポートするファイルタイプ

拡張子 説明
3GP 3GPP, 3GPP 2
7Z 7-Zip
APK ZIP ベース Android パッケージ
AVI オーディオビデオインターリーブ
SH シェルスクリプト
BPLIST バイナリプロパティリスト
BMP, DIB ビットマップ
BZ2 Bunzip2 圧縮
CAB Microsoft Cabinet
CLASS Java バイトコード
CONFIG .NET 設定ファイル
CRT, CERT 証明書
CUR カーソル
DB Windows Thumbs.db サムネイルデータベース
DDS DirectDraw サーフェス
DLL Windows ダイナミックリンクライブラリ
DMG Apple ディスクマウントイメージ
DMP Windows メモリダンプファイル
DOC Microsoft Office Word 97-2003 文書
DOCX Microsoft Office Word OpenXML 文書
EPUB e-Pub 文書
EXE Windows 実行可能ファイル
FLAC ロスレスオーディオ
FLV Flash ビデオ
GIF グラフィックス交換フォーマット
GZ GZ 圧縮
HDP HD Photo(JPEG XR) 画像
HWP レガシー HWP, HWPML, CFBF HWP
ICO アイコン
INI 初期化ファイル
ISO ISO-9660 ディスクイメージ
LNK Windows ショートカットリンク
JP2 JPEG 2000 画像
JPG, JPEG 合同写真専門家グループ画像
LZH LZH 圧縮
M4A MP4 コンテナ(オーディオのみ)
M4V MP4 コンテナ(ビデオ)
MID MIDI サウンド
MKA Matroska コンテナ(オーディオのみ)
MKV Matroska コンテナ(ビデオ)
MOV QuickTime ムービービデオ
MP4 MP4 コンテナ
MSI Microsoft インストーラー
OGG OGG ビデオまたはオーディオ
ODF OpenDocument 数式
ODG OpenDocument グラフィックス
ODP OpenDocument プレゼンテーション
ODS OpenDocument スプレッドシート
ODT OpenDocument テキスト
PAK PAK アーカイブまたは Quake アーカイブ
PDB Microsoft プログラムデータベース
PDF ポータブルドキュメントフォーマット
PFX Microsoft 個人情報交換証明書
PNG ポータブルネットワークグラフィックス画像
PPT Microsoft Office PowerPoint 97-2003 文書
PPTX Microsoft Office PowerPoint OpenXML 文書
PPSX Microsoft Office PowerPoint OpenXML 文書(スライドショー専用)
PSD Photoshop 文書
RAR WinRAR 圧縮
REG Windows レジストリ
RPM RedHat パッケージマネージャーパッケージ
RTF リッチテキスト形式文書
SLN Microsoft Visual Studio ソリューション
SRT SubRip 字幕
SWF Shockwave Flash
SQLITE, DB SQLite データベース
TAR pre-ISO および UStar タイプ TAR パッケージ
TIFF タグ付き画像ファイル形式画像
TXT プレーンテキスト
WAV WAVE オーディオ
WASM バイナリ WebAssembly
WEBM WebM ビデオ
WEBP WebP 画像
XAR XAR パッケージ
XLS Microsoft Office Excel 97-2003 文書
XLSX Microsoft Office Excel OpenXML 文書
XML 拡張可能マークアップ言語文書
Z Z 圧縮
ZIP ZIP パッケージ

Asp.Net MVC および ASP.NET Core の ResumeFileResult(レジューム機能・マルチスレッドダウンロード対応)

ASP.NET Core で MVC/WebAPI アプリケーションを介してファイルデータを転送する際に、レジューム機能とマルチスレッドダウンロードをサポートします。

ETag ヘッダーと Last-Modified ヘッダーを提供します。また、以下の前提条件ヘッダーをサポートします:If-MatchIf-None-MatchIf-Modified-SinceIf-Unmodified-SinceIf-Range

ASP.NET Core 2.0+ 対応

.NET Core 2.0 以降、ASP.NET Core は内部でレジューム機能をサポートしています。そのため、FileResult に対する拡張のみを行っています。Content-Disposition Inline の一部のみを残しています。すべてのコードは基本 .NET クラスに依存しています。

使用方法

.NET Framework

コントローラー内で、FileResult と同様に使用できます。

using Masuit.Tools.Mvc;
using Masuit.Tools.Mvc.ResumeFileResult;
private readonly MimeMapper mimeMapper=new MimeMapper(); // 依存関係注入を推奨

public ActionResult ResumeFileResult()
{
    var path = Server.MapPath("~/Content/test.mp4");
    return new ResumeFileResult(path, mimeMapper.GetMimeFromPath(path), Request);
}

public ActionResult ResumeFile()
{
    return this.ResumeFile("~/Content/test.mp4", mimeMapper.GetMimeFromPath(path), "test.mp4");
}

public ActionResult ResumePhysicalFile()
{
    return this.ResumePhysicalFile(@"D:/test.mp4", mimeMapper.GetMimeFromPath(@"D:/test.mp4"), "test.mp4");
}

ASP.NET Core

ResumeFileResults を使用するには、Startup.csConfigureServices メソッドでサービスを構成する必要があります:

using Masuit.Tools.AspNetCore.ResumeFileResults.Extensions;
public void ConfigureServices(IServiceCollection services)
{
    services.AddResumeFileResult();
}

そして、コントローラー内で FileResult と同様に使用できます。

クリックしてコードを表示
using Masuit.Tools.AspNetCore.ResumeFileResults.Extensions;
private const string EntityTag = "\"TestFile\"";

private readonly IHostingEnvironment _hostingEnvironment;

private readonly DateTimeOffset _lastModified = new DateTimeOffset(2016, 1, 1, 0, 0, 0, TimeSpan.Zero);

/// <summary>
///
/// </summary>
/// <param name="hostingEnvironment"></param>
public TestController(IHostingEnvironment hostingEnvironment)
{
    _hostingEnvironment = hostingEnvironment;
}

[HttpGet("content/{fileName}/{etag}")]
public IActionResult FileContent(bool fileName, bool etag)
{
    string webRoot = _hostingEnvironment.WebRootPath;
    var content = System.IO.File.ReadAllBytes(Path.Combine(webRoot, "TestFile.txt"));
    ResumeFileContentResult result = this.ResumeFile(content, "text/plain", fileName ? "TestFile.txt" : null, etag ? EntityTag : null);
    result.LastModified = _lastModified;
    return result;
}

[HttpGet("content/{fileName}")]
public IActionResult FileContent(bool fileName)
{
    string webRoot = _hostingEnvironment.WebRootPath;
    var content = System.IO.File.ReadAllBytes(Path.Combine(webRoot, "TestFile.txt"));
    var result = new ResumeFileContentResult(content, "text/plain")
    {
        FileInlineName = "TestFile.txt",
        LastModified = _lastModified
    };
    return result;
}

[HttpHead("file")]
public IActionResult FileHead()
{
    ResumeVirtualFileResult result = this.ResumeFile("TestFile.txt", "text/plain", "TestFile.txt", EntityTag);
    result.LastModified = _lastModified;
    return result;
}

[HttpPut("file")]
public IActionResult FilePut()
{
    ResumeVirtualFileResult result = this.ResumeFile("TestFile.txt", "text/plain", "TestFile.txt", EntityTag);
    result.LastModified = _lastModified;
    return result;
}

[HttpGet("stream/{fileName}/{etag}")]
public IActionResult FileStream(bool fileName, bool etag)
{
    string webRoot = _hostingEnvironment.WebRootPath;
    FileStream stream = System.IO.File.OpenRead(Path.Combine(webRoot, "TestFile.txt"));

    ResumeFileStreamResult result = this.ResumeFile(stream, "text/plain", fileName ? "TestFile.txt" : null, etag ? EntityTag : null);
    result.LastModified = _lastModified;
    return result;
}

[HttpGet("stream/{fileName}")]
public IActionResult FileStream(bool fileName)
{
    string webRoot = _hostingEnvironment.WebRootPath;
    FileStream stream = System.IO.File.OpenRead(Path.Combine(webRoot, "TestFile.txt"));

    var result = new ResumeFileStreamResult(stream, "text/plain")
    {
        FileInlineName = "TestFile.txt",
        LastModified = _lastModified
    };

    return result;
}

[HttpGet("physical/{fileName}/{etag}")]
public IActionResult PhysicalFile(bool fileName, bool etag)
{
    string webRoot = _hostingEnvironment.WebRootPath;

    ResumePhysicalFileResult result = this.ResumePhysicalFile(Path.Combine(webRoot, "TestFile.txt"), "text/plain", fileName ? "TestFile.txt" : null, etag ? EntityTag : null);
    result.LastModified = _lastModified;
    return result;
}

[HttpGet("physical/{fileName}")]
public IActionResult PhysicalFile(bool fileName)
{
    string webRoot = _hostingEnvironment.WebRootPath;

    var result = new ResumePhysicalFileResult(Path.Combine(webRoot, "TestFile.txt"), "text/plain")
    {
        FileInlineName = "TestFile.txt",
        LastModified = _lastModified
    };

    return result;
}

[HttpGet("virtual/{fileName}/{etag}")]
public IActionResult VirtualFile(bool fileName, bool etag)
{
    ResumeVirtualFileResult result = this.ResumeFile("TestFile.txt", "text/plain", fileName ? "TestFile.txt" : null, etag ? EntityTag : null);
    result.LastModified = _lastModified;
    return result;
}

上記の例では、データに対して Content-Disposition:attachment を提供します。fileName が指定されていない場合、データは Content-Disposition:inline として提供されます。また、ETag および LastModified ヘッダーを提供できます。

[HttpGet("virtual/{fileName}")]
public IActionResult VirtualFile(bool fileName)
{
    var result = new ResumeVirtualFileResult("TestFile.txt", "text/plain")
    {
        FileInlineName = "TestFile.txt",
        LastModified = _lastModified
    };
    return result;
}

推奨プロジェクト

EntityFrameworkCore と Lucene.NET に基づく全文検索エンジン:Masuit.LuceneEFCore.SearchEngine

オープンソースブログシステム:Masuit.MyBlogs

さらに探索

関連読書

その他の記事
同じカテゴリ / 同じタグ 2026/04/22

各OSバージョンの.NETサポート状況(250707更新)

仮想マシンとテストマシンを使用して、各OSバージョンの.NETサポート状況を確認します。OSインストール後、対応するランタイムをインストールし、Stardustエージェントを実行できることを確認します(合格条件)。

続きを読む
同じカテゴリ / 同じタグ 2026/02/07

AOTの使用経験のまとめ

プロジェクト作成当初から、新機能を追加したり新しい構文を使用したりした場合には、すぐにAOT公開テストを実施するという良い習慣を身につけるべきです。

続きを読む