我使用基于任务的操作生成了代理.
如何使用async/await 正确调用此服务(处理ServiceClient和OperationContext之后)?
我的第一次尝试是:
public async Task<HomeInfo> GetHomeInfoAsync(DateTime timestamp)
{
    using (var helper = new ServiceHelper<ServiceClient, ServiceContract>())
    {
        return await helper.Proxy.GetHomeInfoAsync(timestamp);
    }
}
作为ServiceHelper一个创造ServiceClient和OperationContextScope后来处理它们的类:
try
{
    if (_operationContextScope != null)
    {
        _operationContextScope.Dispose();
    }
    if (_serviceClient != null)
    {
        if (_serviceClient.State != CommunicationState.Faulted)
        {
            _serviceClient.Close();
        }
        else
        {
            _serviceClient.Abort();
        }
    }
}
catch (CommunicationException)
{
    _serviceClient.Abort();
}
catch (TimeoutException)
{
    _serviceClient.Abort();
}
catch (Exception)
{
    _serviceClient.Abort();
    throw;
}
finally …我经常使用async/await来确保ASP.NET MVC Web API线程不被长时间运行的I/O和网络操作阻止,特别是数据库调用.
该System.Data.Entity的命名空间提供各种帮助这里的扩展,如FirstOrDefaultAsync,ContainsAsync,CountAsync等等.
但是,由于数据上下文不是线程安全的,这意味着以下代码存在问题:
var dbContext = new DbContext();
var something = await dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 1);
var morething = await dbContext.someEntities.FirstOrDefaultAsync(e => e.Id == 2);
事实上,我有时会看到例外情况:
System.InvalidOperationException:未关闭连接.连接的当前状态是打开的.
那么正确的模式是否using(new DbContext...)为每个对数据库的异步调用使用单独的块?相反,执行同步可能更有益吗?              
TL; DR:运行任务中的死锁StaTaskScheduler.长版:
我使用的是StaTaskScheduler从ParallelExtensionsExtras中通过平行小组,举办由第三方提供的一些遗留STA COM对象.StaTaskScheduler实现细节的描述如下:
好消息是TPL的实现能够在MTA或STA线程上运行,并考虑到底层API的相关差异,如WaitHandle.WaitAll(当方法提供多个等待句柄时,它只支持MTA线程).
我认为这意味着TPL的阻塞部分将使用等待API来提供消息,例如CoWaitForMultipleHandles,以避免在STA线程上调用时出现死锁情况.
在我的情况下,我相信发生以下情况:进程内STA COM对象A调用进程外对象B,然后期望从B通过回调作为传出调用的一部分.
以简化形式:
var result = await Task.Factory.StartNew(() =>
{
    // in-proc object A
    var a = new A(); 
    // out-of-proc object B
    var b = new B(); 
    // A calls B and B calls back A during the Method call
    return a.Method(b);     
}, CancellationToken.None, TaskCreationOptions.None, staTaskScheduler);
问题是,a.Method(b)永远不会回来.据我所知,这是因为内部阻塞等待BlockingCollection<Task>不会引发消息,因此我对引用语句的假设可能是错误的.
EDITED相同的代码工作测试WinForms应用程序的UI线程上执行时(即,提供TaskScheduler.FromCurrentSynchronizationContext()的,而不是staTaskScheduler到Task.Factory.StartNew).
解决这个问题的正确方法是什么?我应该实现一个自定义同步上下文,它将显式地使用消息CoWaitForMultipleHandles …
我有一个类似的方法:
public async Task SaveItemsAsync(IEnumerable<MyItem> items)
{
    using (var ts = new TransactionScope())
    {
        foreach (var item in items)
        {
            await _repository.SaveItemAsync(item);
        }
        await _repository.DoSomethingElse();
        ts.Complete();
    }
}
这当然有问题,因为TransactionScopeasync/await不能很好用.
它失败并显示InvalidOperationException消息:
"TransactionScope必须放在与它创建的同一个线程上."
我TransactionScopeAsyncFlowOption在这个答案中读到了,这似乎正是我所需要的.
但是,对于这个特定项目,我很难支持.Net 4.0,无法升级到4.5或4.5.1.因此,我的项目中的异步/等待行为由Microsoft.Bcl.Async NuGet包提供.
我似乎无法TransactionScopeAsyncFlowOption在这个或任何其他OOB包中找到.我只是在某个地方错过了吗?
如果没有,是否有其他方法可以达到相同的效果?也就是说 - 我希望事务范围正确完成或回滚,尽管跨越线程有延续.
我DoSomethingElse在上面的示例中添加了说明在事务范围内可能有多个调用,因此在一次调用中简单地将所有项目传递给数据库是不可行的选择.
在它的事项的情况下,库使用直接ADO.Net( ,SqlConnection,SqlCommand等)写入到SQL Server.
UPDATE
我以为我有一个解决方案,涉及从.Net 4.5.1中获取System.Transactions.dll并将其包含在我的项目中.但是,我发现这只适用于我的开发盒,因为它已经安装了4.5.1.部署到仅具有.Net 4.0的计算机时,它不起作用.它只是给了一个MissingMethodException.我正在寻找一种适用于.Net 4.0安装的解决方案.
刚刚开始测试EF6及其异步功能.当我意识到他们不是线程安全时,男孩感到很惊讶.我有点认为那就是重点.
我已经有了Task多年自己的扩展方法,但是我在EF等待的是让它们保持线程安全.
至少我的基于任务的功能被lock编辑为不互相干扰.EF6甚至没有那么远.但主要问题是我的代码与他们的代码共享.即尝试发出异步查询,然后在它完成之前尝试访问导航延迟加载的导航属性(在同一上下文中预先加载的完全独立的实体上).这可以由UI或直接功能之外的其他代码触发,也可以由十几个其他场景触发.
据我所知.dbContext中仅有的两个共享(实体之间)可变资源是连接和更改跟踪(缓存).如果我们可以在功能性上添加锁定,那么我们就会有一个线程安全的上下文.
我们甚至可以分两个阶段完成.如果我们可以实现一个锁定用于查询数据库的集中函数的提供程序.然后任何非跟踪查询 - 通过返回非实体(匿名)对象或通过调用AsNoTracking() - 将是线程安全的,并且即使另一个线程可能要求延迟加载的对象,使用异步函数调用也是安全的.
我们的可扩展性不会更糟,我们现在必须使用每个线程一个上下文,如果你试图跳过一个等待引入一些并行性或者正在工作的事情,甚至Async函数都不在桌面上系统(如wpf)可能会在等待的函数返回任务时触发.
所以我的问题是.有没有人实现这样的提供者.或者有人愿意和我一起工作吗?
multithreading entity-framework task-parallel-library entity-framework-6
下面的代码应该(至少在我看来)创建100 Tasks,它们都在并行等待(这是关于并发的点,右边:D?)并且几乎同时完成.我想,每Task.Delay一个Timer对象在内部创建.
public static async Task MainAsync() {
    var tasks = new List<Task>();
    for (var i = 0; i < 100; i++) {
        Func<Task> func = async () => {
            await Task.Delay(1000);
            Console.WriteLine("Instant");
        };
        tasks.Add(func());
    }
    await Task.WhenAll(tasks);
}
public static void Main(string[] args) {
    MainAsync().Wait();
}
但!当我在Mono上运行时,我会得到非常奇怪的行为:
Tasks不会在同一时间完成,存在着巨大的延迟(大概在500-600ms)加载程序集:/Users/xxxxx/Programming/xxxxx/xxxxxxxxxx/bin/Release/xxxxx.exe
线程开始:#2
线程开始:#3
线程开始:#4
线程开始:#5
线程开始:#6
线程开始:#7
线程完成:#3 < - 显然延迟1000ms完成了?
线程完成:#2 < - 显然延迟1000ms完成了?
线程开始:#8
线程开始:#9
线程开始:#10
线程开始:#11
线程开始:#12
线程开始:#13
... 你懂了. …
我有一个Web API应用程序,其中控制器通过依赖注入(Unity)将服务/存储库等注入其中.让我们假设我IStuffService需要IPrincipal当前请求(或它周围的包装).
Web API的问题似乎是当前Request/User 的唯一可靠来源是Request该实例上的属性ApiController.任何静态的(无论是HttpContext.Current,CallContext.Get/SetData或Thread.Get/SetData)不能保证是相同的线程上,由于网络API的同步性质.
如何可靠地确保特定于请求的上下文通过依赖项传递,更重要的是,操作在整个操作过程中保持正确IPrincipal?
两种选择:
IPrincipal都将它作为方法的参数 - 这是最可靠的方法,但它也要求我在每个方法签名中都有这个东西container.Resolve(opType, new DependencyOverride(typeof(IPrincipal), principal))选项2意味着我的方法签名是干净的,但这也意味着我需要确保所有依赖项都使用TransientLifetimeManager,而不是Singleton甚至是Per-Thread.
有没有比我没有看到更好的解决方案?
以下代码有效
[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 …我的团队正在使用C#5.0中的async/await开发一个多线程应用程序.在实现线程同步的过程中,经过几次迭代,我们想出了一个(可能是新颖的?)新的SynchronizationContext实现,它有一个内部锁:
在所有情况下,在执行委托之前,上下文将自身设置为当前上下文,并在委托返回时恢复原始上下文.
这是一个不寻常的模式,因为我们显然不是第一个写这样的应用程序的人,我想知道:
这是SerializingSynchronizationContext的源代码和GitHub上的一个演示.
以下是它的使用方法:
上下文是可以接受的,因此可以使用以下语句.
await myContext;
这只会导致方法的其余部分在上下文的保护下运行.
我即将开始一个用VBScript编写的遗留系统的迁移项目.它有一个有趣的结构,因为大部分内容是通过将各种组件编写为"WSC"文件来隔离的,这些文件实际上是以类似COM的方式公开VBScript代码的一种方式.从"核心"到这些组件的边界接口是相当紧凑和众所周知的,所以我希望我能够解决编写新核心并重用WSC,推迟他们的重写.
可以通过添加对"Microsoft.VisualBasic"的引用并调用来加载WSC
var component = (dynamic)Microsoft.VisualBasic.Interaction.GetObject("script:" + controlFilename, null);
其中"controlFilename"是完整的文件路径.GetObject返回类型为"System .__ ComObject"的引用,但可以使用.net的"动态"类型访问属性和方法.
这似乎最初工作正常,但我遇到了很多特定情况的问题 - 我担心这可能发生在其他情况下,或者更糟糕的是,坏事情在很多时候都会发生并被掩盖,等到我最不期望的时候爆炸.
引发的异常是"System.ExecutionEngineException"类型,这听起来特别可怕(和模糊)!
我拼凑了我认为最小的重现案例,并希望有人可以对这个问题提出一些看法.我还发现了一些似乎可以阻止它的调整,但我无法解释原因.
创建一个名为"WSCErrorExample"的新的空"ASP.NET Web应用程序"(我在VS 2013/.net 4.5和VS 2010/.net 4.0中完成了这个,它没有区别)
在项目中添加对"Microsoft.VisualBasic"的引用
添加一个名为"Default.aspx"的新"Web窗体",并将以下内容粘贴到"Default.aspx.cs"的顶部
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.VisualBasic;
namespace WSCErrorExample
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            var currentFolder = GetCurrentDirectory();
            var logFile = new FileInfo(Path.Combine(currentFolder, "Log.txt"));
            Action<string> logger = message =>
            {
                // The try..catch is to avoid IO exceptions when reproducing by requesting …我想知道这个场景是否是线程安全的,是否存在我目前没有看到的问题:
从ASP.net控制器我从非静态类调用非静态方法(此类在另一个项目中,类被注入到控制器中).
这个方法(非静态的)做了一些工作,并调用一些其他静态方法传递userId
最后,静态方法做了一些工作(需要userId)
我相信这种方法是线程安全的,并且如果两个用户同时调用此方法,那么一切都将正确完成(让我们说同样的纳秒).我是正确还是完全错误?如果我错了,在ASP.net项目中使用静态方法的正确方法是什么?
编辑
这是代码:)
这是来自控制器的调用:
await _workoutService.DeleteWorkoutByIdAsync(AzureRedisFeedsConnectionMultiplexer.GetRedisDatabase(),AzureRedisLeaderBoardConnectionMultiplexer.GetRedisDatabase(), workout.Id, userId);
这里DeleteWorkoutByIdAsync的样子如下:
public async Task<bool> DeleteWorkoutByIdAsync(IDatabase redisDb,IDatabase redisLeaderBoardDb, Guid id, string userId)
    {
        using (var databaseContext = new DatabaseContext())
        {
            var workout = await databaseContext.Trenings.FindAsync(id);
            if (workout == null)
            {
                return false;
            }
            databaseContext.Trenings.Remove(workout);
            await databaseContext.SaveChangesAsync();
            await RedisFeedService.StaticDeleteFeedItemFromFeedsAsync(redisDb,redisLeaderBoardDb, userId, workout.TreningId.ToString());
        }
        return true;
    }
您可以注意到DeleteWorkoutByIdAsync调用静态方法StaticDeleteFeedItemFromFeedsAsync,如下所示:
public static async Task StaticDeleteFeedItemFromFeedsAsync(IDatabase redisDb,IDatabase redisLeaderBoardDd, string userId, string workoutId)
 {
        var deleteTasks = new List<Task>();
        var feedAllRedisVals = await redisDb.ListRangeAsync("FeedAllWorkouts:" + userId); …With C#5 Async-Await in WCF, after an await if rest of the code continues on a different thread, we loose the Current Operation Context. (OperationContext.Current is null).
I am working on a WCF Service which calls another external service. And there are a few Custom Binding Extensions used in the external service call which access the Operation Context. So I need the Context to be propagated during this call and it cant just work with copying the operation context into …