我们正在从MVC网站上使用WebAPI。我们从这样的控制台应用程序中做了一个概念验证,使用了AddUser Method,它在我们的数据库中调节了一个新用户。
static void Main()
{
M_Users user = new M_Users();
var newUser = new M_Users()
{
Password = "123",
FirstName = "Andrew",
Email = "someAndrew@someplace.com",
AdminCode = 1,
IsDisabled = false,
CountryId = 48,
CityId = 149,
DepartmentId = 3,
CreationDate = DateTime.Now,
CreatorUserId = 1
};
var star = RunAsync(newUser);
star.Wait();
//THIS LINE IS REACHED ALWAYS
Console.WriteLine(star.Result.UserID);
Console.ReadLine();
}
static async Task<M_Users> AddUserAsync(M_Users newUser)
{
M_Users user = new M_Users();
string requestUri = "api/User/AddUser";
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:44873/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP POST
HttpResponseMessage response = await client.PostAsJsonAsync<M_Users>(requestUri, newUser);
if (response.IsSuccessStatusCode)
{
Uri newUserUrl = response.Headers.Location;
user = await response.Content.ReadAsAsync<M_Users>();
}
return user;
}
}
这两个AddUserAsync方法在两种情况下都被称为控制台应用程序和MVC应用程序完全相同,而biz层中的方法也是相同的,这里没有描述似乎不相关。
在控制台中它只是起作用。用户注册并控制打印用户在BD中保存的id。这几乎是我们需要证明的。从同步方法我们可以调用异步方法。现在我们从我们网站的控制器中尝试相同的操作,就像这样。
public ActionResult Index()
{
User spUser = null;
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
var model = new LoginViewModel();
// here we invoke sharepoint context for getting user info to bild the object
M_Users new_user = new M_Users()
{
Password = "123",
FirstName = spUser.Title,
Email = spUser.LoginName.Split('|')[2].ToString(),
AdminCode = 1,
IsDisabled = false,
CountryId = 48,
CityId = 149,
DepartmentId = 3,
CreationDate = DateTime.Now,
CreatorUserId = 1
};
var returnedUser = AddUserAsync(new_user);
returnedUser.Wait(); //HERE IT STOPS RUNNING
//THIS LINE IS NEVER REACHED
ViewBag.UserId = returnedUser.Result.UserID;
return View(model);
}
要继续执行需要做些什么。
我们还尝试了ContinueWith()并运行,但是不执行异步方法,并且数据库中没有记录任何内容。更具体地说,该方法被调用,但它似乎已经过去并且没有任何重新调整。 :(
答案 0 :(得分:6)
这几乎是我们需要证明的。从同步方法我们可以调用异步方法。
这是错误的教训。控制台应用程序使用与ASP.NET不同的线程框架,这就是绊倒你的原因。
我全面解释on my blog;它的要点是await
捕获了一个&#34; context&#34;并使用它来恢复async
方法。在控制台应用中,这个&#34;上下文&#34;是线程池上下文,因此async
方法继续在某个任意线程池线程上运行,并且不关心您是否阻止了调用Wait
的线程。但是,ASP.NET有一个请求上下文,一次只允许在一个线程中,因此async
方法试图在该请求上下文中恢复,但它不能,因为它已经是线程在该上下文中被阻止。
最佳解决方案是允许async
在代码库中增长:
public Task<ActionResult> Index()
{
User spUser = null;
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
var model = new LoginViewModel();
M_Users new_user = new M_Users()
{
Password = "123",
FirstName = spUser.Title,
Email = spUser.LoginName.Split('|')[2].ToString(),
AdminCode = 1,
IsDisabled = false,
CountryId = 48,
CityId = 149,
DepartmentId = 3,
CreationDate = DateTime.Now,
CreatorUserId = 1
};
var returnedUser = await AddUserAsync(new_user);
ViewBag.UserId = returnedUser.UserID;
return View(model);
}