This question seems to be quite old, I accidentally stumbled upon it, and since it has not yet been answered, I decided to bring 2 Β’.
I don't know if such a plugin exists for ASP.NET, but it would be easy to write one:
[AttributeUsage(AttributeTargets.Property)] public class PaperClipAttribute : Attribute, IMetadataAware { public PaperClipAttribute(string uploadPath, params string[] sizes) { if (string.IsNullOrEmpty(uploadPath)) { throw new ArgumentException("Please specify an upload path"); } UploadPath = uploadPath; Sizes = sizes; } public string UploadPath { get; private set; } public string[] Sizes { get; private set; } public void OnMetadataCreated(ModelMetadata metadata) { metadata.AdditionalValues["PaperClip"] = this; } }
then define a custom HttpPostedFileBase for the type HttpPostedFileBase :
public class PaperClipModelBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var paperClip = bindingContext.ModelMetadata.AdditionalValues["PaperClip"] as PaperClipAttribute; if (paperClip == null) { return base.BindModel(controllerContext, bindingContext); } var uploadedFile = base.BindModel(controllerContext, bindingContext) as HttpPostedFileBase; if (uploadedFile == null) { return null; } var uploadPath = controllerContext.HttpContext.Server.MapPath(paperClip.UploadPath); if (!Directory.Exists(uploadPath)) { throw new ArgumentException(string.Format("The specified folder \"{0}\" does not exist", uploadPath)); } var sizes = (from size in paperClip.Sizes let tokens = size.Split('x') select new Size(int.Parse(tokens[0]), int.Parse(tokens[1])) ).ToArray(); foreach (var size in sizes) { var extension = Path.GetExtension(uploadedFile.FileName); var outputFilename = Path.Combine( uploadPath, Path.ChangeExtension( string.Format("image{0}x{1}", size.Width, size.Height), extension ) ); Resize(uploadedFile.InputStream, outputFilename, size); } return base.BindModel(controllerContext, bindingContext); } private void Resize(Stream input, string outputFile, Size size) { using (var image = Image.FromStream(input)) using (var bmp = new Bitmap(size.Width, size.Height)) using (var gr = Graphics.FromImage(bmp)) { gr.CompositingQuality = CompositingQuality.HighSpeed; gr.SmoothingMode = SmoothingMode.HighSpeed; gr.InterpolationMode = InterpolationMode.HighQualityBicubic; gr.DrawImage(image, new Rectangle(0, 0, size.Width, size.Height)); bmp.Save(outputFile); } } }
which will be registered in Application_Start :
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); ModelBinders.Binders[typeof(HttpPostedFileBase)] = new PaperClipModelBinder(); }
and we pretty much did it. All that remains is classic material.
View Model:
public class MyViewModel { [PaperClip("~/App_Data", "100x20", "200x40", "640x480")] [Required(ErrorMessage = "Please select a file to upload")] public HttpPostedFileBase Image { get; set; } }
Controller:
public class HomeController : Controller { public ActionResult Index() { return View(new MyViewModel()); } [HttpPost] public ActionResult Index(MyViewModel model) { if (!ModelState.IsValid) { return View(model); } return Content("thanks for uploading"); } }
View:
@model MyViewModel @using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" })) { @Html.LabelFor(x => x.Image) <input type="file" name="image" /> @Html.ValidationMessageFor(x => x.Image) <input type="submit" value="Upload" /> }