Skip to content

Commit

Permalink
Merge pull request #871 from Cysharp/feature/JsonTranscoding
Browse files Browse the repository at this point in the history
MagicOnion.Server.JsonTranscoding
  • Loading branch information
mayuki authored Nov 28, 2024
2 parents 86fd03a + 9071bd4 commit 42eab71
Show file tree
Hide file tree
Showing 64 changed files with 3,501 additions and 196 deletions.
4 changes: 3 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@
<PackageVersion Include="Multicaster" Version="$(MulticasterVersion)" />
<PackageVersion Include="Multicaster.Distributed.Redis" Version="$(MulticasterVersion)" />
<PackageVersion Include="Multicaster.Distributed.Nats" Version="$(MulticasterVersion)" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="7.0.0" />
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="8.0.0" />
<PackageVersion Include="System.Threading.Channels" Version="8.0.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.1" />
<PackageVersion Include="PolySharp" Version="1.13.2" />
<PackageVersion Include="StackExchange.Redis" Version="2.0.601" />
<PackageVersion Include="System.Text.Json" Version="9.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4" />
</ItemGroup>
<!-- for tests -->
Expand All @@ -58,4 +60,4 @@
<PackageVersion Include="JetBrains.Profiler.Api" Version="$(JetBrainsProfilerApiVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0" />
</ItemGroup>
</Project>
</Project>
46 changes: 45 additions & 1 deletion MagicOnion.sln
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31919.166
Expand Down Expand Up @@ -122,6 +121,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microbenchmark", "Microbenc
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microbenchmark.Client", "perf\Microbenchmark\Microbenchmark.Client\Microbenchmark.Client.csproj", "{CDBB141A-E0A9-4FD8-8260-1FB1E95C4E80}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MagicOnion.Server.JsonTranscoding", "src\MagicOnion.Server.JsonTranscoding\MagicOnion.Server.JsonTranscoding.csproj", "{8A84D0D5-5AD5-4A76-895A-737AEBBDAA27}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MagicOnion.Server.JsonTranscoding.Tests", "tests\MagicOnion.Server.JsonTranscoding.Tests\MagicOnion.Server.JsonTranscoding.Tests.csproj", "{3FE94073-95E0-4006-ADD6-BBE1FAFBAE75}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MagicOnion.Server.InternalTesting", "tests\MagicOnion.Server.InternalTesting\MagicOnion.Server.InternalTesting.csproj", "{1A958468-D9B8-42B0-99CF-0F9358CD0434}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MagicOnion.Server.JsonTranscoding.Swagger", "src\MagicOnion.Server.JsonTranscoding.Swagger\MagicOnion.Server.JsonTranscoding.Swagger.csproj", "{B425F5C5-6411-4461-87C3-07F3048A1724}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "JsonTranscoding", "JsonTranscoding", "{57E6F117-1138-4899-81A2-CC87B20525E4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonTranscodingSample.Server", "samples\JsonTranscoding\JsonTranscodingSample.Server\JsonTranscodingSample.Server.csproj", "{24A21CDA-C3A5-49F2-A1B8-1A93E2E64335}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonTranscodingSample.Shared", "samples\JsonTranscoding\JsonTranscodingSample.Shared\JsonTranscodingSample.Shared.csproj", "{50871ADE-4513-4AC1-8964-740AB6505B31}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -268,6 +281,30 @@ Global
{CDBB141A-E0A9-4FD8-8260-1FB1E95C4E80}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CDBB141A-E0A9-4FD8-8260-1FB1E95C4E80}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CDBB141A-E0A9-4FD8-8260-1FB1E95C4E80}.Release|Any CPU.Build.0 = Release|Any CPU
{8A84D0D5-5AD5-4A76-895A-737AEBBDAA27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8A84D0D5-5AD5-4A76-895A-737AEBBDAA27}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A84D0D5-5AD5-4A76-895A-737AEBBDAA27}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A84D0D5-5AD5-4A76-895A-737AEBBDAA27}.Release|Any CPU.Build.0 = Release|Any CPU
{3FE94073-95E0-4006-ADD6-BBE1FAFBAE75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3FE94073-95E0-4006-ADD6-BBE1FAFBAE75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3FE94073-95E0-4006-ADD6-BBE1FAFBAE75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3FE94073-95E0-4006-ADD6-BBE1FAFBAE75}.Release|Any CPU.Build.0 = Release|Any CPU
{1A958468-D9B8-42B0-99CF-0F9358CD0434}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A958468-D9B8-42B0-99CF-0F9358CD0434}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A958468-D9B8-42B0-99CF-0F9358CD0434}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A958468-D9B8-42B0-99CF-0F9358CD0434}.Release|Any CPU.Build.0 = Release|Any CPU
{B425F5C5-6411-4461-87C3-07F3048A1724}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B425F5C5-6411-4461-87C3-07F3048A1724}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B425F5C5-6411-4461-87C3-07F3048A1724}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B425F5C5-6411-4461-87C3-07F3048A1724}.Release|Any CPU.Build.0 = Release|Any CPU
{24A21CDA-C3A5-49F2-A1B8-1A93E2E64335}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{24A21CDA-C3A5-49F2-A1B8-1A93E2E64335}.Debug|Any CPU.Build.0 = Debug|Any CPU
{24A21CDA-C3A5-49F2-A1B8-1A93E2E64335}.Release|Any CPU.ActiveCfg = Release|Any CPU
{24A21CDA-C3A5-49F2-A1B8-1A93E2E64335}.Release|Any CPU.Build.0 = Release|Any CPU
{50871ADE-4513-4AC1-8964-740AB6505B31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{50871ADE-4513-4AC1-8964-740AB6505B31}.Debug|Any CPU.Build.0 = Debug|Any CPU
{50871ADE-4513-4AC1-8964-740AB6505B31}.Release|Any CPU.ActiveCfg = Release|Any CPU
{50871ADE-4513-4AC1-8964-740AB6505B31}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -315,6 +352,13 @@ Global
{AF21B7BD-7399-41B7-B0D4-08ACDC952E50} = {FEE2B9AB-A1D0-41BA-A172-FC95935542DF}
{F1FD52DD-E8A4-4CF0-A857-1A22443A0324} = {A0CED9FB-5B18-4EE3-859F-CE3A6F90A82A}
{CDBB141A-E0A9-4FD8-8260-1FB1E95C4E80} = {F1FD52DD-E8A4-4CF0-A857-1A22443A0324}
{8A84D0D5-5AD5-4A76-895A-737AEBBDAA27} = {1987061F-8970-4018-8D58-6932961C9EB4}
{3FE94073-95E0-4006-ADD6-BBE1FAFBAE75} = {7ACC27E8-8FBE-4807-B91F-B89AF3CFF7E0}
{1A958468-D9B8-42B0-99CF-0F9358CD0434} = {7ACC27E8-8FBE-4807-B91F-B89AF3CFF7E0}
{B425F5C5-6411-4461-87C3-07F3048A1724} = {1987061F-8970-4018-8D58-6932961C9EB4}
{57E6F117-1138-4899-81A2-CC87B20525E4} = {5A3F5158-7B17-4586-9885-9E60C1393185}
{24A21CDA-C3A5-49F2-A1B8-1A93E2E64335} = {57E6F117-1138-4899-81A2-CC87B20525E4}
{50871ADE-4513-4AC1-8964-740AB6505B31} = {57E6F117-1138-4899-81A2-CC87B20525E4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D5B2E7E3-B727-40A1-BE68-7BAC9B9DE2FE}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\MagicOnion.Server.JsonTranscoding.Swagger\MagicOnion.Server.JsonTranscoding.Swagger.csproj" />
<ProjectReference Include="..\..\..\src\MagicOnion.Server.JsonTranscoding\MagicOnion.Server.JsonTranscoding.csproj" />
<ProjectReference Include="..\..\..\src\MagicOnion.Server\MagicOnion.Server.csproj" />
<ProjectReference Include="..\JsonTranscodingSample.Shared\JsonTranscodingSample.Shared.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using JsonTranscodingSample.Shared;
using MagicOnion.Server.Hubs;

namespace JsonTranscodingSample.Server;

// NOTE: JsonTranscoding is not supported for StreamingHub. JsonTranscoding will ignore the StreamingHub.
public class MyFirstHub : StreamingHubBase<IMyFirstHub, IMyFirstHubReceiver>, IMyFirstHub;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Grpc.Core;
using JsonTranscodingSample.Shared;
using MagicOnion;
using MagicOnion.Server;

namespace JsonTranscodingSample.Server;

public class MyFirstService : ServiceBase<IMyFirstService>, IMyFirstService
{
public UnaryResult<string> SayHelloAsync(string name, int age)
{
return UnaryResult.FromResult($"Hello {name} ({age})!");
}

public UnaryResult<RegisterUserResponse> RegisterUserAsync(RegisterUserRequest request)
{
return new UnaryResult<RegisterUserResponse>(new RegisterUserResponse()
{
Success = true,
Message = $"Welcome {request.Name}!",
RegisteredUser = request,
});
}

public UnaryResult<RegisterUserResponse> RegisterUserWithRoleAsync(RegisterUserRequest request, string role)
{
return new UnaryResult<RegisterUserResponse>(new RegisterUserResponse()
{
Success = true,
Message = $"Welcome {request.Name}! You are registered as '{role}'.",
RegisteredUser = request,
});
}

public UnaryResult ThrowAsync()
{
throw new InvalidOperationException("Something went wrong.");
}

public UnaryResult ThrowWithReturnStatusCodeAsync(int statusCode, string detail)
{
throw new ReturnStatusException((StatusCode)statusCode, detail);
}
}
34 changes: 34 additions & 0 deletions samples/JsonTranscoding/JsonTranscodingSample.Server/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddGrpc();

// Add MagicOnion services to the container and enable JSON transcoding feature.
builder.Services.AddMagicOnion().AddJsonTranscoding();
// Add MagicOnion JSON transcoding Swagger support.
builder.Services.AddMagicOnionJsonTranscodingSwagger();
// Add Swagger generator services.
builder.Services.AddSwaggerGen(options =>
{
// Reflect the XML documentation comments of the service definition in Swagger.
options.IncludeMagicOnionXmlComments(Path.Combine(AppContext.BaseDirectory, "JsonTranscodingSample.Shared.xml"));
});

var app = builder.Build();

// Configure the HTTP request pipeline.

// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
if (app.Environment.IsDevelopment())
{
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
}

app.MapMagicOnionService();
app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");

app.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:5073",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:7192;http://localhost:5073",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https (Production)": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:7192;http://localhost:5073",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using MagicOnion;

namespace JsonTranscodingSample.Shared;

public interface IMyFirstHub : IStreamingHub<IMyFirstHub, IMyFirstHubReceiver>;
public interface IMyFirstHubReceiver;
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using MagicOnion;
using MessagePack;

namespace JsonTranscodingSample.Shared;

/// <summary>
/// This is a service interface for the demonstration.
/// </summary>
public interface IMyFirstService : IService<IMyFirstService>
{
/// <summary>
/// Say hello to the specified name.
/// </summary>
/// <param name="name"> A name to say hello. </param>
/// <param name="age">An age of the person to say hello.</param>
/// <returns>Returns a message to the specified name.</returns>
UnaryResult<string> SayHelloAsync(string name, int age);

/// <summary>
/// Register a user with the specified request.
/// </summary>
/// <param name="request">The request to register a user.</param>
/// <returns>Returns a response to the user registration request.</returns>
UnaryResult<RegisterUserResponse> RegisterUserAsync(RegisterUserRequest request);

/// <summary>
/// Register a user with the specified request and role.
/// </summary>
/// <param name="request">The request to register a user.</param>
/// <param name="role">A role to assign to the user.</param>
/// <returns>Returns a response to the user registration request.</returns>
UnaryResult<RegisterUserResponse> RegisterUserWithRoleAsync(RegisterUserRequest request, string role);

/// <summary>
/// Throw an exception.
/// </summary>
/// <returns></returns>
UnaryResult ThrowAsync();

/// <summary>
/// Throw an exception with the specified status code and detail.
/// </summary>
/// <param name="statusCode">A status code to return.</param>
/// <param name="detail">A detail message to return.</param>
/// <returns></returns>
UnaryResult ThrowWithReturnStatusCodeAsync(int statusCode, string detail);
}

/// <summary>
/// Represents a request to register a user.
/// </summary>
[MessagePackObject]
public class RegisterUserRequest
{
/// <summary>
/// Gets or sets the name of the user.
/// </summary>
[Key(0)]
public required string Name { get; init; }

/// <summary>
/// Gets or sets the age of the user.
/// </summary>
[Key(1)]
public required int Age { get; init; }
}

/// <summary>
/// Represents a response to a user registration request.
/// </summary>
public class RegisterUserResponse
{
/// <summary>
/// Gets or sets a value indicating whether the operation was successful.
/// </summary>
[Key(0)]
public required bool Success { get; init; }

/// <summary>
/// Gets or sets a message.
/// </summary>
[Key(1)]
public required string Message { get; init; }

/// <summary>
/// Gets or sets the registered user.
/// </summary>
[Key(2)]
public required RegisterUserRequest RegisteredUser { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\MagicOnion.Abstractions\MagicOnion.Abstractions.csproj" />
</ItemGroup>

</Project>
Loading

0 comments on commit 42eab71

Please sign in to comment.