Ric*_*lva 0 c# async-await asp.net-web-api asp.net-mvc-5
我们正在从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;
}
}
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,控制台应用程序和MVC应用程序中的AddUserAsync方法都被完全相同,并且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);
}
Run Code Online (Sandbox Code Playgroud)
需要做什么才能继续执行.
我们还尝试使用ContinueWith()并运行,但是不执行异步方法,并且数据库中没有记录任何内容.更具体地说,该方法被调用,但它似乎已经过去并且没有任何重新调整.:(
这几乎是我们需要证明的.从同步方法我们可以调用异步方法.
这是错误的教训.控制台应用程序使用与ASP.NET不同的线程框架,这就是让您失望的原因.
我在博客上完整地解释了它; 它的要点是await捕获"上下文"并使用它来恢复该async方法.在Console应用程序中,此"上下文"是线程池上下文,因此该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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1028 次 |
| 最近记录: |