我正在与c#MVC2和ASP合作.网我的一个表单包含一个文件输入字段,允许用户 Select 任何文件类型,然后将其转换为blob并保存到数据库中.我的问题是,每当用户 Select 的文件超过一定数量的Mb(约8)时,就会出现如下页面错误:

The connection was reset
The connection to the server was reset while the page was loading.

我不介意用户上传的文件有8Mb的限制,但是我需要阻止当前错误的发生,并显示正确的验证消息(最好使用ModelState.AddModelError函数).有人能帮我吗?我似乎无法在页面中发生任何其他事情之前"捕获"错误,因为它发生在控制器内的上载函数中之前.

推荐答案

一种可能性是编写自定义验证属性:

public class MaxFileSizeAttribute : ValidationAttribute
{
    private readonly int _maxFileSize;
    public MaxFileSizeAttribute(int maxFileSize)
    {
        _maxFileSize = maxFileSize;
    }

    public override bool IsValid(object value)
    {
        var file = value as HttpPostedFileBase;
        if (file == null)
        {
            return false;
        }
        return file.ContentLength <= _maxFileSize;
    }

    public override string FormatErrorMessage(string name)
    {
        return base.FormatErrorMessage(_maxFileSize.ToString());
    }
}

然后您可以拥有一个视图模型:

public class MyViewModel
{
    [Required]
    [MaxFileSize(8 * 1024 * 1024, ErrorMessage = "Maximum allowed file size is {0} bytes")]
    public HttpPostedFileBase File { get; set; }
}

控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel());
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        if (!ModelState.IsValid)
        {
            // validation failed => redisplay the view
            return View(model);
        }

        // the model is valid => we could process the file here
        var fileName = Path.GetFileName(model.File.FileName);
        var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
        model.File.SaveAs(path);

        return RedirectToAction("Success");
    }
}

还有一个观点:

@model MyViewModel

@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.TextBoxFor(x => x.File, new { type = "file" })
    @Html.ValidationMessageFor(x => x.File)
    <button type="submit">OK</button>
}

现在,当然,为了让这项功能发挥作用,你必须增加允许的最大上传文件大小.配置为足够大的值:

<!-- 1GB (the value is in KB) -->
<httpRuntime maxRequestLength="1048576" />

对于IIS7:

<system.webServer>
    <security>
        <requestFiltering>
           <!-- 1GB (the value is in Bytes) -->
            <requestLimits maxAllowedContentLength="1073741824" />
        </requestFiltering>
    </security>
</system.webServer>

现在,我们可以进一步使用自定义验证属性,并启用客户端验证以避免浪费带宽.当然,上传前验证文件大小只能使用HTML5 File API.因此,只有支持该API的浏览器才能利用它.

因此,第一步是让我们的自定义验证属性实现IClientValidatable接口,这将允许我们在javascript中附加一个自定义适配器:

public class MaxFileSizeAttribute : ValidationAttribute, IClientValidatable
{
    private readonly int _maxFileSize;
    public MaxFileSizeAttribute(int maxFileSize)
    {
        _maxFileSize = maxFileSize;
    }

    public override bool IsValid(object value)
    {
        var file = value as HttpPostedFileBase;
        if (file == null)
        {
            return false;
        }
        return file.ContentLength <= _maxFileSize;
    }

    public override string FormatErrorMessage(string name)
    {
        return base.FormatErrorMessage(_maxFileSize.ToString());
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = FormatErrorMessage(_maxFileSize.ToString()),
            ValidationType = "filesize"
        };
        rule.ValidationParameters["maxsize"] = _maxFileSize;
        yield return rule;
    }
}

剩下的就是配置自定义适配器了:

jQuery.validator.unobtrusive.adapters.add(
    'filesize', [ 'maxsize' ], function (options) {
        options.rules['filesize'] = options.params;
        if (options.message) {
            options.messages['filesize'] = options.message;
        }
    }
);

jQuery.validator.addMethod('filesize', function (value, element, params) {
    if (element.files.length < 1) {
        // No files selected
        return true;
    }

    if (!element.files || !element.files[0].size) {
        // This browser doesn't support the HTML5 API
        return true;
    }

    return element.files[0].size < params.maxsize;
}, '');

Asp.net相关问答推荐

IISExpress未在ARM64 Mac/.NET 4.8上启动

将 Response.Headers.Add 替换为方法属性decorator

如何格式化搜索字符串以从 Razor 页表中的多个列返回部分搜索字符串?

什么是 SNIReadSyncOverAsync,为什么需要很长时间才能完成?

C# ASP.NET Core Serilog 添加类名和方法到日志(log)

如何调试 Azure 500 内部服务器错误

模型项的类型为 CookMeIndexViewModel,但需要类型为 IEnumerable 的模型项

我应该使用用户名还是用户 ID 来引用 ASP.NET 中经过身份验证的用户

缩小失败.返回未缩小的内容

带有完整内存错误的 WCF 服务(内存门判断失败,因为可用内存) - 如何解决

获取页面上特定类型的所有 Web 控件

ASP.NET 会话超时测试

@(at) 登录文件路径/字符串

如何忽略身份框架的魔力,只使用 OWIN 身份验证中间件来获取我寻求的声明?

Request.Cookies 和 Response.Cookies 之间的区别

主机与 DnsSafeHost

压力测试 ASP.Net 应用程序

使用 ConfigurationManager.RefreshSection 重新加载配置而不重新启动应用程序

如何判断字符串的第一个字符是否是字母,C#中的任何字母

如何检索 X509Store 中的所有证书