简体   繁体   English

无法访问已处理的对象。此错误的原因 - 与依赖注入相关的 Asp.net Core 异常

[英]Cannot access a disposed object.cause of this error - Asp.net Core Exception related to Dependency Injection

I am trying to perform some database operation on receiving the message from Azure service bus.我正在尝试在接收来自 Azure 服务总线的消息时执行一些数据库操作。

I am calling my service and my service internally calls a repository to access db get data and return, but I am getting a System.ObjectDisposedException Exception message on using the context object to access my db.我正在调用我的服务,我的服务在内部调用存储库以访问 db 获取数据并返回,但是我在使用上下文对象访问我的 db 时收到System.ObjectDisposedException Exception消息。

Please guide me through this?请指导我完成这个?

startup.cs启动文件

public Startup(IConfiguration configuration) 
{
    Configuration = configuration;
}

public IConfiguration Configuration 
{
    get;
}

public static string clientId 
{
    get;
    private set;
}

public static string clientSecret 
{
    get;
    private set;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) 
{
    string azureConnectionString = Configuration["ConnectionStrings:DefaultConnection"];

    services.AddControllers();
    clientId = Configuration.GetSection("fuelSDK").GetSection("clientId").Value;
    clientSecret = Configuration.GetSection("fuelSDK").GetSection("clientSecret").Value;

    var dbUtils = new AzureDatabaseUtils();
    var sqlConnection = dbUtils.GetSqlConnection(azureConnectionString);

    services.AddDbContext < DeciemStoreContext > (options = >options.UseSqlServer(sqlConnection));

    #region RegisterServices

    services.AddTransient < IServiceBusConsumer,
    ServiceBusConsumer > ();
    services.AddTransient < IOrderRepository,
    OrderRepository > ();
    services.AddTransient < IOrderService,
    OrderService > ();

    #endregion

    Configuration.GetSection("Global").Get < Global > ();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 
{
    if (env.IsDevelopment()) 
    {
        app.UseDeveloperExceptionPage();
    }

    #region Azure ServiceBus
    using(var scope = app.ApplicationServices.CreateScope()) 
    {
        var bus = scope.ServiceProvider.GetService < IServiceBusConsumer > ();
        bus.RegisterOnMessageHandlerAndReceiveMessages();

    }

    #endregion

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints = > {
        endpoints.MapControllerRoute("api", "api/{controller}/{action}/{id?}");
    });
}

MessageConsumerClass.cs MessageConsumerClass.cs

public interface IServiceBusConsumer 
{
    void RegisterOnMessageHandlerAndReceiveMessages();
    Task CloseQueueAsync();
}

public class ServiceBusConsumer: IServiceBusConsumer 
{
    private IOrderService _orderService;
    private readonly ILogger _logger;

    static ISubscriptionClient subscriptionClient;

    public ServiceBusConsumer(ILogger < ServiceBusConsumer > logger, IOrderService orderService) 
    {
        _logger = logger;
        _orderService = orderService;
        const string ServiceBusConnectionString = "Endpoint=sb://qa10em.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=v2sIQi/2fY2rENS7trnFd38m2wqNJKuWYMFJxWccK8E=";
        const string TopicName = "businessoperation";
        const string SubscriptionName = "SFOperation_sub";

        //SubscriberCreateAsync().Wait();
        subscriptionClient = new SubscriptionClient(ServiceBusConnectionString, TopicName, SubscriptionName);
    }

    public void RegisterOnMessageHandlerAndReceiveMessages()
    {
        var messageHandlerOptions = new MessageHandlerOptions(ExceptionReceivedHandler) {
            MaxConcurrentCalls = 1,
            AutoComplete = false
        };
        subscriptionClient.RegisterMessageHandler(ProcessMessagesAsync, messageHandlerOptions);
    }

    private async Task ProcessMessagesAsync(Message message, CancellationToken token) 
    {
        try 
        {
            Console.WriteLine($ "Received message: SequenceNumber:{message.SystemProperties.SequenceNumber} Body:{Encoding.UTF8.GetString(message.Body)}");

            var mb = JsonConvert.DeserializeObject < MessageBody > (Encoding.UTF8.GetString(message.Body));

            if (mb != null) 
            {
                Global.Entity = mb.Entity;
                Global.ActionName = mb.ActionName;
                Global.Value = mb.Value;
            }
            else 
            {
                Global.Entity = "";
                Global.ActionName = "";
                Global.Value = "";
            }
            await subscriptionClient.CompleteAsync(message.SystemProperties.LockToken);

            //Here I am calling the service to get data
            var orders = _orderService.GetByOrderId(Global.Value);
            //await _orderService.GetByOrderId(Global.Value);
        }
        catch(Exception ex) 
        {
            throw ex;
        }
    }

OrderRepository.cs -- Here in this file I am receiving the DBContext disposed exception OrderRepository.cs -- 在这个文件中,我收到了 DBContext 处理异常

protected DeciemStoreContext _context;
public OrderRepository(DeciemStoreContext context) 
{
    _context = context;
}

public async Task <IEnumerable<Order>> ListAsync() 
{
    return await _context.Order.ToListAsync();
}

public async Task <List<Order>> GetByOrderId(string OrderId) 
{
    try 
    {
        int oid = Convert.ToInt32(OrderId);
        // here while trying to access _context the context seems to have disposed before 
        var order = from o in _context.Order
        where o.OrderId == oid
        orderby o.OrderId
        select new Order 
        {
            OrderId = o.OrderId,
            CustomerId = o.CustomerId,
            ProductSubtotal = o.ProductSubtotal,
            PreTaxSubtotal = o.PreTaxSubtotal,
            DiscountCode = o.DiscountCode,
            DiscountPercent = o.DiscountPercent,
            DiscountAmount = o.DiscountAmount,
            GrandTotal = o.GrandTotal,
            Ponumber = o.Ponumber,
            PostedDate = o.PostedDate
        };

        return await order.ToListAsync();
    }
    catch(Exception ex) 
    {
        throw ex;
    }
}

Look at this line看看这条线

services.AddTransient<IServiceBusConsumer, ServiceBusConsumer>();

here you create a new consumer for each time they are requested (at least once per request).在这里,您为每次请求创建一个新的使用者(每个请求至少一次)。 This means that you open the ServiceBus connection and close it each time when ServiceBusConsumer created.这意味着您每次创建ServiceBusConsumer时都会打开 ServiceBus 连接并关闭它。

Service Bus client objects, such as QueueClient or MessageSender, are created through a MessagingFactory object, which also provides internal management of connections.服务总线客户端对象(例如 QueueClient 或 MessageSender)是通过 MessagingFactory 对象创建的,该对象还提供连接的内部管理。

It is recommended that you do not close messaging factories or queue, topic, and subscription clients after you send a message, and then re-create them when you send the next message.建议您不要在发送消息后关闭消息工厂或队列、主题和订阅客户端,然后在发送下一条消息时重新创建它们。 Closing a messaging factory deletes the connection to the Service Bus service, and a new connection is established when recreating the factory.关闭消息工厂会删除与 Service Bus 服务的连接,并在重新创建工厂时建立新连接。 Establishing a connection is an expensive operation that you can avoid by reusing the same factory and client objects for multiple operations.建立连接是一项代价高昂的操作,您可以通过为多个操作重用相同的工厂和客户端对象来避免该操作。 You can safely use these client objects for concurrent asynchronous operations and from multiple threads.您可以安全地将这些客户端对象用于并发异步操作和来自多个线程。

See Best Practices for performance improvements using Service Bus Messaging请参阅使用服务总线消息传递提高性能的最佳实践

So, to fix that try to register it as a singleton因此,要解决该问题,请尝试将其注册为单例

services.AddSingleton<IServiceBusConsumer, ServiceBusConsumer>();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Asp.net 内核:无法访问已处置的 object。 此错误的常见原因是处理从依赖注入中解析的上下文 - Asp.net core: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection 无法访问ASP.NET Core后台服务中的已处置对象 - Cannot access a disposed object in ASP.NET Core background service 无法访问已处置的 object Asp.net Identity Core - Cannot access a disposed object Asp.net Identity Core 无法访问已处置的 object。 此错误的常见原因是处理从依赖注入中解析的上下文 - Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection 错误:无法访问已处理的对象。 此错误的一个常见原因是处理从依赖注入解决的上下文 - Error: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection &#39;无法访问已处理的对象。 此错误的一个常见原因是处理从依赖注入解决的上下文 - 'Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection .Net core/EF:无法访问已处置的 object。 此错误的常见原因是处理上下文 - .Net core/EF : cannot access a disposed object. A common cause of this error is disposing a context 如何解决asp.net core 2.1中无法访问已处置对象? - How to solve Cannot access a disposed object in asp.net core 2.1? Asp.net Core:无法访问已处置的对象(不同的错误) - Asp.net Core: Can not access a disposed object (different errors) 注入 DbContext 时无法访问 ASP.NET Core 中已处理的对象 - Cannot access a disposed object in ASP.NET Core when injecting DbContext
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM