У меня есть размещенный сервис, который обрабатывает объекты PUT / POST через конечную точку API, то есть, как только дается новый объект или редактируется существующий, (a) размещенный сервис начинает его обрабатывать (долго работает обработать) и (b) полученный / измененный объект, возвращенный (как JSON объект) вызывающей стороне API.
Когда PUT / POST сущность, тут и там я вижу ошибки времени выполнения (например, в JSON serializer), жалующиеся на различные проблемы, такие как:
ObjectDisposedException : Невозможно получить доступ к удаленному объекту. Распространенной причиной этой ошибки является удаление контекста, который был разрешен путем внедрения зависимостей, а затем попытка использовать тот же экземпляр контекста в другом месте вашего приложения. Это может произойти, если вы вызываете Dispose () для контекста или заключаете контекст в оператор using. Если вы используете внедрение зависимости, вы должны позволить контейнеру введения зависимости позаботиться об удалении экземпляров контекста.
или:
InvalidOperationException: вторая операция запущена в этом контексте до завершения предыдущей операции. Обычно это вызвано тем, что разные потоки используют один и тот же экземпляр DbContext.
Изначально я использовал пул контекста базы данных, но в соответствии с этим кажется, что в пуле есть известные проблемы с размещенными службами. Поэтому я переключился обычному AddDbContext
; однако ни то, ни другое не решило проблему.
Вот как я определяю контекст базы данных и размещенную службу:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddCustomDbContext(Configuration);
// This is the hosted service:
services.AddHostedService<MyHostedService>();
}
}
public static class CustomExtensionMethods
{
public static IServiceCollection AddCustomDbContext(
this IServiceCollection services,
IConfiguration configuration)
{
services.AddDbContext<MyContext>(
options =>
{
options
.UseLazyLoadingProxies(true)
.UseSqlServer(
configuration.GetConnectionString("DefaultConnection"),
sqlServerOptionsAction: sqlOptions => { sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); });
});
return services;
}
}
и получаю доступ к контексту базы данных в размещенной службе следующим образом (, как рекомендовано здесь ):
using(var scope = Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<MyContext>();
}
Edit 1
Как уже упоминалось, ошибки происходят по всему коду; однако, поскольку я упомянул ошибки, возникающие на сериализаторе, я делюсь кодом сериализатора следующим образом:
public class MyJsonConverter : JsonConverter
{
private readonly Dictionary<string, string> _propertyMappings;
public MyJsonConverter()
{
_propertyMappings = new Dictionary<string, string>
{
{"id", nameof(MyType.ID)},
{"name", nameof(MyType.Name)}
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JObject obj = new JObject();
Type type = value.GetType();
foreach (PropertyInfo prop in type.GetProperties())
{
if (prop.CanRead)
{
// The above linked errors happen here.
object propVal = prop.GetValue(value, null);
if (propVal != null)
obj.Add(prop.Name, JToken.FromObject(propVal, serializer));
}
}
obj.WriteTo(writer);
}
}
Обновление 2
Пример конечной точки API следующий:
[Route("api/v1/[controller]")]
[ApiController]
public class MyTypeController : ControllerBase
{
private readonly MyContext _context;
private MyHostedService _service;
public MyTypeController (
MyContext context,
MyHostedService service)
{
_context = context;
_service = service
}
[HttpGet("{id}")]
public async Task<ActionResult<IEnumerable<MyType>>> GetMyType(int id)
{
return await _context.MyTypes.FindAsync(id);
}
[HttpPost]
public async Task<ActionResult<MyType>> PostMyType(MyType myType)
{
myType.Status = State.Queued;
_context.MyTypes.Add(myType);
_context.MyTypes.SaveChangesAsync().ConfigureAwait(false);
// the object is queued in the hosted service for execution.
_service.Enqueue(myType);
return CreatedAtAction("GetMyType", new { id = myType.ID }, myType);
}
}