0

I am trying to create a function in an Angular controller which passes an array of TestExpense objects to a C# API which will then handle inserting them into a database. Currently, the API is only configured to do one at a time.

The objects of the array, $scope.TestExpenses, I wish to pass are represented by the following constructor :

function TestExpense(employeeId, expenseDate, taskId, expenseTypeId,
    billingCategory, notes, amount, lastUpdatedDate, lastUpdatedBy, dateSubmitted) {
    this.employeeId = employeeId;
    this.expenseDate = expenseDate;
    this.taskId = taskId;
    this.expenseTypeId = expenseTypeId;
    this.billingCategory = billingCategory;
    this.notes = notes;
    this.amount = amount;
    this.lastUpdatedDate = lastUpdatedDate;
    this.lastUpdatedBy = lastUpdatedBy;
    this.dateSubmitted = dateSubmitted;
    this.location = location;
}

$scope.TestExpenses = [];

The current state of the relevant Angular function submitEntriesToDatabase:

$scope.submitEntriesToDatabase = function () {
    $http.post('/expense/submitExpense', $scope.TestExpenses)
    .success(function (data, status, headers, config) {

    })
    .error(function (data, status, headers, config) {

    });


};

In C#, I have the following model to correspond to my TestExpense object:

public class Expense
{
    public int employeeId { get; set; }
    public string expenseDate { get; set; }
    public int taskId { get; set; }
    public int expenseTypeId { get; set; }
    public int billingCategory { get; set; }
    public string notes { get; set; }
    public float amount { get; set; }
    public string LastUpdatedDate { get; set; }
    public int LastUpdatedBy { get; set; }
    public string dateSubmitted { get; set; }
    public string location { get; set; }
}

And the method to handle the POST in the API:

    public void SubmitExpenses(List<Expense> expenses)
    {

        //using(cnxn)
        //{
        //    using(SqlCommand sqlQuery = new SqlCommand("INSERT INTO Expenses " + 
        //        "(Employee_ID, Task_ID, Expense_Date, Expense_Type_ID, Billing_Category_ID, " + 
        //        "Amount, Notes, Last_Updated_By, Last_Update_Datetime, Date_Submitted, Location) " +
        //        "Values (@employeeId, @taskId, @expenseDate, @expenseTypeId, @billingCategory, @amount, @notes, " +
        //        "@lastUpdatedBy, @lastUpdatedDate, @dateSubmitted, @locationId)", cnxn))
        //    {
        //        sqlQuery.Parameters.Add(new SqlParameter("@employeeId", SqlDbType.Int) { Value = employeeId });
        //        sqlQuery.Parameters.Add(new SqlParameter("@expenseDate", SqlDbType.DateTime) { Value = expenseDate });
        //        sqlQuery.Parameters.Add(new SqlParameter("@taskId", SqlDbType.Int) { Value = taskId });
        //        sqlQuery.Parameters.Add(new SqlParameter("@expenseTypeId", SqlDbType.Int) { Value = expenseTypeId });
        //        sqlQuery.Parameters.Add(new SqlParameter("@billingCategory", SqlDbType.Int) { Value = billingCategory });
        //        sqlQuery.Parameters.Add(new SqlParameter("@notes", SqlDbType.Text) { Value = notes });
        //        sqlQuery.Parameters.Add(new SqlParameter("@amount", SqlDbType.Money) { Value = amount });
        //        sqlQuery.Parameters.Add(new SqlParameter("@lastUpdatedDate", SqlDbType.DateTime) { Value = lastUpdatedDate });
        //        sqlQuery.Parameters.Add(new SqlParameter("@lastUpdatedBy", SqlDbType.Int) { Value = lastUpdatedBy });
        //        sqlQuery.Parameters.Add(new SqlParameter("@dateSubmitted", SqlDbType.DateTime) { Value = dateSubmitted });
        //        sqlQuery.Parameters.Add(new SqlParameter("@locationId", SqlDbType.VarChar) { Value = "Radnor" });


        //        cnxn.Open();
        //        sqlQuery.ExecuteNonQuery();
        //    }
        //}



    }

The lines that are commented out in my SubmitExpenses work to insert a single entry (with the appropriate method signature, not what is there now). It is also that functionality which I wish to imitate with the List<Expenses> expenses argument being passed to it. From what I gather, I need to deserialize the JSON string that will represent my $scope.TestExpenses array, but I am unsure of how to start to parse out individual Expense objects from it.

The relevant route in RouteConfig.cs:

routes.MapRoute(
     name:"SubmitExpense",
     url:"expense/submitExpense",
     defaults: new
     {
           controller = "Expense",
           action = "SubmitExpenses"
     }
);

Any guidance would be much appreciated!

5
  • What is the route that has been setup, how has that been applied to this function? Commented Aug 12, 2016 at 15:34
  • It is as seen in the $http.post. I know that data is passed to the SubmitExpenses method in my controller, but I am unaware of how to break down the List passed as an argument, which I feel is a problem independent of route. Commented Aug 12, 2016 at 15:41
  • I edited the post because I hadn't properly indented the SubmitClasses method header. Sorry. Commented Aug 12, 2016 at 15:43
  • Please clarify how the SubmitExpenses function gets called on your server. Commented Aug 12, 2016 at 15:57
  • The route is posted, but I do not really see how it is relevant since I know the application and API are connected. Literally, only the method header is changed, which has nothing to do with the routes. Commented Aug 12, 2016 at 16:02

3 Answers 3

2

From what I gather, I need to deserialize the JSON string that will represent my $scope.TestExpenses array, but I am unsure of how to start to parse out individual Expense objects from it.

Simple. Use the [FromBody] decorator in your method signature. Your default JSON serializer settings setup for all the controllers will try parse the string into the Expense list - if you're using Json.NET, it can handle this automatically.

public void SubmitExpenses([FromBody] List<Expense> expenses)
Sign up to request clarification or add additional context in comments.

3 Comments

I will try this now. So I should be able to access an element from the expenses argument as an Expense object by its index, and then access each individual element's properties?
+1 for your help, @toadflakz. I didn't actually require [FromBody] as detailed by @naveen, but I appreciate you did help me get on the right path.
he is correct. its just that web api uses JSON.NET +1
1

From what I gather, I need to deserialize the JSON string that will represent my $scope.TestExpenses array, but I am unsure of how to start to parse out individual Expense objects from it.

No. You don't need to do a thing to de-serialize. It will be auto-deserialized.

A better implementation of the POST request will be this.

$scope.submitEntriesToDatabase = function() {
    var config = {
        method: "POST",
        url: '/expense/submitExpense',
        data: $scope.TestExpenses
    };
    $http(config).then(function(response) {
        //success
    }, function(response) {
        //error
    });
};

If the property names in the array are same as that of the the object in your generic list, the web api will automatically convert the javascript array to List<T>.

P.S: Do not use .success and .error callbacks as they are obsolete. Use .then

2 Comments

Thank you very much! Also, +1 for giving me insight into proper usage for $http.post
$http.post is equally good. $http gives us more control. its also more readable in my opinion
0

The correct way to do a post in angular 1.x, using $http is:

$http.post('/my/url',{foo:bar}).then(function(result) {
     console.log(result.data);  // data property on result contains your data
});

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.