Uploading file to controller using typescript - angularjs

I am using ASP.NET MVC 5 for the back-end and Angular + Typescript for the front-end of a web application.
I am trying to upload a file to the server, but for some reason the controller is not getting the file as parameter (the parameter in the controller is null).
I'm sharing below code.
Thanks in advance!
HTML:
<input id="filePath" name="filePath" type="file" accept="image/*" />
<a id="uploadImage" ng-click="ctrl.uploadFile()">Upload</a>
Typescript:
// controller class:
uploadFile(): void {
var filePathInput: any = $("#filePath");
if (filePathInput[0].files) {
var file: any = filePathInput[0].files[0];
var resource: any = this.service.uploadFile();
resource.save(file, (result: any) => {
if (!result || !result.success) {
alert("error");
} else {
alert("ok");
}
});
}
}
// service class:
uploadFile(): ng.resource.IResourceClass<IMyResource> {
return this.$resource("/MyController/UploadImage", null, { method: "POST" });
}
Backend Controller:
[HttpPost]
public JsonResult UploadImage([FromBody]HttpPostedFileBase file)
{
if (file == null || file.ContentLength == 0)
{
return NullParameterResponse();
}
else
{
file.SaveAs("/img/" + Path.GetFileName(file.FileName));
return SuccessResponse();
}
}

TransformRequest function: This makes your request to be sent as a FormData instead as a JSon object.
formDataObject(data: any): any {
var fd = new FormData();
angular.forEach(data, function (value, key) {
fd.append(key, value);
});
return fd;
}
In your angular resource, define the save options and pass the transformRequest function you created earlier.
uploadChequeFile(): ng.resource.IResourceClass<IChequeLoanResource> {
return this.$resource<IChequeLoanResource>("/Cheque/UploadChequeImage", null,
{
save: {
method: "POST",
transformRequest: this.formDataObject,
headers: { 'Content-Type': undefined, enctype: 'multipart/form-data' }
}
});
}
In your controller, just call your save method from the resource passing your file.
var chequeFilePathInput: any = $("#chequeFilePath");
if (chequeFilePathInput[0].files) {
var resource: ng.resource.IResourceClass<services.IChequeLoanResource> = this.uLendService.uploadChequeFile();
resource.save({ "files": chequeFilePathInput[0].files[0] }, (result: any) => {
if (!result || !result.success) {
this.errorMessage = "Error al subir la imagen al servidor. Por favor contáctanos si el error persiste.";
} else {
this.chequeLoan.cheque.filePath = result.message;
this.saveChequeLoan();
}
});
} else {
this.errorMessage = "La imagen del cheque es requerida.";
}
Finally, your controller must receive the IList parameters (with the same name defined in your angular controller)
public JsonResult UploadChequeImage(IList<IFormFile> files)
{
try
{
if (files != null && files.Count > 0)
{
return CreateResponse(true, CreateFile(files[0], #"img\cheques"));
}

Related

abp.ajax({ Post Issue: Null Value being passed to the server side using abp.ajax({

I'm having some problems passing the data from my razor page to the server. It is passing NULL value from my abp.ajax({. Is there anything I'm missing from my ajax or the server-side code:
I'm using RAZOR PAGES ABP Framework 5.3
MY AJAX:
$("#frmDistrict").on("submit",
function (event) {
event.preventDefault();
const Url = $(this).attr("action");
const formData = $(this).serialize();
abp.ajax({
type: 'POST',
url: url,
data: JSON.stringify(formData)
}).then(function (result) {
if (data.isValid) {
if (data.IsNew) {
abp.notify.success(data.retmsg);
window.location.href = data.returl;
} else {
}
abp.notify.success(data.retmsg);
} else {
DisplayModelStateErrors(data.retmsg);
}
}).catch(function () {
alert("request failed :(");
});
});
MY SERVER CODE:
public async Task<JsonResult> OnPostAsync()
{
var rt = await Mediator.Send(new CreateDistrictCommand
{
District = district
});
if (rt.Failed) return new JsonResult(new { isValid = false, IsNew = true, retmsg =
rt.Message, sdata = rt.Data });
var retmsg = "District " + rt.Data.Name + " Created successfully.";
var returl = "/Districts/";
return new JsonResult(new { isValid = true, IsNew = true, retmsg, returl });
}
MY FORM
<form method="post" id="frmDistrict" >
<partial name="_AddEditDistrict" model="Model.District" />
</form>
If I use the standard ajax call
``$.ajax({ it works fine
but abp.ajax({ doesn't work
Many thanks
Zak

The current request is not a multipart request in angularJS and Spring Rest

I am trying to upload file using AngularJS on client side and Spring RESTApi on server side but getting
Error
org.springframework.web.multipart.MultipartException: The current request is not a multipart request
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.assertIsMultipartRequest(RequestParamMethodArgumentResolver.java:216)
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.resolveName(RequestParamMethodArgumentResolver.java:167)
.......
[http-bio-8080-exec-1] WARN org.springframework.web.servlet.PageNotFound - Request method 'POST' not supported
Rest API
Below is a simple Java Post function:
#RequestMapping(method = RequestMethod.POST)
public String saveFile(
#RequestParam("file") MultipartFile file) {
return "success";
}
In Angular, I am using Resource service to send request.
Chrome Developer Tool output
Request Payload
------WebKitFormBoundarydFRgXclyfPVixdHo
Content-Disposition: form-data; name="file"; filename="Release_Notes.txt"
Content-Type: text/plain
------WebKitFormBoundarydFRgXclyfPVixdHo--
Angular Service
function FileUploadService($resource) {
return $resource('/fileUpload/:id', {}, {
'save' : {
method : 'POST',
transformRequest: function(data, headersGetter) {
var headers = headersGetter();
headers['Content-Type'] = undefined;
if (data == undefined) {
return data;
}
var fd = new FormData();
var createKey = function(_keys_, currentKey) {
var keys = angular.copy(_keys_);
keys.push(currentKey);
var formKey = keys.shift()
if (keys.length) {
formKey += "[" + keys.join("][") + "]"
}
return formKey;
};
var addToFd = function(object, keys) {
angular.forEach(object, function(value, key) {
var formKey = createKey(keys, key);
if (value instanceof File) {
fd.append(formKey, value);
} else if (value instanceof FileList) {
if (value.length == 1) {
fd.append(formKey, value[0]);
} else {
angular.forEach(value, function(file, index) {
fd.append(formKey + '[' + index + ']', file);
});
}
} else if (value && (typeof value == 'object' || typeof value == 'array')) {
var _keys = angular.copy(keys);
_keys.push(key)
addToFd(value, _keys);
} else {
fd.append(formKey, value);
}
});
};
addToFd(data, []);
return fd;
}
}
});
}
Any hint to avoid this error?
Method assertIsMultipartRequest from RequestParamMethodArgumentResolver class is called.
The method asserts that it is a post request and content type starts with multipart/
if (!"post".equals(request.getMethod().toLowerCase())) {
return false;
}
String contentType = request.getContentType();
return (contentType != null && contentType.toLowerCase().startsWith("multipart/"));
Your content type, on the other hand, is
Content-Type: text/plain
And an exception is thrown.
#RequestMapping(method = RequestMethod.POST)
your value attribute is missing in the requestmapping it should be like this
#RequestMapping(value="/fileupload/save/{id}" ,method = RequestMethod.POST)
and use this code when creating angular resource
$resource('fileupload/save/:id',
{id:'1'}, {
save: {method:'POST', params:{charge:true}}
});
in springBoot theres not much to configure when uploading the file.
but you can add these properties to your application property file to change the file size limits.
# File size limit
multipart.maxFileSize = 3Mb
# Total request size for a multipart/form-data
multipart.maxRequestSize = 20Mb
The above issue is resolved by:
1) Creating a MultipartResolver bean in WebAppConfig.java as shown below:
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
return multipartResolver;
}
2) Replacing AngularJS FileUploadService (which is using Resource service) with http as shown below:
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
});
Hope it helps.

how to save two file from two different html file upload in same function using angularjs and MVC3

here is my all code i am trying to upload small image and large image separate but angularjs not let me allow to do this, it only taking one file but not taking other one. plz anyone help with this. thanks in advance.
<div ng-app="eventModule" >
<div ng-controller="eventController">
<div>
<span >Thumbnail Image</span>
<input type="file" id="fileToUpload" onchange="angular.element(this).scope().selectThumbnail(this.files)" accept="image/*" />
</div>
<div>
<span >Large Image</span>
<input type="file" onchange="angular.element(this).scope().selectLargeImage(this.files)" class="LargeImageSubCategory" />
</div>
</div>
<span data-ng-click="SaveFile()">Submit</span>
</div>
<script>
var eventModule = angular.module('eventModule', []);
eventModule.controller('eventController', function ($scope,ArticleService, $http, $sce) {
$scope.selectThumbnail = function (file) {
$scope.SelectedThumbnail = file[0];
}
$scope.selectLargeImage = function (file) {
$scope.SelectedLargeImage = file[0];
}
$scope.SaveFile = function () {
$scope.IsFormSubmitted = true;
$scope.Message = "";
ArticleService.UploadFile($scope.SelectedThumbnail, $scope.SelectedLargeImage).then(function (d) {
alert(d.Message);
ClearForm();
}, function (e) {
alert(e);
});
};
});
eventModule.service("ArticleService", function ($http, $q) {
this.UploadFile = function (Thumbnail, LargeImage, TitleHeading, Topic, SmallDesc, LargeDesc) {
var formData = new FormData();
formData.append("Thumbnail", Thumbnail);
formData.append("LargeImage", LargeImage);
// here when i am trying to send two files so controller is not called
//and function is breaking and alert is comming "File Upload Failed"
formData.append("TitleHeading", TitleHeading);
formData.append("Topic", Topic);
var defer = $q.defer();
$http.post("/Articles/SaveFiles", formData,
{
withCredentials: true,
headers: { 'Content-Type': undefined },
transformRequest: angular.identity
}).success(function (d) {
defer.resolve(d);
}).error(function () {
defer.reject("File Upload Failed!");
});
return defer.promise;
}
});
</script>
//And My ArticlesController.cs code is
[HttpPost]
public JsonResult SaveFiles(string TitleHeading, string Topic)
{
string Message, fileName, actualFileName;
Message = fileName = actualFileName = string.Empty;
bool flag = false;
if (Request.Files != null)
{
var file = Request.Files[0];
actualFileName = file.FileName;
fileName = Guid.NewGuid() + Path.GetExtension(file.FileName);
int size = file.ContentLength;
try
{
file.SaveAs(Path.Combine(Server.MapPath("~/UploadedFiles"), fileName));
using (TCDataClassesDataContext dc = new TCDataClassesDataContext())
{
Article insert = new Article();
insert.ArticleId = Guid.NewGuid();
insert.TitleHeading = TitleHeading;
insert.SmallImagePath = fileName;
dc.Articles.InsertOnSubmit(insert);
dc.SubmitChanges();
Message = "File uploaded successfully";
flag = true;
}
}
catch (Exception)
{
Message = "File upload failed! Please try again";
}}
return new JsonResult { Data = new { Message = Message, Status = flag } };
}
You are appending the files to the formdata, thus you need to specify the Thumbnail and LargeImage as parameters of your MVC controller. Please see below:
[HttpPost]
public JsonResult SaveFiles(
HttpPostedFileBase thumbnail
, HttpPostedFileBase largeImage
, string titleHeading
, string topic)
{
string Message, fileName, actualFileName;
Message = fileName = actualFileName = string.Empty;
bool flag = false;
if (thumbnail != null && thumbnail.ContentLength != 0)
{
SaveFile(thumbnail);
}
if (largeImage != null && largeImage.ContentLength != 0)
{
SaveFile(largeImage);
}
return new JsonResult { Data = new { Message = Message, Status = flag } };
}
private void SaveFile(
HttpPostedFileBase httpFile)
{
var actualFileName = httpFile.FileName;
var fileName = Guid.NewGuid() + Path.GetExtension(httpFile.FileName);
int size = httpFile.ContentLength;
try
{
httpFile.SaveAs(Path.Combine(Server.MapPath("~/UploadedFiles"), fileName));
using (TCDataClassesDataContext dc = new TCDataClassesDataContext())
{
Article insert = new Article();
insert.ArticleId = Guid.NewGuid();
insert.TitleHeading = TitleHeading;
insert.SmallImagePath = fileName;
dc.Articles.InsertOnSubmit(insert);
dc.SubmitChanges();
Message = "File uploaded successfully";
flag = true;
}
}
catch (Exception)
{
Message = "File upload failed! Please try again";
}
}

Custom Route using Attribute Routing in WebApi

I'm working on retrieving list of Movie Details from DB using WebAPi. I've http verbs and it does work as normal. I've a scenario where i've to get records based on categories like Title, Date, Rating
WebConfig:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional, action = "ActionName" }
Controller :
[HttpGet]
[GET("api/GetMovieByCategory/{movieData}")]
public IEnumerable<MovieData> GetMovieByCategory(MovieData movieData)
{
IEnumerable<MovieData> movieDataByCat = null;
string[] paramCast;
if(movieData.Cast.Count()!=0)
paramCast = movieData.Cast;
IEnumerable<MovieData> GetAllMovies = null;
GetAllMovies = repo.GetAll();`
if (movieData.Cast == null || movieData.Cast.Count() == 0)
{
movieDataByCat = from data in GetAllMovies
where (data.Classification == (movieData.Classification == null ? string.Empty : movieData.Classification) ||
data.Genre == (movieData.Genre == null ? string.Empty : movieData.Genre) ||
data.Rating == movieData.Rating ||
data.ReleaseDate == movieData.ReleaseDate ||
data.Title == (movieData.Title == null ? string.Empty : movieData.Title))
select data;
}
return movieDataByCat;
}
Angular Service :
//GetByCategory
this.getbyCat = function (Movie) {
return $http.get("/api/values/GetMovieByCategory/" + Movie);
};
when i try to execute, i'm getting an exception as follows,
Remote Address:[::1]:50948
Request URL:http://localhost:50948/api/values/GetMovieByCategory/[object%20Object]
Request Method:GET
Status Code:404 Not Found
I've no idea how to overcome this and get it resolved. I'm in beginner level. Please help.
Rest of all verbs (get,put,post) are working fine.
Note : I've installed NugetPackage AttributeRouting.Web.Http; for Route.
Update 1 :
Contoller.js :
$scope.srchbycat = function () {
var Movie = {
_title:"",
_genre: "",
_classification:"",
_releaseDate: "",
_rating: "",
_cast: ""
};
Movie = {
_title: $scope.txttitle,
_genre: $scope.txtGenre,
_classification: $scope.txtClassification,
_releaseDate: $scope.txtDate,
_rating: $scope.user.txtRating,
_cast: $scope.txtCast
};
var promisePost = MyService.getbyCat(Movie);
Recent Error :
Remote Address:[::1]:50948
Request URL:http://localhost:50948/api/values/GetMovieByCategory/?_genre=sdf
Request Method:GET
Status Code:400 Bad Request
In the Angular Service, instead of appending the Movie object, pass it as parameter.
eg.
//GetByCategory
this.getbyCat = function (Movie) {
return $http.get("/api/values/GetMovieByCategory/", { params: Movie});
};
This will make the HTTP get with the the properties as url parameters.
And I dont think there is a need for the {movieData} parameter in the Route defined, since WebApi will automatically Serialize the url parameters to the object MovieData
eg.
index.js
angular.module('index.services', []).
factory('indexService', function ($http) {
var api = 'api/values/GetData';
var indexAPI = {};
indexAPI.getData = function (params) {
return $http.get(api, { params: params });
}
return indexAPI;
});
angular.module('index.controllers', ['index.services']).
controller('indexController', function ($scope, indexService) {
$scope.getData = function () {
var params = {
name: 'test',
age: '10'
};
$scope.errorOccured = false;
indexService.getData(params).then(function (response) {
$scope.data = response.data;
}, function (response) {
$scope.errorOccured = true;
});
}
});
angular.module('index', ['index.controllers']);
Index.cshtml
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.1/angular.js"></script>
<script src="~/Scripts/app/index.js"></script>
<div ng-app="index" ng-controller="indexController">
<button ng-click="getData()">Get Data</button>
<div ng-if="errorOccured==true">Error Occured</div>
<div ng-repeat="item in data">
<div>{{item}}</div>
</div>
</div>
DataRequestModel.cs
public class DataRequestModel
{
public string Name { get; set; }
public string Age { get; set; }
}
ValuesController.cs
public class ValuesController : ApiController
{
[HttpGet]
public IEnumerable<string> GetData([FromUri]DataRequestModel dataRequest)
{
return new string[] { dataRequest.Name, dataRequest.Age.ToString() };
}
}

Restangular and Asp.Net WebApi Post

I am trying to call Asp.Net WebApi method declared as:
[HttpPost]
[ActionName("Login2")]
public bool Login(UserInfo userinfo)
{
return userinfo.Username == "sandeep#sa.com" && userinfo.Password == "chandra";
}
And from Restangular the code looks like:
var lUserInfo = { Username: this.fEmail, Password: this.fPassword };
this.fLoginService.withConfig(x => x.setDefaultHeaders({ 'Content-Type': 'application/json' }))
.all("v1Values").post("Login2", null,
{ userinfo: lUserInfo }).then(
x => {
var lLoggedIn: boolean = x == "true";
this.fSessionService.fUserAuthenticated = lLoggedIn;
if (lLoggedIn) {
this.fLocation.path('/dashboard');
return;
}
Utilities.Dialog.showError('Invalid Email or Password');
});
I get this error:
"OPTIONS http://myserver:7220/api/v1Values 500 (Internal Server Error)"
I just can't get this to work. I can't see userinfo passed in the body.
What am I doing wrong?

Resources