<configuration>
<system.webServer>
<rewrite>
<outboundRules>
<rule name="Add CORS header for fonts" preCondition="IsFontFile">
<match serverVariable="RESPONSE_Access-Control-Allow-Origin" pattern=".*" />
<action type="Rewrite" value="*" />
</rule>
<preConditions>
<preCondition name="IsFontFile">
<add input="{REQUEST_URI}" pattern="\.woff2$|\.woff$|\.ttf$|\.eot$|\.otf$" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
</system.webServer>
</configuration>
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);
}
}
}
<configuration>
<system.webServer>
<security>
<requestFiltering>
<hiddenSegments>
<add segment=".svn" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
</configuration>

public class UploadController : ApiController
{
public async Task<object> PostFormData()
{
var provider = new MultipartMemoryStreamProvider();
if (! Request.Content.IsMimeMultipartContent())
{
return "no file";
}
//要注意這裡的 await
await Request.Content.ReadAsMultipartAsync(provider);
foreach (var content in provider.Contents)
{
if (content.Headers.ContentDisposition.FileName != null)
{
string localFilename = content.Headers.ContentDisposition.FileName.Replace("\"", "");
System.IO.Directory.CreateDirectory(HttpContext.Current.Server.MapPath(@"~/App_Data/Temp/"));
string filename = HttpContext.Current.Server.MapPath(@"~/App_Data/Temp/" + localFilename);
if (System.IO.File.Exists(filename))
{
System.IO.File.Delete(filename);
}
using (var fileStream = new FileStream(filename, FileMode.Create, FileAccess.Write))
{
var contentStream = await content.ReadAsStreamAsync();
await contentStream.CopyToAsync(fileStream);
Trace.WriteLine("Save To" + filename);
}
}
}
return "OK";
}
}
/// <summary>
/// 檔案檢查
/// </summary>
/// <param name="actionContext"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
Trace.WriteLine("ApiCheckFile OnActionExecutingAsync");
var request = actionContext.Request;
if (!request.Content.IsMimeMultipartContent())
{
return;
}
var provider = new MultipartMemoryStreamProvider();
await request.Content.ReadAsMultipartAsync(provider);
//把 provider 存入 System.Web.HttpContext.Current.Items 之中,以便在 controller 中再度使用
System.Web.HttpContext.Current.Items["MimeMultipartContentProvider"] = provider;
foreach (var content in provider.Contents)
{
if (content.Headers.ContentDisposition.FileName != null)
{
var filename = content.Headers.ContentDisposition.FileName.Replace("\"", "");
Trace.WriteLine(filename);
var ext = System.IO.Path.GetExtension(filename);
if (!".jpg,.jpeg,.png".Contains(ext.ToLower()))
{
throw new Exception("file format error.");
}
}
}
return;
}
public async Task<object> PostFormData()
{
//改由 HttpContext.Current.Items 中,讀取資料。
MultipartMemoryStreamProvider provider = (MultipartMemoryStreamProvider)System.Web.HttpContext.Current.Items["MimeMultipartContentProvider"];
//如果沒有經過 filter,provider會是 null, 這時就要直接由 Request.Content 讀入 provider
if (provider == null)
{
provider = new MultipartMemoryStreamProvider();
Request.Content.ReadAsMultipartAsync(provider);
}
foreach (var content in provider.Contents)
{
if (content.Headers.ContentDisposition.FileName != null)
{
string localFilename = content.Headers.ContentDisposition.FileName.Replace("\"", "");
Trace.WriteLine("FileName: " + localFilename);
Trace.WriteLine("FileName: " + @"~/App_Data/Temp/" + localFilename);
System.IO.Directory.CreateDirectory(HttpContext.Current.Server.MapPath(@"~/App_Data/Temp/"));
string filename = HttpContext.Current.Server.MapPath(@"~/App_Data/Temp/" + localFilename);
if (System.IO.File.Exists(filename))
{
System.IO.File.Delete(filename);
}
using (var fileStream = new FileStream(filename, FileMode.Create, FileAccess.Write))
{
var contentStream = await content.ReadAsStreamAsync();
await contentStream.CopyToAsync(fileStream);
Trace.WriteLine("Save To" + filename);
}
}
else
{
var contentStream = await content.ReadAsStreamAsync();
var reader = new System.IO.StreamReader(contentStream);
var data = reader.ReadToEnd();
Trace.WriteLine("data: " + data);
}
}
return "OK";
}
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
Debug.WriteLine("MvcCheckFileFilter OnActionExecuting");
if (actionContext.HttpContext.Request.Files.Count > 0)
{
for (int i = 0; i < actionContext.HttpContext.Request.Files.Count; i++)
{
System.Web.HttpPostedFileBase file = actionContext.HttpContext.Request.Files[i];
if (System.IO.Path.GetExtension(file.FileName) != ".jpg")
{
throw new Exception("file format error.");
}
Debug.WriteLine(i + "MvcCheckFileFilter OnActionExecuting File type: " + file.FileName.ToString());
}
}
//以下寫法會發生錯誤: 無法將類型 'System.String' 的物件轉換為類型 'System.Web.HttpPostedFileBase'。
//foreach (HttpPostedFileBase file in actionContext.HttpContext.Request.Files)
//{
// if (System.IO.Path.GetExtension(file.FileName) != ".jpg")
// {
// throw new Exception("file format error.");
// }
//}
}






<security>
<authentication>
<anonymousAuthentication enabled="false" />
<windowsAuthentication enabled="true" />
</authentication>
</security>

<section name="anonymousAuthentication" overrideModeDefault="Deny" />
<section name="windowsAuthentication" overrideModeDefault="Deny" />



