I am using MVC 5 on .Net and I have a user flow that looks like this:
- User enters address into an form.
- Form gets posted to controller using AJAX.
- Controller records address into the database.
- Controller makes a WebClient request to Bing Maps to geocode the address into latitude and longitude.
- Controller records latitude and longitude to the database.
- Controller returns an AJAX result that is rendered client-side into the updated view with the address and the latitude/longitude.
I know that the call to Bing Maps should happen in an async context so that my site's speed is uncoupled from that of Bing Maps.
Instead I think my flow should work like this:
- User enters address into an form.
- Form gets posted to controller using AJAX.
- Controller records address into the database.
- Controller launches an async task to do the geocoding and update the database
- Controller returns an AJAX result to the client that shows the updated address and tells it to poll client-side for the completion of the geocode result.
I am stuck on step #4. Here is what I have:
public ActionResult GetLocation(int id)
{
Listing li = db.Listings.Find(id);
Task.Run(() => {
// update geocode if necessary
if (li.BizAddress.GeoStatus != BusinessAddress.GeocodeStatus.UpToDate &&
DateTime.Now - li.BizAddress.LastGeoAttempt > TimeSpan.FromHours(1))
{
Geocoder geo = new Geocoder();
GeocodeResult gr = geo.Geocode(li.BizAddress).Result;
if (gr.BadResult != true)
{
li.BizAddress.Latitude = gr.Location.Latitude;
li.BizAddress.Longitude = gr.Location.Longitude;
li.BizAddress.GeoStatus = BusinessAddress.GeocodeStatus.UpToDate;
}
else
{
// failed
li.BizAddress.Latitude = 0;
li.BizAddress.Longitude = 0;
li.BizAddress.GeoStatus = BusinessAddress.GeocodeStatus.BadResult;
}
li.BizAddress.LastGeoAttempt = DateTime.Now;
db.SaveChanges();
}
});
return PartialView("~/Views/Listing/ListingPartials/_Location.cshtml", li);
}
However I get an exception that the db context has been disposed of when I get to db.SaveChanges().
I want my Task to run async inside of a closure so that db is still a valid undisposed variable.
Is this possible? I'm new to async programming and I don't know all of the idioms yet.
Additional info: I am rendering my panel in my View like this:
@{Html.Action("GetLocation", new { id = Model.ID });}
I want to keep this behavior since loading it with AJAX may hurt SEO.