Sunday 29 July 2018

upload a file in AngularJS and also for upload the same file twice

In this post we are going to see how to upload the file to a endpoint and also for upload the same file twice.

Normally what will happen if we upload the same file twice, it wont reflect the changes in the file input control, for that to reflect we have to reset the value to null of that element

Create a View:
we are creating a view which consists of one file upload control, and we are referring the two scripts one is angular js, another one is app.js

<!DOCTYPE html>
<html>
<head>
<title>File upload</title>
<script src="./angular.js"></script>
    <script src="app.js"></script>
</head>

<body >
<div ng-app="myApp">
    <div ng-controller="mainController">
        Browse File <input file-model="file" type="file">
    </div>
</div>
</body>

</html>

we are creating a angular module

var app = angular.module('myApp', []);


Create a Controller:
we are creating a controller which consists of following dependencies one is $scope and another one is httpService. we are calling a submit function whenever file is selected. if the upload is success or failure we are resetting the input file value to null. i.e resetting the value


app.
controller('mainController', ['$scope','httpService',function($scope, httpService){

    $scope.
title = 'Sample File upload';

   
$scope.submit = function(){

        httpService.
uploadFile($scope.file).then(function(data){
           
/* This event will reset the file, so same file can be upload again */
           
$scope.$broadcast('resetfile');
       
},function (error) {
            $scope.
$broadcast('resetfile');
       
});

   
};

   
$scope.$watch('file', function (newFile, oldFile) {
       
if(newFile!=undefined) {
            $scope.
submit();
           
console.log('file changed',newFile);
       
}
    })
;

}]);



Create a Directive:
we are creating a directive which will set the modal value, whenever there is a change in the fileupload control, i.e whenever you select a file, we will parse the attrs.fileModel and assign the value to that model on change.

app.directive('fileModel',function ($parse) {

return {

    restrict:'A',
    link: function(scope, element, attrs) {

        var modal = $parse(attrs.fileModel);
        var modalSetter = modal.assign;

        element.bind('change',function () {
            scope.$apply(function () {
                modalSetter(scope, element[0].files[0]);
            })
        });

        scope.$on('resetfile',function (event) {
            element.val(null);
        });

    }

}

});



Create a Service:


app.service('httpService',function ($http) {

    this.uploadFile = function (file) {

        var fileFormData = new FormData();
        fileFormData.append('file', file);

        return $http.post('https://www.sampleservice.com/upload', fileFormData, {
            transformRequest: angular.identity,
            headers: {'Content-Type': undefined}
        });

    }

});



Output:
*********






If you see the above console, logging of same file twice in upload is reflected by code

From this post we can learn how to upload a file in Angular js and also for upload the same file twice

Call the Async method inside the Parallel.Foreach and wait for all Async methods to finish execution c#

In this post we are going to see how to call a Async methods inside Parallel.Foreach and wait for all Async methods to finish execution. First let we the Parallel.Foreach in c#


    public class Person
    {
        HttpHelper helper = new HttpHelper();

        public async Task CalculateParallel()
        {
            List<Product> products = new List<Product>();
            int successCount = 0;
            for (int i = 0; i < 50; i++)
            {
                products.Add(new Product());
            }

            Parallel.ForEach(products, async (prod) =>
            {
                await ParallelTask(prod);
                if (prod.Index > 0)
                    successCount++;
            });

            Console.WriteLine(successCount);           
        }

        public async Task ParallelTask(Product prod)
        {
            var data = await helper.Get("https://reqres.in/api/users/2");
            prod.Index = 1;
        }
    }

    public class Product
    {
        public int Index { get; set; }
    }


HttpHelper:

 public class HttpHelper
    {
        HttpClient client = new HttpClient();

        public async Task<string> Get(string url)
        {
            string dataObjects = string.Empty;
            // Add an Accept header for JSON format.
            client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));

            // List data response.
            HttpResponseMessage response = await client.GetAsync(url);  /
            if (response.IsSuccessStatusCode)
            {
                // Parse the response body.
               dataObjects = await response.Content.ReadAsStringAsync();
            }
            else
            {
            Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
            }
            return dataObjects;
        }
    }




In the above code you can see that we are populating a collection then in parallel.foreach we are iterating that collection and call the async method in parallel.foreach.

Now what will happen is the parallel.Foreach wont wait for all async method to finish, before that, it reaches the console.writeline , see the below screenshot the successCount is 0  instead of 50, that means it comes before finishing the all async methods to finish, you can see in the screenshot that index value assign after the console.writeline executes.





Now we will solve this issue , that is iterating the collection in parallel and will wait for all async methods to finish, To achieve this.

Solution
1. Open Manage Nuget Packages
2. Search for AsyncEnumerator version 2.2.1 and install it.



3. Add the following namespace in file using System.Collections.Async;
4. Now change your code like below

await products.ParallelForEachAsync(async (prod) =>
            {
                await ParallelTask(prod);
                if (prod.Index > 0)
                    successCount++;

            });

In the above code you can see that we are using await before {collections}.ParallelForeachAsync this will wait for all async methods to finish

public class Person
    {
        HttpHelper helper = new HttpHelper();

        public async Task CalculateParallel()
        {
            List<Product> products = new List<Product>();
            int successCount = 0;
            for (int i = 0; i < 50; i++)
            {
                products.Add(new Product());
            }

            await products.ParallelForEachAsync(async (prod) =>
            {
                await ParallelTask(prod);
                if (prod.Index > 0)
                    successCount++;
            });

            Console.WriteLine(successCount);           
        }

        public async Task ParallelTask(Product prod)
        {
            var data = await helper.Get("https://reqres.in/api/users/2");
            prod.Index = 1;
        }

    }

Now we can see the output like successCount is 50 in the below screenshot.




From the above code you can learn how to call the async methods inside the Parallel.Foreach and wait for all Async methods to finish execution.