簡體   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