gpt4 book ai didi

c# - “无法访问已处置的上下文实例。”从存储库调用方法时出错

转载 作者:行者123 更新时间:2023-12-05 02:29:58 29 4
gpt4 key购买 nike

我正在尝试从服务的存储库中调用方法。

上下文、存储库和服务都被定义为作用域服务。

这是我首先调用的方法:

  public async void ReceiveWebhook(HttpContext httpContext)
{
// some unimportant checks here

var productPurchaseRequest = new ProductPurchaseRequest
{
Amount = Convert.ToInt32(result?.Quantity),
Timestamp = DateTime.Now,
ProductType = productType,
PaymentProviderOrderId = Convert.ToInt32(result?.OrderId),
PaymentProviderProductId = Convert.ToInt32(result?.ProductId),
PaymentProviderTransactionId = result?.TransactionId!,
PaymentModel = PaymentModel.Subscription,
PhoneNumber = result?.Passthrough!
//todo: change payment model
};
var bought = await _productProvisioningRepository.PurchaseProduct(productPurchaseRequest);

}

这是存储库中的方法:PurchaseProduct():

    public async Task<bool> PurchaseProduct(ProductPurchaseRequest productPurchaseRequest)
{
await using var transactionScope = await _context.Database.BeginTransactionAsync();

var query = from u in _context.signumid_user
where u.PhoneNumber == productPurchaseRequest.PhoneNumber
select u;

var user = await query.FirstOrDefaultAsync();

if (user == null)
{
return false;
//todo: log user with phone number does not exist
}

try
{
var transaction = new Transaction
{
Timestamp = productPurchaseRequest.Timestamp,
PaymentProviderOrderId = productPurchaseRequest.PaymentProviderOrderId,
PaymentProviderProductId = productPurchaseRequest.PaymentProviderProductId,
PaymentProviderTransactionId = productPurchaseRequest.PaymentProviderTransactionId
};
var transactionDb = await _context.signumid_transaction.AddAsync(transaction);
await _context.SaveChangesAsync();

var productEntry = new ProductEntry
{
Amount = productPurchaseRequest.Amount,
ExpiryDate = productPurchaseRequest.Timestamp.AddMonths(1),
PaymentModel = (int) PaymentModel.Subscription,
ProductType = productPurchaseRequest.ProductType,
UserId = 1
};

var productEntryDb = await _context.signumid_product_entry.AddAsync(productEntry);
await _context.SaveChangesAsync();

var transactionProductEntry = new Transaction_ProductEntry
{
TransactionId = transactionDb.Entity.Id,
ProductEntryId = productEntryDb.Entity.Id
};

var transactionProductEntryDb = await _context.sisgnumid_transaction_product_entry.AddAsync(transactionProductEntry);
await _context.SaveChangesAsync();

//todo: check if everything is okay with database entries

await transactionScope.CommitAsync();
return true;
}
catch (Exception e)
{
// todo: add log
Console.WriteLine(e);
await transactionScope.RollbackAsync();
return false;
}
}

这是 program.cs 文件:

using System.Diagnostics;
using System.Reflection;
using System.Text.Json.Serialization;
using FluentMigrator.Runner;
using Hangfire;
using Hangfire.PostgreSql;
using Hangfire.SQLite;
using Hangfire.SqlServer;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Http.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.DataEncryption;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Newtonsoft.Json;
using Serilog;
using Serilog.Exceptions;
using Serilog.Exceptions.Core;
using Signumid.ExceptionMiddleware;
using Signumid.Global;
using Signumid.MigratorRunner;
using Signumid.ProductProvisioning;
using Signumid.ProductProvisioning.Migrations;

var builder = WebApplication.CreateBuilder(args);
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath(builder.Environment.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
var configurationRoot = configurationBuilder.Build();
ConfigureLogging(configurationRoot);

var applicationSettings = new Signumid.ApplicationSettings.ApplicationSettings();

configurationRoot.Bind(applicationSettings);

SignumIdGlobal.InitialiseApplicationSettings(applicationSettings);

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.Configure<JsonOptions>(options =>
{
options.SerializerOptions.PropertyNameCaseInsensitive = false;
options.SerializerOptions.PropertyNamingPolicy = null;
options.SerializerOptions.WriteIndented = true;
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
});

MigratorRunner.MigrateDatabase(builder.Services,
SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.ConnectionString,
SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.DatabaseProvider,
Assembly.GetAssembly(typeof(InitialMigration)));


builder.Services.AddScoped<ProductProvisioningContext>();
builder.Services.AddScoped<ProductProvisioningRepository>();
builder.Services.AddScoped<ProductProvisioningService>();


ConfigureHangfire(builder.Services);
ConfigureHealthCheck(builder.Services);

builder.Services.AddCors(options =>
options.AddPolicy("CorsPolicy",
corsPolicyBuilder =>
{
corsPolicyBuilder
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.SetIsOriginAllowed(_ => true)
.WithExposedHeaders("Content-Disposition", "Content-Length");
}));

builder.Services.AddAuthorization();

var app = builder.Build();
// Configure hangfire to use the new JobActivator we defined.

// Use the previously configured CorsPolicy policy
app.UseCors("CorsPolicy");

app.ConfigureExceptionHandler();
// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI();

app.UseHttpsRedirection();

app.MapHealthChecks("/v/1/health/basic");
app.MapHealthChecks("/v/1/health/simplified",
new HealthCheckOptions
{
ResponseWriter = async (context, report) =>
{
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(JsonConvert.SerializeObject(new
{
status = report.Status.ToString(),
monitors = report.Entries.Select(e => new
{key = e.Key, value = Enum.GetName(typeof(HealthStatus), e.Value.Status)})
}));
}
}
).RequireHost(SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.HealthCheckHosts);

app.MapGet("/v/1/signer/getAvailableSignatures",
(string phoneNumber, int productType, ProductProvisioningService service) => service.RetrieveRemainingProductAmountForUser(phoneNumber, productType));

app.MapGet("/v/1/signer/generatePayLink",
(string phoneNumber, int quantity, int productId, ProductProvisioningService service) => service.GeneratePayLink(phoneNumber, quantity, productId));

app.MapPost("/v/1/signer/receiveWebhook",
(HttpContext context, ProductProvisioningService service) => service.ReceiveWebhook(context));

app.UseAuthorization();

app.UseHangfireDashboard();
GlobalConfiguration.Configuration
.UseActivator(new HangfireActivator(app.Services));


var runner = app.Services.GetRequiredService<IMigrationRunner>();
// Execute the migrations
runner.MigrateUp();

app.Run();

static void ConfigureLogging(IConfigurationRoot configuration)
{
try
{
Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg));
Serilog.Debugging.SelfLog.Enable(Console.Error);
// Impossible to set with appsettings:
// https://stackoverflow.com/questions/58587661/json-configuration-for-serilog-exception-destructurers/58622735#58622735
// https://github.com/RehanSaeed/Serilog.Exceptions/issues/58
var loggingConfiguration = new LoggerConfiguration()
.Enrich
.WithExceptionDetails(new DestructuringOptionsBuilder().WithDefaultDestructurers())
.ReadFrom
.Configuration(configuration);

Log.Logger = loggingConfiguration
.CreateLogger();
}
catch (Exception e)
{
Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg));
Serilog.Debugging.SelfLog.Enable(Console.Error);
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.MinimumLevel.Debug() // set to minimal in serilog
.CreateLogger();
Log.Debug(e,
"Unable to import serilog configuration from appsettings.json, logging only to console. Error: {@Ex}", e);
}

var currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += UnhandledExceptionHandler;
}

static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
{
var e = (Exception) args.ExceptionObject;
Log.Fatal(e, "Unhandled exception caught : {@error}", e);
Log.Fatal("Runtime terminating: {0}", args.IsTerminating);
}

static void ConfigureHealthCheck(IServiceCollection services)
{
if (SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.DatabaseProvider.Equals("SqlLite",
StringComparison.InvariantCultureIgnoreCase))
{
services.AddHealthChecks()
.AddSqlite(SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.ConnectionString);
}
else if (SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.DatabaseProvider.Equals(
"postgresql",
StringComparison.InvariantCultureIgnoreCase))
{
services.AddHealthChecks()
.AddNpgSql(SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.ConnectionString);
}
else if (SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.DatabaseProvider.Equals(
"sqlserver",
StringComparison.InvariantCultureIgnoreCase))
{
services.AddHealthChecks()
.AddSqlServer(SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.ConnectionString);
}
else
{
services.AddHealthChecks();
}
}

static void ConfigureHangfire(IServiceCollection services)
{
services.AddHangfire(configuration =>
{
configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings();
});

if (SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.DatabaseProvider.Equals("SqlLite",
StringComparison.InvariantCultureIgnoreCase))
{
GlobalConfiguration.Configuration.UseSQLiteStorage(SignumIdGlobal.ApplicationSettings
.ProductProvisioningApplicationSettings
.ConnectionString, new SQLiteStorageOptions
{
SchemaName = "product_provisioning"
});
}
else if (SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.DatabaseProvider.Equals(
"postgresql",
StringComparison.InvariantCultureIgnoreCase))
{
GlobalConfiguration.Configuration.UsePostgreSqlStorage(
SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.ConnectionString,
new PostgreSqlStorageOptions
{
SchemaName = "product_provisioning"
});
}
else if (SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.DatabaseProvider.Equals(
"sqlserver",
StringComparison.InvariantCultureIgnoreCase))
{
GlobalConfiguration.Configuration.UseSqlServerStorage(
SignumIdGlobal.ApplicationSettings.ProductProvisioningApplicationSettings.ConnectionString,
new SqlServerStorageOptions
{
SchemaName = "product_provisioning"
});
}

services.AddHangfireServer();
}

当我声明事务范围时,方法的第一行出现错误。错误如下:

Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.Object name: 'ProductProvisioningContext'.

screenshot of the error

最佳答案

你的ReceiveWebhookasync void,改成返回Task:

public async Task ReceiveWebhook(HttpContext httpContext)

否则 ASP.NET Core 不能等到处理结束,将在处理程序完成之前完成请求(包括处理创建的范围和一次性依赖项,如数据库上下文)。

阅读更多:

  1. async/await - when to return a Task vs void?
  2. Why exactly is void async bad?
  3. async Task vs async void
  4. Async/Await - Best Practices in Asynchronous Programming

关于c# - “无法访问已处置的上下文实例。”从存储库调用方法时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72000020/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com