【问题标题】:C# file upload not supported typeC# 文件上传不支持类型
【发布时间】:2020-12-01 02:35:01
【问题描述】:

我正在尝试将文件从 react 前端上传到 c# wcf 后端。该文件正在服务中正确接收,但保存后未在任何程序中打开。 Windows 图像查看器显示该文件格式不受支持。

后端的代码是

string FilePath = Path.Combine
               (HostingEnvironment.MapPath("~/Images"), fileName);

            int length = 0;
            using (FileStream writer = new FileStream(FilePath, FileMode.Create))
            {
                int readCount;
                var buffer = new byte[8192];
                while ((readCount = stream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    writer.Write(buffer, 0, readCount);
                    length += readCount;
                }
            }

react 前端是

import React, {useState} from 'react';
import './App.css';
import axios from 'axios';

function App() {

  const [myfile, setFile] = useState()

  const handleChange = (e) => {
    setFile(e.target.files[0]);
  }

  const handleClick = () => {

    let file = myfile;

    let formData = new FormData();
    formData.append('Image',file,file.name);
    formData.append('ImageCaption','Testfile');

    axios({
      url: 'http://localhost:48526/Service1.svc/UploadFile?fileName=' + file.name,
      method: 'POST',
      data: formData
    }).then((res) => {
      console.log(res)
    })
  } 

  return (
    <div className="App">
      <div className="">
        <label>Select file</label>
        <input type="file" name="file" onChange={(e) => handleChange(e)}></input>
        <button onClick={handleClick}>Uplaod</button>
      </div>
    </div>
  );
}

export default App;

original picture

【问题讨论】:

  • 你能把整个错误信息贴出来吗?
  • stream的类型是什么?您是否有理由不使用docs.microsoft.com/en-us/dotnet/api/…(以避免您的字节数组等)?
  • @mjwills 文件在那里,它将保存保存到目标文件夹,但不知何故它正在改变文件的类型。正在保存相同的字节数和相同的名称和扩展名,但是当您尝试访问文件窗口时会出现类型不支持的错误
  • 请在您的问题中附上您尝试上传的文件示例,以及您的 C# 代码写入文件系统的结果文件(以便我们进行比较)。
  • 请分享minimal reproducible example,包括stream的来源。

标签: c# reactjs wcf file-upload


【解决方案1】:

这是因为你直接将整个表单提交给了WCF服务,并将整个表单保存为图片,所以需要在WCF服务获取到流后进行解析。

这是我的演示:

 [ServiceContract]
 [CustContractBehavior]
    public interface IReceiveData
    {
        [WebInvoke(UriTemplate = "UploadFile/{fileName}")]
        void UploadFile(string fileName, Stream fileContents);
    }
    public class RawDataService : IReceiveData
    {
        public void UploadFile(string fileName, Stream fileContents)
        {

            AntsCode.Util.MultipartParser parser = new AntsCode.Util.MultipartParser(fileContents);


            if (parser.Success)
            {
                System.IO.File.WriteAllBytes(@"c:\test.png", parser.FileContents);
            }
            else
            {
                Console.WriteLine("error");
            }



        }
    }

我使用MultipartParser解析流。关于multipartparser的信息,请参考以下链接:

https://archive.codeplex.com/?p=multipartparser

您也可以直接将以下类添加到您的项目中:

using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;


namespace AntsCode.Util
{
    public class MultipartParser
    {
        public MultipartParser(Stream stream)
        {
            this.Parse(stream, Encoding.UTF8);
        }

        public MultipartParser(Stream stream, Encoding encoding)
        {
            this.Parse(stream, encoding);
        }

        private void Parse(Stream stream, Encoding encoding)
        {
            this.Success = false;

            // Read the stream into a byte array
            byte[] data = ToByteArray(stream);

            // Copy to a string for header parsing
            string content = encoding.GetString(data);

            // The first line should contain the delimiter
            int delimiterEndIndex = content.IndexOf("\r\n");

            if (delimiterEndIndex > -1)
            {
                string delimiter = content.Substring(0, content.IndexOf("\r\n"));

                // Look for Content-Type
                Regex re = new Regex(@"(?<=Content\-Type:)(.*?)(?=\r\n\r\n)");
                Match contentTypeMatch = re.Match(content);

                // Look for filename
                re = new Regex(@"(?<=filename\=\"")(.*?)(?=\"")");
                Match filenameMatch = re.Match(content);

                // Did we find the required values?
                if (contentTypeMatch.Success && filenameMatch.Success)
                {
                    // Set properties
                    this.ContentType = contentTypeMatch.Value.Trim();
                    this.Filename = filenameMatch.Value.Trim();

                    // Get the start & end indexes of the file contents
                    int startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n".Length;

                    byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter);
                    int endIndex = IndexOf(data, delimiterBytes, startIndex);

                    int contentLength = endIndex - startIndex;

                    // Extract the file contents from the byte array
                    byte[] fileData = new byte[contentLength];

                    Buffer.BlockCopy(data, startIndex, fileData, 0, contentLength);

                    this.FileContents = fileData;
                    this.Success = true;
                }
            }
        }

        private int IndexOf(byte[] searchWithin, byte[] serachFor, int startIndex)
        {
            int index = 0;
            int startPos = Array.IndexOf(searchWithin, serachFor[0], startIndex);

            if (startPos != -1)
            {
                while ((startPos + index) < searchWithin.Length)
                {
                    if (searchWithin[startPos + index] == serachFor[index])
                    {
                        index++;
                        if (index == serachFor.Length)
                        {
                            return startPos;
                        }
                    }
                    else
                    {
                        startPos = Array.IndexOf<byte>(searchWithin, serachFor[0], startPos + index);
                        if (startPos == -1)
                        {
                            return -1;
                        }
                        index = 0;
                    }
                }
            }

            return -1;
        }

        private byte[] ToByteArray(Stream stream)
        {
            byte[] buffer = new byte[32768];
            using (MemoryStream ms = new MemoryStream())
            {
                while (true)
                {
                    int read = stream.Read(buffer, 0, buffer.Length);
                    if (read <= 0)
                        return ms.ToArray();
                    ms.Write(buffer, 0, read);
                }
            }
        }

        public bool Success
        {
            get;
            private set;
        }

        public string ContentType
        {
            get;
            private set;
        }

        public string Filename
        {
            get;
            private set;
        }

        public byte[] FileContents
        {
            get;
            private set;
        }
    }
   
}

如果问题仍然存在,请随时告诉我。

更新

这是我的项目目录,是一个控制台项目:

Program.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using AntsCode.Util;
namespace ConsoleApp58
{
    public class ServerMessageLogger : IDispatchMessageInspector
    {
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            return null;
        }
        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            WebOperationContext ctx = WebOperationContext.Current;
            ctx.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
        }
    }

    [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, AllowMultiple = false)]
    public class CustContractBehaviorAttribute : Attribute, IContractBehavior, IContractBehaviorAttribute
    {
        public Type TargetContract => throw new NotImplementedException();

        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
            return;
        }

        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            return;
        }

        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
        {
            dispatchRuntime.MessageInspectors.Add(new ServerMessageLogger());
        }

        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {
            return;
        }
    }

    [ServiceContract]
    [CustContractBehavior]
    public interface IReceiveData
    {
        [WebInvoke(UriTemplate = "UploadFile/{fileName}")]
        void UploadFile(string fileName, Stream fileContents);
    }
    public class RawDataService : IReceiveData
    {
        public void UploadFile(string fileName, Stream fileContents)
        {

            AntsCode.Util.MultipartParser parser = new AntsCode.Util.MultipartParser(fileContents);


            if (parser.Success)
            {

                try
                {
                    System.IO.File.WriteAllBytes(@"c:\test.png", parser.FileContents);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);

                }
            }
            else
            {
                Console.WriteLine("error");
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {

            string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            ServiceHost host = new ServiceHost(typeof(RawDataService), new Uri(baseAddress));
            host.AddServiceEndpoint(typeof(IReceiveData), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior() { HelpEnabled = true });
            host.Open();
            Console.WriteLine("Host opened");
            Console.ReadKey();
        }
    }
}

多部分解析器

using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace AntsCode.Util
{
    public class MultipartParser
    {
        public MultipartParser(Stream stream)
        {
            this.Parse(stream, Encoding.UTF8);
        }

        public MultipartParser(Stream stream, Encoding encoding)
        {
            this.Parse(stream, encoding);
        }

        private void Parse(Stream stream, Encoding encoding)
        {
            this.Success = false;

            // Read the stream into a byte array
            byte[] data = ToByteArray(stream);

            // Copy to a string for header parsing
            string content = encoding.GetString(data);

            // The first line should contain the delimiter
            int delimiterEndIndex = content.IndexOf("\r\n");

            if (delimiterEndIndex > -1)
            {
                string delimiter = content.Substring(0, content.IndexOf("\r\n"));

                // Look for Content-Type
                Regex re = new Regex(@"(?<=Content\-Type:)(.*?)(?=\r\n\r\n)");
                Match contentTypeMatch = re.Match(content);

                // Look for filename
                re = new Regex(@"(?<=filename\=\"")(.*?)(?=\"")");
                Match filenameMatch = re.Match(content);

                // Did we find the required values?
                if (contentTypeMatch.Success && filenameMatch.Success)
                {
                    // Set properties
                    this.ContentType = contentTypeMatch.Value.Trim();
                    this.Filename = filenameMatch.Value.Trim();

                    // Get the start & end indexes of the file contents
                    int startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n".Length;

                    byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter);
                    int endIndex = IndexOf(data, delimiterBytes, startIndex);

                    int contentLength = endIndex - startIndex;

                    // Extract the file contents from the byte array
                    byte[] fileData = new byte[contentLength];

                    Buffer.BlockCopy(data, startIndex, fileData, 0, contentLength);

                    this.FileContents = fileData;
                    this.Success = true;
                }
            }
        }

        private int IndexOf(byte[] searchWithin, byte[] serachFor, int startIndex)
        {
            int index = 0;
            int startPos = Array.IndexOf(searchWithin, serachFor[0], startIndex);

            if (startPos != -1)
            {
                while ((startPos + index) < searchWithin.Length)
                {
                    if (searchWithin[startPos + index] == serachFor[index])
                    {
                        index++;
                        if (index == serachFor.Length)
                        {
                            return startPos;
                        }
                    }
                    else
                    {
                        startPos = Array.IndexOf<byte>(searchWithin, serachFor[0], startPos + index);
                        if (startPos == -1)
                        {
                            return -1;
                        }
                        index = 0;
                    }
                }
            }

            return -1;
        }

        private byte[] ToByteArray(Stream stream)
        {
            byte[] buffer = new byte[32768];
            using (MemoryStream ms = new MemoryStream())
            {
                while (true)
                {
                    int read = stream.Read(buffer, 0, buffer.Length);
                    if (read <= 0)
                        return ms.ToArray();
                    ms.Write(buffer, 0, read);
                }
            }
        }

        public bool Success
        {
            get;
            private set;
        }

        public string ContentType
        {
            get;
            private set;
        }

        public string Filename
        {
            get;
            private set;
        }

        public byte[] FileContents
        {
            get;
            private set;
        }
    }

}

尝试传输下图:

【讨论】:

  • 感谢您的帮助。我正在尝试您的解决方案,它在目录上授予权限未授予错误。我试图用 System.IO.File.WriteAllBytes(HttpContext.Current.Server.MapPath("~/Image/"), parser.FileContents);但仍然显示未找到路径的错误。请指导如何解决。我感谢您的帮助。谢谢
  • 抱歉无法重现您的问题,建议您尝试使用 System.IO.File.WriteAllBytes(@"c:\test.png", parser.FileContents 将图片保存到 C 盘) 首先,然后以管理员身份运行它。它可以在我的电脑上运行。
  • 我将提供我的项目,您可以尝试创建它进行测试。
  • WCF 传输的默认数据大小为 64KB。图片超过64KB会报错。
  • 所以要传输的图片必须小于64KB。
猜你喜欢
  • 2018-06-18
  • 2021-10-15
  • 2021-05-26
  • 2019-10-07
  • 2022-06-11
  • 1970-01-01
  • 2011-06-21
  • 2019-10-25
  • 2018-10-29
相关资源
最近更新 更多