how to upload file with ng-file-upload in asp.mvc ?
I'm using this code to upload file with ng-file-upload in asp.mvc :
public class HomeController : Controller, IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
bool result;
try
{
HttpPostedFile file = context.Request.Files[0];
if (file.ContentLength > 0)
{
string nameFile = Guid.NewGuid().ToString("N") + Path.GetExtension(file.FileName);
var path = Path.Combine(Server.MapPath(Url.Content("~/Temp/")), nameFile);
file.SaveAs(path);
}
result = true;
}
catch (Exception exception)
{
result = false;
}
context.Response.Write(result);
}
public bool IsReusable
{
get
{
return false;
}
}
}
script :
$scope.$watch('file', function (file) {
if (file&&!file.$error) {
$scope.upload($scope.file);
}
});
$scope.upload = function (file) {
Upload.upload({
url: getBaseUrl() + 'Home/ProcessRequest',
file: file
}).progress(function(evt) {
$scope.progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + $scope.progressPercentage + '% ' + evt.config.file.name);
}).success(function (data, status, headers, config) {
console.log('file ' + config.file.name + 'uploaded. Response: ' + data);
}).error(function (data, status, headers, config) {
console.log('error status: ' + status);
});
};
error :
POST http://localhost:1726/Home/ProcessRequest 500 (Internal Server Error)
No parameterless constructor defined for this object.
edit :
I'm using this code :
public class HomeController : Controller
{
[HttpPost]
[AllowUploadSpecialFilesOnly(".pdf,.doc,.docx,ppt,pptx,.mp3")]
public JsonResult Resume(HttpPostedFileBase file)
{
bool result;
try
{
if (file != null && file.ContentLength > 0 && file.FileName != null)
{
string nameFile = Guid.NewGuid().ToString("N") + Path.GetExtension(file.FileName);
var path = Path.Combine(Server.MapPath(Url.Content("~/Temp/")), nameFile);
file.SaveAs(path);
}
result = true;
}
catch (Exception exception)
{
result = false;
}
return Json(new
{
Result = result
}, JsonRequestBehavior.AllowGet);
}
}
html :
<form class="form-horizontal text-center" role="form" name="upload_form" >
<div class="form-group">
<div class="btn btn-primary" ngf-pattern="'.pdf,.doc,.docx,ppt,pptx,.mp3,.apk'" ngf-select ng-model="file">Send</div>
</div>
<span class="progress" ng-show="file.progress >= 0">
<div class="ng-binding" style="width:{{file.progress}}%" ng-bind="file.progress + '%'"></div>
</span>
</form>
scropt :
$scope.upload = function (file) {
Upload.upload({
url: getBaseUrl() + 'Home/Resume',
file: file
}).progress(function(evt) {
$scope.progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + $scope.progressPercentage + '% ' + evt.config.file.name);
}).success(function (data, status, headers, config) {
console.log('file ' + config.file.name + 'uploaded. Response: ' + data);
}).error(function (data, status, headers, config) {
console.log('error status: ' + status);
});
};
this is fine. But progressPercentage is always 100% but the file is being uploaded
here master https://github.com/danialfarid/ng-file-upload
and see tutorial http://jsfiddle.net/danialfarid/0mz6ff9o/135/
STEP 0 follow the tutorial step above
STEP 1
modif url parameter in index.cshtml
url: '#Url.Action("UploadDocument")',
file.upload = Upload.upload({
url: '#Url.Action("UploadDocument")',
data: {
File: file,
Description:'test'
}
});
STEP 2
in c# Controller create UploadDocument(UploadRq data)
public JsonResult UploadDocument(UploadRq data)
{
//your code
//string filename = Path.GetFileName(data.File.FileName);
//data.File.SaveAs(Server.MapPath("~/DocumentUploaded/") + filename);
return Json("Saved", JsonRequestBehavior.AllowGet);
}
STEP 3
create class UploadRq.cs
public class UploadRq
{
public HttpPostedFileBase File { get; set; }
public string Description { get; set; }
}
Related
I trying, searching since several hours and no success
I've a mvc/vue/quasar application where I try to upload a photo from a button
In my cshtml file
<q-input type="file" ref="myFileAvatar" v-on:change="handleFileUpload()" v-model="avatar" style="display:none" accept="image/*"/>
<q-btn round color="primary" icon="cloud_upload" #click="getAvatar" ></q-btn >
I send file from my js, method section
getAvatar: function () {this.$refs.myFileAvatar.$el.click()},
handleFileUpload() {
//const files = Array.from(this.avatar).filter((file) => { return file.size < 102500 && file.type.substring(0, 6) == 'image/' });
let formData = new FormData();
formData.append('ownerID', this.profildata.ownerid);
formData.append('file', this.avatar);
axios.post('/forms/default/uploadProfilImage', formData, { headers: { 'Content-Type': 'multipart/form-data' } })
.then(function (response) {
//TODO
});
}
And in my controler
public JsonNetResult uploadProfilImage(Guid ownerID, HttpPostedFileBase file)
{
resultModel resultUpload = new resultModel();
if (this.Request.Files != null && this.Request.Files.Count == 1)//My old version with q-uploader
{
}
else { resultUpload.status = resultMessage.resultValue.error; resultUpload.message = "Oups, ou sont les fichiers"; }
return JsonNetResult.JsonNet(resultUpload);
}
Problem : file is null even if in developper mode in chrome, I see file is a FileList
ownerID is good... I try several type instead of HttpPostedFileBase but nothing (execpt object give a array of string...)
thanks for your help
finally...
It's a type of parameter problem like I thougth
handleFileUpload() {
if (this.avatar[0].size < 102500 && this.avatar[0].type.substring(0, 6) == 'image/') {
let formData = new FormData();
formData.append('file', this.avatar[0]);//One file
formData.append('ownerID', this.profildata.ownerid);
let self = this
axios.post('/forms/default/uploadProfilImage', formData, { headers: { 'Content-Type': 'multipart/form-data' } })
.then(function (response) {
if (response.data.status == 0) { self.profildata.idFichierAvatar = response.data.model.id; } else { self.showNotifError(response.data.message); }
this.avatar = '';
});
}
else { this.showNotifError("L'image ne répond pas aux critères");}
}
and mvc side
[HttpPost]
public JsonNetResult uploadProfilImage(HttpPostedFileBase file,Guid ownerID )
{
resultModel resultUpload = new resultModel();
if (file != null)
{
}
else { resultUpload.status = resultMessage.resultValue.error; resultUpload.message = "Oups, ou sont les fichiers"; }
return JsonNetResult.JsonNet(resultUpload);
}
##UPDATE : Multiple##
And for multiple files
in q-input add multiple property
in server side :
[HttpPost]
public JsonNetResult uploadProfilImage(HttpPostedFileBase[] files,Guid ownerID )
And To send files from js
handleFile() {
let formData = new FormData();
for (var i = 0; i < this.newfiles.length; i++) {
let fichier = this.newfiles[i];
formData.append('files[' + i + ']', fichier);
}
formData.append('ownerID', this.ownerid);
let self = this
axios.post('/files/joinFile/uploadFiles', formData, { headers: { 'Content-Type': 'multipart/form-data' } })
.then(function (response) {
if (response.data.status == 0) { self.files = response.data.model; } else { self.showNotifError(response.data.message); }
this.newfiles = '';
});
}
I hope it's full for everyone who have same problem :-)
I created a web app using asp.net-mvc and Jquery
when I added the below code my application automatically stop running without throwing any error, I don't know Whether it is my visual studio 19 or IIS which is being crashed
<label for="myfile">Select a file:</label>
<input type="file" id="myfile" name="myfile">
To verify I created an asp.net mvc sample project and paste the above code in the index page but the same problem comes
Image
what can I do to solve this?
Do you have
enctype="multipart/form-data"
property in your form element?
<form id="upload">
<input type="file" id="file" class="form-control">
</form>
Jquery
$('#upload').submit(function (e) {
e.preventDefault(); // stop the standard form submission
var File_Name = $("#file").prop('files')[0].name;
var ext = File_Name.split('.').pop();
if (ext == "pdf" || ext == "docx" || ext == "doc" || ext == "png" || ext ==
"jpg" || ext == "jpeg" || ext == "txt") {
var lastIndex = $("#file").prop('files')[0].name.lastIndexOf(".") + 1;
var form = new FormData();
form.append("file", $("#file").prop('files')[0]);
$.ajax({
url: '/Main/SaveDocument',
type: 'POST',
data: form,
cache: false,
contentType: false,
processData: false,
success: function (data) {
console.log(data.UploadedFileCount + ' file(s) uploaded successfully');
if (data == "999") {
swal("Note", "Some Error Occurred. File Not uploaded successfully.", "error");
}
},
error: function (xhr, error, status) {
console.log(error, status + " " + xhr);
}
});
}
else {
swal("Note", "File Type Not Supported.", "warning");
}
});
C#
public ActionResult SaveDocument()
{
//file
var file = System.Web.HttpContext.Current.Request.Files["file"];
var CheckCnic = hr_FTPEntities.File_description.Where(x => x.uploader_CNIC == userCNIC).FirstOrDefault();
if(CheckCnic == null)
{
HttpPostedFileBase filebase = new HttpPostedFileWrapper(file);
if (filebase.ContentLength > 0)
{
var fileName = Path.GetFileName(filebase.FileName);
string path = Path.Combine(Server.MapPath(basePath + departmentName) + "/");
File_description file_Description = new File_description();
int fileCount = hr_FTPEntities.File_description.Select(x => x).ToList().Count + 1;
int lastIndexOfDot = fileName.LastIndexOf(".") - 1;
string finalFileName = fileName.Substring(0, lastIndexOfDot) + "_" + fileCount + fileName.Substring(lastIndexOfDot + 1);
file_Description.file_name = finalFileName.ToString();
try
{
filebase.SaveAs(path + (finalFileName));
}
catch(Exception ex)
{
return Json("999");
}
}
return Json("000");
}
else
{
return Json("888");
}
}
You could try to use the below code:
View(Index.cshtml) :
<input type="file" id="FileUpload1" />
<input type="button" id="btnUpload" value="Upload Files" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
$(document).ready(function(){
$('#btnUpload').click(function () {
// Checking whether FormData is available in browser
if (window.FormData !== undefined) {
var fileUpload = $("#FileUpload1").get(0);
var files = fileUpload.files;
// Create FormData object
var fileData = new FormData();
// Looping over all files and add it to FormData object
for (var i = 0; i < files.length; i++) {
fileData.append(files[i].name, files[i]);
}
// Adding one more key to FormData object
fileData.append('username', 'test');
$.ajax({
url: '/Home/UploadFiles',
type: "POST",
contentType: false, // Not to set any content header
processData: false, // Not to process data
data: fileData,
success: function (result) {
alert(result);
},
error: function (err) {
alert(err.statusText);
}
});
} else {
alert("FormData is not supported.");
}
});
});
</script>
Controller (HomeController.cs):
[HttpPost]
public ActionResult UploadFiles()
{
// Checking no of files injected in Request object
if (Request.Files.Count > 0)
{
try
{
// Get all files from Request object
HttpFileCollectionBase files = Request.Files;
for (int i = 0; i < files.Count; i++)
{
//string path = AppDomain.CurrentDomain.BaseDirectory + "Uploads/";
//string filename = Path.GetFileName(Request.Files[i].FileName);
HttpPostedFileBase file = files[i];
string fname;
// Checking for Internet Explorer
if (Request.Browser.Browser.ToUpper() == "IE" || Request.Browser.Browser.ToUpper() == "INTERNETEXPLORER")
{
string[] testfiles = file.FileName.Split(new char[] { '\\' });
fname = testfiles[testfiles.Length - 1];
}
else
{
fname = file.FileName;
}
// Get the complete folder path and store the file inside it.
fname = Path.Combine(Server.MapPath("~/Uploads/"), fname);
file.SaveAs(fname);
}
// Returns message that successfully uploaded
return Json("File Uploaded Successfully!");
}
catch (Exception ex)
{
return Json("Error occurred. Error details: " + ex.Message);
}
}
else
{
return Json("No files selected.");
}
}
Make sure your IIS site contains the upload folder and enough permission to access the folder.
If you still face the same issue then try to use the different browser.
check event viewer logs or try to collect the dup and analyze the dump using the DebugDiag tool.
I'm trying to download a file to iOS using the CrossDownloadManager, but I can not find the file anywhere! I debugged and I see that it recognizes the HTTP and "donwload" the file but can not find the file.
I'm using Ipad ios11.
I do not know if there is an easier way, but this plugin seemed more viable.
My code:
CrossDownloadManager.Current.CollectionChanged += (sender, e) =>
System.Diagnostics.Debug.WriteLine(
"[DownloadManager] " + e.Action +
" -> New items: " + (e.NewItems?.Count ?? 0) +
" at " + e.NewStartingIndex +
" || Old items: " + (e.OldItems?.Count ?? 0) +
" at " + e.OldStartingIndex
);
var Url2 = "https://mysite/myfile.pdf"; //here i put my file, its ok.
DownloadFile(Url2);
}
public async void DownloadFile(String fileName)
{
await Task.Yield();
//await Navigation.PushPopupAsync(new DownloadingPage());
await Task.Run(() =>
{
var downloadManager = CrossDownloadManager.Current;
var file = downloadManager.CreateDownloadFile(fileName);
downloadManager.Start(file, true);
while (isDownloading)
{
isDownloading = IsDownloading(file);
}
});
//await Navigation.PopAllPopupAsync();
if (!isDownloading)
{
await DisplayAlert("File Status", "File Donwload","OK");
//DependencyService.Get<IToast>().ShowToast(“Baixou”);
}
}
public bool IsDownloading(IDownloadFile file)
{
if (file == null) return false;
switch (file.Status)
{
case DownloadFileStatus.INITIALIZED:
case DownloadFileStatus.PAUSED:
case DownloadFileStatus.PENDING:
case DownloadFileStatus.RUNNING:
return true;
case DownloadFileStatus.COMPLETED:
case DownloadFileStatus.CANCELED:
case DownloadFileStatus.FAILED:
return false;
default:
throw new ArgumentOutOfRangeException();
}
}
public void AbortDownloading()
{
CrossDownloadManager.Current.Abort(File);
}
And in iOS part, I put:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
Downloaded();
return base.FinishedLaunching(app, options);
}
public void Downloaded()
{
CrossDownloadManager.Current.PathNameForDownloadedFile = new System.Func<IDownloadFile, string>
(file => {
string fileName = (new NSUrl(file.Url, false)).LastPathComponent;
System.Diagnostics.Debug.WriteLine(Environment.SpecialFolder.Resources);
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Resources), fileName);
});
}
public override void HandleEventsForBackgroundUrl(UIApplication application, string sessionIdentifier, Action completionHandler)
{
CrossDownloadManager.BackgroundSessionCompletionHandler = completionHandler;
}
I am at a loss as to why my authentication cookie disappears. I am using Valums Ajax Upload in conjunction with a couple other ajax requests to build a user's avatar. It is very random as to when the cookie disappears. I can upload 4 files without an issue, then 2 files maybe (after another login). It seems after I call the CreateAvatar method, that is where there might be an issue, but like I said, it doesn't happen all the time. What am I missing?
JavaScript:
$(function () {
//This is the Upload Method
var fileCount = 0;
var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader'),
action: '/Admin/Avatar/AvatarUpload',
debug: true,
params: {
'userId': '#ViewBag.UserId'
},
onSubmit: function (id, fileName) {
fileCount++;
},
onComplete: function (id, fileName, responseJson) {
if (responseJson.success) {
//fileCount--;
if (createAvatar(responseJson.file, responseJson.imageId)) {
fileCount--;
} else {
fileCount--;
//alert('There was an error when trying to save ' + fileName);
}
} else {
$("span.qq-upload-file:contains(" + fileName + ")").text(responseJson.errorMessage);
fileCount--;
}
if (fileCount == 0) {
}
},
onCancel: function (id, fileName) {
fileCount--;
if (fileCount == 0) {
parent.$.fn.colorbox.close();
}
}
});
});
//This Creates the Avatar Object
function createAvatar(fileName, imageId) {
var avatarUploadModel = {
UploadFileName: fileName,
UserId: '#ViewBag.UserId',
ImageId: imageId
};
$.ajax({
url: '/Admin/Avatar/CreateAvatar/',
type: 'POST',
cache: false,
timeout: 100000,
data: JSON.stringify(avatarUploadModel),
contentType: 'application/json; charset=utf-8',
dataType: "json",
error: function (xhr, status, error) {
alert(error + " " + status);
},
success: function (data) {
if (data.success) {
loadAvatar(data.avatarModel);
return true;
} else {
return false;
}
}
});
}
//This loads the partial to view the avatar after upload
function loadAvatar(avatarModel) {
$.ajax({
url: '/Admin/Avatar/AvatarEdit',
type: 'GET',
cache: false,
timeout: 100000,
data: avatarModel,
dataType: "html",
error: function (xhr, status, error) {
alert(error + " " + status);
},
success: function (data) {
$("#avatarOriginal").html(data);
}
});
}
Login Method:
var user = _userService.GetByUserName(model.Username);
var authTicket = new
FormsAuthenticationTicket(1, //version
user.Id.ToString(), // user name
DateTime.Now,
DateTime.Now.AddMinutes(40), //Expiration
model.RememberMe, //Persistent,
user.Username);
var encTicket = FormsAuthentication.Encrypt(authTicket);
HttpContext.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
return Json(new {success = true, url = model.ReturnUrl}, JsonRequestBehavior.AllowGet);
Upload Method on Controller:
[HttpPost]
public ActionResult AvatarUpload(HttpPostedFileBase fileData)
{
var id = Guid.NewGuid();
string fileName;
var serverPath = Server.MapPath("~/Areas/Admin/TemporaryUploads/");
if (fileData != null)
{
var fileRenamed = System.IO.Path.GetFileName(id + "_" + fileData.FileName);
fileName = Server.MapPath("~/Areas/Admin/TemporaryUploads/" + fileRenamed);
fileData.SaveAs(fileName);
}
else
{
var ajaxUploadFileData = Request["qqfile"];
fileName = Path.Combine(serverPath, id + "_" + Path.GetFileName(ajaxUploadFileData));
using (var output = System.IO.File.Create(fileName))
{
Request.InputStream.CopyTo(output);
}
}
return Json(new {success = true, file = fileName, imageId = id}, JsonRequestBehavior.AllowGet);
}
Create Avatar Method:
[HttpPost]
public ActionResult CreateAvatar(AvatarModel avatarModel)
{
try
{
var image = new WebImage(avatarModel.UploadFileName).Resize(400, 400, true);
var imageFileName = Path.GetFileName(avatarModel.UploadFileName);
var avatar = new Domain.YogaDiVitaContext.Model.Avatar()
{
CreatedById = Guid.Parse(HttpContext.User.Identity.Name),
ModifiedById = Guid.Parse(HttpContext.User.Identity.Name),
UserId = avatarModel.UserId,
Image = new Image()
{
CreatedById = Guid.Parse(HttpContext.User.Identity.Name),
ModifiedById = Guid.Parse(HttpContext.User.Identity.Name),
OriginalImageRelativePath = "original/" + imageFileName
}
};
var user = UserService.FindById(avatarModel.UserId);
if (user.Avatar != null)
RemoveAvatar(user.Avatar);
avatar = _avatarService.Create(avatar);
user.Avatar = avatar;
UserService.Update(user);
var basePath = Server.MapPath("~/" + avatar.ToAvatarBasePath(GlobalVariables.AvatarPath));
Directory.CreateDirectory(basePath);
Directory.CreateDirectory(basePath + "/thumbnail");
Directory.CreateDirectory(basePath + "/fullsize");
Directory.CreateDirectory(basePath + "/original");
image.Save(Server.MapPath("~/" + avatar.ToAvatarOriginalPath(GlobalVariables.AvatarPath)));
avatarModel.Width = image.Width;
avatarModel.Height = image.Height;
avatarModel.Top = image.Height*0.1;
avatarModel.Left = image.Width*0.9;
avatarModel.Right = image.Width*0.9;
avatarModel.Bottom = image.Height*0.9;
avatarModel.OriginalImagePath = "/" + avatar.ToAvatarOriginalPath(GlobalVariables.AvatarPath);
System.IO.File.Delete(avatarModel.UploadFileName);
return Json(new {success = true, avatarModel}, JsonRequestBehavior.AllowGet);
}
catch (Exception exception)
{
return Json(new {message = exception.Message}, JsonRequestBehavior.AllowGet);
}
}
Load Avatar Partial:
public ActionResult AvatarEdit(AvatarModel avatarModel)
{
return PartialView("AvatarCropPartial", avatarModel);
}
How can I display ModelState errors returned by JSON?
I want to do something like this:
if (!ValidateLogOn(Name, currentPassword))
{
ModelState.AddModelError("_FORM", "Username or password is incorrect.");
//Return a json object to the javascript
return Json(new { ModelState });
}
What must be my code in the view to read the ModelState errors and display them?
My actual code in the view to read the JSON values is as follows:
function createCategoryComplete(e) {
var obj = e.get_object();
alert(obj.Values);
}
This is draft code but the same idea works for me in production.
The main idea here is that Json errors have predefined tag names, that no normal objects will have. For errors validation errors HTML is re-created using JavaScript (both top summary and form elements highlighting).
Server side:
public static JsonResult JsonValidation(this ModelStateDictionary state)
{
return new JsonResult
{
Data = new
{
Tag = "ValidationError",
State = from e in state
where e.Value.Errors.Count > 0
select new
{
Name = e.Key,
Errors = e.Value.Errors.Select(x => x.ErrorMessage)
.Concat(e.Value.Errors.Where(x => x.Exception != null).Select(x => x.Exception.Message))
}
}
};
}
in action:
if (!ModelState.IsValid && Request.IsAjaxRequest())
return ModelState.JsonValidation();
Client side:
function getValidationSummary() {
var el = $(".validation-summary-errors");
if (el.length == 0) {
$(".title-separator").after("<div><ul class='validation-summary-errors ui-state-error'></ul></div>");
el = $(".validation-summary-errors");
}
return el;
}
function getResponseValidationObject(response) {
if (response && response.Tag && response.Tag == "ValidationError")
return response;
return null;
}
function CheckValidationErrorResponse(response, form, summaryElement) {
var data = getResponseValidationObject(response);
if (!data) return;
var list = summaryElement || getValidationSummary();
list.html('');
$.each(data.State, function(i, item) {
list.append("<li>" + item.Errors.join("</li><li>") + "</li>");
if (form && item.Name.length > 0)
$(form).find("*[name='" + item.Name + "']").addClass("ui-state-error");
});
}
$.ajax(... function(response) {
CheckValidationErrorResponse(xhr.responseText); } );
Why not return the original ModelState object to the client, and then use jQuery to read the values. To me it looks much simpler, and uses the common data structure (.net's ModelState)
C#:
return Json(ModelState);
js:
var message = "";
if (e.response.length > 0) {
$.each(e.response, function(i, fieldItem) {
$.each(fieldItem.Value.Errors, function(j, errItem) {
message += errItem.ErrorMessage;
});
message += "\n";
});
alert(message);
}
this is a tiny tweak to queen3's client side code which handles specific validation messages, and creates a similar document to that created by MVC3:
function getValidationSummary() {
var $el = $(".validation-summary-errors > ul");
if ($el.length == 0) {
$el = $("<div class='validation-summary-errors'><ul></ul></div>")
.hide()
.insertBefore('fieldset:first')
.find('ul');
}
return $el;
}
function getResponseValidationObject(response) {
if (response && response.Tag && response.Tag == "ValidationError")
return response;
return null;
}
function isValidationErrorResponse(response, form, summaryElement) {
var $list,
data = getResponseValidationObject(response);
if (!data) return false;
$list = summaryElement || getValidationSummary();
$list.html('');
$.each(data.State, function (i, item) {
var $val, lblTxt, errorList ="";
if (item.Name) {
$val = $(".field-validation-valid,.field-validation-error")
.first("[data-valmsg-for=" + item.Name + "]")
.removeClass("field-validation-valid")
.addClass("field-validation-error");
$("input[name=" + item.Name + "]").addClass("input-validation-error")
lblTxt = $("label[for=" + item.Name + "]").text();
if (lblTxt) { lblTxt += ": "; }
}
if ($val.length) {
$val.text(item.Errors.shift());
if (!item.Errors.length) { return; }
}
$.each(item.Errors, function (c,val) {
errorList += "<li>" + lblTxt + val + "</li>";
});
$list.append(errorList);
});
if ($list.find("li:first").length) {$list.closest("div").show(); }
return true;
}
See below for code with a few amendments to Brent's answer. CheckValidationErrorResponse looks for the Validation Summary regardless of whether it's in the valid or invalid state, and inserts it if not found. If validation errors are found in the response, it applies the validation-summary-errors class to the Summary, else it applies validation-summary-valid. It assumes CSS is present to control the visibility of the Summary.
The code clears existing instances of field-validation-error, and reapplies them for errors found in the response.
function getValidationSummary(form) {
var $summ = $(form).find('*[data-valmsg-summary="true"]');
if ($summ.length == 0)
{
$summ = $('<div class="validation-summary-valid" data-valmsg-summary="true"><ul></ul></div>');
$summ.appendTo(form);
}
return $summ;
}
function getValidationList(summary) {
var $list = $(summary).children('ul');
if ($list.length == 0) {
$list = $('<ul></ul>');
$list.appendTo(summary);
}
return $list;
}
function getResponseValidationErrors(data) {
if (data && data.ModelErrors && data.ModelErrors.length > 0)
return data.ModelErrors;
return null;
}
function CheckValidationErrorResponse(data, form, summaryElement) {
var errors = getResponseValidationErrors(data);
var $summ = summaryElement || getValidationSummary(form);
var $list = getValidationList($summ);
$list.html('');
$(form).find(".field-validation-error")
.removeClass("field-validation-error")
.addClass("field-validation-valid");
if (!errors)
{
$summ.removeClass('validation-summary-errors').addClass('validation-summary-valid');
return false;
}
$.each(errors, function (i, item) {
var $val, $input, errorList = "";
if (item.Name) {
$val = $(form).find(".field-validation-valid, .field-validation-error")
.filter("[data-valmsg-for=" + item.Name + "]")
.removeClass("field-validation-valid")
.addClass("field-validation-error");
$input = $(form).find("*[name='" + item.Name + "']");
if (!$input.is(":hidden") && !$val.length)
{
$input.parent().append("<span class='field-validation-error' data-valmsg-for='" + item.Name + "' data-valmsg-replace='false'>*</span>");
}
$input.addClass("input-validation-error");
}
$.each(item.Errors, function (c, err) {
errorList += "<li>" + err + "</li>";
});
$list.append(errorList);
});
$summ.removeClass('validation-summary-valid').addClass('validation-summary-errors');
return true;
}
C#
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ModelState.IsValid == false)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
JavaScript
$.ajax({
type: "GET",
url: "/api/xxxxx",
async: 'false',
error: function (xhr, status, err) {
if (xhr.status == 400) {
DisplayModelStateErrors(xhr.responseJSON.ModelState);
}
},
....
function DisplayModelStateErrors(modelState) {
var message = "";
var propStrings = Object.keys(modelState);
$.each(propStrings, function (i, propString) {
var propErrors = modelState[propString];
$.each(propErrors, function (j, propError) {
message += propError;
});
message += "\n";
});
alert(message);
};
If you are returning JSON, you cannot use ModelState. Everything that the view needs should be contained inside the JSON string. So instead of adding the error to the ModelState you could add it to the model you are serializing:
public ActionResult Index()
{
return Json(new
{
errorControl = "_FORM",
errorMessage = "Username or password is incorrect.",
someOtherProperty = "some other value"
});
}