1. Stop SMTPSVC service [Display Name: Simple Mail Transfer Protocol (SMTP)]
2. Stop IISADMIN service [Display name: IIS Admin Service]
3. Edit "C:\Windows\System32\inetsrv\MetaBase.xml"
4. Find: <IIsSmtpServer Location ="/LM/SmtpSvc/1"
5. Add (Settings are alphabetical): RelayIpList=""
6. Save file
7. Start IISAdmin Service
8. Start SMTPSVC service
PromiseAll: async function (array) {
let taskList = [];
let propList = [];
for (let obj of array) {
for (let prop in obj) {
taskList.push(obj[prop]);
propList.push(prop);
}
}
let resp = await Promise.all(taskList);
let result = {};
let counter = 0;
for (let prop of propList) {
result[prop] = resp[counter];
counter += 1;
}
return result;
}
const taskList = [{
adPosition : BannerPositionDataService.GetList(),
big : BannerDataService.GetList(100),
smallTop : BannerDataService.GetOne(200),
smallBottom : BannerDataService.GetOne(300),
section2 : BannerDataService.GetList(400),
section3 : BannerDataService.GetList(500),
section4 : BannerDataService.GetList(600),
recommends : ProductDataService.GetRndList()
}];
let resps = await UJ.PromiseAll(taskList);
DeepBinding: function (vueData, data) {
if (Array.isArray(data)) {
if (!Array.isArray(vueData)) {
vueData = [];
} else {
vueData.splice(0);
}
for (let prop in data) {
vueData.push(data[prop]);
}
}
else if (typeof (data) === 'object') {
if (Object.keys(data).length === 0) {
return;
}
for (let prop in data) {
if (vueData[prop] === undefined || data[prop] === null ||
(!Array.isArray(vueData[prop] && vueData !== null && typeof (data) !== 'object'))) {
vueData[prop] = data[prop];
} else {
this.DeepBinding(vueData[prop], data[prop]);
}
}
} else {
vueData = data;
}
}
UJ.DeepBinding(this, resp);
var root = "C://wdqd/qwewq";
var addPath = @"//\\/fwef/qwf";
var addPath2 = @"5fwfef/qwf";
var addPath3 = @"//fwef/qwf";
var addPath4 = @"\\\fwef/qwf";
var addPath5 = @"\\\\\/fwef/qwf";
var result = root.AddPath(addPath, addPath2, addPath3, addPath4, addPath5);
Console.WriteLine(result);
public static class Helper
{
public static string AddPath(this string value, params string[] addPaths)
{
if (string.IsNullOrEmpty(value))
{
throw new Exception("起始目錄不可以為空字串");
}
if (value.Contains("..") || addPaths.Any(x => x.Contains("..")))
{
throw new Exception($"value: {value}, addPaths: {addPaths.Where(x => x.Contains("..")).ToOneString()} 檔名與路徑不可包含 ..");
}
var paths = addPaths.Select(x => x.Substring(x.FindLastContinuousCharPosition('/', '\\') + 1).SafeFilename()).ToList();
if (paths.Any(x => System.IO.Path.IsPathRooted(x)))
{
throw new Exception("不可併入完整路徑 ..");
}
paths.Insert(0, value.SafeFilename());
return System.IO.Path.Combine(paths.ToArray());
}
public static string ToOneString<T>(this IEnumerable<T> list, string separator = ",")
{
var strList = list.Select(x => x.ToString());
return string.Join(separator, strList);
}
public static int FindLastContinuousCharPosition(this string input, params char[] targets)
{
int lastPosition = -1;
for (int i = 0; i < input.Length; i++)
{
if (targets.Contains(input[i]))
{
lastPosition = i;
}
else
{
break;
}
}
return lastPosition;
}
public static string SafeFilename(this string value)
{
return GetValidFilename(value);
}
public static string GetValidFilename(string value)
{
string ValidFilenameCharacters = @"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\-_$.@:/# ";
if (value.Contains(".."))
{
throw new Exception("路徑中不可包含 .. ");
}
string newUrl = "";
for (int i = 0; i < value.Length; i++)
{
var c = value.Substring(i, 1);
int k = ValidFilenameCharacters.IndexOf(c);
if (k < 0)
{
throw new Exception($"檔名 '{value}' 中有非法的字元 '" + c + "'。");
}
newUrl += ValidFilenameCharacters.Substring(k, 1);
}
return newUrl;
}
}
public ConcurrentBag<V2SalesOrderGetDataList> ConcurencyGetApp91OrderDetails(List<string> TMCodes, int shopId, ref ConcurrentBag<string> orderErrMsgs)
{
#region 平行查詢
ConcurrentBag<V2SalesOrderGetDataList> result = new ConcurrentBag<V2SalesOrderGetDataList>();
ConcurrentBag<string> errs = new ConcurrentBag<string>();
ConcurrentQueue<string> TMCodeQueues = new ConcurrentQueue<string>();
TMCodes.ForEach(x => TMCodeQueues.Enqueue(x));
Action searchOrderDetail = () =>
{
if (!TMCodeQueues.IsEmpty)
{
string TMCode = string.Empty;
while (TMCodeQueues.TryDequeue(out TMCode))
{
V2SalesOrderGetReqModel reqModel = new V2SalesOrderGetReqModel()
{
ShopId = shopId,
TGCode = null,
TMCode = TMCode,
TSCode = null,
};
try
{
V2SalesOrderGet91API req = new V2SalesOrderGet91API();
var resp = req.Execute(reqModel, shopId);
if (resp.Status == "Success")
{
foreach (var l in resp.Data.List)
{
result.Add(l);
}
}
else
{
//主單編號 , 錯誤原因
errs.Add(TMCode + " , " + resp.ErrorMessage);
}
}
catch (Exception ex)
{
errs.Add(TMCode + " , " + ex.Message);
}
}
}
};
//指派Thread
Parallel.Invoke(searchOrderDetail, searchOrderDetail);
#endregion
//查詢失敗
orderErrMsgs = errs;
return result;
}
/// <summary>
/// 會把物件 Parameter 的各 Property 帶入 SQL 中.
/// </summary>
/// <param name="dbct"></param>
/// <param name="sql"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static async Task<int> ExecuteParameterSqlAsync(this DbContext dbct, string sql, object parameters)
{
return await dbct.Database.ExecuteSqlRawAsync(sql, parameters.ToSqlParamsArray());
}
public async Task<object> EfTest()
{
var dbct = Ds.NewContext.GvContext;
var insertSql = @"Insert into ProfileEvent(JobId,[Name],GvShoplineId,LiShoplineId,Phone,Email,LineId,GaClientId)
Values(@JobId, @Name, null , null , null , @Email, @GaClientId , @GaClientId )";
//執行 SQL 的原生寫法
await dbct.Database.ExecuteSqlRawAsync(insertSql, new object[]
{
new SqlParameter("@JobId", 10),
new SqlParameter("@Email", "XX'TT"),
new SqlParameter("@Name", "AA'BB"),
new SqlParameter("@GaClientId", "GaClientId"),
});
//執行 SQL 的擴充寫法
await dbct.ExecuteParameterSqlAsync(insertSql, new
{
JobId = 10,
Email = "XX'TT",
Name = "AA'BB",
GaClientId = "GaClientId"
});
//關於查詢
string name = "%'B%";
//原生寫法
var res1 = await dbct.ProfileEvents.FromSqlRaw("Select top 100 * from ProfileEvent where Name like @name",
new object[]
{
new SqlParameter("@name", "%'B%")
})
.ToListAsync();
//擴充, object to SqlParameter array
var res2 = await dbct.ProfileEvents.FromSqlRaw("Select top 100 * from ProfileEvent where Name like @name",
new { name }.ToSqlParamsArray())
.ToListAsync();
var res3 = await dbct.ProfileEvents.FromSql($"Select top 100 * from ProfileEvent where Name like {name}")
.ToListAsync();
var res4 = await dbct.ProfileEvents.FromSqlInterpolated($"Select top 100 * from ProfileEvent where Name like {name}")
.ToListAsync();
return new { res1, res2, res3, res4 };
}
<ItemGroup>
<PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
<PackageReference Include="SQLiteNetExtensions.Async" Version="2.1.0" />
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.4" />
<PackageReference Include="SQLitePCLRaw.core" Version="2.1.4" />
<PackageReference Include="SQLitePCLRaw.lib.e_sqlite3" Version="2.1.4" />
<PackageReference Include="SQLitePCLRaw.provider.dynamic_cdecl" Version="2.1.4" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
</ItemGroup>
static List<Brush> CaptchaBrushes = null;
public static FileStreamResult CreateCaptcha(string captcha)
{
if (CaptchaBrushes == null)
{
CaptchaBrushes = new List<Brush>();
CaptchaBrushes.Add(Brushes.White);
CaptchaBrushes.Add(Brushes.Gold);
CaptchaBrushes.Add(Brushes.LightSkyBlue);
CaptchaBrushes.Add(Brushes.LimeGreen);
CaptchaBrushes.Add(Brushes.AliceBlue);
CaptchaBrushes.Add(Brushes.AntiqueWhite);
CaptchaBrushes.Add(Brushes.BurlyWood);
CaptchaBrushes.Add(Brushes.Silver);
}
int width = 90;
int height = 45;
//https://stackoverflow.com/questions/61365732/cannot-access-a-closed-stream-when-returning-filestreamresult-from-c-sharp-netc
//Using statements close and unload the variable from memory set in the using statement which is why you are getting an error trying to access a closed memory stream.You don't need to use a using statement if you are just going to return the result at the end.
//這個 memory stream 不用關閉或 dispose
var ms = new MemoryStream();
// 釋放所有在 GDI+ 所佔用的記憶體空間 ( 非常重要!! )
using (Bitmap _bmp = new Bitmap(width, height))
using (Graphics _graphics = Graphics.FromImage(_bmp))
using (Font _font = new Font("Courier New", 24, FontStyle.Bold)) // _font 設定要出現在圖片上的文字字型、大小與樣式
{
// (封裝 GDI+ 繪圖介面) 所有繪圖作業都需透過 Graphics 物件進行操作
_graphics.Clear(Color.Black);
// 如果想啟用「反鋸齒」功能,可以將以下這行取消註解
//_graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
// 將亂碼字串「繪製」到之前產生的 Graphics 「繪圖板」上
var x = 10;
for(var i = 0; i < captcha.Length; i++)
{
_graphics.DrawString(captcha.Substring(i, 1), _font, CaptchaBrushes[Su.MathUtil.GetRandomInt(CaptchaBrushes.Count)], x, Su.MathUtil.GetRandomInt(15));
x += 10 + Su.MathUtil.GetRandomInt(10);
}
// 畫線
_graphics.DrawLine(new Pen(CaptchaBrushes[Su.MathUtil.GetRandomInt(CaptchaBrushes.Count)], 1),
Su.MathUtil.GetRandomInt(0, Convert.ToInt32((width * 0.9 / 2))), 0, Su.MathUtil.GetRandomInt(Convert.ToInt32(width / 2), Convert.ToInt32(width * 1.9 / 2)), height);
_graphics.DrawLine(new Pen(CaptchaBrushes[Su.MathUtil.GetRandomInt(CaptchaBrushes.Count)], 1),
Su.MathUtil.GetRandomInt(Convert.ToInt32(width / 2), Convert.ToInt32(width * 1.9 / 2)), 0, Su.MathUtil.GetRandomInt(0, Convert.ToInt32((width * 0.9 / 2))), height);
_graphics.DrawLine(new Pen(CaptchaBrushes[Su.MathUtil.GetRandomInt(CaptchaBrushes.Count)], 1),
0,
Su.MathUtil.GetRandomInt(height / 2),
width,
height / 2 + Su.MathUtil.GetRandomInt(height / 2)
);
_graphics.DrawLine(new Pen(CaptchaBrushes[Su.MathUtil.GetRandomInt(CaptchaBrushes.Count)], 1),
0,
height / 2 + Su.MathUtil.GetRandomInt(height / 2),
width,
Su.MathUtil.GetRandomInt(height / 2)
);
_bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
}
ms.Seek(0, SeekOrigin.Begin);
// Controller 的型別為 FileResult
return new FileStreamResult(ms, "image/jpeg")
{ FileDownloadName = $"{DateTime.Now.Ymdhmsf()}.jpg" };
}
namespace Web.Controllers
{
public class CaptchaController : Controller
{
[Route("captcha")]
public async Task<FileStreamResult> Index()
{
//產生 Captcha 並存入 Session 之中。目前是四位數字
string captcha = (await Ah.ReGetAsync<object>("api/kol/create-captcha-code")).ToString();
//產生圖檔並回傳 FileStreamResult
return Su.Wu.CreateCaptcha(captcha);
}
}
}