1

My situation is that I creating objects as well as saving and updating these objects in my database. I have an object Slot Plan which, by default, has around 123 slot objects and I have to write these into the database.

Depending on the case scenarios, i'd have to create many slot plans, so create and update could happen hundreds or thousands of times, which is time consuming. (creating 10 slot plans lasted around 3 minutes for me)

I understand that it really will take time, but how can I have the create and update run in the background and allow the user to continue navigate through the program to parts independent from the slots and slot plan?

Here's a snippet of my current code:

    [HttpPost]
    public ActionResult BookingRequestDetails(BookingRequestDetails model)
    {
        //Omitted code
        if(shipmentinfo.ShipmentType.Equals("Export"))
            CreateSlotPlan((DateTime)shipmentinfo.PickupDate, (DateTime shipmentinfo.PickupDateLast);

        return RedirectToAction("Home");
    }

public void CreateSlotPlan(DateTime firstdate, DateTime lastdate)
    {
        for (DateTime i = firstdate; i <= lastdate; i = i.AddDays(1))
        {
            SlotPlan slotplan = slotplanmanager.FindByDate(i);
            if (slotplan == null)
            {
                slotplan = new SlotPlan { Date = i };
                slotplanmanager.CreateSlotPlan(slotplan);

                for (int j = 1; j <= 9; j++)
                {
                    Slot slot = new Slot
                    {
                        Location = "A" + j
                    };

                    slotmanager.CreateSlot(slot);
                    slotplan.Slots.Add(slot);
                    slotplanmanager.UpdateSlotPlan(slotplan);
                    slotmanager.UpdateSlot(slot);
                }

                for (int j = 1; j <= 36; j++)
                {
                    Slot slot = new Slot
                    {
                        Location = "B" + j
                    };

                    slotmanager.CreateSlot(slot);
                    slotplan.Slots.Add(slot);
                    slotplanmanager.UpdateSlotPlan(slotplan);
                    slotmanager.UpdateSlot(slot);
                }

                for (int j = 1; j <= 12; j++)
                {
                    Slot slot = new Slot
                    {
                        Location = "C" + j
                    };

                    slotmanager.CreateSlot(slot);
                    slotplan.Slots.Add(slot);
                    slotplanmanager.UpdateSlotPlan(slotplan);
                    slotmanager.UpdateSlot(slot);
                }

                for (int j = 1; j <= 6; j++)
                {
                    Slot slot = new Slot
                    {
                        Location = "D" + j
                    };

                    slotmanager.CreateSlot(slot);
                    slotplan.Slots.Add(slot);
                    slotplanmanager.UpdateSlotPlan(slotplan);
                    slotmanager.UpdateSlot(slot);
                }

                for (int j = 1; j <= 60; j++)
                {
                    Slot slot = new Slot
                    {
                        Location = "E" + j
                    };

                    slotmanager.CreateSlot(slot);
                    slotplan.Slots.Add(slot);
                    slotplanmanager.UpdateSlotPlan(slotplan);
                    slotmanager.UpdateSlot(slot);
                }
            }
        }
    }

The code "return RedirectToAction("Home");" wouldn't execute unless "CreateSlotPlan(DateTime firstdate, DateTime lastdate)" is finished. I read that using async-await could solve my problem. But I don't know how to go about with asynchronous programming in my current code. Any help is appreciated.

JeanDeus
  • 85
  • 1
  • 7
  • 1
    Unfortunately this isn't a C# question. This is a javascript problem. You need to learn about a technique in HTML5/JS called AJAX. The `async` `await` does not affect the client in any way or form. – Aron May 17 '16 at 10:03
  • thanki you @Aron. When I click the submit on client side, the page would just load until all the database stuff is finish and then redirect kicks in. I'm trying to achieve that RedirectToAction executes while the database is finishing up on creating and updating. I am familiar with AJAX and I'll try it out. – JeanDeus May 17 '16 at 10:12
  • Call my old-fashioned, but if you have tasks that take minutes, why don't you use a System.ComponentModel.BackgroundWorker? Surely the extra time needed to create a full thread is nothing compared to the time it takes to create your slots? – Harald Coppoolse May 17 '16 at 11:33
  • @HaraldDutch because BackgroundWorker won't keep the AppDomain alive and it may get shut down before your work completes. Imagine a console program where you use BackgroundWorker but did not put a `Console.ReadLine()` at the end of main and instead just did `static void Main() { StartMyBackgroundWorker(); }`. Would you expect BackgroundWorker to reliably finish your work that takes a few minutes to complete in this program? – Scott Chamberlain May 17 '16 at 14:18

1 Answers1

0

If you really need to redirect immediately and then queue up this work, you can do so by using the HostingEnvironment.QueueBackgroundItem. You might gain some insights from this SO Q & A. You controller entry-point would look something like this:

[HttpPost]
public ActionResult BookingRequestDetails(BookingRequestDetails model)
{
    // Omitted code
    if(shipmentinfo.ShipmentType.Equals("Export"))
    {
        // This will return immediately, but the work will be queued up
        HostingEnvironment.QueueBackgroundItem(() =>
            CreateSlotPlan((DateTime)shipmentinfo.PickupDate, 
                           (DateTime)shipmentinfo.PickupDateLast));
    }

    return RedirectToAction("Home");
}

Schedules a task which can run in the background, independent of any request.

Community
  • 1
  • 1
David Pine
  • 23,787
  • 10
  • 79
  • 107
  • One important note, `QueueBackgroundItem` will only reliably give you a extra 90 seconds for the work to be completed (the length is the minimum value of `HttpRuntimeSection.ShutdownTimeout` and processModel `shutdownTimeLimit` which defaults to 90). For something that takes 3 minutes I would not rely on `QueueBackgroundItem`. – Scott Chamberlain May 17 '16 at 14:22