相关疑难解决方法(0)

使用async/await调用WCF服务的模式

我使用基于任务的操作生成了代理.

如何使用async/await 正确调用此服务(处理ServiceClientOperationContext之后)?

我的第一次尝试是:

public async Task<HomeInfo> GetHomeInfoAsync(DateTime timestamp)
{
    using (var helper = new ServiceHelper<ServiceClient, ServiceContract>())
    {
        return await helper.Proxy.GetHomeInfoAsync(timestamp);
    }
}
Run Code Online (Sandbox Code Playgroud)

作为ServiceHelper一个创造ServiceClientOperationContextScope后来处理它们的类:

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 …
Run Code Online (Sandbox Code Playgroud)

.net c# asp.net wcf async-await

59
推荐指数
2
解决办法
5万
查看次数

EF数据上下文 - 异步/等待和多线程

我经常使用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);
Run Code Online (Sandbox Code Playgroud)

事实上,我有时会看到例外情况:

System.InvalidOperationException:未关闭连接.连接的当前状态是打开的.

那么正确的模式是否using(new DbContext...)每个对数据库的异步调用使用单独的块?相反,执行同步可能更有益吗?

.net c# multithreading entity-framework async-await

47
推荐指数
2
解决办法
4万
查看次数

StaTaskScheduler和STA线程消息泵送

TL; DR:运行任务中的死锁StaTaskScheduler.长版:

我使用的是StaTaskSchedulerParallelExtensionsExtras中通过平行小组,举办由第三方提供的一些遗留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);
Run Code Online (Sandbox Code Playgroud)

问题是,a.Method(b)永远不会回来.据我所知,这是因为内部阻塞等待BlockingCollection<Task>不会引发消息,因此我对引用语句的假设可能是错误的.

EDITED相同的代码工作测试WinForms应用程序的UI线程上执行时(即,提供TaskScheduler.FromCurrentSynchronizationContext()的,而不是staTaskSchedulerTask.Factory.StartNew).

解决这个问题的正确方法是什么?我应该实现一个自定义同步上下文,它将显式地使用消息CoWaitForMultipleHandles …

.net c# com task-parallel-library async-await

27
推荐指数
2
解决办法
9314
查看次数

如何在.NET 4.0中使用Microsoft.Bcl.Async支持TransactionScope中的异步方法?

我有一个类似的方法:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这当然有问题,因为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安装的解决方案.

.net c# .net-4.0 transactionscope async-await

22
推荐指数
1
解决办法
7983
查看次数

线程安全的实体框架6

刚刚开始测试EF6及其异步功能.当我意识到他们不是线程安全时,男孩感到很惊讶.我有点认为那就是重点.

我已经有了Task多年自己的扩展方法,但是我在EF等待的是让它们保持线程安全.

至少我的基于任务的功能被lock编辑为不互相干扰.EF6甚至没有那么远.但主要问题是我的代码与他们的代码共享.即尝试发出异步查询,然后在它完成之前尝试访问导航延迟加载的导航属性(在同一上下文中预先加载的完全独立的实体上).这可以由UI或直接功能之外的其他代码触发,也可以由十几个其他场景触发.

据我所知.dbContext中仅有的两个共享(实体之间)可变资源是连接和更改跟踪(缓存).如果我们可以在功能性上添加锁定,那么我们就会有一个线程安全的上下文.

我们甚至可以分两个阶段完成.如果我们可以实现一个锁定用于查询数据库的集中函数的提供程序.然后任何非跟踪查询 - 通过返回非实体(匿名)对象或通过调用AsNoTracking() - 将是线程安全的,并且即使另一个线程可能要求延迟加载的对象,使用异步函数调用也是安全的.

我们的可扩展性不会更糟,我们现在必须使用每个线程一个上下文,如果你试图跳过一个等待引入一些并行性或者正在工作的事情,甚至Async函数都不在桌面上系统(如wpf)可能会在等待的函数返回任务时触发.

所以我的问题是.有没有人实现这样的提供者.或者有人愿意和我一起工作吗?

multithreading entity-framework task-parallel-library entity-framework-6

18
推荐指数
1
解决办法
9496
查看次数

Task.Delay是否开始一个新线程?

下面的代码应该(至少在我看来)创建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();
}
Run Code Online (Sandbox Code Playgroud)

但!当我在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

... 你懂了. …

c# mono multithreading async-await .net-4.5

10
推荐指数
2
解决办法
4429
查看次数

如何通过依赖注入传递Web API请求?

我有一个Web API应用程序,其中控制器通过依赖注入(Unity)将服务/存储库等注入其中.让我们假设我IStuffService需要IPrincipal当前请求(或它周围的包装).

Web API的问题似乎是当前Request/User 的唯一可靠来源是Request实例上的属性ApiController.任何静态的(无论是HttpContext.Current,CallContext.Get/SetDataThread.Get/SetData)不能保证是相同的线程上,由于网络API的同步性质.

如何可靠地确保特定于请求的上下文通过依赖项传递,更重要的是,操作在整个操作过程中保持正确IPrincipal

两种选择:

  1. 每个需要的方法IPrincipal都将它作为方法的参数 - 这是最可靠的方法,但它也要求我在每个方法签名中都有这个东西
  2. 将IPrincipal注入服务的ctor,使用Unity中的DependencyOverride在每个请求上激活对象图的新内容: container.Resolve(opType, new DependencyOverride(typeof(IPrincipal), principal))

选项2意味着我的方法签名是干净的,但这也意味着我需要确保所有依赖项都使用TransientLifetimeManager,而不是Singleton甚至是Per-Thread.

有没有比我没有看到更好的解决方案?

.net c# asp.net async-await asp.net-web-api

10
推荐指数
1
解决办法
2218
查看次数

为什么我不能将异步查询移动到方法中?

以下代码有效

[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 …
Run Code Online (Sandbox Code Playgroud)

c# asynchronous async-await c#-5.0

8
推荐指数
1
解决办法
3407
查看次数

使用async/await时,使用自定义SynchronizationContext序列化执行

我的团队正在使用C#5.0中的async/await开发一个多线程应用程序.在实现线程同步的过程中,经过几次迭代,我们想出了一个(可能是新颖的?)新的SynchronizationContext实现,它有一个内部锁:

  1. 在致电Post时:
    • 如果可以进行锁定,则立即执行委托
    • 如果无法获取锁定,则委托将排队
  2. 致电发送时:
    • 如果可以执行锁定,则执行委托
    • 如果无法进行锁定,则线程被阻止

在所有情况下,在执行委托之前,上下文将自身设置为当前上下文,并在委托返回时恢复原始上下文.

这是一个不寻常的模式,因为我们显然不是第一个写这样的应用程序的人,我想知道:

  1. 这种模式真的很安全吗?
  2. 有没有更好的方法来实现线程同步?

这是SerializingSynchronizationContext的源代码和GitHub上的一个演示.

以下是它的使用方法:

  • 每个需要保护的类都会像互斥锁一样创建自己的上下文实例.
  • 上下文是可以接受的,因此可以使用以下语句.

    await myContext;

    这只会导致方法的其余部分在上下文的保护下运行.

  • 该类的所有方法和属性都使用此模式来保护数据.在等待之间,一次只能有一个线程在上下文中运行,因此状态将保持一致.当达到await时,允许下一个计划的线程在上下文中运行.
  • 如果需要,自定义SynchronizationContext可以与AsyncLock结合使用,即使在等待表达式的情况下也能保持原子性.
  • 类的同步方法也可以使用自定义上下文进行保护.

.net c# synchronizationcontext async-await

7
推荐指数
1
解决办法
2496
查看次数

C#/ WSC(COM)互操作中的FatalExecutionEngineError

我即将开始一个用VBScript编写的遗留系统的迁移项目.它有一个有趣的结构,因为大部分内容是通过将各种组件编写为"WSC"文件来隔离的,这些文件实际上是以类似COM的方式公开VBScript代码的一种方式.从"核心"到这些组件的边界接口是相当紧凑和众所周知的,所以我希望我能够解决编写新核心并重用WSC,推迟他们的重写.

可以通过添加对"Microsoft.VisualBasic"的引用并调用来加载WSC

var component = (dynamic)Microsoft.VisualBasic.Interaction.GetObject("script:" + controlFilename, null);
Run Code Online (Sandbox Code Playgroud)

其中"controlFilename"是完整的文件路径.GetObject返回类型为"System .__ ComObject"的引用,但可以使用.net的"动态"类型访问属性和方法.

这似乎最初工作正常,但我遇到了很多特定情况的问题 - 我担心这可能发生在其他情况下,或者更糟糕的是,坏事情在很多时候都会发生并被掩盖,等到我最不期望的时候爆炸.

引发的异常是"System.ExecutionEngineException"类型,这听起来特别可怕(和模糊)!

我拼凑了我认为最小的重现案例,并希望有人可以对这个问题提出一些看法.我还发现了一些似乎可以阻止它的调整,但我无法解释原因.

  1. 创建一个名为"WSCErrorExample"的新的空"ASP.NET Web应用程序"(我在VS 2013/.net 4.5和VS 2010/.net 4.0中完成了这个,它没有区别)

  2. 在项目中添加对"Microsoft.VisualBasic"的引用

  3. 添加一个名为"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 …
    Run Code Online (Sandbox Code Playgroud)

c# asp.net com vbscript wsc

7
推荐指数
1
解决办法
3295
查看次数

从ASP.net项目调用静态异步方法

我想知道这个场景是否是线程安全的,是否存在我目前没有看到的问题:

  1. 从ASP.net控制器我从非静态类调用非静态方法(此类在另一个项目中,类被注入到控制器中).

  2. 这个方法(非静态的)做了一些工作,并调用一些其他静态方法传递userId

  3. 最后,静态方法做了一些工作(需要userId)

我相信这种方法是线程安全的,并且如果两个用户同时调用此方法,那么一切都将正确完成(让我们说同样的纳秒).我是正确还是完全错误?如果我错了,在ASP.net项目中使用静态方法的正确方法是什么?

编辑

这是代码:)

这是来自控制器的调用:

await _workoutService.DeleteWorkoutByIdAsync(AzureRedisFeedsConnectionMultiplexer.GetRedisDatabase(),AzureRedisLeaderBoardConnectionMultiplexer.GetRedisDatabase(), workout.Id, userId);
Run Code Online (Sandbox Code Playgroud)

这里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;
    }
Run Code Online (Sandbox Code Playgroud)

您可以注意到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); …
Run Code Online (Sandbox Code Playgroud)

c# asp.net

7
推荐指数
1
解决办法
1254
查看次数

Propagate OperationContext into Async WCF Call

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 …

c# wcf operationcontext async-await c#-5.0

6
推荐指数
1
解决办法
2312
查看次数