Reputation: 2824
I have a controller action in mvc 4 app:
public ActionResult Index()
{
GetStartedModel gsModel = new GetStartedModel();
return View(gsModel);
}
and ViewModel:
public class GetStartedModel
{
public IEnumerable<SelectListItem> listA { get; set; }
public IEnumerable<SelectListItem> listB { get; set; }
public GetStartedModel()
{
TestDataWebServiceHelper service = new TestDataWebServiceHelper();
this.GetData(service);
}
private async void SetData(TestDataWebServiceHelper service)
{
listA = await this.SetListA(service);
listB = await this.SetListB(service);
}
private async Task<IEnumerable<SelectListItem>> SetListA(TestDataWebServiceHelper service)
{
List<String> rawList = new List<String>();
rawList = await service.GetValuesAsync("json");
return rawList.Select(x => new SelectListItem { Text = x, Value = x });
}
private async Task<IEnumerable<SelectListItem>> SetListB(TestDataWebServiceHelper service)
{
List<String> rawList = new List<String>();
rawList = await service.GetValuesAsync("json");
return rawList.Select(x => new SelectListItem { Text = x, Value = x });
}
}
When I call this controller action I receive following error:
An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>.
So, questions:
Upvotes: 1
Views: 4470
Reputation: 1892
There a few things to take care about "async" are as follows :
Task
or Task< return-type >
.Now coming to your questions,
You should put your this code in a ViewModel:
private async void SetData(TestDataWebServiceHelper service)
{
listA = await this.SetListA(service);
listB = await this.SetListB(service);
}
private async Task<IEnumerable<SelectListItem>> SetListA(TestDataWebServiceHelper service)
{
List<String> rawList = new List<String>();
rawList = await service.GetValuesAsync("json");
return rawList.Select(x => new SelectListItem { Text = x, Value = x });
}
private async Task<IEnumerable<SelectListItem>> SetListB(TestDataWebServiceHelper service)
{
List<String> rawList = new List<String>();
rawList = await service.GetValuesAsync("json");
return rawList.Select(x => new SelectListItem { Text = x, Value = x });
}
and then you should call it whenever needed.
(Hope this helps...)
Upvotes: 0
Reputation: 244777
There are two problems in your code:
You shouldn't start async void
operations from constructor like this. In fact, you usually shouldn't start any async
operations from constructor and you also shouldn't use async void
methods at all (except for event handlers).
I think that in your case, async
factory method instead of an constructor makes the most sense:
private GetStartedModel()
{}
public static async Task<GetStartedModel> Create()
{
var service = new TestDataWebServiceHelper();
var result = new GetStartedModel();
listA = await result.SetListA(service);
listB = await result.SetListB(service);
return result;
}
For more details, see Stephen Cleary's post on async
constructors.
You need to make your controller action async
too:
public async Task<ActionResult> Index()
{
var gsModel = await GetStartedModel.Create()
return View(gsModel);
}
Upvotes: 5