3

イメージを base64String としてエンコードし、それを http POST 要求の一部としてサーバーに送信するコンソール アプリケーションがあります。

問題は、それを開いてサーバー側を調べると、データがなくなっていることです。

文字列を送信するために使用しているコードは次のとおりです-

HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(ip);
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
string formPostString = "image=" + HttpUtility.UrlEncode(imageBase64String);
byte[] buffer = ASCIIEncoding.ASCII.GetBytes(formPostString);
webRequest.ContentLength = buffer.Length;
using (Stream webStream = webRequest.GetRequestStream())
{
    webStream.Write(buffer, 0, buffer.Length);
}

そして、私がそれをサーバー側で処理しているコード-

private void OnRequest(object source, RequestEventArgs args)
{
    IHttpClientContext context = (IHttpClientContext)source;
    IHttpRequest request = args.Request;

    ImageConverter imgConvert = new ImageConverter();
    string imageBase64String = request.Form["image"].Value;
    Image newImg = imgConvert.Base64StringToImage(imageBase64String);
    newImg.Save(@"..\Images\test.png", System.Drawing.Imaging.ImageFormat.Png);
}

新しい Image オブジェクトを作成する段階に達すると、imageBase64String は null になります。なぜこれが起こっているのか特定できないようです。

4

1 に答える 1

3

あなたが示したクライアント コードは、決してリクエストを送信しません。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 完了ポートを利用する非同期クライアント要求です。

于 2012-07-13T20:24:48.687 に答える