问题描述
我正在尝试将文件从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,buffer.Length)) != 0)
{
writer.Write(buffer,readCount);
length += readCount;
}
}
反应前端是
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;
解决方法
这是因为您将整个表单直接提交给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,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,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,buffer.Length);
if (read <= 0)
return ms.ToArray();
ms.Write(buffer,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,ClientRuntime clientRuntime)
{
return;
}
public void ApplyDispatchBehavior(ContractDescription contractDescription,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)
{
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();
}
}
}
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,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;
}
}
}
尝试传输以下图像: