GraphQL集成与.netcore服务
引用:
<ItemGroup>
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.SystemTextJson" Version="5.2.2" />
<PackageReference Include="GraphQL.Server.Ui.GraphiQL" Version="7.1.1" />
<PackageReference Include="Grpc.AspNetCore" Version="2.27.0" />
</ItemGroup>
代码:
/// <summary>
/// Startup.cs
/// </summary>
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc().Services
.AddControllers();
}
// 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();
}
app.UseGraphQLGraphiQL();
app.UseRouting();
app.Use(async (context, next) =>
{
if (context.Request.Path.StartsWithSegments("/graphql"))
{
GraphQLRequest request;
using (var streamReader = new StreamReader(context.Request.Body))
{
request = JsonConvert.DeserializeObject<GraphQLRequest>(await streamReader.ReadToEndAsync());
var schema = new Schema() { Query = GroupQurey.Instance, Mutation = GroupQurey.Instance };
var result = await new DocumentExecuter()
.ExecuteAsync(doc =>
{
doc.Schema = schema;
doc.Query = request.Query;
//!! Dictionary do not inherit from IDictionary
doc.Inputs = JsonConvert.SerializeObject(request.Variables).ToInputs(); ;
doc.OperationName = request.OperationName;
doc.UnhandledExceptionDelegate += (ex) =>
{
int a = 10;
};
}).ConfigureAwait(false);
var json = await new DocumentWriter(indent: true).WriteToStringAsync(result);
await context.Response.WriteAsync(json);
}
}
else
await next.Invoke();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapControllers();
endpoints.MapGrpcService<GreeterService>();
endpoints.MapGet("/_proto", async ctx =>
{
ctx.Response.ContentType = "text/plain";
using var fs = new FileStream(Path.Combine(env.ContentRootPath, "Protos", "greet.proto"), FileMode.Open, FileAccess.Read);
using var sr = new StreamReader(fs);
while (!sr.EndOfStream)
{
var line = await sr.ReadLineAsync();
if (line != "/* >>" || line != "<< */")
{
await ctx.Response.WriteAsync(line);
}
}
});
});
}
}
public class GraphQLRequest
{
[JsonProperty(propertyName: "query")]
public string Query;
[JsonProperty(propertyName: "variables")]
public Dictionary<string, object> Variables;
[JsonProperty(propertyName: "operationName")]
public string OperationName;
}
/// <summary>
/// GroupQuery.cs
/// </summary>
public class GroupQurey : ObjectGraphType
{
private static GroupQurey _instance;
public static GroupQurey Instance
{
get
{
if (_instance == null)
_instance = new GroupQurey();
return _instance;
}
}
private GroupQurey()
{
Name = "group";
Field<ItemType>("item",
arguments: new QueryArguments(
new QueryArgument<IntGraphType> { Name = "index" },
new QueryArgument<StringGraphType> { Name = "name" }),
resolve: context =>
{
var index = context.GetArgument<int?>("index");
var name = context.GetArgument<string>("name");
return DataSource.Instance().GetItem(index, name);
});
Field<ListGraphType<ItemType>>("items",
arguments: new QueryArguments(
new QueryArgument<IntGraphType> { Name = "page", DefaultValue = 0 },
new QueryArgument<IntGraphType> { Name = "size", DefaultValue = 5 }),
resolve: context =>
{
var page = context.GetArgument<int>("page");
var size = context.GetArgument<int>("size");
return DataSource.Instance().GetItems(page, size);
});
Field<ItemType>("addItem",
arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<ItemInputType>> { Name = "item" }),
resolve: context =>
{
var item = context.GetArgument<Item>("item");
return DataSource.Instance().Add(item);
});
}
}
public class Item
{
/// <summary>
/// !! must property instead of field
/// </summary>
public int Index { get; set; }
public string Name { get; set; }
public string URL { get; set; }
}
public class ItemType : ObjectGraphType<Item>
{
public ItemType()
{
Name = "Item";
Field("index", P => P.Index);
Field("name", p => p.Name);
Field("url", p => p.URL, nullable: true);
}
}
public class ItemInputType : InputObjectGraphType<Item>
{
public ItemInputType()
{
Name = "ItemInput";
Field("name", p => p.Name);
Field("url", p => p.URL, nullable: true);
}
}
public class DataSource
{
private object _lock = new object();
private static DataSource _instance;
public static DataSource Instance()
{
if (_instance == null)
_instance = new DataSource();
return _instance;
}
private DataSource()
{
for (int i = 0; i < 100; i++)
{
_items.Add(new Item { Index = i, Name = $"name{i}", URL = string.Empty });
}
_items.Add(new Item { Index = 100, Name = "name100" });
}
private List<Item> _items = new List<Item>();
public List<Item> GetItems(int page, int size)
{
return _items.Skip(page * size).Take(size).ToList();
}
public Item GetItem(int? index, string name)
{
if (index != null)
return _items.FirstOrDefault(p => p.Index == index);
else if (name != null)
return _items.FirstOrDefault(p => p.Name == name);
else
return _items[0];
}
public Item Add(Item item)
{
Item tmp = new Item { Index = -1, Name = item.Name, URL = item.URL };
lock (_lock)
{
tmp.Index = _items.Count();
_items.Add(tmp);
}
return tmp.Index == -1 ? null : tmp;
}
}
#GraphiQL
mutation addItem($add: ItemInput!) {
add_result: addItem(item: $add) {
...member
}
}
query queryPage($page: Int, $size: Int) {
items(page: $page, size: $size) {
...member
}
}
query getItemByIndexOrName($index: Int, $name: String) {
index_result: item(index: $index) {
...member
}
name_result: item(name: $name) {
...member
}
}
fragment member on Item {
index
name
url
}
#Variables
{
"index": 3,
"name": "name100",
"page":0,
"size":200,
"add": {"name":"addItem","url":""}
}