3

I have a few problems regarding ASP .NET MVC 4 Parallel Programming. I want to use Parallel programming, because of receive data from multiple API calls at same time.

Here are some small examples

RootObjectRS fairsearchRS1 = new RootObjectRS();
RootObjectRS fairsearchRS2 = new RootObjectRS();
RootObjectRS fairsearchRS3 = new RootObjectRS();

fairsearchRS1 = MakeRequest(searchUrl, WWWToken, request.TripType1, request.TripfromAirPort1, request.TriptoAirPort1, request.FlyfromDate1, request.FlytoDate1, request.Flyclass, request.Passengers, starting, reqstid);        
fairsearchRS2 = MakeRequest(searchUrl, WWWToken, request.TripType2, request.TripfromAirPort2, request.TriptoAirPort2, request.FlyfromDate2, request.FlytoDate2, request.Flyclass, request.Passengers, starting, reqstid);        
fairsearchRS3 = MakeRequest(searchUrl, WWWToken, request.TripType3, request.TripfromAirPort3, request.TriptoAirPort3, request.FlyfromDate3, request.FlytoDate3, request.Flyclass, request.Passengers, starting, reqstid);

This is just small example of my code. Using make request I'm calling those API's,and get data from them and bind it to those rootobjectRS, objects.

Right now I'm sending these requests one by one. But I need to do this at same time and I need to wait till those 3 request data arrive.

So how should I approach this using parallel or another programming method? Because right now it takes 1 minutes. But if I do this same time then I can do this in 20 seconds. That's main thing save time.

I don't know if this parallel programming concept is possible from ASP .NET MVC4. But if someone can give me support for this, then that would be great help. At least some good tutorial also great help.

Edit

Actually this is my makeRequest function,

 public static RootObjectRS MakeRequest(string requestUrl, SeneruUBT.Models.TokenModels token, string triptype, string from, string to, string flyin, string flyout, string flyclass, string passengers, DateTime starting, int reqstid)
        {

            HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
            request.Method = "POST";
            request.ContentType = "application/json";
            request.Headers.Add("Authorization", token.token_type + " " + token.access_token);
            request.Accept = "application/json";

            string ttrip = triptype;

            var streamWriter = new StreamWriter(request.GetRequestStream());

            if (ttrip.Equals("OneWay"))
            {
                RootObject searchBFMRQO = CreateRequestObjectOneWay(triptype, from, to, flyin, flyclass, passengers);
                String searchString = JsonConvert.SerializeObject(searchBFMRQO);
                streamWriter.Write(JsonConvert.SerializeObject(searchBFMRQO));

                streamWriter.Flush();
            }
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            var httpResponse = (HttpWebResponse)request.GetResponse();
            int sc = (int)httpResponse.StatusCode;
            System.Diagnostics.Debug.Write(sc);
            if (httpResponse.StatusCode != HttpStatusCode.OK)
            {

                using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                {
                    var result = streamReader.ReadToEnd();
                    RootObjectRS errorresult = JsonConvert.DeserializeObject<RootObjectRS>(result);

                    return (errorresult);
                }
            }
            else
            {
                var resp = new StreamReader(httpResponse.GetResponseStream()).ReadToEnd();

                RootObjectRS searchResponse = JsonConvert.DeserializeObject<RootObjectRS>(resp.ToString());

                SearchResponseFlightService ResponsFlSer = null;
                ResponsFlSer = new SearchResponseFlightService(new UBTRepository.UBTUnitofWorks(new UBTRepository.TravelEntities()));
                SearchResponseFlight ReFl = new SearchResponseFlight();


                ReFl.searchRequestID = reqstid;
                ReFl.StopQuantity = "1";
                ReFl.responseJson = resp.ToString();
                DateTime ending = DateTime.Now;
                ReFl.responseDuration = ending.Subtract(starting).Milliseconds;
                ReFl.starttimestamp = starting;

                ReFl.endtimestamp = ending;

                ResponsFlSer.Add(ReFl);

                searchResponse.reqid = reqstid;

                return (searchResponse);
            }


        }

I think now it can be little bit easy to understand.


After Change my make request to async it doesnt work-t give error in MakeRequestAsync.

 public static async Task RootObjectRS MakeRequestAsync(string requestUrl, SeneruUBT.Models.TokenModels token, string triptype, string from, string to, string flyin, string flyout, string flyclass, string passengers, DateTime starting, int reqstid)
    {

        HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
        request.Method = "POST";
        request.ContentType = "application/json";
        request.Headers.Add("Authorization", token.token_type + " " + token.access_token);
        request.Accept = "application/json";

        string ttrip = triptype;

        var streamWriter = new StreamWriter(await request.GetRequestStreamAsync());

        if (ttrip.Equals("OneWay"))
        {
            RootObject searchBFMRQO = CreateRequestObjectOneWay(triptype, from, to, flyin, flyclass, passengers);
            String searchString = JsonConvert.SerializeObject(searchBFMRQO);
            streamWriter.Write(JsonConvert.SerializeObject(searchBFMRQO));

            streamWriter.Flush();
        }
        HttpWebResponse response = await (HttpWebResponse)request.GetResponseAsync();
        var httpResponse = await (HttpWebResponse)request.GetResponseAsync();
        int sc = (int)httpResponse.StatusCode;
        System.Diagnostics.Debug.Write(sc);

            var resp = new StreamReader(await httpResponse.GetResponseStreamAsync()).ReadToEnd();

            RootObjectRS searchResponse = JsonConvert.DeserializeObject<RootObjectRS>(resp.ToString());

            SearchResponseFlightService ResponsFlSer = null;
            ResponsFlSer = new SearchResponseFlightService(new UBTRepository.UBTUnitofWorks(new UBTRepository.TravelEntities()));
            SearchResponseFlight ReFl = new SearchResponseFlight();


            ReFl.searchRequestID = reqstid;
            ReFl.StopQuantity = "1";
            ReFl.responseJson = resp.ToString();
            DateTime ending = DateTime.Now;
            ReFl.responseDuration = ending.Subtract(starting).Milliseconds;
            ReFl.starttimestamp = starting;

            ReFl.endtimestamp = ending;

            ResponsFlSer.Add(ReFl);

            searchResponse.reqid = reqstid;

            return (searchResponse);



        }
TDM
  • 115
  • 15
  • Where would this code live. Are you making a request to an MVC site? And if so, where is the request coming from? – Benjamin Drolet Aug 18 '16 at 17:28
  • actually i'm requesting from different web API 's yes i'm developing mvc site currently hosted in azure app services. – TDM Aug 18 '16 at 17:33
  • I modified my answer based on your implementation of MakeRequest. Take a look. That should solve what you are trying to accomplish. – Benjamin Drolet Aug 20 '16 at 10:42
  • I did the way you suggest.but i got error after modify my MakeRequest to MakeRequestAsync.i did add that part inside my question.i'm not sure what i missed, using System.Threading.Tasks; i also added. not sure why this error coming, --(Additionally can i debug these async requests on my local macine before publish to azure?) – TDM Aug 20 '16 at 15:55
  • Yes you can debug. What is the error you are getting? – Benjamin Drolet Aug 22 '16 at 18:13

2 Answers2

0

You want to first modify MakeRequest to MakeRequestAsync. Essentially anytime the method is accessing some I/O operation Microsoft provides an async version of that. (read the article below to understand what that does)

public static async Task<RootObjectRS> MakeRequestAsync(string requestUrl, SeneruUBT.Models.TokenModels token, string triptype, string from, string to, string flyin, string flyout, string flyclass, string passengers, DateTime starting, int reqstid)
    {

        HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
        request.Method = "POST";
        request.ContentType = "application/json";
        request.Headers.Add("Authorization", token.token_type + " " + token.access_token);
        request.Accept = "application/json";

        string ttrip = triptype;

        var streamWriter = new StreamWriter(await request.GetRequestStreamAsync());

        if (ttrip.Equals("OneWay"))
        {
            RootObject searchBFMRQO = CreateRequestObjectOneWay(triptype, from, to, flyin, flyclass, passengers);
            String searchString = JsonConvert.SerializeObject(searchBFMRQO);
            streamWriter.Write(JsonConvert.SerializeObject(searchBFMRQO));

            streamWriter.Flush();
        }
        HttpWebResponse response = await (HttpWebResponse)request.GetResponseAsync();
        var httpResponse = await (HttpWebResponse)request.GetResponseAsync();
        int sc = (int)httpResponse.StatusCode;
        System.Diagnostics.Debug.Write(sc);
        if (httpResponse.StatusCode != HttpStatusCode.OK)
        {

            using (var streamReader = new StreamReader(await httpResponse.GetResponseStreamAsync()))
            {
                var result = streamReader.ReadToEnd();
                RootObjectRS errorresult = JsonConvert.DeserializeObject<RootObjectRS>(result);

                return (errorresult);
            }
        }
        else
        {
            var resp = new StreamReader(await httpResponse.GetResponseStreamAsync()).ReadToEnd();

            RootObjectRS searchResponse = JsonConvert.DeserializeObject<RootObjectRS>(resp.ToString());

            SearchResponseFlightService ResponsFlSer = null;
            ResponsFlSer = new SearchResponseFlightService(new UBTRepository.UBTUnitofWorks(new UBTRepository.TravelEntities()));
            SearchResponseFlight ReFl = new SearchResponseFlight();


            ReFl.searchRequestID = reqstid;
            ReFl.StopQuantity = "1";
            ReFl.responseJson = resp.ToString();
            DateTime ending = DateTime.Now;
            ReFl.responseDuration = ending.Subtract(starting).Milliseconds;
            ReFl.starttimestamp = starting;

            ReFl.endtimestamp = ending;

            ResponsFlSer.Add(ReFl);

            searchResponse.reqid = reqstid;

            return (searchResponse);
        }


    }

The method above could use some refactoring (there is a lot going on in it =))

Now that MakeRequestAsync exists, modify the code below as such.

RootObjectRS fairsearchRS1 = new RootObjectRS();
RootObjectRS fairsearchRS2 = new RootObjectRS();
RootObjectRS fairsearchRS3 = new RootObjectRS();

var fairsearchRS1Task = MakeRequestAsync(searchUrl, WWWToken, request.TripType1, request.TripfromAirPort1, request.TriptoAirPort1, request.FlyfromDate1, request.FlytoDate1, request.Flyclass, request.Passengers, starting, reqstid);        
var fairsearchRS2Task = MakeRequestAsync(searchUrl, WWWToken, request.TripType2, request.TripfromAirPort2, request.TriptoAirPort2, request.FlyfromDate2, request.FlytoDate2, request.Flyclass, request.Passengers, starting, reqstid);        
var fairsearchRS3Task = MakeRequestAsync(searchUrl, WWWToken, request.TripType3, request.TripfromAirPort3, request.TriptoAirPort3, request.FlyfromDate3, request.FlytoDate3, request.Flyclass, request.Passengers, starting, reqstid);

fairsearchRS1 = await fairsearchRS1Task;
fairsearchRS2 = await fairsearchRS2Task;
fairsearchRS3 = await fairsearchRS3Task;    

Note: You don't want to do something like Task.Run. This will create a new thread. See this excerpt:

"The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active. You can use Task.Run to move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just waiting for results to become available."

From: https://msdn.microsoft.com/en-us/library/mt674882.aspx

Starting a new thread an an IIS hosted application is bad practice. See: https://blogs.msdn.microsoft.com/tmarq/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications/

  • Big assumption. If it doesn't exist you can call it Asynchronously using the Task object (see my answer) – matt-dot-net Aug 18 '16 at 18:57
  • Using Task.Run is bad practice and shouldn't be used. See http://stackoverflow.com/questions/33764366/is-task-run-considered-bad-practise-in-an-asp-net-mvc-web-application – Benjamin Drolet Aug 18 '16 at 21:05
  • I did edit my code,now there is my makerequest function.i think now its easy to your references. – TDM Aug 19 '16 at 02:54
  • @BenjaminDrolet async/await is same as Task.Run... Just two different patterns to accomplish exactly same thing. – matt-dot-net Aug 19 '16 at 20:43
  • @matt-dot-net Can you cite your sources on this? I don't believe that is true. From my understanding on this, await async will free up a thread. While Task.Run Creates a new one. https://msdn.microsoft.com/en-us/library/mt674882.aspx – Benjamin Drolet Aug 19 '16 at 20:49
  • https://msdn.microsoft.com/en-us/library/ee728598(v=vs.100).aspx#Anchor_4 – matt-dot-net Aug 20 '16 at 02:34
  • @matt-dot-net The article you posted makes no mention of Task.Run. It essentially talks about how to make use of Async methods that already exist. I have updated my answer. I explain why Task.Run is a bad idea and cite my source. I also provide an excerpt from an msdn article that says the same. – Benjamin Drolet Aug 20 '16 at 10:25
  • @BenjaminDrolet i did try you way but i got error from follwing part --- public static async Task RootObjectRS MakeRequestAsync(string requestUrl, SeneruUBT.Models.TokenModels token, string triptype, string from, string to, string flyin, string flyout, string flyclass, string passengers, DateTime starting, int reqstid) {} – TDM Aug 20 '16 at 15:46
  • @TDM what was the error? Make sure to mark any method that calls await is marked with a async. – Benjamin Drolet Aug 20 '16 at 20:24
  • yes i did the same way you did.but i removed some of async calls inside make request method.but my make request is async request.but it gives error.it says ; expected with MakeRequestAsync ... public static async Task RootObjectRS MakeRequestAsync(string requestUrl, SeneruUBT.Models.TokenModels token, string triptype, string from, string to, string flyin, string flyout, string flyclass, string passengers, DateTime starting, int reqstid) – TDM Aug 21 '16 at 13:50
  • @BenjaminDrolet is there something do i need to setup before create async functions with async wait? – TDM Aug 21 '16 at 16:46
  • @TDM It looks like you're missing a ";" somewhere. – Benjamin Drolet Aug 22 '16 at 18:16
  • @BenjaminDrolet Actually it comes after add this "async Task" part.without this part no error.but after i added this part then there is ; missing error. – TDM Aug 23 '16 at 02:56
  • @TDM I found the error. The method signature was public static async Task RootObjectRS MakeRequestAsync, which has two return types. You'll want to return a Task of a type. So, public static async Task MakeRequestAsync should work. I've also updated the code in my answer to reflect these changes. – Benjamin Drolet Aug 23 '16 at 10:55
  • Thanks a lot @BenjaminDrolet.it works fine i did some small modifications. still i'm developing this part.but this works fine. – TDM Aug 28 '16 at 08:41
-1
    var tasks = new Task[] {
        Task.Run(() => MakeRequest()),
        Task.Run(() => MakeRequest()),
        Task.Run(() => MakeRequest())
        };

    Task.WaitAll(tasks);

Task.Run might not be the appropriate way to apply the async pattern. Find the right way to do the ansync pattern for your three long-running calls.

matt-dot-net
  • 4,204
  • 21
  • 24
  • Can you please explain this method please? Is this multithreading? – TDM Aug 18 '16 at 15:48
  • It really depends on where the code lives. If this is IIS hosted. It would be bad practice to start a new thread. – Benjamin Drolet Aug 18 '16 at 17:27
  • Don't confuse the use of Task with spawning a thread. Task just represents an asynchronous operation – matt-dot-net Aug 18 '16 at 18:56
  • This is bad practice in an IIS hosted application. See http://stackoverflow.com/questions/33764366/is-task-run-considered-bad-practise-in-an-asp-net-mvc-web-application – Benjamin Drolet Aug 18 '16 at 21:06
  • I disagree that it is bad practice. It is bad practice to spawn threads in ASP.Net context, but that's not what we are doing with Task.Run. Asynchronous pattern can definitely help the performance of our web application. – matt-dot-net Aug 19 '16 at 20:44
  • https://msdn.microsoft.com/en-us/library/ee728598(v=vs.100).aspx#Anchor_4 – matt-dot-net Aug 20 '16 at 02:34