Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 托管服务中数据库上下文的并发问题_C#_Asp.net Core_Dependency Injection_Dbcontext_Asp.net Core Hosted Services - Fatal编程技术网

C# 托管服务中数据库上下文的并发问题

C# 托管服务中数据库上下文的并发问题,c#,asp.net-core,dependency-injection,dbcontext,asp.net-core-hosted-services,C#,Asp.net Core,Dependency Injection,Dbcontext,Asp.net Core Hosted Services,我有一个托管服务,它通过API端点处理对象PUT/POST,也就是说,只要给出一个新实体或编辑一个现有实体,(a)托管服务开始处理它(一个长时间运行的进程),以及(b)接收/修改的对象(作为JSON对象)返回给API调用方 当放置/发布一个实体时,我会到处看到运行时错误(例如,在object JSON serializer)抱怨不同的问题,例如: ObjectDisposedException:无法访问已处置的对象。此错误的一个常见原因是处理通过依赖项注入解析的上下文,然后在应用程序的其他位置尝

我有一个托管服务,它通过API端点处理对象PUT/POST,也就是说,只要给出一个新实体或编辑一个现有实体,(a)托管服务开始处理它(一个长时间运行的进程),以及(b)接收/修改的对象(作为JSON对象)返回给API调用方

当放置/发布一个实体时,我会到处看到运行时错误(例如,在object JSON serializer)抱怨不同的问题,例如:

ObjectDisposedException:无法访问已处置的对象。此错误的一个常见原因是处理通过依赖项注入解析的上下文,然后在应用程序的其他位置尝试使用相同的上下文实例。如果对上下文调用Dispose(),或将上下文包装到using语句中,则可能会发生这种情况。如果您使用的是依赖项注入,那么应该让依赖项注入容器处理上下文实例

或:

InvalidOperationException:在上一个操作完成之前,在此上下文上启动了第二个操作。这通常是由使用同一DbContext实例的不同线程引起的

最初我使用的是数据库上下文池,但该池似乎已经知道托管服务存在问题。因此,我切换到常规的
AddDbContext
;然而,这两者都没有解决问题

以下是我定义数据库上下文和托管服务的方式:

公共类启动
{
public void配置服务(IServiceCollection服务)
{
AddCustomDbContext(配置);
//这是托管服务:
services.AddHostedService();
}
}
公共静态类CustomExtensionMethods
{
公共静态IServiceCollection AddCustomDbContext(
这是电子收款服务,
i配置(配置)
{
services.AddDbContext(
选项=>
{
选择权
.UseLazyLoadingProxies(真)
.UseSqlServer(
configuration.GetConnectionString(“DefaultConnection”),
SQLServerOptionAction:sqlOptions=>{sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);});
});
返回服务;
}
}
我访问托管服务中的数据库上下文,如下所示():

使用(var scope=Services.CreateScope())
{
var context=scope.ServiceProvider.GetRequiredService();
}
编辑1 如前所述,错误发生在整个代码中;但是,由于我提到了序列化程序上发生的错误,我将在以下内容中共享序列化程序代码:

公共类MyJsonConverter:JsonConverter
{
私人现成字典(u property mappings);;
公共MyJsonConverter()
{
_propertyMappings=新字典
{
{“id”,nameof(MyType.id)},
{“name”,nameof(MyType.name)}
};
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
JObject obj=新的JObject();
Type Type=value.GetType();
foreach(type.GetProperties()中的PropertyInfo属性)
{
如果(道具可阅读)
{
//上述链接错误发生在此处。
object propVal=prop.GetValue(值,null);
if(propVal!=null)
Add(prop.Name,JToken.FromObject(propVal,serializer));
}
}
书面对象(作者);
}
}
更新2 API端点示例如下所示:

[路由(“api/v1/[控制器]”)]
[ApiController]
公共类MyTypeController:ControllerBase
{
私有只读MyContext\u上下文;
私人MyHostedService_服务;
公共MyTypeController(
MyContext上下文,
MyHostedService服务)
{
_上下文=上下文;
_服务=服务
}
[HttpGet(“{id}”)]
公共异步任务GetMyType(int id)
{
返回wait_context.MyTypes.FindAsync(id);
}
[HttpPost]
公共异步任务PostMyType(MyType MyType)
{
myType.Status=State.Queued;
_context.MyTypes.Add(myType);
_context.MyTypes.saveChangesSync().ConfigureAwait(false);
//对象在托管服务中排队等待执行。
_服务排队(myType);
返回CreateDataAction(“GetMyType”,新的{id=myType.id},myType);
}
}

以下几行最有可能导致
ObjectDisposedException
错误:

return await _context.MyTypes.FindAsync(id);

这是因为您依赖于此变量:

private readonly MyContext _context;
因为对象
myType
已附加到该上下文

正如我前面提到的,发送上下文实体进行序列化不是一个好主意,因为当序列化程序有机会启动时,上下文可能已经被释放。改为使用模型(即
Models
文件夹中的类),并将真实实体中的所有相关属性映射到该模型。例如,您可以创建一个名为
MyTypeViewModel
的类,该类仅包含需要返回的属性:

public class MyTypeViewModel
{
    public MyTypeViewModel(MyType obj)
    {
        Map(obj);
    }

    public int ID { get; set; }

    private void Map(MyType obj)
    {
        this.ID = obj.ID;
    }
}
然后使用视图模型,而不是返回实体:

var model = new MyTypeViewModel(myType);
return CreatedAtAction("GetMyType", new { id = myType.ID }, model);
至于
invalidooperationexception
,我的猜测是,由于您没有等待
savechangesync
方法,因此序列化程序在原始操作仍在进行时触发,导致对上下文的双击,从而导致错误


savechangesync
方法上使用
wait
应该可以解决这个问题,但是您仍然需要停止发送延迟加载的实体进行序列化

进一步查看后,服务本身可能也会引起问题,因为您正在向其传递对对象
myType
的引用:

_service.Enqueue(myType);
<
_service.Enqueue(myType);