あなたが示したクライアント コードは、決してリクエストを送信しません。webRequest.GetResponse()
リクエストを送信するには、電話する必要があります。しかし、私はWebClientを訴えるこのクライアントコードを単純化します:
using (var client = new WebClient())
{
var data = new NameValueCollection
{
{ "image", imageBase64String }
};
var result = client.UploadValues(ip, data);
Console.WriteLine(Encoding.Default.GetString(result));
}
サーバー側のコードに関する限り、質問で言及していないサードパーティのフレームワークを使用しているようです。たとえば、次の ASP.NET ハンドラは~/UploadImage.ashx
、前に示したクライアントで完全に正常に動作します ( )。
public class UploadImage : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var imageBase64String = context.Request.Form["image"];
var imageBuffer = Convert.FromBase64String(imageBase64String);
using (var stream = new MemoryStream(imageBuffer))
using (var image = Image.FromStream(stream))
{
image.Save(@"c:\work\test.png");
}
context.Response.ContentType = "text/plain";
context.Response.Write("upload successful");
}
public bool IsReusable
{
get { return false; }
}
}
しかし、サーバーにファイルをアップロードする場合、なぜ車輪を再発明するのでしょうか? application/x-www-form-urlencoded
ホイールが再発明された Base64 エンコーディングがあるのに、なぜ base64 を使用するのmultipart/form-data
ですか?
エンコーディングのために特別に設計されたこれを利用するようにクライアントを改善しましょう。1 つ以上のファイルを直接アップロードできる WebClient の拡張メソッドを作成することから始めましょう。
public class UploadFile
{
public UploadFile()
{
ContentType = "application/octet-stream";
}
public string Name { get; set; }
public string Filename { get; set; }
public string ContentType { get; set; }
public Stream Stream { get; set; }
}
public static class WebClientExtensions
{
public static byte[] UploadFiles(this WebClient client, string address, IEnumerable<UploadFile> files, NameValueCollection values)
{
var request = WebRequest.Create(address);
request.Method = "POST";
var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);
request.ContentType = "multipart/form-data; boundary=" + boundary;
boundary = "--" + boundary;
using (var requestStream = request.GetRequestStream())
{
// Write the values
foreach (string name in values.Keys)
{
var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
requestStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"{1}{1}", name, Environment.NewLine));
requestStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);
requestStream.Write(buffer, 0, buffer.Length);
}
// Write the files
foreach (var file in files)
{
var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
requestStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"{2}", file.Name, file.Filename, Environment.NewLine));
requestStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", file.ContentType, Environment.NewLine));
requestStream.Write(buffer, 0, buffer.Length);
file.Stream.CopyTo(requestStream);
buffer = Encoding.ASCII.GetBytes(Environment.NewLine);
requestStream.Write(buffer, 0, buffer.Length);
}
var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + "--");
requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length);
}
using (var response = request.GetResponse())
using (var responseStream = response.GetResponseStream())
using (var stream = new MemoryStream())
{
responseStream.CopyTo(stream);
return stream.ToArray();
}
}
}
クライアントは次のようになります。
byte[] image = ... go and fetch the image that you want to upload
using (var stream = new MemoryStream(image))
using (var client = new WebClient())
{
var files = new[]
{
new UploadFile
{
Name = "image",
Filename = "test.jpg",
ContentType = "image/jpg",
Stream = stream
}
};
var result = client.UploadFiles("http://localhost:6830/uploadimage.ashx", files, new NameValueCollection());
Console.WriteLine(Encoding.Default.GetString(result));
}
そして、前に見た処理するサーバー:
public class UploadImage : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var uploadedImage = context.Request.Files["image"];
using (var image = Image.FromStream(uploadedImage.InputStream))
{
image.Save(@"c:\work\test.png");
}
context.Response.ContentType = "text/plain";
context.Response.Write("upload successful");
}
public bool IsReusable
{
get { return false; }
}
}
このコードを改善するための次のステップは何だと思いますか? 回答: もちろん、ファイルがサーバーにアップロードされるのを待っている間、呼び出しスレッドをブロックする代わりに、I/O 完了ポートを利用する非同期クライアント要求です。