我正在尝试从Azure服务总线接收消息时执行一些数据库操作。我正在调用我的服务,而我的服务内部调用了一个存储库来访问db获取数据并返回。但是我在使用上下文对象访问我的数据库时收到System.ObjectDisposedException异常消息
请指导我完成这个吗?
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
-----------------------
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连接并关闭它。
Service Bus客户端对象,例如QueueClient或MessageSender,是通过MessagingFactory对象创建的,该对象还提供了连接的内部管理。
建议您在发送消息后不要关闭消息传递工厂或队列,主题和订阅客户端,然后在发送下一条消息时重新创建它们。关闭消息传递工厂将删除与服务总线服务的连接,并且在重新创建工厂时会建立新的连接。建立连接是一项昂贵的操作,可以通过将同一工厂对象和客户端对象重用于多个操作来避免。您可以安全地将这些客户端对象用于并发异步操作并从多个线程使用。
请参见Best Practices for performance improvements using Service Bus Messaging
所以,要解决此问题,请尝试将其注册为单例
services.AddSingleton<IServiceBusConsumer, ServiceBusConsumer>();