代码改变世界

ASP.NET MVC 3 扩展之增加一个验证上传文件扩展名的 DataAnnotation

2012-06-02 22:52  音乐让我说  阅读(651)  评论(0编辑  收藏  举报

直接贴代码:

FileExtensionsAttribute.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

/// <summary>
/// 文件扩展名验证器
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class FileExtensionsAttribute : DataTypeAttribute, IClientValidatable {
    private string _extensions;

    public FileExtensionsAttribute()
        : base("upload") {
            ErrorMessage = "字段 {0} 仅仅支持以下格式的扩展名: {1}!";
    }

    public string Extensions {
        get {
            return String.IsNullOrWhiteSpace(_extensions) ? "png,jpg,jpeg,gif" : _extensions;
        }
        set {
            _extensions = value;
        }
    }

    private string ExtensionsFormatted {
        get {
            return ExtensionsParsed.Aggregate((left, right) => left + ", " + right);
        }
    }

    private string ExtensionsNormalized {
        get {
            return Extensions.Replace(" ", "").Replace(".", "").ToLowerInvariant();
        }
    }

    private IEnumerable<string> ExtensionsParsed {
        get {
            return ExtensionsNormalized.Split(',').Select(e => "." + e);
        }
    }

    public override string FormatErrorMessage(string name) {
        return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, ExtensionsFormatted);
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
        var rule = new ModelClientValidationRule {
            ValidationType = "accept",
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName())
        };
        rule.ValidationParameters["exts"] = ExtensionsNormalized;
        yield return rule;
    }

    public override bool IsValid(object value) {
        if (value == null) {
            return true;
        }

        HttpPostedFileBase valueAsFileBase = value as HttpPostedFileBase;
        if (valueAsFileBase != null) {
            return ValidateExtension(valueAsFileBase.FileName);
        }

        string valueAsString = value as string;
        if (valueAsString != null) {
            return ValidateExtension(valueAsString);
        }

        return false;
    }

    private bool ValidateExtension(string fileName) {
        try {
            return ExtensionsParsed.Contains(Path.GetExtension(fileName).ToLowerInvariant());
        }
        catch (ArgumentException) {
            return false;
        }
    }
}

示例代码:

public class HomeController : Controller
{
    [HttpGet]
    public ActionResult Add()
    {
        return View(new UserInfo());
    }

    [HttpPost]
    public ActionResult Add(UserInfo user)
    {
        if(!ModelState.IsValid)
        {
            return View(user);
        }
        return Content("ok");
    }
}

UserInfo.cs

public class UserInfo
{
    [Required]
    public string Name { get; set; }

    [Required]
    [Display(Name = "照片")]
    [FileExtensions(Extensions = "txt,rar")]
    public HttpPostedFileBase Photos { get; set; }
}

Add.cshtml

@model TestMvc.MvcUI.Models.UserInfo

@{
    ViewBag.Title = "Add";
}

<h2>Add</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm("Add", "Home", new { }, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>UserInfo</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Photos)
        </div>
        <div class="editor-field">
            <input type="file" name="Photos" />
            @Html.ValidationMessageFor(model => model.Photos)
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

 

谢谢浏览!