问题描述
我正在 Asp Net Core 3.1 中构建 GraphQL API。我正在尝试添加一个 订阅,以便在添加新实体时向订阅者发送新实体。 当我从 /ui/playground 执行订阅时,与服务器的握手似乎成功了:
GraphQL http 请求 websocket:
当我执行添加评论的突变时,它成功并在数据库上创建了一条记录,但上面的屏幕仍然如此,没有更新,没有从套接字接收到数据。
这是突变:
Field<ReviewType>(
"createReview",arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<ReviewInput>>
{
Name = "reviewInput"
}
),resolve: context =>
{
var review = context.GetArgument<Review>("reviewInput");
var rev = reviewService.Add(review);
return rev;
}
);
ShopSubscrition.cs
public partial class ShopSubscription : ObjectGraphType
{
private readonly IReviewService _reviewService;
public ShopSubscription(IReviewService reviewService)
{
_reviewService = reviewService;
AddField(new EventStreamFieldType
{
Name = "reviewAdded",Type = typeof(ReviewType),Resolver = new FuncFieldResolver<Review>((context) => context.source as Review),Subscriber = new EventStreamResolver<Review>((context) => _reviewService.ReviewAdded())
});
}
}
ReviewService.cs
public class ReviewService : IReviewService
{
private readonly IReviewRepository _reviewRepository;
private readonly ISubject<Review> _sub = new ReplaySubject<Review>(1);
public ReviewService(IReviewRepository reviewRepository)
{
_reviewRepository = reviewRepository;
}
public Review Add(Review review)
{
var addedEntity = _reviewRepository.Add(review);
_sub.OnNext(review);
return review;
}
public IObservable<Review> ReviewAdded()
{
return _sub.AsObservable();
}
}
我也发布了 Startup.cs,也许它会有所帮助。
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddDbContext<ShopDbContext>(opt =>
opt.UsesqlServer(Configuration.GetConnectionString("Default")));
services.AddScoped<IsupplierRepository,supplierRepository>();
services.AddScoped<IProductRepository,ProductRepository>();
services.AddScoped<IReviewRepository,ReviewRepository>();
services.AddScoped<IReviewService,ReviewService>();
services.AddSingleton<IDataLoaderContextAccessor,DataLoaderContextAccessor>();
services.AddSingleton<DataLoaderDocumentListener>();
services.AddScoped<ShopSchema>();
services.AddGraphQL(options =>
{
options.EnableMetrics = false;
})
.AddWebSockets()
.AddSystemTextJson()
.AddGraphTypes(typeof(ShopSchema),ServiceLifetime.Scoped).AddDataLoader();
services.AddControllers()
.AddNewtonsoftJson(o => o.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}
public void Configure(IApplicationBuilder app,IWebHostEnvironment env,ShopDbContext dbContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("Cors");
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseWebSockets();
app.UseGraphQLWebSockets<ShopSchema>("/graphql");
app.UseGraphQL<ShopSchema>();
app.UseGraphQLPlayground(options: new GraphQLPlaygroundOptions { GraphQLEndPoint ="/graphql",SchemaPollingEnabled = false });
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
dbContext.SeedData();
}
}
预先感谢您的帮助。
解决方法
经过深入调查后,我发现了问题所在。我发布了解决方案,也许可以帮助某人。
问题是关于依赖注入:包含订阅“通知逻辑”的类(在我的例子中是 ReviewService.cs)必须注册为 Singleton 而不是 Scoped。这引起了一种连锁反应,使存储库类注册为 Transient。 这是工作代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("Cors",builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddDbContext<ShopDbContext>(opt =>
opt.UseSqlServer(Configuration.GetConnectionString("Default")));
services.AddTransient<ISupplierRepository,SupplierRepository>();
services.AddTransient<IProductRepository,ProductRepository>();
services.AddTransient<IReviewRepository,ReviewRepository>();
services.AddSingleton<IReviewService,ReviewService>();
services.AddSingleton<IDataLoaderContextAccessor,DataLoaderContextAccessor>();
services.AddSingleton<DataLoaderDocumentListener>();
services.AddScoped<ShopSchema>();
services.AddGraphQL(options =>
{
options.EnableMetrics = false; // info sulla richiesta (ms,campi richiesti,ecc)
})
.AddWebSockets()
.AddSystemTextJson()
.AddGraphTypes(typeof(ShopSchema),ServiceLifetime.Scoped).AddDataLoader();
services.AddControllers()
.AddNewtonsoftJson(o => o.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}