I am trying to use ng-file-upload to upload files and save blob to database as in my previous question Ng-File-Upload to Save PDF Blob to Database
I believe that I have the "correct" code to complete the task, but the problem now is that I cannot get the code to "hit" the method in the ApiController. If I put the method in a regular async controller, it finds it (but then I can't use half of the code needed because it doesn't work unless it is in a controller that inherits from ApiController), but it won't find the same method in the ApiController. What am I missing?
Here is the Angular Controller Code:
angular.module('myModule').controller('DocumentCtrl', function ($scope, $interval, $window, $filter, $q, $timeout, Upload, $http) {
$scope.uploadPic = function (file) {
file.upload = Upload.upload({
url: '/SSQV4/SSQV5/Document/UploadEMRDocument',
method: 'POST',
data: { file: file }
})
}
})
Here is the MVC Controller Code:
public class DocumentController : ApiController
{
public async Task<IHttpActionResult> UploadEMRDocument()
{
try
{
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
var f = provider.Contents.First(); // assumes that the file is the only data
if (f != null)
{
var filename = f.Headers.ContentDisposition.FileName.Trim('\"');
filename = Path.GetFileName(filename);
var buffer = await f.ReadAsByteArrayAsync();
//buffer now contains the file content,
//and filename has the original filename that was uploaded
//do some processing with it (e.g. save to database)
}
else
{
return BadRequest("Attachment failed to upload");
}
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
return Ok();
}
}
I am assuming that this is some sort of routing issue, but I'm not sure. Any Assistance is greatly appreciated!
I needed to change the url to
url: '/SSQV4/SSQV5/api/Document/UploadEMRDocument'
Now it hits it. Thanks for your help Nava-Prev.Queti!
Related
I am doing an angular application with asp.net mvc and i made a registration form with identity, I have layout and index mvc view which i just write in it ng-view tag and i inject html pages in it, I am doing a http post request from angular controller to mvc action method but the request does not go to the mvc action, whereas when i change th views to mvc views and make a templateUrl in angular map to mvc method it works well.
Can any one help me in this problem.
[HttpPost]
[AllowAnonymous]
public async Task<JsonResult> Register(RegisterViewModel model)
{
string message = "";
if (ModelState.IsValid)
{
var user = new ApplicationUser
{
FirstName = model.FirstName,
MiddleName = model.MiddleName,
LastName = model.LastName,
UserName = model.Email,
Email = model.Email,
UserStatus = UserStatus.Waiting
};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
message = "Success";
}
else
{
AddErrors(result);
message = "InvalidEmail";
}
}
else
{
message = "Failed!";
}
return new JsonResult { Data = message, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
and this is my angular controller
MyApp.controller('RegisterController', ['$scope','$http',function ($scope, $http) {
$scope.message = '';
$scope.isFormValid = false;
//Check Form Validation
$scope.$watch('f1.$valid', function (newValue) {
$scope.isFormValid = newValue;
});
//Save Data
$scope.SaveData = function (data) {
$scope.submitted = true;
$scope.message = '';
if ($scope.isFormValid) {
$http({
method: 'POST',
url: '/Account/Register',
data: data
}).then(function (response) {
// check your response (if a success status code was resolved)
console.log(response.data);
}, function (error) {
// check your error response
console.log(error);
});
} else {
$scope.message = "Please Fill the blanks";
}
}
}]);
and this is my html page:
<div ng-controller="RegisterController">
<form name="f1" ng-submit="SaveData(user)" novalidate>
controls here
</form
1) Check your browser console for any javascript errors, if you have any, resolve them and try again!
2) Check you have the correct ActionMethodSelectorAttribute attribute ([HttpPost]) over your controller method and that your method name is spelt correctly.
3) Check that you have the correct path in your request.
4) Check you are sending the correct data to the controller!!!
5) Check that the method is public.
6) Check that you are authorised to access that controller/method.
7) Check that you don't have any duplicate method names with either, a) the same parameters and name (if your not using an ActionMethodSelectorAttribute, or b) the same names and method select attributes.
8) Remove all parameters from your method, put a breakpoint at the start of the method, and try making the request and see if it hits the breakpoint. If it works without parameters and not with, then you are not passing the correct required data into the method.
9) Make your request and check the response!! (example below):
// make your request
$http({
method: 'POST',
url: '/Controller/Method',
data: {
foo: bar
}
}).then(function(response) {
// check your response (if a success status code was resolved)
console.log(response);
}, function(error) {
// check your error response
console.log(error);
});
If you have a 404 then your method was not found, if you have a 500 then something blew up in your code, if you have a 401 then you are unauthorised etc... This is really useful to actually know what is going on with your request...
10) Check your application is running!
I'm using an x-auth-token generated by spring session to maintain communication, this is fine for ajax requests.I have a problem though, I have files that are not currently being fetched by ajax.
These files are user uploaded content, pdfs, html with css and fonts, basically things the browser can render, so making an ajax force download button isn't an option (though maybe there's a way to do this to view them that I'm not thinking of). Currently they are just being requested by a browser GET via <a href links, so no header is included.
I am using AngularJS. What's the best way to address this issue?
I know this question is a couple months old, but I ran into this problem with AngularJS when I first moved to using Spring Session also. It's a little hacky, but it essentially uses AngularJS's HTTP to retrieve the document and save it in a BLOB in the Browser. Then, a hidden <a> tag is created with a link to the BLOB and the link is clicked programmatically. I have an AngularJS service called 'saveBlob' that handles this:
app.service('saveBlob', ['$http', function ($http) {
return {
download: function(url, fileName) {
$http.get(url, { responseType: 'arraybuffer' }).then(function(response) {
var blob = new Blob(
[ response.data ],
{ type: response.headers('Content-Type') }
);
var objUrl = window.URL.createObjectURL(blob);
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = objUrl;
if (fileName) {
a.download = fileName;
}
else {
var regex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g;
var match = regex.exec(response.headers('Content-Disposition'));
var fn = match[1];
a.download = fn.substring(1, fn.length - 1);
}
a.click();
window.URL.revokeObjectURL(url);
});
}
}
}]);
The 'saveBlob' service is then called by a directive called 'httpHref':
app.directive('httpHref', ['$http', 'saveBlob', function ($http, saveBlob) {
return {
link: function ($scope, elem, attrs) {
function revokeObjectURL() {
if ($scope.objectURL) {
URL.revokeObjectURL($scope.objectURL);
}
}
$scope.$watch('objectURL', function (objectURL) {
elem.attr('href', objectURL);
});
$scope.$on('$destroy', function () {
revokeObjectURL();
});
attrs.$observe('httpHref', function (url) {
elem[0].onclick = function() {
saveBlob.download(url);
};
});
}
};
}]);
I adapted this code from This GitHub Repository (which is licensed under the MIT License), so thank you to the contributors of that project for helping me with this!
I have a AddCategory() method in my Controller:
[RoutePrefix("api")]
public class CategoryController : ApiController
{
....
[Route("addCategory")]
[HttpPost]
public void AddCategory(string category)
{
var getCat = category;
}
At the my Home.html i have button Save New Category i wrote the $http.post method for it:
var testString = "TEST String";
var req = {
method: 'POST',
url: '/api/addCategory',
data: testString,
};
$http(req).then(function successCallback(response) {
console.log("Success");
}, function errorCallback(response) {
console.log("Eror");
});
But i have the next error:
angular.js:11442 POST http://localhost:6059/api/addCategory 404 (Not
Found)
At the Network bookmark in Development console i finded the error:
may be it's important but i disabled XML in WebApiConfig.cs:
var json = GlobalConfiguration.Configuration.Formatters;
json.JsonFormatter.UseDataContractJsonSerializer = true;
json.Remove(json.XmlFormatter);
May be somebody knows how i can change it ? Thanks for your answers!
You method Post need to return IHttpActionResult. or your request http always returns code 404.
Try this :
[RoutePrefix("api")]
public class CategoryController : ApiController
{
....
[Route("addCategory")]
[HttpPost]
public IHttpActionResult AddCategory(string category)
{
var getCat = category;
if(getCat != null)
return Ok();
return NotFound();
}
I advice you to use Api Rest in C# with $resource angular. In my mind, it's the best pattern.
The problem is related to the service you are calling, 404 means not found:
404 http error
therefore something in the service URL or in your local server is not working.
I am using ABP (ASP.NET Boilerplate) Web API and angularjs to build a SinglePageApplication. I already got it working to call the server side methods via angular and the abp framework. It is easy to just send JSON-data but I have no idea how to send files.
Here is an example of sending JSON-Data:
Server-Code
public class PostAppService : ApplicationService, IPostAppService
{
public LoginOutput Login(LoginInput input)
{
doSomeStuffHere();
}
}
[DependsOn(typeof(AbpWebApiModule))]
public class SimpleTaskSystemWebApiModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
DynamicApiControllerBuilder
.ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")
.Build();
}
}
Client-Code
(function() {
var app = angular.module('app');
var controllerId = 'sts.views.authentication.login';
app.controller(controllerId, [
'$scope', '$location', 'abp.services.tasksystem.authentication',
function ($scope, $location, authService) {
var vm = this;
vm.user = {
username: '',
password: ''
};
var localize = abp.localization.getSource('SimpleTaskSystem');
vm.login = function () {
abp.ui.setBusy(
null,
authService.login(
vm.user
).success(function(response) {
displayLoggedInMessage();
})
);
};
}
]);
})();
I would like to do something like this but instead of sending JSON-Data I would like to send an image selected via:
<input type="file"/>
Any ideas?
A good way of achieving upload file:
Create a controller named UploadController from the base
AbpController
Add a method to upload the file. Let's name it ProductPhoto
public JsonResult ProductPhoto(string comment, int productId)
{
try
{
if (!Request.Files.Any() || Request.Files[0] == null)
{
return null;
}
var fileName = Guid.NewGuid();
var uniqueFilePath = #"~\Upload\ProductPhotos\" + fileName;
Request.Files[0].SaveAs(uniqueFilePath);
//save your additional parameters such as comment, productId
return Json(new
{
Success = true,
FileName = fileName
});
}
catch (Exception ex)
{
Logger.Error(ex.ToString);
return Json(new
{
Success = false
});
}
}
On the client send send the file using jquery or angular
vm.showProductPhotoUploadFileDialog = function () {
var formData = = new FormData()
formData .append("productId", vm.form.product.id);
formData .append("formId", vm.form.id);
if (vm.newProductPhoto.comment) {
formData .append("comment", vm.newProductPhoto.comment);
}
$('#productPhotoFileInput').click();
};
After upload completes get the result using callback
vm.productPhotoUploaded = function (response) {
if (!response.success) {
return;
}
vm.productPhotoFileName = response.fileName;
};
At this step you have the unique filename generated on the server for this file. Now you can update your client side object. Or you can go on your cascade savings.
Note: One disadvantage of this approach is; when user uploads file and then cancels the master entity save, you have to manually handle to delete the temp file uploaded to server.
I am trying to access an update rest method with AngularJs, but it is giving me 400 bad request error.
Here is my code.
#RestController
#RequestMapping("/api/loggedInUser")
public class UserController {
#RequestMapping(value = "/{id}",method = RequestMethod.PUT)
public AppUser updateLoggedInUser(#RequestBody AppUser user){
return userService.updateAppUser(user);
}
}
Here is the code for accessing the service from AngularJs:
App.factory('LoggedInUserService', ['$resource', function($resource) {
console.log('service injected');
return {
getLoggedInUser: $resource('api/loggedInUser', {}, {
query: {method: 'GET'}
}),
updateLoggedInUser: $resource('api/loggedInUser/:id', {}, {
update: {method: 'PUT', params: {id: '#id'}}
})
};
}]);
Here is the code for accessing the service in my app.js file.
.run(function($location, $rootScope, LoggedInUserService) {
LoggedInUserService.getLoggedInUser.query(function(loggedInUser) {
$rootScope.loggedInUser = loggedInUser;
console.log($rootScope.loggedInUser.username);
if (loggedInUser.role[0].authority === 'ADMIN_ROLE' && loggedInUser.pristineAccess) {
$rootScope.loggedInUser.isAdmin = true;
$rootScope.pristineAccess = false;
LoggedInUserService.updateLoggedInUser.update($rootScope.loggedInUser);
$location.path('/admin');
} else {
$rootScope.loggedInUser.isAdmin = false;
$location.path('/dashboard');
}
});
});
When I remove the #RequestBody annotation I don't get a 400 error but the parameter doesn't get populated.
What am I doing wrong here? I used the same kind of code in another place in the same application and it worked fine. The only difference here is that the rest method argument parameter is an entity object and not a pojo.
add consumes = MediaType.APPLICATION_JSON_VALUE to your controller method and check your POST content with web developers tool or firebug or simmilar tool
#RequestMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE,method = RequestMethod.PUT)
public AppUser updateLoggedInUser(#RequestBody AppUser user){
return userService.updateAppUser(user);
}