I am working on an asp.net mvc application and I am using Entity Framework and AngularJS in it. I am using AngularJS's $http service to call an action method and retrieve data from the server. The correct data is retrieved from the server (I confirmed this by debugging), but somehow an error occurs after the action method returns the retrieved data and the error callback function is fired instead of the success callback function. And then I get a status 500 in the browser's console.
Here are the involved blocks of codes:
(From angularjs controller)
$http({
url: rootUrl + "User/GetUser",//'#Url.Action("GetUser","User")',
method: 'POST',
params: {
uname: $scope.username,
pword: $scope.pass
}
}).then(function (response) {
alert('success!');
$scope.user = response.data;
if ($scope.user.Fullname != undefined) {
$http({
url: rootUrl + "Session/Set",
method: "POST",
data: {
"key": "curr_user",
"value": JSON.stringify($scope.user)
}
});
window.location.href = rootUrl + 'Product/List/';
} else {
//invalid login
$("input[name='password']").select();
$("#validation-summary").html("Wrong email or password.");
$scope.invalidlogin = true;
$(btnLogin).removeClass('disabled');
$(btnLogin).text("Submit");
}
(From mvc controller)
[HttpPost]
public JsonResult GetUser(string uname, string pword)
{
JBManager manager = null;
using (SE_Context db = new SE_Context())
{
try
{
manager = db.Managers
.Include("Transactions.Items")
.Where(m => m.Username == uname && m.Password == pword)
.FirstOrDefault();
//At this point, manager has the desired data
return Json(manager, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return null;
}
}
}
And here's a screenshot of the error in the browser:
Would really appreciate any help. Thanks!
UPDATE:
Everything was working fine before I used Entity Framework. (Just in case it has something to do with the issue)
I think your issue is nested objects.You can flatten object graphs that contain nested objects using DTOs (Data Transfer Objects).
You can just try simple example as like below.If it'll work then you need to extend it to work with your EF query.
public class MyDto
{
public string Name { get; set; }
}
[HttpPost]
public JsonResult GetUser(string uname, string pword)
{
JBManager manager = null;
using (SE_Context db = new SE_Context())
{
try
{
//construct the DTO here
manager = db.Managers.Select(a=> new MyDto(
{
Name = a.Name
})).FirstOrDefault(m => m.Username == uname && m.Password == pword);
return Json(manager, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return null;
}
}
}
You can read more about DTOs here : Create Data Transfer Objects (DTOs)
Related
i want to create a file in client side using Angular or Javascript and send it to server.
Using MVC controller my server function is
public void SavePivotFile(HttpPostedFileBase file)
{
try
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~"), System.Configuration.ConfigurationManager.AppSettings["reportsFolder"].ToString(), fileName);
file.SaveAs(path);
}
}
catch(Exception e)
{
throw;
}
}
Now, in my client side, i have a object that i want to send in SavePivotFile like a file. I tried this but doesnt work. The object 'options' is JSON.
$http({
method: 'GET',
url: '/FileManager/SavePivotFile',
params: {
file: options,
}
}).then(function successCallback(response) {
showNotification('The changes have been saved.', 'info');
}, function errorCallback(response) {
showNotification('Failed to save the file.', 'error');
});
Also i tried to create new FormData() before send but also doesn't work. How cat take options JSON object and pass it to server like file?
//C# Code
[HttpPost]
[Route('FileManager/SavePivotFile')]
// you can use [Allow(Role)] to allow particular role. Google it!
public void SavePivotFile(HttpPostedFileBase file)
{
try
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~"), System.Configuration.ConfigurationManager.AppSettings["reportsFolder"].ToString(), fileName);
file.SaveAs(path);
}
}
catch(Exception e)
{
throw;
}
}
//Angular Code
$http.post('FileManager/SavePivotFile',options)//Optionsistheobjectuwanttosend
.success(function(res){
//your code. since the c# method isvoid you will not get any response
})
.error(function(e){
//your error handling
})
The HttpPostedFileBase model should be similar to options. That way you can access the JSON in c#.
Let me know if this works.
Hi I am developing restfull web api application. After inserting data into database i want to return 0 for success,1 for error and data as unique id assigned to the user. I want to return above data in json format. My requirement is i have to send data to controller in json format and receive data in json format. I have following code and it is working but i want to ask few points here.
Below is my User_Creation controller code.
public result Post(Noor_Users users)
{
result obj = new result();
if (ModelState.IsValid)
{
entityObject.Noor_Users.Add(users);
int result = entityObject.SaveChanges();
if(result==1)
{
obj.success = 0;
obj.id = 5;
return obj;
}
else
{
obj.error = 1;
return obj;
}
}
else
{
obj.error = 1;
return obj;
}
}
}
My service.js file contains below code.
app.service("UserCreation", function ($http) {
this.saveSubscriber = function (sub) {
return $http({
method: 'post',
data: JSON.stringify(sub),
url: 'api/User_Creation',
contentType: "application/json"
});
}
});
This is my controller.js code.
app.controller('UserCreation', function ($scope, UserCreation) {
$scope.saveSubs = function () {
var sub = {
user_email: $scope.user_email,
user_password: $scope.user_password,
};
var saveSubs = UserCreation.saveSubscriber(sub);
saveSubs.then(function (data) {
alert(JSON.stringify(data.data));
}, function (error) {
console.log('Oops! Something went wrong while saving the data.')
})
};
});
I am expecting response in json format as below.
● status - 0 for success, 1 for failure.
● data
○ id - unique id assigned to the user
● error - error message if failed
This is working absolutelt fine. I have below line of code in webapiconfig.cs file
config.Formatters.JsonFormatter.SupportedMediaTypes
.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("text/html"));
With this line of code always i can receive data in json format. But in angularjs success call i need to stringify recieved data. If all my data is returning in json then again why i should convert it to json? Also someone can tell me is above logic is a good practice to return data? Thank you.
Try the following steps:
Add this two line of code on top of your WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
Edit you controller action with following one
public IHttpActionResult Post(Noor_Users users)
{
result obj = new result();
if (ModelState.IsValid)
{
entityObject.Noor_Users.Add(users);
int result = entityObject.SaveChanges();
if (result == 1)
{
obj.success = 0;
obj.id = 5;
}
else
{
obj.error = 1;
}
}
else
{
obj.error = 1;
}
return Ok(obj);
}
Controller code of Angular Js...
FactoryPBD.showPbdCostCompareData(data).success(
function(result) {
if(result != ""){
//doing my processing and working fine
}).error(function(result,status,message){
console.log("result" , result);
//getting undefined in all the above variable
});
Service code:
showPbdCostCompareData : function(filter) {
promise = $http({
url : 'pbd/showPbdCostCompareData?serachFilterJson='+JSON.stringify(filter),
method : "POST"
});
return promise;
}
Java Controller:-
#RequestMapping(value = "/showPbdCostCompareData", method = RequestMethod.POST)
public #ResponseBody ResponseEntity<String> showPbdCostCompareData(HttpServletRequest request,
#RequestParam String serachFilterJson) {
try {
if (null != serachFilterJson && !"".equalsIgnoreCase(serachFilterJson)) {
Gson gson = new Gson();
SearchCriteriaBean searchCriteriaObj = gson.fromJson(serachFilterJson, SearchCriteriaBean.class);
CnHeaderBean cnHeaderBean = pbdServiceImpl.getPbdCostCompareCnHeaderData(searchCriteriaObj); //getting the value from sevice
List<PbdCostCompareBean> pbdCostCompareList = null;
if (null != cnHeaderBean) {
if("F".equalsIgnoreCase(cnHeaderBean.getPbdType())){
searchCriteriaObj.setFromPartIscb(cnHeaderBean.getFromPartIscb());
searchCriteriaObj.setToPartIscb(cnHeaderBean.getToPartIscb());
pbdCostCompareList = pbdServiceImpl.getPbdCostComparisonData(searchCriteriaObj); //getting the value from sevice
}else{
return new ResponseEntity<String>("Incorrect PBD Type",HttpStatus.SERVICE_UNAVAILABLE);
}
} else {
return new ResponseEntity<String>(HttpStatus.SERVICE_UNAVAILABLE);
}
HashMap<Integer, Object> costCompareMap = new HashMap<Integer, Object>();
costCompareMap.put(1, cnHeaderBean);
costCompareMap.put(2, pbdCostCompareList);
costCompareMap.put(3, pbdServiceImpl.validateUserAccess(searchCriteriaObj, serviceUtility.getUserFromSession(request)));
String pbdDataJsonResponse = gson.toJson(costCompareMap);
return new ResponseEntity<String>(pbdDataJsonResponse, HttpStatus.OK);
} else {
return new ResponseEntity<String>(HttpStatus.SERVICE_UNAVAILABLE);
}
} catch (C2PCException e) {
return new ResponseEntity<String>(e.getMessage(),HttpStatus.SERVICE_UNAVAILABLE);
}
}
I am using Spring Rest controller with Angular js for my project. Things are working fine and data is properly sent to client side when there is no error at Java side. But in case there is an exception at java side then depending upon the exception i want to return my message to the user.My response text is not getting transmitted to the client side. Any help will be appreciated. Code is provided above
Here in above e.getMessage, i get my custom message which i have set in mu service layer and throws the exception from there. But in the client side in error message i get all the values as undefined.
I assume that in angular js when an error occurs, a JSON is expected and not html/text
So, convert the exception to json.
You can create a class
ie
class ClassErrorMessage {
private String errorCode;
private String errorMessage;
ClassErrorMessage() {
}
//getters and setters
}
and then
catch (C2PCException e) {
ClassErrorMessage classErrorMessage= new ClassErrorMessage();
classErrorMessage.setErrorCode("some code that you may want");
classErrorMessage.setErrorMessage(e.getMessage());
String error = gson.toJson(classErrorMessage);
return new ResponseEntity<String>(error,HttpStatus.SERVICE_UNAVAILABLE);
}
and let me know if this worked for you
I am trying to delete an object and return an list which does trigger the web api controller method but then get the error
Expected response to contain an object but got an array (Request: DELETE
$scope.deleteProduct = function (productId) {
productResource.delete({
id: productId
}, function (data) {
$scope.products = data;
});
}
Resource controller
function productResource($resource) {
return $resource("/api/products/:id");
}
Web api controller
public IQueryable Delete(int id)
{
var repository = new ProductRepository();
return repository.Delete(id).AsQueryable();
}
And this is the call to the database which returns a list of products.
internal List<Product> Delete(int Id)
{
IDbConnection connection;
using (connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Liberty"].ToString()))
{
var result = connection.QueryMultiple("DeleteProduct", new{prodId = Id}, commandType: CommandType.StoredProcedure);
var products = result.Read<Product>().ToList();
return products;
}
}
How am I going about this the wrong way?
You could specify that the return type of the DELETE operation is an array because that's what your Web API controller returns:
function productResource($resource) {
return $resource("/api/products/:id", { }, {
'delete': {
method: 'DELETE',
isArray: true
}
});
}
IN angular js i am trying to send a post request her is the controller.
.controller('ActivationController',['$http','$location','$routeParams','AuthService',
function($http, $location, $routeParams, AuthService){
var location = $location.path();
var activation_code = $routeParams.code;
var activationLink = "http://localhost:18678/api/User/ActivateUser";
console.log(activation_code);
if(activation_code){
$http({method:"post", url:activationLink, data:activation_code}).success(function(response){
console.log(response);
}).error(function(error){
console.log(error);
});
}
}]);
and in asp.net web API her is the method.
[HttpPost]
public HttpResponseMessage ActivateUser([FromBody]string activation_code)
{
if (!string.IsNullOrWhiteSpace(activation_code))
{
string decode_token = HttpUtility.UrlDecode(activation_code); ;
string token_string = Crypto.Decrypt(activation_code, passPhrase);
if (token_string != null)
{
User activateAcc = db.Users.Where(user => user.ConfirmToken == token_string).SingleOrDefault();
if (activateAcc != null)
{
activateAcc.IsActive = true;
try
{
db.SaveChanges();
var credential = new UserCredential();
credential.EmailAddress = activateAcc.UserMail;
credential.Password = activateAcc.UserPassword;
return Request.CreateResponse(HttpStatusCode.OK, credential);
}
catch
{
return Request.CreateResponse(HttpStatusCode.Ambiguous, "cannot confirm account");
}
}
else
{
return Request.CreateResponse(HttpStatusCode.NotAcceptable, "invalid account");
}
}
else
{
return Request.CreateResponse(HttpStatusCode.NoContent, "invalid token data");
}
}
else
{
return Request.CreateResponse(HttpStatusCode.NoContent, "missing activation code");
}
}
The problem is when the controller fire the request is made but without sending any data to the server. The [FromBody]string activation_codeis null
Wrap your parameter in quotes:
$http({method:"post", url:activationLink, data: '"' + activation_code + '"'});
Explanation
For Web API to bind to a simple string primitive, the body must be specified as:
"some string here"
For example:
POST http://localhost:5076/api/values HTTP/1.1
User-Agent: Fiddler
Host: localhost:5076
Content-Type: application/json
Content-Length: 7
"Alice"
The quotes are important. For more information, check this article.