以下代码有效
[Route("case-studies/{slug}")]
public async Task<ActionResult> Details(string slug)
{
var item = await Db.Pages.OfType<CaseStudy>()
.WithSlug(slug)
.FirstOrDefaultAsync();
if (item == null)
{
return HttpNotFound();
}
var related = await Db.Pages.OfType<CaseStudy>()
.Where(r => r.Client == item.Client && r.Id != item.Id)
.Where(r => !r.IsArchived)
.Include(r => r.Media)
.Take(3)
.Project()
.To<RelatedPageModel>()
.ToListAsync();
var archived = await Db.Pages.OfType<CaseStudy>()
.Where(r => r.Client == item.Client && r.Id != item.Id)
.Where(r => r.IsArchived)
.Take(3)
.Project()
.To<RelatedPageModel>()
.ToListAsync();
ViewData.Model = new DetailPageModel<CaseStudy>()
{
Item = item,
RelatedItems = related,
ArchivedItems = archived
};
return View();
}
然而,当我尝试重构异步方法调用时,如下所示
[Route("case-studies/{slug}")]
public async Task<ActionResult> Details(string slug)
{
var item = await Db.Pages.OfType<CaseStudy>()
.WithSlug(slug)
.FirstOrDefaultAsync();
if (item == null)
{
return HttpNotFound();
}
var related = await GetRelatedCaseStudies(item, false);
var archived = await GetRelatedCaseStudies(item, true);
ViewData.Model = new DetailPageModel<CaseStudy>()
{
Item = item,
RelatedItems = related,
ArchivedItems = archived
};
return View();
}
private Task<List<RelatedPageModel>> GetRelatedCaseStudies(CaseStudy casestudy, bool archived)
{
return Db.Pages.OfType<CaseStudy>()
.Where(r => r.Client == casestudy.Client && r.Id != casestudy.Id)
.Where(x => x.IsArchived == archived)
.Include(r => r.Media)
.Take(3)
.Project().To<RelatedPageModel>()
.ToListAsync();
}
它没有给我以下错误
在上一个异步操作完成之前,在此上下文上启动了第二个操作。使用“await”确保在该上下文上调用另一个方法之前已完成任何异步操作。任何实例成员都不能保证线程安全。
这是为什么?我怎么才能做到这一点?
更新:
Db在基本控制器中声明如下
private WebSiteDb db;
protected WebSiteDb Db
{
get
{
LazyInitializer.EnsureInitialized(ref db, () => new WebSiteDb());
return db;
}
}
WebSiteDb扩展DbContext如下
[DbConfigurationType(typeof(DbConfig))]
public class WebSiteDb : DbContext
{
static WebSiteDb() {
Database.SetInitializer<WebSiteDb>(new WebSiteDbInitializer());
}
public IDbSet<Page> Pages { get; set; }
public IDbSet<Media> Media { get; set; }
...some missing sets
public WebSiteDb() : base("MyDatabaseName") { }
}
如果我在方法内部等待,则会从方法内部抛出错误
WithSlug()如下所示
public static IQueryable<T> WithSlug<T>(this IQueryable<T> pages, string slug) where T : Page
{
return pages.Where(p => p.Slug == slug);
}
如果函数中缺少async Wait,则应为:
private async Task<List<RelatedPageModel>> GetRelatedCaseStudies(CaseStudy casestudy, bool archived)
{
return await Db.Pages.OfType<CaseStudy>()
.Where(r => r.Client == casestudy.Client && r.Id != casestudy.Id)
.Where(x => x.IsArchived == archived)
.Include(r => r.Media)
.Take(3)
.Project().To<RelatedPageModel>()
.ToListAsync();
}
如果没有这些,它将在不同的线程中同时运行两个调用,导致同时对上下文进行两次点击。
下面的测试代码运行良好。显示的实现。用弹头(弹头)
class Program
{
static void Main( string[] args )
{
using( var db = new TestEntities() )
{
db.EntityBs.Add( new EntityB()
{
EntityBId = 78
} );
db.SaveChanges();
Task.WaitAll( Test( db ) );
}
var input = Console.ReadLine();
}
static Task<List<EntityB>> GetEntityBsAsync( TestEntities db )
{
return db.EntityBs.ToListAsync();
}
static async Task Test( TestEntities db )
{
var a0 = await GetEntityBsAsync( db );
var a1 = await GetEntityBsAsync( db );
}
}
用最新的EF 6.1.0测试版试试你的代码。当前EF6对线程安全的定义有点模糊:
线程安全性
虽然线程安全会使异步更有用,但它是一种正交特性。考虑到EF与由用户代码组成的图进行交互以维护状态,并且没有简单的方法来确保该代码也是线程安全的,因此在最常见的情况下,我们是否能够实现对它的支持尚不清楚。
目前,EF将检测开发人员是否一次尝试执行两个异步操作并抛出。
看起来您的代码不会同时执行两个以上的异步操作,但是在ASP. NET中,线程切换可能并且确实发生在wait
延续之间。理论上,EF6仍然应该支持这种情况。但是,要消除由于ASP. NET中缺乏线程亲和力而导致的EF6错误的可能性,您可以从相关问题中尝试我的ThreadWitAffinityContext
,如下所示:
public async Task<ActionResult> Details(string slug)
{
Func<Task<ActionResult>> doAsync = async () =>
{
var item = await Db.Pages.OfType<CaseStudy>()
.WithSlug(slug)
.FirstOrDefaultAsync();
if (item == null)
{
return HttpNotFound();
}
var related = await Db.Pages.OfType<CaseStudy>()
.Where(r => r.Client == item.Client && r.Id != item.Id)
.Where(r => !r.IsArchived)
.Include(r => r.Media)
.Take(3)
.Project()
.To<RelatedPageModel>()
.ToListAsync();
var archived = await Db.Pages.OfType<CaseStudy>()
.Where(r => r.Client == item.Client && r.Id != item.Id)
.Where(r => r.IsArchived)
.Take(3)
.Project()
.To<RelatedPageModel>()
.ToListAsync();
ViewData.Model = new DetailPageModel<CaseStudy>()
{
Item = item,
RelatedItems = related,
ArchivedItems = archived
};
return View();
};
using (var staThread = new Noseratio.ThreadAffinity.ThreadWithAffinityContext(
staThread: false, pumpMessages: false))
{
return await staThread.Run(() => doAsync(), CancellationToken.None);
}
}
注意,这不是一个生产解决方案,但它可能有助于发现EF6中的错误。如果有bug,您可以考虑使用另一个助手类ThreadAffinityTaskScheduler,直到该bug在未来的EF版本中修复为止ThreadAffinityTaskScheduler运行一个由ThreadWithAffinityContext
线程组成的池,因此应比上述代码具有更好的扩展性。链接的问题包含一个使用示例。
问题内容: 经过一整天的研究和尝试,我终于放弃了 纯AJAX的 上传文件(ps:本文如何与JQuery异步上传文件?埋了我的最后希望) 我的问题可能没什么意义,但是我仍然想知道为什么ajax(或XMLHttpRequest)不能处理这个问题?为什么文件不能像真正的httprequest那样传输? 问题答案: 出于安全原因,JavaScript无法读取本地文件,因此我们无法使用AJAX发送数据。 但
我正在运行这样一个简单的SQL连接和select,但在运行查询时,我遇到了非常奇怪的错误。 警告:mysqli_fetch_array()希望参数1是mysqli_结果,布尔值在第23行的C:\xampp\htdocs\Webmaster\run\forum_mc.php中给出 警告:mysqli_query():第24行()上C:\xampp\htdocs\Webmaster\run\forum
问题内容: 为什么将AJAX称为异步?它如何完成与服务器的异步通信? 问题答案: 它是异步的,因为它不会锁定浏览器。如果您触发Ajax请求,则用户在等待响应时仍可以工作。当服务器返回响应时,将运行一个回调来处理它。 您可以根据需要进行同步,如果需要,可以在请求未完成时将浏览器锁定(因此,大多数情况下这是不合适的)
所以我理解为什么从异步返回空洞通常没有意义,但我遇到了一种我认为完全有效的情况。请考虑以下人为的示例: 我意识到这是一个不寻常的例子,但我试图使其简单化和更普遍化。有人能向我解释为什么这是可怕的代码,以及我如何修改它以正确遵循约定吗? 谢谢你的任何帮助。
问题内容: 我对git和詹金斯都很陌生。 我将密钥添加到bitbucket和本地计算机中时: 我可以克隆。 但是,当我将相同的url()添加到Jenkins存储库url时,出现以下错误: 问题答案: 您还需要为Jenkins用户设置ssh密钥。 通常的想法是,您登录到Jenkins框,并成为“ jenkins”用户。您可以为您的Jenkins用户打电话,所以请确保使用正确的名称。一旦成为Jenki
问题内容: 以下语句: 因错误而失败: 为什么在这里需要演员表? 我发现了几篇文章,解释了为什么您不能进行反向操作(将T分配给a),但这是显而易见的(可以理解)。 注意:我在Eclipse Luna下对此进行编码,所以我不知道这是Luna Quirk还是泛型中确实不了解的东西。 问题答案: 协方差vs协方差vs不变性 是 不变的 。 结果是, 是 不是一个亚型 的 在Java中,变量可以保存 相同