[英]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.