- Repository URL: https://github.com/ldqk/Masuit.Tools

Contains some commonly used operation classes, mostly static classes, encryption/decryption, reflection operations, weighted random selection algorithm, distributed short ids, expression trees, linq extensions, file compression, multi-threaded downloading and FTP client, hardware information, string extension methods, date/time extension operations, Chinese lunar calendar, large file copying, image cropping, captcha, resumable downloading, collection extensions, Excel export, and many other common wrappers. Many features in one, code size less than 2MB!

Project development model: daily code accumulation + online collection
⭐⭐⭐ If you like this project, please Star, Fork, Follow triple quality care ♂ note ⭐⭐⭐
If you have any questions about this project or encounter any problems during use, you can directly open an issue or contact me privately. I will provide you with completely free technical guidance. Of course, if you feel embarrassed to accept free guidance and want to tip me appropriately, I won't refuse! 🤣🤣🤣
This project is supported by JetBrains!
Star Trend
Please note:
Once any company that uses this open-source project or references this project or contains code from this project loses a lawsuit under labor law (including but not limited to illegal layoffs, overtime employment, child labor, etc.), once discovered, the author of this project has the right to claim usage fees for this project (2-5 times the registered capital of the company's business registration as the authorization fee for this project), or directly prohibit the use of any source code containing this project! Any nature of outsourcing companies or 996 companies that need to use this library must contact the author for commercial authorization! Other enterprises or individuals can use it freely without restrictions. 996 is not using people, it's wasting people. An 8-hour work system allows you to have time for self-improvement and future competitiveness. Oppose 996, it's everyone's responsibility!
Recommended Development Environment
Operating System: Windows 10 1903 and above
Development Tool: VisualStudio2019 v16.5 and above
SDK: .NET Core 2.1.0 and all later versions
Install Package
Basic Functionality Package
.NET Framework version of the package is temporarily suspended due to abnormal packaging environment.
.NET Framework ≥ 4.6.1
PM> Install-Package Masuit.Tools.Net
.NET Standard ≥ 2.1 or if you only want to use basic features
Recommended first choice for general projects
PM> Install-Package Masuit.Tools.Abstraction
.NET Core ≥ 2.1
Recommended first choice for .NET Core projects
PM> Install-Package Masuit.Tools.Core
.NET Framework 4.5 Special Edition
Please note: This is a .NET Framework 4.5 specific version. Compared to the 4.6.1 and .NET Core versions, it strips out Redis, HTML, file compression, ASP.NET extensions, hardware monitoring, Session extensions, and some other features. If your project version is higher than 4.5, be sure to use the above version package to enjoy the full feature experience!
PM> Install-Package Masuit.Tools.Net45
Value-Added Packages
Masuit.Tools.AspNetCore
Recommended first choice for AspNetCore projects
ASP.NET Core Web specific package, includes all features of Masuit.Tools.Core, and adds some additional support for ASP.NET Core Web functionality.
Masuit.Tools.Excel
Independent package for Excel import/export
Masuit.Tools.NoSQL.MongoDBClient
Independent package for MongoDB encapsulation operation class
Register Configuration for the Tool Library
The tool library requires external configuration sections. For .NET Framework projects, configure in the AppSettings section of web.config/app.config. For .NET Core projects, configure in appsettings.json:
EmailDomainWhiteList, a whitelist of domain names needed for email validation, separated by commas, each element supports regular expressions. If not configured, the email whitelist validation is not enabled. Example:
"^\\w{1,5}@qq.com,^\\w{1,5}@163.com,^\\w{1,5}@gmail.com,^\\w{1,5}@outlook.com"EmailDomainBlockList, a blacklist of domain names needed for email validation, separated by commas, each element supports regular expressions. The blacklist takes precedence over the whitelist. If not configured, the email blacklist/whitelist validation is not enabled.
public Startup(IConfiguration configuration)
{
configuration.AddToMasuitTools(); // If not called, it will automatically attempt to load appsettings.json by default
}
Feature Demo Code
Online Experience
https://replit.com/@ldqk/MasuitToolsDemo?v=1#main.cs
1. Check if a string is an Email, phone number, URL, IP address, ID card number, etc.
var (isMatch, match) = "337845818@qq.com".MatchEmail(); // You can add EmailDomainWhiteList and EmailDomainBlockList in appsettings.json to configure email domain whitelist/blacklist, separated by commas, e.g., "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();// Validate Chinese mainland ID card number
bool isCNPatentNumber = "200410018477.9".MatchCNPatentNumber(); // Validate Chinese patent application number or patent number, with or without check digit, with or without "." before check digit, both can be validated. The number to be validated should not have CN, ZL prefix.
2. Hardware Monitoring (Windows only, some functions only support physical machine mode)
float load = SystemInfo.CpuLoad;// Get CPU usage
long physicalMemory = SystemInfo.PhysicalMemory;// Get total physical memory
long memoryAvailable = SystemInfo.MemoryAvailable;// Get available physical memory
double freePhysicalMemory = SystemInfo.GetFreePhysicalMemory();// Get available physical memory
double temperature = SystemInfo.GetCPUTemperature();// Get CPU temperature
int cpuCount = SystemInfo.GetCpuCount();// Get CPU core count
var ipAddress = SystemInfo.GetLocalIPs();// Get all local IP addresses
string localUsedIp = SystemInfo.GetLocalUsedIP();// Get the currently used IP address
IList<string> macAddress = SystemInfo.GetMacAddress();// Get all MAC addresses of network cards
string osVersion = Windows.GetOsVersion();// Get OS version
RamInfo ramInfo = SystemInfo.GetRamInfo();// Get memory info
var cpuSN=SystemInfo.GetCpuInfo()[0].SerialNumber; // CPU serial number
var driveSN=SystemInfo.GetDiskInfo()[0].SerialNumber; // Hard disk serial number
// Quick methods
var cpuInfos = CpuInfo.Locals; // Quickly get CPU info
var ramInfo = RamInfo.Local; // Quickly get memory info
var diskInfos = DiskInfo.Locals; // Quickly get hard disk info
var biosInfo = BiosInfo.Local; // Quickly get motherboard info
3. HTML Anti-XSS Processing:
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'>Logout</a></span>
<input name='q' id='searchBoxInput'/>
<input id='searchBoxSubmit' type='submit' value='Submit' />
</form>
</div>";
string s = html.HtmlSantinizerStandard();//After cleaning: <div><span><a href="/users/account/LogOff">Logout</a></span></div>
4. Clean Windows System Memory:
Similar to the acceleration ball function of various system optimization software
Windows.ClearMemorySilent();
5. Arbitrary Base Conversion
Can be used to generate short ids, short hashes, random strings, etc., pure mathematical operations.
NumberFormater nf = new NumberFormater(36);//Built-in 2-62 base conversion
//NumberFormater nf = new NumberFormater("0123456789abcdefghijklmnopqrstuvwxyz");// Custom base characters, can be used to generate captcha
string s36 = nf.ToString(12345678);
long num = nf.FromString("7clzi");
Console.WriteLine("12345678's base 36 is: " + s36); // 7clzi
Console.WriteLine("Base 36 '7clzi' is: " + num); // 12345678
var s = new NumberFormater(62).ToString(new Random().Next(100000, int.MaxValue)); // Generate random string with random number
// Extension method call
var bin=12345678.ToBase(36);// Decimal to base 36: 7clzi
var num="7clzi".FromBase(36);// Base 36 to decimal: 12345678
// Large number base conversion
var num = "e6186159d38cd50e0463a55e596336bd".FromBaseBig(16); // Large number hex to decimal
Console.WriteLine(num); // Decimal: 305849028665645097422198928560410015421
Console.WriteLine(num.ToBase(64)); // Base 64: 3C665pQUPl3whzFlVpoPqZ, 22 characters
Console.WriteLine(num.ToBase(36)); // Base 36: dmed4dkd5bhcg4qdktklun0zh, 25 characters
Console.WriteLine(num.ToBase(7)); // Base 7: 2600240311641665565300424545154525131265221035, 46 characters
Console.WriteLine(num.ToBase(12)); // Base 12: 5217744842749978a756b22135b16a5998a5, 36 characters
Console.WriteLine(num.ToBase(41)); // Base 41: opzeBda2aytcEeudEquuesbk, 24 characters
6. Nanosecond Precision Timer
HiPerfTimer timer = HiPerfTimer.StartNew();
for (int i = 0; i < 100000; i++)
{
//todo
}
timer.Stop();
Console.WriteLine("Time for 100k for loop: "+timer.Duration+"s");
double time = HiPerfTimer.Execute(() =>
{
for (int i = 0; i < 100000; i++)
{
//todo
}
});
Console.WriteLine("Time for 100k for loop: "+time+"s");
7. Generate Distributed Unique Ordered Short 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("Time to generate 1M ids: " + time + "s"); //2.6891495s
8. Chinese Lunar Calendar Conversion
ChineseCalendar.CustomHolidays.Add(DateTime.Parse("2018-12-31"),"New Year's Day");//Custom holidays
ChineseCalendar today = new ChineseCalendar(DateTime.Parse("2018-12-31"));
Console.WriteLine(today.ChineseDateString);// 二零一八年十一月廿五
Console.WriteLine(today.AnimalString);// Zodiac: Dog
Console.WriteLine(today.GanZhiDateString);// Stem-Branch: 戊戌年甲子月丁酉日
Console.WriteLine(today.DateHoliday);// Get holidays based on Gregorian calendar
...
9. LINQ Expression Tree Extensions
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 and AndIf available, perform And only if condition met
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 and OrIf available, perform Or only if condition met
bool b=func("abc");// true
queryable.WhereIf(!string.IsNullOrEmpty(name),e=>e.Name==name)
.WhereIf(()=> age.HasValue,e=>e.Age>=age); // IQueryable WhereIf extension, perform Where only if condition met
10. Template Engine
var tmp = new Template("{{name}}, Hello!");
tmp.Set("name", "Jack");
string s = tmp.Render();//Jack, Hello!
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", "Jack");
string s = tmp.Render();// throw Template variable {{greet}} not used
11. List to DataTable
var list = new List<MyClass>()
{
new MyClass()
{
Name = "Zhang San",
Age = 22
},
new MyClass()
{
Name = "Li Si",
Age = 21
},
new MyClass()
{
Name = "Wang Wu",
Age = 28
}
};
var table = list.Select(c => new{Name=c.Name, Age=c.Age}).ToDataTable();// Will automatically fill columns Name and Age
12. File Compression and Decompression
.NET Framework
MemoryStream ms = SevenZipCompressor.ZipStream(new List<string>()
{
@"D:\1.txt",
"http://ww3.sinaimg.cn/large/87c01ec7gy1fsq6rywto2j20je0d3td0.jpg",
});//Compress to memory stream
SevenZipCompressor.Zip(new List<string>()
{
@"D:\1.txt",
"http://ww3.sinaimg.cn/large/87c01ec7gy1fsq6rywto2j20je0d3td0.jpg",
}, zip);//Compress to zip
SevenZipCompressor.UnRar(@"D:\Download\test.rar", @"D:\Download\");//Extract rar
SevenZipCompressor.Decompress(@"D:\Download\test.tar", @"D:\Download\");//Auto-detect and decompress archive
SevenZipCompressor.Decompress(@"D:\Download\test.7z", @"D:\Download\");
ASP.NET Core
Startup.cs
services.AddSevenZipCompressor();
Inject ISevenZipCompressor via constructor
private readonly ISevenZipCompressor _sevenZipCompressor;
public Test(ISevenZipCompressor sevenZipCompressor)
{
_sevenZipCompressor = sevenZipCompressor;
}
Usage is the same as .NET Framework version
13. Simple Log Component (It works, okay? .jpg)
LogManager.LogDirectory=AppDomain.CurrentDomain.BaseDirectory+"/logs";
LogManager.Event+=info =>
{
//todo: register some event operations
};
LogManager.Info("Log a message");
LogManager.Error(new Exception("Exception message"));
14. FTP Client
FtpClient ftpClient = FtpClient.GetAnonymousClient("192.168.2.2");//Create an anonymous client
//FtpClient ftpClient = FtpClient.GetClient("192.168.2.3","admin","123456");// Create a client with username and password
ftpClient.Delete("/1.txt");// Delete file
ftpClient.Download("/test/2.txt","D:\\test\\2.txt");// Download file
ftpClient.UploadFile("/test/22.txt","D:\\test\\22.txt",(sum, progress) =>
{
Console.WriteLine("Uploaded: "+progress*1.0/sum);
});//Upload file with progress
List<string> files = ftpClient.GetFiles("/");//List ftp server files
...
15. Multi-threaded Background Download
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("Download progress: "+downloader.TotalProgress+"%");
Console.WriteLine("Download speed: "+downloader.TotalSpeedInBytes/1024/1024+"MBps");
};
mtd.FileMergeProgressChanged+=(sender, e) =>
{
Console.WriteLine("Download completed");
};
mtd.FileMergedComplete+=(sender,e)=>{
Console.WriteLine("File merge completed");
};
mtd.Start();//Start download
//mtd.Pause(); // Pause download
//mtd.Resume(); // Resume download
16. Encryption/Decryption / Hash
var enc="123456".MDString();// MD5
var enc="123456".MDString("abc");// MD5 with salt
var enc="123456".MDString2();// MD5 double
var enc="123456".MDString2("abc");// MD5 double with salt
var enc="123456".MDString3();// MD5 triple
var enc="123456".MDString3("abc");// MD5 triple with salt
string aes = "123456".AESEncrypt();// AES encrypt to ciphertext
string s = aes.AESDecrypt(); //AES decrypt to plaintext
string aes = "123456".AESEncrypt("abc");// AES key encrypt to ciphertext
string s = aes.AESDecrypt("abc"); //AES key decrypt to plaintext
string enc = "123456".DesEncrypt();// DES encrypt to ciphertext
string s = enc.DesDecrypt(); //DES decrypt to plaintext
string enc = "123456".DesEncrypt("abcdefgh");// DES key encrypt to ciphertext
string s = enc.DesDecrypt("abcdefgh"); //DES key decrypt to plaintext
RsaKey rsaKey = RsaCrypt.GenerateRsaKeys();// Generate RSA key pair
string encrypt = "123456".RSAEncrypt(rsaKey.PublicKey);// Public key encrypt
string s = encrypt.RSADecrypt(rsaKey.PrivateKey);// Private key decrypt
string s = "123".Crc32();// Generate crc32 digest
string s = "123".Crc64();// Generate crc64 digest
string s = "123".SHA256();// Generate SHA256 digest
string pub="hello,world!";
string hidden="ldqk";
var str = pub.InjectZeroWidthString(hidden); // Extension method call: hide "ldqk" as zero-width string in "hello,world!"
var str = ZeroWidthCodec.Encrypt(pub,hidden); // Class call: hide "ldqk" as zero-width string in "hello,world!"
var dec = str.DecodeZeroWidthString(); // Extension method call: decrypt hidden string "ldqk" from zero-width string ciphertext
var dec = ZeroWidthCodec.Decrypt(str); // Class call: decrypt hidden string "ldqk" from zero-width string ciphertext
var enc = hidden.EncodeToZeroWidthText(); // Extension method call: encode string to zero-width string
var enc = ZeroWidthCodec.Encode(); // Class call: encode string to zero-width string
17. Entity Validation
public class MyClass
{
[IsEmail] // You can add EmailDomainWhiteList in appsettings.json to configure email domain whitelist, separated by commas
public string Email { get; set; }
[IsPhone]
public string PhoneNumber { get; set; }
[IsIPAddress]
public string IP { get; set; }
[MinValue(0, ErrorMessage = "Minimum age is 0"), MaxValue(100, ErrorMessage = "Maximum age is 100")]
public int Age { get; set; }
[ComplexPassword]// Password complexity validation
public string Password { get; set; }
[EnumOf] // Check if valid enum value
public MyEnum MyEnum { get; set; }
[MinItemsCount(1)] // Check collection has at least 1 element
public List<string> Strs { get; set; }
}
18. HTML Operations
List<string> srcs = "html".MatchImgSrcs().ToList();// Get all img src attributes from HTML string
var imgTags = "html".MatchImgTags();// Get all img tags from HTML string
var str="html".RemoveHtmlTag(); // Remove HTML tags
...
19. DateTime Extensions
double milliseconds = DateTime.Now.GetTotalMilliseconds();// Get millisecond timestamp
double microseconds = DateTime.Now.GetTotalMicroseconds();// Get microsecond timestamp
double nanoseconds = DateTime.Now.GetTotalNanoseconds();// Get nanosecond timestamp
double seconds = DateTime.Now.GetTotalSeconds();// Get second timestamp
double minutes = DateTime.Now.GetTotalMinutes();// Get minute timestamp
...
20. IP Address and URL
bool inRange = "192.168.2.2".IpAddressInRange("192.168.1.1","192.168.3.255");// Check if IP address is within this range
bool isPrivateIp = "172.16.23.25".IsPrivateIP();// Check if private address
bool isExternalAddress = "http://baidu.com".IsExternalAddress();// Check if external URL
// Requires baiduAK configuration
string isp = "114.114.114.114".GetISP(); // Get ISP operator info
PhysicsAddress physicsAddress = "114.114.114.114".GetPhysicsAddressInfo().Result;// Get detailed geographic info object
Tuple<string, List<string>> ipAddressInfo = "114.114.114.114".GetIPAddressInfo().Result;// Get detailed geographic info collection
21. Element Deduplication
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. Enum Extensions
public enum MyEnum
{
[Display(Name = "Read")]
[Description("Read")]
Read,
[Display(Name = "Write")]
[Description("Write")]
Write
}
Dictionary<int, string> dic1 = typeof(MyEnum).GetDictionary();// Get enum value and string representation dictionary
var dic2 = typeof(MyEnum).GetDescriptionAndValue();// Get string representation and enum value dictionary
string desc = MyEnum.Read.GetDescription();// Get Description label
string display = MyEnum.Read.GetDisplay();// Get Display label Name property
var value = typeof(MyEnum).GetValue("Read");// Get enum value from string representation
string enumString = 0.ToEnumString(typeof(MyEnum));// Get string representation from enum value
23. Fixed-length Queue and ConcurrentHashSet Implementation
If .NET5 or above, it is recommended to use the framework's built-in Channel to achieve this functionality
LimitedQueue<string> queue = new LimitedQueue<string>(32);// Declare a fixed-length queue with capacity 32
ConcurrentLimitedQueue<string> queue = new ConcurrentLimitedQueue<string>(32);// Declare a thread-safe fixed-length queue with capacity 32
var set = new ConcurrentHashSet<string>(); // Usage consistent with hashset
24. Reflection Operations
MyClass myClass = new MyClass();
PropertyInfo[] properties = myClass.GetProperties();// Get property list
myClass.SetProperty("Email","1@1.cn");// Set value to object
myClass.DeepClone(); // Deep copy object with nested levels
25. Get Thread-Unique Object
CallContext<T>.SetData("db",dbContext);//Set thread-unique object
CallContext<T>.GetData("db");//Get thread-unique object
26. Email Sending
new Email()
{
SmtpServer = "smtp.masuit.com",// SMTP server
SmtpPort = 25, // SMTP server port
EnableSsl = true,// Use SSL
Username = "admin@masuit.com",// Email username
Password = "123456",// Email password
Tos = "10000@qq.com,10001@qq.com", // Recipients
Subject = "Test Email",// Email subject
Body = "Hello",// Email body
}.SendAsync(s =>
{
Console.WriteLine(s);// Callback after successful send
});// Send email asynchronously
27. Simple Image Processing
ImageUtilities.CompressImage(@"F:\src\1.jpg", @"F:\dest\2.jpg");//Lossless image compression
"base64".SaveDataUriAsImageFile();// Convert Base64 string to image
Image image = Image.FromFile(@"D:\1.jpg");
image.MakeThumbnail(@"D:\2.jpg", 120, 80, ThumbnailCutMode.LockWidth);//Generate thumbnail
Bitmap bmp = new Bitmap(@"D:\1.jpg");
Bitmap newBmp = bmp.BWPic(bmp.Width, bmp.Height);//Convert to black and white
Bitmap newBmp = bmp.CutAndResize(new Rectangle(0, 0, 1600, 900), 160, 90);//Crop and resize
bmp.RevPicLR(bmp.Width, bmp.Height);//Mirror left-right
bmp.RevPicUD(bmp.Width, bmp.Height);//Mirror up-down
var marker=ImageWatermarker(stream);
stream=maker.AddWatermark("Watermark Text","Font File",FontSize,color,WatermarkPosition,Margin); // Add watermark text to image
stream=maker.AddWatermark(WatermarkImage,WatermarkPosition,Margin,FontSize,Font); // Add watermark image to image
// Image similarity comparison
var hasher = new ImageHasher();
var hash1 = hasher.DifferenceHash256("Image1"); // Use difference hash algorithm to compute 256-bit hash of image
var hash2 = hasher.DifferenceHash256("Image2"); // Use difference hash algorithm to compute 256-bit hash of image
//var hash1 = hasher.AverageHash64("Image1"); // Use average algorithm to compute 64-bit hash of image
//var hash2 = hasher.AverageHash64("Image2"); // Use average algorithm to compute 64-bit hash of image
//var hash1 = hasher.DctHash("Image1"); // Use DCT algorithm to compute 64-bit hash of image
//var hash2 = hasher.DctHash("Image2"); // Use DCT algorithm to compute 64-bit hash of image
//var hash1 = hasher.MedianHash64("Image1"); // Use median algorithm to compute 64-bit hash of image
//var hash2 = hasher.MedianHash64("Image2"); // Use median algorithm to compute 64-bit hash of image
var sim=ImageHasher.Compare(hash1,hash2); // Image similarity, range: [0,1]
var imageFormat=stream.GetImageType(); // Get actual image format
28. Random Numbers
Random rnd = new Random();
int num = rnd.StrictNext();//Generate true random number
double gauss = rnd.NextGauss(20,5);//Generate Gaussian normal distribution random number
var s = new NumberFormater(62).ToString(new Random().Next(100000, int.MaxValue));//Generate random string
29. Weighted Selection
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();//Select 1 element by weight
var list=data.WeightedItems(2);//Select 2 elements by weight
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();//Select 1 element by weight
var list = selector.SelectMultiple(3);//Select 3 elements by weight
30. EF Core Supports AddOrUpdate Method
/// <summary>
/// Add or update article entity by Id
/// </summary>
public override Post SavePost(Post t)
{
DataContext.Set<Post>().AddOrUpdate(t => t.Id, t);
return t;
}
31. Sensitive Information Masking
"13123456789".Mask(); // 131****5678
"admin@masuit.com".MaskEmail(); // a****n@masuit.com
32. Collection Extensions
var list = new List<string>()
{
"1","3","3","3"
};
list.AddRangeIf(s => s.Length > 1, "1", "11"); // Add elements with length > 1 to list
list.AddRangeIfNotContains("1", "11"); // Add elements not already in list
list.RemoveWhere(s => s.Length<1); // Remove elements with length < 1
list.InsertAfter(0, "2"); // Insert after first element
list.InsertAfter(s => s == "1", "2"); // Insert after element "1"
var dic = list.ToDictionarySafety(s => s); // Safely convert to dictionary, only add one key for duplicates
var dic = list.ToConcurrentDictionary(s => s); // Convert to concurrent dictionary, only add one key for duplicates
var dic = list.ToDictionarySafety(s => s, s => s.GetHashCode()); // Safely convert to dictionary, only add one key for duplicates
dic.AddOrUpdate("4", 4); // Add or update key-value pair
dic.AddOrUpdate(new Dictionary<string, int>()
{
["5"] = 5,["55"]=555
}); // Batch add or update key-value pairs
dic.AddOrUpdate("5", 6, (s, i) => 66); // If adding, value is 6; if updating, value is 66
dic.AddOrUpdate("5", 6, 666); // If adding, value is 6; if updating, value is 666
dic.GetOrAdd("7",77); // Dictionary get or add element
dic.GetOrAdd("7",()=>77); // Dictionary get or add element
dic.AsConcurrentDictionary(); // Convert normal dictionary to concurrent dictionary
var table=list.ToDataTable(); // Convert to DataTable
table.AddIdentityColumn(); // Add auto-increment column to DataTable
table.HasRows(); // Check if DataTable has data rows
table.ToList<T>(); // DataTable to List
var set = list.ToHashSet(s=>s.Name);// Convert to HashSet
var cts = new CancellationTokenSource(100); // Cancellation token
await list.ForeachAsync(async i=>{
await Task.Delay(100);
Console.WriteLine(i);
},cts.Token); // Async foreach
await list.ForAsync(async (item,index)=>{
await Task.Delay(100);
Console.WriteLine(item+"_"+index);
},cts.Token); // Async for with index
await list.SelectAsync(async i=>{
await Task.Delay(100);
return i*10;
}); // Async Select
await list.SelectAsync(async (item,index)=>{
await Task.Delay(100);
return item*10;
}); // Async Select with index
string s=list.Join(",");//Join string collection into comma-separated single string
var max=list.MaxOrDefault(); // Get max value, no error when collection is empty
var max=list.MaxOrDefault(selector); // Get max value, no error when collection is empty
var max=list.MaxOrDefault(selector,default); // Get max value, no error when collection is empty
var max=list.MinOrDefault(); // Get min value, no error when collection is empty
var max=list.MinOrDefault(selector); // Get min value, no error when collection is empty
var max=list.MinOrDefault(selector,default); // Get min value, no error when collection is empty
var stdDev=list.Select(s=>s.ConvertTo<int>()).StandardDeviation(); // Calculate standard deviation
var pages=queryable.ToPagedList(1,10); // Paged query
var pages=await queryable.ToPagedListAsync(1,10); // Paged query async
var nums=Enumerable.Range(1, 10).ExceptBy(Enumerable.Range(5, 10), i => i); // Set difference by key
var nums=Enumerable.Range(1, 10).IntersectBy(Enumerable.Range(5, 10), i => i); // Set intersection by key
var nums=Enumerable.Range(1, 10).SequenceEqual(Enumerable.Range(5, 10), i => i); // Check sequence equality
var nums=Enumerable.Range(1, 10).OrderByRandom(); // Random order
// Multiple collection intersection
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]
// Change element index in collection
list.ChangeIndex(item,3); // Change index of element item to 3
list.ChangeIndex(t=>t.Id=="123",2); // Change index of element with id "123" to 2
33. Mime Types
var mimeMapper = new MimeMapper();
var ext = mimeMapper.GetExtensionFromMime("image/jpeg"); // .jpg
var mime = mimeMapper.GetMimeFromExtension(".jpg"); // image/jpeg
34. DateTime Extensions
DateTime.Now.GetTotalSeconds(); // Get seconds since 1970-01-01 00:00:00
DateTime.Now.GetTotalMilliseconds(); // Get milliseconds since 1970-01-01 00:00:00
DateTime.Now.GetTotalMicroseconds(); // Get microseconds since 1970-01-01 00:00:00
DateTime.Now.GetTotalNanoseconds(); // Get nanoseconds since 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(); //String to DateTime
// Time range calculation tool
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")); // Union two time ranges, result: 2020-8-3~2020-8-6
range.In(DateTime.Parse("2020-8-3"), DateTime.Parse("2020-8-6"));//Check if within a time range, true
var (intersected,range2) = range.Intersect(DateTime.Parse("2020-8-4"), DateTime.Parse("2020-8-6"));//Check if two time ranges intersect, (true,2020-8-3~2020-8-4)
range.Contains(DateTime.Parse("2020-8-3"), DateTime.Parse("2020-8-4"));//Check if contains a time range, true
...
35. Stream Related
stream.SaveAsMemoryStream(); // Convert any stream to memory stream
stream.ToArray(); // Convert any stream to byte array
stream.ToArrayAsync(); // Convert any stream to byte array async
stream.ShuffleCode(); // Stream shuffle, append a few null bytes at the end, use with caution for important data, may cause stream corruption
// Pooled memory stream, usage same as MemorySteam
using var ms=PooledMemoryStream();
// Large memory stream, supports up to 1TB memory data, recommended when data stream >2GB, usage same as MemorySteam
using var ms=LargeMemoryStream();
// Fast file stream copy
FileStream fs = new FileStream(@"D:\boot.vmdk", FileMode.OpenOrCreate, FileAccess.ReadWrite);
{
//fs.CopyToFile(@"D:\1.bak");//Sync copy large file
fs.CopyToFileAsync(@"D:\1.bak");//Async copy large file
string md5 = fs.GetFileMD5Async().Result;//Async get file MD5
string sha1 = fs.GetFileSha1();//Async get file SHA1
}
memoryStream.SaveFile("filename"); // Save memory stream to file
36. Numeric Conversion
1.2345678901.Digits8(); // Truncate decimal to 8 digits
1.23.ConvertTo<int>(); // Decimal to int
1.23.ConvertTo<T>(); // Decimal to T basic type
bool b=1.23.TryConvertTo<T>(out result); // Decimal to T basic type
var num=1.2345.ToDecimal(2); //Convert to decimal with 2 decimal places
37. INI Configuration File Operations (Windows only)
INIFile ini=new INIFile("filename.ini");
ini.IniWriteValue(section,key,value); // Write value
ini.IniReadValue(section,key); // Read value
ini.ClearAllSection(); // Clear all sections
ini.ClearSection(section); // Clear section
38. Radar Chart Calculation Engine
Use case: Calculate similarity of two polygons, user profiling, etc.
var points=RadarChartEngine.ComputeIntersection(chart1,chart2); // Get intersection area of two polygons
points.ComputeArea(); // Calculate polygon area
39. Tree Structure Implementation
Basic interfaces:
ITreeChildren: Interface with Children property
ITreeParent: Interface with Parent property
ITree: Inherits ITreeParent and ITreeChildren, plus Name property
Related extension methods:
trees.Filter(func); // Filter from tree collection
trees.Flatten(); // Flatten data
tree.AllChildren(); // Get all children
tree.AllParent(); // Get all parents
tree.IsRoot(); // Check if root node
tree.IsLeaf(); // Check if leaf node
tree.Level(); // Get depth/level
tree.Path(); // Get full path
var tree=list.ToTree(c => c.Id, c => c.Pid);//Convert collection inheriting ITreeParent<T>, ITreeChildren<T> to tree structure
var tree=list.ToTreeGeneral(c => c.Id, c => c.Pid);//Convert general collection to tree structure
40. Simple Excel Export
Requires additional dependency package: Masuit.Tools.Excel
var stream=list.Select(item=>new{
Name=item.Name,
Age=item.Age,
item.Gender,
Avatar=Image.FromStream(filestream) //Image column
}).ToDataTable().ToExcel("Sheet1"); //Custom column name export
var stream=list.ToDataTable("Sheet1").ToExcel("File password");
Some conventions:
- Image columns support Stream, Bitmap, IEnumerable
, IEnumerable , IDictionary<string,Stream>, IDictionary<string,MemoryStream>, IDictionary<string,Bitmap> types; - For IDictionary type image columns, the dictionary key is the full URL of the image hyperlink;
- Default field name as column name for export;
- If list is a specific strong type, it will first look for each field's Description attribute; if Description is present, use it as column name.
- ToExcel method supports direct calls on DataTable, List
, Dictionary<string, DataTable>
41. EFCore Entity Comparison
Get changes of a specific entity
var changes=dbContext.GetChanges<Post>();//Get changed field info
var added=dbContext.GetAdded<Post>();//Get added entity field info
var removed=dbContext.GetRemoved<Post>();//Get removed entity field info
var allchanges=dbContext.GetAllChanges<Post>();//Get all added, modified, removed entity field info
Get changes of all entities
var changes=dbContext.GetChanges();//Get changed field info
var added=dbContext.GetAdded();//Get added entity field info
var removed=dbContext.GetRemoved();//Get removed entity field info
var allchanges=dbContext.GetAllChanges();//Get all added, modified, removed entity field info
Comparison info includes property info, old value, new value, entity info, key info, change status, etc.
42. Any Type Supports Chained Calls
a.Next(func1).Next(func2).Next(func3);
"123".Next(s=>s.ToInt32()).Next(x=>x*2).Next(x=>Math.Log(x));
43. Newtonsoft.Json Contract Resolvers for Allowed Field Deserialization Only
DeserializeOnlyContractResolver
This resolver, for class properties marked with DeserializeOnlyJsonPropertyAttribute, takes effect during deserialization and is ignored during serialization.
public class ClassDto
{
[DeserializeOnlyJsonProperty]
public string MyProperty { get; set; }
public int Num { get; set; }
}
JsonConvert.SerializeObject(new MyClass(),new JsonSerializerSettings()
{
ContractResolver = new DeserializeOnlyContractResolver() // Configure to use DeserializeOnlyContractResolver
});
For global use in WebAPI:
//In Startup.ConfigureServices
services.AddMvc().AddNewtonsoftJson(options =>
{
var resolver = new DeserializeOnlyContractResolver();
resolver.NamingStrategy = new CamelCaseNamingStrategy();
options.SerializerSettings.ContractResolver = resolver;
});
FallbackJsonPropertyResolver
This resolver allows setting multiple aliases for a property, supporting multiple alias keys during deserialization, compensating for the limitation of the official JsonProperty alias attribute that only allows a single alias.
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() // Configure to use FallbackJsonPropertyResolver
});
CompositeContractResolver
This resolver is a combination of DeserializeOnlyContractResolver and FallbackJsonPropertyResolver.
44. ASP.NET Core Action Model Binder BodyOrDefaultModelBinder Supporting queryString, Form, and JSON Request Types
Usage:
Import package: Masuit.Tools.AspNetCore
PM> Install-Package Masuit.Tools.AspNetCore
Startup configuration:
services.AddMvc(options =>
{
options.ModelBinderProviders.InsertBodyOrDefaultBinding();
})
Mark the action parameter model with [FromBodyOrDefault] attribute, can also be omitted. Example code:
[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. String SimHash Similarity Algorithm
var dis="12345678".HammingDistance("1234567");
var dis=new SimHash("12345678").HammingDistance(new SimHash("1234567"));
46. Real File Type Detection
// Multiple ways, choose as you like
var detector=new FileInfo(filepath).DetectFiletype();
//var detector=File.OpenRead(filepath).DetectFiletype();
//var detector=FileSignatureDetector.DetectFiletype(filepath);
detector.Precondition;//Basic file type
detector.Extension;//Real extension
detector.MimeType;//MimeType
detector.FormatCategories;//Format category
Default Supported File Types
| Extension | Description |
|---|---|
| 3GP | 3GPP, 3GPP 2 |
| 7Z | 7-Zip |
| APK | ZIP based Android Package |
| AVI | Audio-Video Interleave |
| SH | Shell Script |
| BPLIST | Binary Property List |
| BMP, DIB | Bitmap |
| BZ2 | Bunzip2 Compressed |
| CAB | Microsoft Cabinet |
| CLASS | Java Bytecode |
| CONFIG | .NET Configuration File |
| CRT, CERT | Certificate |
| CUR | Cursor |
| DB | Windows Thumbs.db Thumbnail Database |
| DDS | DirectDraw Surface |
| DLL | Windows Dynamic Linkage Library |
| DMG | Apple Disk Mount Image |
| DMP | Windows Memory Dump File |
| DOC | Microsoft Office Word 97-2003 Document |
| DOCX | Microsoft Office Word OpenXML Document |
| EPUB | e-Pub Document |
| EXE | Windows Executive |
| FLAC | Loseless Audio |
| FLV | Flash Video |
| GIF | Graphics Interchage Format |
| GZ | GZ Compressed |
| HDP | HD Photo(JPEG XR) Image |
| HWP | Legacy HWP, HWPML, CFBF HWP |
| ICO | Icon |
| INI | Initialization File |
| ISO | ISO-9660 Disc Image |
| LNK | Windows Shortcut Link |
| JP2 | JPEG 2000 Image |
| JPG, JPEG | Joint Photographic Experts Group Image |
| LZH | LZH Compressed |
| M4A | MP4 Container Contained Audio Only |
| M4V | MP4 Container Contained Video |
| MID | Midi Sound |
| MKA | Matroska Container Contained Audio Only |
| MKV | Matroska Container Contained Video |
| MOV | QuickTime Movie Video |
| MP4 | MP4 Container Contained Contents |
| MSI | Microsoft Installer |
| OGG | OGG Video or Audio |
| ODF | OpenDocument Formula |
| ODG | OpenDocument Graphics |
| ODP | OpenDocument Presentation |
| ODS | OpenDocument Spreadsheet |
| ODT | OpenDocument Text |
| PAK | PAK Archive or Quake Archive |
| PDB | Microsoft Program Database |
| Portable Document Format | |
| PFX | Microsoft Personal Information Exchange Certificate |
| PNG | Portable Network Graphics Image |
| PPT | Microsoft Office PowerPoint 97-2003 Document |
| PPTX | Microsoft Office PowerPoint OpenXML Document |
| PPSX | Microsoft Office PowerPoint OpenXML Document for Slideshow only |
| PSD | Photoshop Document |
| RAR | WinRAR Compressed |
| REG | Windows Registry |
| RPM | RedHat Package Manager Package |
| RTF | Rich Text Format Document |
| SLN | Microsoft Visual Studio Solution |
| SRT | SubRip Subtitle |
| SWF | Shockwave Flash |
| SQLITE, DB | SQLite Database |
| TAR | pre-ISO Type and UStar Type TAR Package |
| TIFF | Tagged Image File Format Image |
| TXT | Plain Text |
| WAV | Wave Audio |
| WASM | Binary WebAssembly |
| WEBM | WebM Video |
| WEBP | WebP Image |
| XAR | XAR Package |
| XLS | Microsoft Office Excel 97-2003 Document |
| XLSX | Microsoft Office Excep OpenXML Document |
| XML | Extensible Markup Language Document |
| Z | Z Compressed |
| ZIP | ZIP Package |
Asp.Net MVC and ASP.NET Core ResumeFileResult Supporting Resumable Download and Multi-threaded Download
Provides resumable download and multi-threaded download support when transmitting file data through MVC/WebAPI applications in ASP.NET Core.
It provides ETag and Last-Modified headers. It also supports the following precondition headers: If-Match, If-None-Match, If-Modified-Since, If-Unmodified-Since, If-Range.
Supports ASP.NET Core 2.0+
From .NET Core 2.0, ASP.NET Core natively supports resumable download. So this is just an extension to FileResult. Only the "Content-Disposition" Inline part is left. All code relies on underlying .NET classes.
How to Use
.NET Framework
In your controller, you can use it like FileResult.
using Masuit.Tools.Mvc;
using Masuit.Tools.Mvc.ResumeFileResult;
private readonly MimeMapper mimeMapper=new MimeMapper(); // Dependency injection recommended
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
To use ResumeFileResults, you must configure the service in the ConfigureServices method of Startup.cs:
using Masuit.Tools.AspNetCore.ResumeFileResults.Extensions;
public void ConfigureServices(IServiceCollection services)
{
services.AddResumeFileResult();
}
Then in your controller, you can use it like FileResult.
Click to view code
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;
}
The above examples will provide "Content-Disposition: attachment" for your data. When no fileName is provided, data will be provided as "Content-Disposition: inline". Additionally, it can provide ETag and LastModified headers.
[HttpGet("virtual/{fileName}")]
public IActionResult VirtualFile(bool fileName)
{
var result = new ResumeVirtualFileResult("TestFile.txt", "text/plain")
{
FileInlineName = "TestFile.txt",
LastModified = _lastModified
};
return result;
}
Recommended Projects
Full-text search engine based on EntityFrameworkCore and Lucene.NET: Masuit.LuceneEFCore.SearchEngine
Open-source blog system: Masuit.MyBlogs