C# 当使用通过Unity注入的共享实体时,如何生成子线程进程?

C# 当使用通过Unity注入的共享实体时,如何生成子线程进程?,c#,asp.net-mvc,multithreading,unity-container,C#,Asp.net Mvc,Multithreading,Unity Container,我有一个ASP.NETMVC3解决方案,它运行从web服务获取数据的批导入过程。对于每一行/循环,流程最多需要发送四封电子邮件。我想在后台线程中启动这些电子邮件,这样主线程就不必等待电子邮件发送。子电子邮件线程需要在电子邮件发送完成或失败时更新数据库审核表 我遇到的问题是,我使用Unity将IEmailer类注入到我的主进程线程中,这也将“主进程线程”datacontext分配到emailer类中。因此,如果主循环已经完成,当电子邮件发送者尝试更新审核表时,如果datacontext已经关闭,则

我有一个ASP.NETMVC3解决方案,它运行从web服务获取数据的批导入过程。对于每一行/循环,流程最多需要发送四封电子邮件。我想在后台线程中启动这些电子邮件,这样主线程就不必等待电子邮件发送。子电子邮件线程需要在电子邮件发送完成或失败时更新数据库审核表

我遇到的问题是,我使用Unity将IEmailer类注入到我的主进程线程中,这也将“主进程线程”datacontext分配到emailer类中。因此,如果主循环已经完成,当电子邮件发送者尝试更新审核表时,如果datacontext已经关闭,则会出现错误(一种可能的情况)

我如何告诉Unity将新的datacontext分配给我的新emailer线程,或者如何告诉emailer类使用不同的Unity容器(我想是配置了瞬态datacontext?)

这是我的精简代码。(我意识到我可以在emailer中实例化一个“new MyDataContext()”,但肯定有更好的方法)

任何帮助、建议、想法或意见都将不胜感激-谢谢

IOC容器

this.unityContainer = new UnityContainer()
    .RegisterType<IDataProvider, DataProvider>()
    .RegisterType(typeof(IEmailer), typeof(Emailer))
    .RegisterType<DbContext, MyDataContext>(new HierarchicalLifetimeManager());
Emailer类(用于子线程)

DataProvider(通过ctor注入包含datacontext)


我正试着重新解释你的解释,看看我是否理解正确

您的导入程序在主线程上运行。您导入的每一行都会发送大量电子邮件。您的电子邮件发件人需要在流程成功或失败时将审核信息写入数据库

emailer被注入到您的导入程序中,并且两者都依赖于从
DbContext
派生的类?这与
DbContext
的实例相同吗?如果是:你为什么要分享这个例子?发送电子邮件的每个任务不是独立于所有其他任务吗?如果是,请删除层次结构CallifeTimeManager

您可以将属性注入用于
IDataProvider
。我明白这是一种必须具备的依赖性。如果是这种情况,您应该像对其他类一样使用构造函数注入。顺便说一下:。您还可以在调用
RegisterType
时使用
InjectionProperty
配置属性注入


更新

据我所知,统一永远不会自行清理。这意味着我无论如何都不会期望它在
DbContext
上调用
Dispose
。您是否有说明
HierarchyCallifeTimeManager
正确处理对象的参考?我会非常有兴趣读它

HierarchyCallifeTimeManager
的工作方式与
ContainerControlled LifetimeManager
相同,只要您不处理子容器。这基本上意味着您在所有线程中都有一个上下文实例。如果您只是删除该生命周期管理器,那么无论何时需要一个新实例作为依赖项,您都会得到一个新实例。那应该能解决你的问题


如果需要处理上下文实例,我将为上下文注入一个工厂,而不是实例。只需声明一个类型为
的ctor参数
Func
Unity将自动为您生成委托(顺便说一句,该功能称为自动工厂)。然后您可以使用(var ctx=dbContextFactory()){…}

感谢您花时间来讨论我的问题。是的,你的措辞在逻辑上是正确的。
DbContext
在应用程序中运行良好的实体之间共享,但显然不能跨线程共享。我是DI新手,我所做的阅读指向对
DbContext
使用
HierarchyCallifeTimeManager
,以确保正确处理它。我使用的是EF CodeFirst方法(不确定它是否有区别?)。如何单独配置emailer以使用新的
DbContext
实例?谢谢您的更新。我读了一篇关于Unity如何不能正确处理对象的文章,但现在我找不到了。最接近我的是这篇文章,它更详细地解释了
层次结构CallifetimeManager
(以及其他)。你是说我应该抛弃
HLTM
,一切都使用transient(默认值)?我以前确实尝试过,但很快就发现从
DbContext
返回的数据不一致。关于自动化工厂的有趣提示,我会调查的,干杯@keithl8041你遇到了什么样的矛盾?只要您在
DbContext
上调用
SaveChanges
,这些更改将保留在数据库中。只要没有发生这种情况,所有的更改都将只存在于上下文的本地存储中。我正在获取不应该返回的数据,这是描述它的唯一方法。好像datacontext正在缓存或没有清除数据。我会再试一次,并汇报具体情况。顺便提一下,关于使用mvc3处理datacontext。请注意,我并没有实际使用Unity.MVC3实现,只是指出了本文供参考。是的,我确认,我已在一个操作中清空了表中的所有数据(使用SaveChanges()),然后运行一个方法,请求返回完整数据集的数据,尽管数据库表中没有实际数据。我做了与添加数据相反的操作(使用SaveChanges()),数据没有添加到数据库中,尽管它在上下文中可用。类似于
DbContext
似乎正在缓存以前请求中的旧数据集。回到
AsHierarchicalControlled()
使上下文如我所期望的那样工作。我不相信删除HTLM是一个有效的解决方案。
public class DataSyncer : IDataSyncer
{
    public DataSyncer(IDataProvider dataProvider, IEmailer emailer)            {
            this.dataProvider = dataProvider;
            this.emailer = emailer;
        }

    public void Import(Guid key)        {
        // some import code
        emailer.EmailAddress = "someone@somewhere.com";
        emailer.Subject = "subject line";
        new Thread(emailer.SendMail).Start(); // send email in new thread
    }
}
public class Emailer : IEmailer
{
    [Dependency]
    public IDataProvider DataProvider { get; set; }
    // etc 
} 
public DataProvider(MyDataContext context, // etc) { // etc }