![](/img/trans.png)
[英]Asp.net core: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection
[英]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.