Xamarin.Forms调用WCF传图遇413(RequestEntityTooLarge)错误求助
解决WCF 413(RequestEntityTooLarge)错误及Xamarin.Forms文件上传最优方案
先排查413错误的核心问题
你遇到的413错误是因为请求实体大小超过了服务器允许的上限,虽然你调整了WCF的配置,但可能还有几个关键配置没到位:
1. 补充IIS和ASP.NET的请求大小限制
你的web.config里的<httpRuntime>节点缺少maxRequestLength配置(这个参数单位是KB,默认仅4096KB=4MB),需要添加并设置足够大的值:
<system.web> <compilation debug="true" targetFramework="4.6.1" /> <httpRuntime targetFramework="4.6.1" maxRequestLength="2097152" /> <!-- 设置为2GB --> </system.web>
同时还要检查IIS站点的请求筛选设置:
- 打开IIS管理器,找到你的服务站点
- 点击「请求筛选」→「编辑功能设置」
- 把「最大允许内容长度」(单位是字节)调整为足够大的值,比如
2147483648(2GB)
2. 修正WCF绑定的配置错误
你的web.config存在绑定配置不匹配的问题:
- 你定义了
basicHttpBinding的配置BasicHttpBinding_IQuery_service,但客户端节点用的是webHttpBinding,并且绑定配置指向了BasicHttpBinding的配置,这会导致WCF服务实际没有使用到你设置的大消息限制。 - 配置中缺少
<services>节点,没有明确将服务与你定义的绑定配置关联,WCF会使用默认的basicHttpBinding(默认maxReceivedMessageSize仅65536字节)。
需要补充<services>节点,示例如下(替换YourNamespace为你实际的服务命名空间):
<system.serviceModel> <!-- 其他原有配置保持不变 --> <services> <service name="YourNamespace.Query_service" behaviorConfiguration="GlobalBehavior"> <endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IQuery_service" contract="YourNamespace.IQuery_service" behaviorConfiguration="GlobalEndpoint" /> </service> </services> <!-- 其他原有配置保持不变 --> </system.serviceModel>
3. 优化服务端上传代码
你的上传方法存在资源泄漏风险,fileStream被赋值后又在using里重复引用,会导致双重Dispose。建议直接在using中创建文件流,同时用Path.Combine避免路径拼接错误:
public bool UploadToFolder(byte[] file_bytes, string file_name) { bool isSuccess = false; string strFolderPath = System.Configuration.ConfigurationManager.AppSettings.Get(@"dest\path"); try { if (!string.IsNullOrEmpty(strFolderPath) && !string.IsNullOrEmpty(file_name)) { string strFileFullPath = Path.Combine(strFolderPath, file_name); using (var fs = new FileStream(strFileFullPath, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { fs.Write(file_bytes, 0, file_bytes.Length); isSuccess = true; } } } catch (Exception ex) { // 建议记录日志而非直接抛出原始异常,避免泄露敏感信息 throw new FaultException("文件上传失败,请稍后重试"); } return isSuccess; }
Xamarin.Forms文件上传的最优方案
WCF虽然可用,但现在更推荐REST API(如ASP.NET Core Web API)+ HttpClient的组合,跨平台支持更好、更轻量、生态更丰富。以下是具体建议:
1. 替换WCF为ASP.NET Core Web API
将上传服务改成ASP.NET Core Web API,它天生支持大文件上传,配置更简单:
- 在
Program.cs中配置请求大小限制:
builder.Services.Configure<FormOptions>(options => { options.MultipartBodyLengthLimit = 2147483648; // 设置为2GB });
- 编写上传接口:
[ApiController] [Route("api/upload")] public class UploadController : ControllerBase { [HttpPost] public async Task<IActionResult> Upload(IFormFile file) { var uploadPath = Path.Combine(Directory.GetCurrentDirectory(), "uploads"); Directory.CreateDirectory(uploadPath); var filePath = Path.Combine(uploadPath, file.FileName); using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } return Ok(new { success = true }); } }
2. 客户端用HttpClient流式上传
Xamarin.Forms中用HttpClient上传,支持流式传输(避免把整个文件读进内存)和进度监控:
using var httpClient = new HttpClient(); using var content = new MultipartFormDataContent(); // 从MediaPicker获取文件流 var result = await MediaPicker.PickPhotoAsync(); if (result != null) { using var stream = await result.OpenReadAsync(); var fileContent = new StreamContent(stream); fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg"); content.Add(fileContent, "file", result.FileName); // 监控上传进度 var progressHandler = new ProgressMessageHandler(); progressHandler.HttpSendProgress += (sender, args) => { double progress = args.ProgressPercentage; // 更新UI进度条 MainThread.BeginInvokeOnMainThread(() => { // progressBar.Progress = progress / 100; }); }; var client = HttpClientFactory.Create(progressHandler); var response = await client.PostAsync("http://your-server/api/upload", content); if (response.IsSuccessStatusCode) { await DisplayAlert("成功", "文件上传完成", "OK"); } else { await DisplayAlert("错误", "上传失败", "OK"); } }
3. 额外优化建议
- 图片压缩:上传前在客户端压缩图片,减少文件大小。可以用SkiaSharp库调整分辨率和质量:
using SkiaSharp; // 图片压缩示例 public byte[] CompressImage(byte[] imageData, int quality = 70, int maxWidth = 1920) { using var inputStream = new MemoryStream(imageData); using var originalBitmap = SKBitmap.Decode(inputStream); int newWidth = originalBitmap.Width > maxWidth ? maxWidth : originalBitmap.Width; int newHeight = (int)((float)newWidth / originalBitmap.Width * originalBitmap.Height); using var resizedBitmap = originalBitmap.Resize(new SKImageInfo(newWidth, newHeight), SKFilterQuality.High); using var image = SKImage.FromBitmap(resizedBitmap); using var outputStream = new MemoryStream(); image.Encode(SKEncodedImageFormat.Jpeg, quality).SaveTo(outputStream); return outputStream.ToArray(); }
- 分块上传:对于超大文件,分成多个小块上传,实现断点续传,避免因网络问题重新上传整个文件。
- HTTPS传输:确保上传请求用HTTPS,保障数据安全。
内容的提问来源于stack exchange,提问作者Leonardo Bassi
相关产品推荐
相关产品推荐

