繁体   English   中英

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

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

我正在尝试在接收来自 Azure 服务总线的消息时执行一些数据库操作。

我正在调用我的服务,我的服务在内部调用存储库以访问 db 获取数据并返回,但是我在使用上下文对象访问我的 db 时收到System.ObjectDisposedException Exception消息。

请指导我完成这个?

启动文件

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

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 -- 在这个文件中,我收到了 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;
    }
}

看看这条线

services.AddTransient<IServiceBusConsumer, ServiceBusConsumer>();

在这里,您为每次请求创建一个新的使用者(每个请求至少一次)。 这意味着您每次创建ServiceBusConsumer时都会打开 ServiceBus 连接并关闭它。

服务总线客户端对象(例如 QueueClient 或 MessageSender)是通过 MessagingFactory 对象创建的,该对象还提供连接的内部管理。

建议您不要在发送消息后关闭消息工厂或队列、主题和订阅客户端,然后在发送下一条消息时重新创建它们。 关闭消息工厂会删除与 Service Bus 服务的连接,并在重新创建工厂时建立新连接。 建立连接是一项代价高昂的操作,您可以通过为多个操作重用相同的工厂和客户端对象来避免该操作。 您可以安全地将这些客户端对象用于并发异步操作和来自多个线程。

请参阅使用服务总线消息传递提高性能的最佳实践

因此,要解决该问题,请尝试将其注册为单例

services.AddSingleton<IServiceBusConsumer, ServiceBusConsumer>();

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM