Merge remote-tracking branch 'upstream/master'
This commit is contained in:
Коммит
2e690fe998
|
@ -57,6 +57,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{301F812B
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MessagePack.UniversalCodeGenerator", "src\MessagePack.UniversalCodeGenerator\MessagePack.UniversalCodeGenerator.csproj", "{10AD85DD-929D-49B8-BD43-45242C2644B7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MessagePack.AspNetCoreMvcFormatter.Tests", "tests\MessagePack.AspNetCoreMvcFormatter.Tests\MessagePack.AspNetCoreMvcFormatter.Tests.csproj", "{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -247,6 +249,18 @@ Global
|
|||
{10AD85DD-929D-49B8-BD43-45242C2644B7}.Release|x64.Build.0 = Release|Any CPU
|
||||
{10AD85DD-929D-49B8-BD43-45242C2644B7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{10AD85DD-929D-49B8-BD43-45242C2644B7}.Release|x86.Build.0 = Release|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Release|x64.Build.0 = Release|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -267,6 +281,7 @@ Global
|
|||
{814F94D6-1413-4ACB-B1B5-A3488CAA1E6B} = {BF4C4202-5015-4FBD-80E6-D0F36A06F700}
|
||||
{2A32A538-BA26-4D89-85D0-E4249AFA0837} = {BF4C4202-5015-4FBD-80E6-D0F36A06F700}
|
||||
{10AD85DD-929D-49B8-BD43-45242C2644B7} = {86309CF6-0054-4CE3-BFD3-CA0AA7DB17BC}
|
||||
{79C2B2CB-872A-4BA9-82DC-60F6DD77F940} = {19FE674A-AC94-4E7E-B24C-2285D1D04CDE}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {26F0752B-06F7-44AD-BFEE-8F2E36B3AA27}
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MessagePack.AspNetCoreMvcFormatter
|
||||
{
|
||||
public class MessagePackOutputFormatter : IOutputFormatter //, IApiResponseTypeMetadataProvider
|
||||
{
|
||||
const string ContentType = "application/x-msgpack";
|
||||
static readonly string[] SupportedContentTypes = new[] { ContentType };
|
||||
|
||||
readonly MessagePackSerializer.NonGeneric serializer;
|
||||
|
||||
public MessagePackOutputFormatter()
|
||||
: this((IFormatterResolver)null)
|
||||
{
|
||||
}
|
||||
|
||||
public MessagePackOutputFormatter(IFormatterResolver resolver)
|
||||
: this(new MessagePackSerializer.NonGeneric(new MessagePackSerializer(resolver)))
|
||||
{
|
||||
}
|
||||
|
||||
public MessagePackOutputFormatter(MessagePackSerializer.NonGeneric serializer)
|
||||
{
|
||||
this.serializer = serializer ?? new MessagePackSerializer.NonGeneric(new MessagePackSerializer());
|
||||
}
|
||||
|
||||
//public IReadOnlyList<string> GetSupportedContentTypes(string contentType, Type objectType)
|
||||
//{
|
||||
// return SupportedContentTypes;
|
||||
//}
|
||||
|
||||
public bool CanWriteResult(OutputFormatterCanWriteContext context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public Task WriteAsync(OutputFormatterWriteContext context)
|
||||
{
|
||||
context.HttpContext.Response.ContentType = ContentType;
|
||||
|
||||
// 'object' want to use anonymous type serialize, etc...
|
||||
if (context.ObjectType == typeof(object))
|
||||
{
|
||||
if (context.Object == null)
|
||||
{
|
||||
context.HttpContext.Response.Body.WriteByte(MessagePackCode.Nil);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
// use concrete type.
|
||||
serializer.Serialize(context.Object.GetType(), context.HttpContext.Response.Body, context.Object);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
serializer.Serialize(context.ObjectType, context.HttpContext.Response.Body, context.Object);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MessagePackInputFormatter : IInputFormatter // , IApiRequestFormatMetadataProvider
|
||||
{
|
||||
const string ContentType = "application/x-msgpack";
|
||||
static readonly string[] SupportedContentTypes = new[] { ContentType };
|
||||
|
||||
readonly MessagePackSerializer.NonGeneric serializer;
|
||||
|
||||
public MessagePackInputFormatter()
|
||||
: this((IFormatterResolver)null)
|
||||
{
|
||||
}
|
||||
|
||||
public MessagePackInputFormatter(IFormatterResolver resolver)
|
||||
: this(new MessagePackSerializer.NonGeneric(new MessagePackSerializer(resolver)))
|
||||
{
|
||||
}
|
||||
|
||||
public MessagePackInputFormatter(MessagePackSerializer.NonGeneric serializer)
|
||||
{
|
||||
this.serializer = serializer ?? new MessagePackSerializer.NonGeneric(new MessagePackSerializer());
|
||||
}
|
||||
|
||||
//public IReadOnlyList<string> GetSupportedContentTypes(string contentType, Type objectType)
|
||||
//{
|
||||
// return SupportedContentTypes;
|
||||
//}
|
||||
|
||||
public bool CanRead(InputFormatterContext context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
|
||||
{
|
||||
var request = context.HttpContext.Request;
|
||||
var result = serializer.Deserialize(context.ModelType, request.Body);
|
||||
return InputFormatterResult.SuccessAsync(result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
namespace MessagePack.AspNetCoreMvcFormatter
|
||||
{
|
||||
public class LZ4MessagePackInputFormatter : MessagePackInputFormatter
|
||||
{
|
||||
public LZ4MessagePackInputFormatter()
|
||||
: base(new LZ4MessagePackSerializer.NonGeneric())
|
||||
{
|
||||
}
|
||||
|
||||
public LZ4MessagePackInputFormatter(IFormatterResolver resolver)
|
||||
: base(new LZ4MessagePackSerializer.NonGeneric(resolver))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
namespace MessagePack.AspNetCoreMvcFormatter
|
||||
{
|
||||
public class LZ4MessagePackOutputFormatter : MessagePackOutputFormatter
|
||||
{
|
||||
public LZ4MessagePackOutputFormatter()
|
||||
: base(new LZ4MessagePackSerializer.NonGeneric())
|
||||
{
|
||||
}
|
||||
|
||||
public LZ4MessagePackOutputFormatter(IFormatterResolver resolver)
|
||||
: base(new LZ4MessagePackSerializer.NonGeneric(resolver))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
|
||||
namespace MessagePack.AspNetCoreMvcFormatter
|
||||
{
|
||||
public class MessagePackInputFormatter : IInputFormatter
|
||||
{
|
||||
private const string ContentType = "application/x-msgpack";
|
||||
private readonly MessagePackSerializer.NonGeneric serializer;
|
||||
|
||||
public MessagePackInputFormatter()
|
||||
: this(new MessagePackSerializer.NonGeneric(new MessagePackSerializer()))
|
||||
{
|
||||
}
|
||||
|
||||
public MessagePackInputFormatter(IFormatterResolver resolver)
|
||||
: this(new MessagePackSerializer.NonGeneric(new MessagePackSerializer(resolver)))
|
||||
{
|
||||
}
|
||||
|
||||
public MessagePackInputFormatter(MessagePackSerializer.NonGeneric serializer)
|
||||
{
|
||||
this.serializer = serializer ?? new MessagePackSerializer.NonGeneric();
|
||||
}
|
||||
|
||||
public bool CanRead(InputFormatterContext context) =>
|
||||
context.HttpContext.Request.ContentType == ContentType;
|
||||
|
||||
public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
|
||||
{
|
||||
var request = context.HttpContext.Request;
|
||||
var result = this.serializer.Deserialize(context.ModelType, request.Body);
|
||||
return InputFormatterResult.SuccessAsync(result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
|
||||
namespace MessagePack.AspNetCoreMvcFormatter
|
||||
{
|
||||
public class MessagePackOutputFormatter : IOutputFormatter
|
||||
{
|
||||
private const string ContentType = "application/x-msgpack";
|
||||
private readonly MessagePackSerializer.NonGeneric serializer;
|
||||
|
||||
public MessagePackOutputFormatter()
|
||||
: this(new MessagePackSerializer.NonGeneric(new MessagePackSerializer()))
|
||||
{
|
||||
}
|
||||
|
||||
public MessagePackOutputFormatter(IFormatterResolver resolver)
|
||||
: this(new MessagePackSerializer.NonGeneric(new MessagePackSerializer(resolver)))
|
||||
{
|
||||
}
|
||||
|
||||
public MessagePackOutputFormatter(MessagePackSerializer.NonGeneric serializer)
|
||||
{
|
||||
this.serializer = serializer ?? new MessagePackSerializer.NonGeneric();
|
||||
}
|
||||
|
||||
public bool CanWriteResult(OutputFormatterCanWriteContext context) =>
|
||||
context.HttpContext.Request.ContentType == ContentType;
|
||||
|
||||
public Task WriteAsync(OutputFormatterWriteContext context)
|
||||
{
|
||||
context.HttpContext.Response.ContentType = ContentType;
|
||||
|
||||
if (context.ObjectType == typeof(object))
|
||||
{
|
||||
if (context.Object == null)
|
||||
{
|
||||
context.HttpContext.Response.Body.WriteByte(MessagePackCode.Nil);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.serializer.Serialize(context.Object.GetType(), context.HttpContext.Response.Body, context.Object);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.serializer.Serialize(context.ObjectType, context.HttpContext.Response.Body, context.Object);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -327,7 +327,7 @@ namespace MessagePack.CodeGenerator
|
|||
var unionAttrs = type.GetAttributes().Where(x => x.AttributeClass == typeReferences.UnionAttribute).Select(x => x.ConstructorArguments).ToArray();
|
||||
if (unionAttrs.Length == 0)
|
||||
{
|
||||
throw new MessagePackGeneratorResolveFailedException("Serialization Type must mark UnionAttribute." + " type: " + type.Name);
|
||||
throw new MessagePackGeneratorResolveFailedException("Serialization Type must mark UnionAttribute." + " type: " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
|
||||
}
|
||||
|
||||
// 0, Int 1, SubType
|
||||
|
@ -466,7 +466,7 @@ namespace MessagePack.CodeGenerator
|
|||
var contractAttr = type.GetAttributes().FirstOrDefault(x => x.AttributeClass == typeReferences.MessagePackObjectAttribute);
|
||||
if (contractAttr == null)
|
||||
{
|
||||
throw new MessagePackGeneratorResolveFailedException("Serialization Object must mark MessagePackObjectAttribute." + " type: " + type.Name);
|
||||
throw new MessagePackGeneratorResolveFailedException("Serialization Object must mark MessagePackObjectAttribute." + " type: " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
|
||||
}
|
||||
|
||||
var isIntKey = true;
|
||||
|
@ -546,11 +546,11 @@ namespace MessagePack.CodeGenerator
|
|||
if (!member.IsReadable && !member.IsWritable) continue;
|
||||
|
||||
var key = item.GetAttributes().FirstOrDefault(x => x.AttributeClass == typeReferences.KeyAttribute)?.ConstructorArguments[0];
|
||||
if (key == null) throw new MessagePackGeneratorResolveFailedException("all public members must mark KeyAttribute or IgnoreMemberAttribute." + " type: " + type.Name + " member:" + item.Name);
|
||||
if (key == null) throw new MessagePackGeneratorResolveFailedException("all public members must mark KeyAttribute or IgnoreMemberAttribute." + " type: " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " member:" + item.Name);
|
||||
|
||||
var intKey = (key.Value.Value is int) ? (int)key.Value.Value : (int?)null;
|
||||
var stringKey = (key.Value.Value is string) ? (string)key.Value.Value : (string)null;
|
||||
if (intKey == null && stringKey == null) throw new MessagePackGeneratorResolveFailedException("both IntKey and StringKey are null." + " type: " + type.Name + " member:" + item.Name);
|
||||
if (intKey == null && stringKey == null) throw new MessagePackGeneratorResolveFailedException("both IntKey and StringKey are null." + " type: " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " member:" + item.Name);
|
||||
|
||||
if (searchFirst)
|
||||
{
|
||||
|
@ -561,21 +561,21 @@ namespace MessagePack.CodeGenerator
|
|||
{
|
||||
if ((isIntKey && intKey == null) || (!isIntKey && stringKey == null))
|
||||
{
|
||||
throw new MessagePackGeneratorResolveFailedException("all members key type must be same." + " type: " + type.Name + " member:" + item.Name);
|
||||
throw new MessagePackGeneratorResolveFailedException("all members key type must be same." + " type: " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " member:" + item.Name);
|
||||
}
|
||||
}
|
||||
|
||||
if (isIntKey)
|
||||
{
|
||||
member.IntKey = (int)intKey;
|
||||
if (intMemebrs.ContainsKey(member.IntKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.Name + " member:" + item.Name);
|
||||
if (intMemebrs.ContainsKey(member.IntKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " member:" + item.Name);
|
||||
|
||||
intMemebrs.Add(member.IntKey, member);
|
||||
}
|
||||
else
|
||||
{
|
||||
member.StringKey = (string)stringKey;
|
||||
if (stringMembers.ContainsKey(member.StringKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.Name + " member:" + item.Name);
|
||||
if (stringMembers.ContainsKey(member.StringKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " member:" + item.Name);
|
||||
|
||||
member.IntKey = hiddenIntKey++;
|
||||
stringMembers.Add(member.StringKey, member);
|
||||
|
@ -602,11 +602,11 @@ namespace MessagePack.CodeGenerator
|
|||
if (!member.IsReadable && !member.IsWritable) continue;
|
||||
|
||||
var key = item.GetAttributes().FirstOrDefault(x => x.AttributeClass == typeReferences.KeyAttribute)?.ConstructorArguments[0];
|
||||
if (key == null) throw new MessagePackGeneratorResolveFailedException("all public members must mark KeyAttribute or IgnoreMemberAttribute." + " type: " + type.Name + " member:" + item.Name);
|
||||
if (key == null) throw new MessagePackGeneratorResolveFailedException("all public members must mark KeyAttribute or IgnoreMemberAttribute." + " type: " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " member:" + item.Name);
|
||||
|
||||
var intKey = (key.Value.Value is int) ? (int)key.Value.Value : (int?)null;
|
||||
var stringKey = (key.Value.Value is string) ? (string)key.Value.Value : (string)null;
|
||||
if (intKey == null && stringKey == null) throw new MessagePackGeneratorResolveFailedException("both IntKey and StringKey are null." + " type: " + type.Name + " member:" + item.Name);
|
||||
if (intKey == null && stringKey == null) throw new MessagePackGeneratorResolveFailedException("both IntKey and StringKey are null." + " type: " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " member:" + item.Name);
|
||||
|
||||
if (searchFirst)
|
||||
{
|
||||
|
@ -624,14 +624,14 @@ namespace MessagePack.CodeGenerator
|
|||
if (isIntKey)
|
||||
{
|
||||
member.IntKey = (int)intKey;
|
||||
if (intMemebrs.ContainsKey(member.IntKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.Name + " member:" + item.Name);
|
||||
if (intMemebrs.ContainsKey(member.IntKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " member:" + item.Name);
|
||||
|
||||
intMemebrs.Add(member.IntKey, member);
|
||||
}
|
||||
else
|
||||
{
|
||||
member.StringKey = (string)stringKey;
|
||||
if (stringMembers.ContainsKey(member.StringKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.Name + " member:" + item.Name);
|
||||
if (stringMembers.ContainsKey(member.StringKey)) throw new MessagePackGeneratorResolveFailedException("key is duplicated, all members key must be unique." + " type: " + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " member:" + item.Name);
|
||||
|
||||
member.IntKey = hiddenIntKey++;
|
||||
stringMembers.Add(member.StringKey, member);
|
||||
|
@ -658,7 +658,7 @@ namespace MessagePack.CodeGenerator
|
|||
}
|
||||
|
||||
// struct allows null ctor
|
||||
if (ctor == null && isClass) throw new MessagePackGeneratorResolveFailedException("can't find public constructor. type:" + type.Name);
|
||||
if (ctor == null && isClass) throw new MessagePackGeneratorResolveFailedException("can't find public constructor. type:" + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
|
||||
|
||||
var constructorParameters = new List<MemberSerializationInfo>();
|
||||
if (ctor != null)
|
||||
|
@ -688,7 +688,7 @@ namespace MessagePack.CodeGenerator
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new MessagePackGeneratorResolveFailedException("can't find matched constructor parameter, parameterType mismatch. type:" + type.Name + " parameterIndex:" + ctorParamIndex + " paramterType:" + item.Type.Name);
|
||||
throw new MessagePackGeneratorResolveFailedException("can't find matched constructor parameter, parameterType mismatch. type:" + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " parameterIndex:" + ctorParamIndex + " paramterType:" + item.Type.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -701,7 +701,7 @@ namespace MessagePack.CodeGenerator
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new MessagePackGeneratorResolveFailedException("can't find matched constructor parameter, index not found. type:" + type.Name + " parameterIndex:" + ctorParamIndex);
|
||||
throw new MessagePackGeneratorResolveFailedException("can't find matched constructor parameter, index not found. type:" + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " parameterIndex:" + ctorParamIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -720,7 +720,7 @@ namespace MessagePack.CodeGenerator
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new MessagePackGeneratorResolveFailedException("duplicate matched constructor parameter name:" + type.Name + " parameterName:" + item.Name + " paramterType:" + item.Type.Name);
|
||||
throw new MessagePackGeneratorResolveFailedException("duplicate matched constructor parameter name:" + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " parameterName:" + item.Name + " paramterType:" + item.Type.Name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -738,7 +738,7 @@ namespace MessagePack.CodeGenerator
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new MessagePackGeneratorResolveFailedException("can't find matched constructor parameter, parameterType mismatch. type:" + type.Name + " parameterName:" + item.Name + " paramterType:" + item.Type.Name);
|
||||
throw new MessagePackGeneratorResolveFailedException("can't find matched constructor parameter, parameterType mismatch. type:" + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " parameterName:" + item.Name + " paramterType:" + item.Type.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -751,7 +751,7 @@ namespace MessagePack.CodeGenerator
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new MessagePackGeneratorResolveFailedException("can't find matched constructor parameter, index not found. type:" + type.Name + " parameterName:" + item.Name);
|
||||
throw new MessagePackGeneratorResolveFailedException("can't find matched constructor parameter, index not found. type:" + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " parameterName:" + item.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -761,7 +761,7 @@ namespace MessagePack.CodeGenerator
|
|||
|
||||
if (ctor == null)
|
||||
{
|
||||
throw new MessagePackGeneratorResolveFailedException("can't find matched constructor. type:" + type.Name);
|
||||
throw new MessagePackGeneratorResolveFailedException("can't find matched constructor. type:" + type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MessagePack.CodeGenerator
|
||||
{
|
||||
|
@ -56,7 +55,7 @@ namespace MessagePack.CodeGenerator
|
|||
return;
|
||||
}
|
||||
|
||||
SHOW_HELP:
|
||||
SHOW_HELP:
|
||||
Console.WriteLine("mpc arguments help:");
|
||||
option.WriteOptionDescriptions(Console.Out);
|
||||
IsParsed = false;
|
||||
|
@ -71,93 +70,102 @@ namespace MessagePack.CodeGenerator
|
|||
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
static int Main(string[] args)
|
||||
{
|
||||
var cmdArgs = new CommandlineArguments(args);
|
||||
if (!cmdArgs.IsParsed)
|
||||
try
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Generator Start...
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
Console.WriteLine("Project Compilation Start:" + cmdArgs.InputPath);
|
||||
|
||||
var collector = new TypeCollector(cmdArgs.InputPath, cmdArgs.ConditionalSymbols, true, cmdArgs.IsUseMap);
|
||||
|
||||
Console.WriteLine("Project Compilation Complete:" + sw.Elapsed.ToString());
|
||||
Console.WriteLine();
|
||||
|
||||
sw.Restart();
|
||||
Console.WriteLine("Method Collect Start");
|
||||
|
||||
var (objectInfo, enumInfo, genericInfo, unionInfo) = collector.Collect();
|
||||
|
||||
Console.WriteLine("Method Collect Complete:" + sw.Elapsed.ToString());
|
||||
|
||||
Console.WriteLine("Output Generation Start");
|
||||
sw.Restart();
|
||||
|
||||
var objectFormatterTemplates = objectInfo
|
||||
.GroupBy(x => x.Namespace)
|
||||
.Select(x => new FormatterTemplate()
|
||||
var cmdArgs = new CommandlineArguments(args);
|
||||
if (!cmdArgs.IsParsed)
|
||||
{
|
||||
Namespace = cmdArgs.GetNamespaceDot() + "Formatters" + ((x.Key == null) ? "" : "." + x.Key),
|
||||
objectSerializationInfos = x.ToArray(),
|
||||
})
|
||||
.ToArray();
|
||||
return 0;
|
||||
}
|
||||
|
||||
var enumFormatterTemplates = enumInfo
|
||||
.GroupBy(x => x.Namespace)
|
||||
.Select(x => new EnumTemplate()
|
||||
// Generator Start...
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
Console.WriteLine("Project Compilation Start:" + cmdArgs.InputPath);
|
||||
|
||||
var collector = new TypeCollector(cmdArgs.InputPath, cmdArgs.ConditionalSymbols, true, cmdArgs.IsUseMap);
|
||||
|
||||
Console.WriteLine("Project Compilation Complete:" + sw.Elapsed.ToString());
|
||||
Console.WriteLine();
|
||||
|
||||
sw.Restart();
|
||||
Console.WriteLine("Method Collect Start");
|
||||
|
||||
var (objectInfo, enumInfo, genericInfo, unionInfo) = collector.Collect();
|
||||
|
||||
Console.WriteLine("Method Collect Complete:" + sw.Elapsed.ToString());
|
||||
|
||||
Console.WriteLine("Output Generation Start");
|
||||
sw.Restart();
|
||||
|
||||
var objectFormatterTemplates = objectInfo
|
||||
.GroupBy(x => x.Namespace)
|
||||
.Select(x => new FormatterTemplate()
|
||||
{
|
||||
Namespace = cmdArgs.GetNamespaceDot() + "Formatters" + ((x.Key == null) ? "" : "." + x.Key),
|
||||
objectSerializationInfos = x.ToArray(),
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
var enumFormatterTemplates = enumInfo
|
||||
.GroupBy(x => x.Namespace)
|
||||
.Select(x => new EnumTemplate()
|
||||
{
|
||||
Namespace = cmdArgs.GetNamespaceDot() + "Formatters" + ((x.Key == null) ? "" : "." + x.Key),
|
||||
enumSerializationInfos = x.ToArray()
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
var unionFormatterTemplates = unionInfo
|
||||
.GroupBy(x => x.Namespace)
|
||||
.Select(x => new UnionTemplate()
|
||||
{
|
||||
Namespace = cmdArgs.GetNamespaceDot() + "Formatters" + ((x.Key == null) ? "" : "." + x.Key),
|
||||
unionSerializationInfos = x.ToArray()
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
var resolverTemplate = new ResolverTemplate()
|
||||
{
|
||||
Namespace = cmdArgs.GetNamespaceDot() + "Formatters" + ((x.Key == null) ? "" : "." + x.Key),
|
||||
enumSerializationInfos = x.ToArray()
|
||||
})
|
||||
.ToArray();
|
||||
Namespace = cmdArgs.GetNamespaceDot() + "Resolvers",
|
||||
FormatterNamespace = cmdArgs.GetNamespaceDot() + "Formatters",
|
||||
ResolverName = cmdArgs.ResolverName,
|
||||
registerInfos = genericInfo.Cast<IResolverRegisterInfo>().Concat(enumInfo).Concat(unionInfo).Concat(objectInfo).ToArray()
|
||||
};
|
||||
|
||||
var unionFormatterTemplates = unionInfo
|
||||
.GroupBy(x => x.Namespace)
|
||||
.Select(x => new UnionTemplate()
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(resolverTemplate.TransformText());
|
||||
sb.AppendLine();
|
||||
foreach (var item in enumFormatterTemplates)
|
||||
{
|
||||
Namespace = cmdArgs.GetNamespaceDot() + "Formatters" + ((x.Key == null) ? "" : "." + x.Key),
|
||||
unionSerializationInfos = x.ToArray()
|
||||
})
|
||||
.ToArray();
|
||||
var text = item.TransformText();
|
||||
sb.AppendLine(text);
|
||||
}
|
||||
sb.AppendLine();
|
||||
foreach (var item in unionFormatterTemplates)
|
||||
{
|
||||
var text = item.TransformText();
|
||||
sb.AppendLine(text);
|
||||
}
|
||||
sb.AppendLine();
|
||||
foreach (var item in objectFormatterTemplates)
|
||||
{
|
||||
var text = item.TransformText();
|
||||
sb.AppendLine(text);
|
||||
}
|
||||
|
||||
var resolverTemplate = new ResolverTemplate()
|
||||
{
|
||||
Namespace = cmdArgs.GetNamespaceDot() + "Resolvers",
|
||||
FormatterNamespace = cmdArgs.GetNamespaceDot() + "Formatters",
|
||||
ResolverName = cmdArgs.ResolverName,
|
||||
registerInfos = genericInfo.Cast<IResolverRegisterInfo>().Concat(enumInfo).Concat(unionInfo).Concat(objectInfo).ToArray()
|
||||
};
|
||||
Output(cmdArgs.OutputPath, sb.ToString());
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(resolverTemplate.TransformText());
|
||||
sb.AppendLine();
|
||||
foreach (var item in enumFormatterTemplates)
|
||||
{
|
||||
var text = item.TransformText();
|
||||
sb.AppendLine(text);
|
||||
Console.WriteLine("String Generation Complete:" + sw.Elapsed.ToString());
|
||||
return 0;
|
||||
}
|
||||
sb.AppendLine();
|
||||
foreach (var item in unionFormatterTemplates)
|
||||
catch (Exception ex)
|
||||
{
|
||||
var text = item.TransformText();
|
||||
sb.AppendLine(text);
|
||||
Console.WriteLine("Unhandled Error:" + ex);
|
||||
return 1;
|
||||
}
|
||||
sb.AppendLine();
|
||||
foreach (var item in objectFormatterTemplates)
|
||||
{
|
||||
var text = item.TransformText();
|
||||
sb.AppendLine(text);
|
||||
}
|
||||
|
||||
Output(cmdArgs.OutputPath, sb.ToString());
|
||||
|
||||
Console.WriteLine("String Generation Complete:" + sw.Elapsed.ToString());
|
||||
}
|
||||
|
||||
static void Output(string path, string text)
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MessagePack.CodeGenerator
|
||||
{
|
||||
internal static class ProcessUtil
|
||||
{
|
||||
public static async Task<int> ExecuteProcessAsync(string fileName, string args, Stream stdout, Stream stderr, TextReader stdin, CancellationToken ct = default(CancellationToken))
|
||||
{
|
||||
var psi = new ProcessStartInfo(fileName, args);
|
||||
psi.UseShellExecute = false;
|
||||
psi.CreateNoWindow = true;
|
||||
psi.RedirectStandardError = stderr != null;
|
||||
psi.RedirectStandardOutput = stdout != null;
|
||||
psi.RedirectStandardInput = stdin != null;
|
||||
using (var proc = new Process())
|
||||
using (var cts = new CancellationTokenSource())
|
||||
using (var exitedct = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, ct))
|
||||
{
|
||||
proc.StartInfo = psi;
|
||||
proc.EnableRaisingEvents = true;
|
||||
proc.Exited += (sender, ev) =>
|
||||
{
|
||||
cts.Cancel();
|
||||
};
|
||||
if (!proc.Start())
|
||||
{
|
||||
throw new InvalidOperationException($"failed to start process(fileName = {fileName}, args = {args})");
|
||||
}
|
||||
int exitCode = 0;
|
||||
await Task.WhenAll(
|
||||
Task.Run(() =>
|
||||
{
|
||||
exitCode = StdinTask(proc, stdin, exitedct, cts);
|
||||
if(exitCode < 0)
|
||||
{
|
||||
proc.Dispose();
|
||||
}
|
||||
})
|
||||
,
|
||||
Task.Run(async () =>
|
||||
{
|
||||
if (stdout != null)
|
||||
{
|
||||
await RedirectOutputTask(proc.StandardOutput.BaseStream, stdout, exitedct.Token, "stdout");
|
||||
}
|
||||
})
|
||||
,
|
||||
Task.Run(async () =>
|
||||
{
|
||||
if (stderr != null)
|
||||
{
|
||||
await RedirectOutputTask(proc.StandardError.BaseStream, stderr, exitedct.Token, "stderr");
|
||||
}
|
||||
})
|
||||
);
|
||||
if(exitCode >= 0)
|
||||
{
|
||||
return proc.ExitCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
static int StdinTask(Process proc, TextReader stdin, CancellationTokenSource exitedct, CancellationTokenSource cts)
|
||||
{
|
||||
if (stdin != null)
|
||||
{
|
||||
while (!exitedct.Token.IsCancellationRequested)
|
||||
{
|
||||
var l = stdin.ReadLine();
|
||||
if (l == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
proc.StandardInput.WriteLine(l);
|
||||
}
|
||||
proc.StandardInput.Dispose();
|
||||
}
|
||||
exitedct.Token.WaitHandle.WaitOne();
|
||||
if (cts.IsCancellationRequested)
|
||||
{
|
||||
proc.WaitForExit();
|
||||
var exitCode = proc.ExitCode;
|
||||
return exitCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
proc.StandardOutput.Dispose();
|
||||
proc.StandardError.Dispose();
|
||||
proc.Kill();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static async Task RedirectOutputTask(Stream procStdout, Stream stdout, CancellationToken ct, string suffix)
|
||||
{
|
||||
if (stdout != null)
|
||||
{
|
||||
var buf = new byte[1024];
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
var bytesread = await procStdout.ReadAsync(buf, 0, 1024, ct).ConfigureAwait(false);
|
||||
if(bytesread <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
stdout.Write(buf, 0, bytesread);
|
||||
}
|
||||
catch(NullReferenceException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch(ObjectDisposedException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -17,6 +17,103 @@ namespace MessagePack.CodeGenerator
|
|||
// Utility and Extension methods for Roslyn
|
||||
internal static class RoslynExtensions
|
||||
{
|
||||
static (string fname, string args) GetBuildCommandLine(string csprojPath, string tempPath, bool useDotNet)
|
||||
{
|
||||
string fname = "dotnet";
|
||||
const string tasks = "ResolveAssemblyReferencesDesignTime;ResolveProjectReferencesDesignTime;ResolveComReferencesDesignTime;Compile";
|
||||
// from Buildalyzer implementation
|
||||
// https://github.com/daveaglick/Buildalyzer/blob/b42d2e3ba1b3673a8133fb41e72b507b01bce1d6/src/Buildalyzer/Environment/BuildEnvironment.cs#L86-L96
|
||||
Dictionary<string, string> properties = new Dictionary<string, string>()
|
||||
{
|
||||
{"IntermediateOutputPath", tempPath},
|
||||
{"ProviderCommandLineArgs", "true"},
|
||||
{"GenerateResourceMSBuildArchitecture", "CurrentArchitecture"},
|
||||
{"DesignTimeBuild", "true"},
|
||||
{"BuildProjectReferences","false"},
|
||||
{"SkipCompilerExecution","true"},
|
||||
{"DisableRarCache", "true"},
|
||||
{"AutoGenerateBindingRedirects", "false"},
|
||||
{"CopyBuildOutputToOutputDirectory", "false"},
|
||||
{"CopyOutputSymbolsToOutputDirectory", "false"},
|
||||
{"SkipCopyBuildProduct", "true"},
|
||||
{"AddModules", "false"},
|
||||
{"UseCommonOutputDirectory", "true"},
|
||||
{"GeneratePackageOnBuild", "false"},
|
||||
{"RunPostBuildEvent", "false"},
|
||||
{"SolutionDir", new FileInfo(csprojPath).FullName}
|
||||
};
|
||||
var propargs = string.Join(" ", properties.Select(kv => $"/p:{kv.Key}=\"{kv.Value}\""));
|
||||
// how to determine whether command should be executed('dotnet msbuild' or 'msbuild')?
|
||||
if (useDotNet)
|
||||
{
|
||||
fname = "dotnet";
|
||||
return (fname, $"msbuild \"{csprojPath}\" /t:{tasks} {propargs} /bl:\"{Path.Combine(tempPath, "build.binlog")}\" /v:n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fname = "msbuild";
|
||||
return (fname, $"\"{csprojPath}\" /t:{tasks} {propargs} /bl:\"{Path.Combine(tempPath, "build.binlog")}\" /v:n");
|
||||
}
|
||||
}
|
||||
static async Task<bool> TryExecute(string csprojPath, string tempPath, bool useDotNet)
|
||||
{
|
||||
// executing build command with output binary log
|
||||
var (fname, args) = GetBuildCommandLine(csprojPath, tempPath, useDotNet);
|
||||
try
|
||||
{
|
||||
using (var stdout = new MemoryStream())
|
||||
using (var stderr = new MemoryStream())
|
||||
{
|
||||
var exitCode = await ProcessUtil.ExecuteProcessAsync(fname, args, stdout, stderr, null).ConfigureAwait(false);
|
||||
if (exitCode == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// write process output to stdout and stderr when error.
|
||||
using (var stdout2 = new MemoryStream(stdout.ToArray()))
|
||||
using (var stderr2 = new MemoryStream(stderr.ToArray()))
|
||||
using (var consoleStdout = Console.OpenStandardOutput())
|
||||
using (var consoleStderr = Console.OpenStandardError())
|
||||
{
|
||||
await stdout2.CopyToAsync(consoleStdout).ConfigureAwait(false);
|
||||
await stderr2.CopyToAsync(consoleStderr).ConfigureAwait(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"exception occured(fname={fname}, args={args}):{e}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static async Task<AnalyzerResult[]> GetAnalyzerResults(AnalyzerManager analyzerManager, string csprojPath, params string[] preprocessorSymbols)
|
||||
{
|
||||
var tempPath = Path.Combine(new FileInfo(csprojPath).Directory.FullName, "__buildtemp");
|
||||
try
|
||||
{
|
||||
if (!await TryExecute(csprojPath, tempPath, true).ConfigureAwait(false))
|
||||
{
|
||||
Console.WriteLine("execute `dotnet msbuild` failed, retry with `msbuild`");
|
||||
if (!await TryExecute(csprojPath, tempPath, false).ConfigureAwait(false))
|
||||
{
|
||||
throw new Exception("failed to build project");
|
||||
}
|
||||
}
|
||||
// get results of analysis from binarylog
|
||||
return analyzerManager.Analyze(Path.Combine(tempPath, "build.binlog")).ToArray();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(tempPath))
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static async Task<Compilation> GetCompilationFromProject(string csprojPath, params string[] preprocessorSymbols)
|
||||
{
|
||||
var analyzerOptions = new AnalyzerManagerOptions();
|
||||
|
@ -26,7 +123,7 @@ namespace MessagePack.CodeGenerator
|
|||
var projectAnalyzer = manager.GetProject(csprojPath); // addproj
|
||||
// projectAnalyzer.AddBuildLogger(new Microsoft.Build.Logging.ConsoleLogger(Microsoft.Build.Framework.LoggerVerbosity.Minimal));
|
||||
|
||||
var workspace = manager.GetWorkspaceWithPreventBuildEvent();
|
||||
var workspace = await manager.GetWorkspaceWithPreventBuildEventAsync().ConfigureAwait(false);
|
||||
|
||||
workspace.WorkspaceFailed += WorkSpaceFailed;
|
||||
var project = workspace.CurrentSolution.Projects.First();
|
||||
|
@ -43,36 +140,20 @@ namespace MessagePack.CodeGenerator
|
|||
Console.WriteLine(e);
|
||||
}
|
||||
|
||||
public static AdhocWorkspace GetWorkspaceWithPreventBuildEvent(this AnalyzerManager manager)
|
||||
// WIP function for getting Roslyn's workspace from csproj
|
||||
public static async Task<AdhocWorkspace> GetWorkspaceWithPreventBuildEventAsync(this AnalyzerManager manager)
|
||||
{
|
||||
// info article: https://qiita.com/skitoy4321/items/9edfb094549f5167a57f
|
||||
var projPath = manager.Projects.First().Value.ProjectFile.Path;
|
||||
var tempPath = Path.Combine(new FileInfo(projPath).Directory.FullName, "__buildtemp") + System.IO.Path.DirectorySeparatorChar;
|
||||
|
||||
var envopts = new EnvironmentOptions();
|
||||
// "Clean" and "Build" is listed in default
|
||||
// Modify to designtime system https://github.com/dotnet/project-system/blob/master/docs/design-time-builds.md#targets-that-run-during-design-time-builds
|
||||
// that prevent Pre/PostBuildEvent
|
||||
|
||||
envopts.TargetsToBuild.Clear();
|
||||
// Clean should not use(if use pre/post build, dll was deleted).
|
||||
// envopts.TargetsToBuild.Add("Clean");
|
||||
envopts.TargetsToBuild.Add("ResolveAssemblyReferencesDesignTime");
|
||||
envopts.TargetsToBuild.Add("ResolveProjectReferencesDesignTime");
|
||||
envopts.TargetsToBuild.Add("ResolveComReferencesDesignTime");
|
||||
envopts.TargetsToBuild.Add("Compile");
|
||||
envopts.GlobalProperties["IntermediateOutputPath"] = tempPath;
|
||||
try
|
||||
var ws = new AdhocWorkspace();
|
||||
foreach (var result in await GetAnalyzerResults(manager, projPath))
|
||||
{
|
||||
return GetWorkspace(manager, envopts);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(tempPath))
|
||||
// getting only successful build
|
||||
if (result.Succeeded)
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
result.AddToWorkspace(ws);
|
||||
}
|
||||
}
|
||||
return ws;
|
||||
}
|
||||
|
||||
public static AdhocWorkspace GetWorkspace(this AnalyzerManager manager, EnvironmentOptions envOptions)
|
||||
|
|
|
@ -0,0 +1,363 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MessagePack.AspNetCoreMvcFormatter;
|
||||
using MessagePack.Resolvers;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace MessagePack.Tests.ExtensionTests
|
||||
{
|
||||
public class AspNetCoreMvcFormatterTest
|
||||
{
|
||||
private const string MsgPackContentType = "application/x-msgpack";
|
||||
|
||||
private MessagePackSerializer serializer = new MessagePackSerializer();
|
||||
private LZ4MessagePackSerializer lz4Serializer = new LZ4MessagePackSerializer();
|
||||
|
||||
[Fact]
|
||||
public async Task MessagePackFormatter()
|
||||
{
|
||||
var person = new User
|
||||
{
|
||||
UserId = 1,
|
||||
FullName = "John Denver",
|
||||
Age = 35,
|
||||
Description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
|
||||
};
|
||||
|
||||
var messagePackBinary = this.serializer.Serialize(person);
|
||||
|
||||
// OutputFormatter
|
||||
var outputFormatterContext = GetOutputFormatterContext(person, typeof(User), MsgPackContentType);
|
||||
var outputFormatter = new MessagePackOutputFormatter(StandardResolver.Instance);
|
||||
|
||||
outputFormatter.CanWriteResult(outputFormatterContext).IsTrue();
|
||||
|
||||
await outputFormatter.WriteAsync(outputFormatterContext);
|
||||
|
||||
var body = outputFormatterContext.HttpContext.Response.Body;
|
||||
|
||||
Assert.NotNull(body);
|
||||
body.Position = 0;
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
body.CopyTo(ms);
|
||||
Assert.Equal(messagePackBinary, ms.ToArray());
|
||||
}
|
||||
|
||||
// InputFormatter
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Features.Set<IHttpResponseFeature>(new TestResponseFeature());
|
||||
httpContext.Request.Body = new NonSeekableReadStream(messagePackBinary);
|
||||
httpContext.Request.ContentType = MsgPackContentType;
|
||||
|
||||
var inputFormatterContext = CreateInputFormatterContext(typeof(User), httpContext);
|
||||
|
||||
var inputFormatter = new MessagePackInputFormatter();
|
||||
|
||||
inputFormatter.CanRead(inputFormatterContext).IsTrue();
|
||||
|
||||
var result = await inputFormatter.ReadAsync(inputFormatterContext);
|
||||
|
||||
Assert.False(result.HasError);
|
||||
|
||||
var userModel = Assert.IsType<User>(result.Model);
|
||||
userModel.IsStructuralEqual(person);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MessagePackFormatterCanNotRead()
|
||||
{
|
||||
var person = new User();
|
||||
|
||||
// OutputFormatter
|
||||
var outputFormatterContext = GetOutputFormatterContext(person, typeof(User), "application/json");
|
||||
var outputFormatter = new MessagePackOutputFormatter(StandardResolver.Instance);
|
||||
|
||||
outputFormatter.CanWriteResult(outputFormatterContext).IsFalse();
|
||||
|
||||
// InputFormatter
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Features.Set<IHttpResponseFeature>(new TestResponseFeature());
|
||||
httpContext.Request.Body = new NonSeekableReadStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(person)));
|
||||
httpContext.Request.ContentType = "application/json";
|
||||
|
||||
var inputFormatterContext = CreateInputFormatterContext(typeof(User), httpContext);
|
||||
|
||||
var inputFormatter = new MessagePackInputFormatter();
|
||||
|
||||
inputFormatter.CanRead(inputFormatterContext).IsFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LZ4MessagePackFormatter()
|
||||
{
|
||||
var person = new User
|
||||
{
|
||||
UserId = 1,
|
||||
FullName = "John Denver",
|
||||
Age = 35,
|
||||
Description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
|
||||
};
|
||||
|
||||
var messagePackBinary = this.serializer.Serialize(person);
|
||||
var lz4MessagePackBinary = this.lz4Serializer.Serialize(person);
|
||||
|
||||
// OutputFormatter
|
||||
var outputFormatterContext = GetOutputFormatterContext(person, typeof(User), MsgPackContentType);
|
||||
var outputFormatter = new LZ4MessagePackOutputFormatter(StandardResolver.Instance);
|
||||
await outputFormatter.WriteAsync(outputFormatterContext);
|
||||
var body = outputFormatterContext.HttpContext.Response.Body;
|
||||
|
||||
Assert.NotNull(body);
|
||||
body.Position = 0;
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
body.CopyTo(ms);
|
||||
var binary = ms.ToArray();
|
||||
|
||||
binary.IsNot(messagePackBinary);
|
||||
binary.Is(lz4MessagePackBinary);
|
||||
}
|
||||
|
||||
// InputFormatter
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Features.Set<IHttpResponseFeature>(new TestResponseFeature());
|
||||
httpContext.Request.Body = new NonSeekableReadStream(messagePackBinary);
|
||||
httpContext.Request.ContentType = MsgPackContentType;
|
||||
|
||||
var inputFormatterContext = CreateInputFormatterContext(typeof(User), httpContext);
|
||||
|
||||
var inputFormatter = new LZ4MessagePackInputFormatter();
|
||||
|
||||
var result = await inputFormatter.ReadAsync(inputFormatterContext);
|
||||
|
||||
Assert.False(result.HasError);
|
||||
|
||||
var userModel = Assert.IsType<User>(result.Model);
|
||||
userModel.IsStructuralEqual(person);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LZ4MessagePackFormatterCanNotRead()
|
||||
{
|
||||
var person = new User();
|
||||
|
||||
// OutputFormatter
|
||||
var outputFormatterContext = GetOutputFormatterContext(person, typeof(User), "application/json");
|
||||
var outputFormatter = new LZ4MessagePackOutputFormatter(StandardResolver.Instance);
|
||||
|
||||
outputFormatter.CanWriteResult(outputFormatterContext).IsFalse();
|
||||
|
||||
// InputFormatter
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Features.Set<IHttpResponseFeature>(new TestResponseFeature());
|
||||
httpContext.Request.Body = new NonSeekableReadStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(person)));
|
||||
httpContext.Request.ContentType = "application/json";
|
||||
|
||||
var inputFormatterContext = CreateInputFormatterContext(typeof(User), httpContext);
|
||||
|
||||
var inputFormatter = new LZ4MessagePackInputFormatter();
|
||||
|
||||
inputFormatter.CanRead(inputFormatterContext).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see href="https://github.com/aspnet/Mvc/blob/master/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs#L453">JsonOutputFormatterTests.cs#L453</see>
|
||||
/// </summary>
|
||||
private static OutputFormatterWriteContext GetOutputFormatterContext(
|
||||
object outputValue,
|
||||
Type outputType,
|
||||
string contentType = "application/xml; charset=utf-8",
|
||||
MemoryStream responseStream = null)
|
||||
{
|
||||
var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse(contentType);
|
||||
|
||||
var actionContext = GetActionContext(mediaTypeHeaderValue, responseStream);
|
||||
return new OutputFormatterWriteContext(
|
||||
actionContext.HttpContext,
|
||||
new TestHttpResponseStreamWriterFactory().CreateWriter,
|
||||
outputType,
|
||||
outputValue)
|
||||
{
|
||||
ContentType = new StringSegment(contentType),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see href="https://github.com/aspnet/Mvc/blob/master/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs#L472">JsonOutputFormatterTests.cs#L472</see>
|
||||
/// </summary>
|
||||
private static ActionContext GetActionContext(
|
||||
MediaTypeHeaderValue contentType,
|
||||
MemoryStream responseStream = null)
|
||||
{
|
||||
var request = new Mock<HttpRequest>();
|
||||
var headers = new HeaderDictionary();
|
||||
request.Setup(r => r.ContentType).Returns(contentType.ToString());
|
||||
request.SetupGet(r => r.Headers).Returns(headers);
|
||||
headers[HeaderNames.AcceptCharset] = contentType.Charset.ToString();
|
||||
var response = new Mock<HttpResponse>();
|
||||
response.SetupGet(f => f.Body).Returns(responseStream ?? new MemoryStream());
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.SetupGet(c => c.Request).Returns(request.Object);
|
||||
httpContext.SetupGet(c => c.Response).Returns(response.Object);
|
||||
return new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see href="https://github.com/aspnet/Mvc/blob/master/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonInputFormatterTest.cs#L717">JsonInputFormatterTest.cs#L717</see>
|
||||
/// </summary>
|
||||
private InputFormatterContext CreateInputFormatterContext(
|
||||
Type modelType,
|
||||
HttpContext httpContext,
|
||||
string modelName = null,
|
||||
bool treatEmptyInputAsDefaultValue = false)
|
||||
{
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForType(modelType);
|
||||
|
||||
return new InputFormatterContext(
|
||||
httpContext,
|
||||
modelName: modelName ?? string.Empty,
|
||||
modelState: new ModelStateDictionary(),
|
||||
metadata: metadata,
|
||||
readerFactory: new TestHttpRequestStreamReaderFactory().CreateReader,
|
||||
treatEmptyInputAsDefaultValue: treatEmptyInputAsDefaultValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see href="https://github.com/aspnet/Mvc/blob/master/test/Microsoft.AspNetCore.Mvc.Formatters.Json.Test/JsonInputFormatterTest.cs#L791">JsonInputFormatterTest.cs#L791</see>
|
||||
/// </summary>
|
||||
private class TestResponseFeature : HttpResponseFeature
|
||||
{
|
||||
public override void OnCompleted(Func<object, Task> callback, object state)
|
||||
{
|
||||
// do not do anything
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see href="https://github.com/aspnet/Mvc/blob/master/test/Microsoft.AspNetCore.Mvc.Core.TestCommon/TestHttpResponseStreamWriterFactory.cs">TestHttpResponseStreamWriterFactory.cs</see>
|
||||
/// </summary>
|
||||
private class TestHttpResponseStreamWriterFactory : IHttpResponseStreamWriterFactory
|
||||
{
|
||||
private const int DefaultBufferSize = 16 * 1024;
|
||||
|
||||
public TextWriter CreateWriter(Stream stream, Encoding encoding)
|
||||
{
|
||||
return new HttpResponseStreamWriter(stream, encoding, DefaultBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see href="https://github.com/aspnet/Mvc/blob/master/test/Microsoft.AspNetCore.Mvc.Core.TestCommon/TestHttpRequestStreamReaderFactory.cs">TestHttpRequestStreamReaderFactory.cs</see>
|
||||
/// </summary>
|
||||
private class TestHttpRequestStreamReaderFactory : IHttpRequestStreamReaderFactory
|
||||
{
|
||||
public TextReader CreateReader(Stream stream, Encoding encoding)
|
||||
{
|
||||
return new HttpRequestStreamReader(stream, encoding);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see href="https://github.com/aspnet/Mvc/blob/master/test/Microsoft.AspNetCore.Mvc.Core.TestCommon/NonSeekableReadableStream.cs">NonSeekableReadableStream.cs</see>
|
||||
/// </summary>
|
||||
private class NonSeekableReadStream : Stream
|
||||
{
|
||||
private Stream _inner;
|
||||
|
||||
public NonSeekableReadStream(byte[] data)
|
||||
: this(new MemoryStream(data))
|
||||
{
|
||||
}
|
||||
|
||||
public NonSeekableReadStream(Stream inner)
|
||||
{
|
||||
_inner = inner;
|
||||
}
|
||||
|
||||
public override bool CanRead => _inner.CanRead;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
count = Math.Max(count, 1);
|
||||
return _inner.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
count = Math.Max(count, 1);
|
||||
return _inner.ReadAsync(buffer, offset, count, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class User
|
||||
{
|
||||
[Key(0)]
|
||||
public int UserId { get; set; }
|
||||
|
||||
[Key(1)]
|
||||
public string FullName { get; set; }
|
||||
|
||||
[Key(2)]
|
||||
public int Age { get; set; }
|
||||
|
||||
[Key(3)]
|
||||
public string Description { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="Moq" Version="4.10.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\MessagePack.AspNetCoreMvcFormatter\MessagePack.AspNetCoreMvcFormatter.csproj" />
|
||||
<ProjectReference Include="..\..\src\MessagePack\MessagePack.csproj" />
|
||||
<ProjectReference Include="..\MessagePack.Tests\MessagePack.Tests.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -23,7 +23,7 @@
|
|||
<PackageReference Include="System.Collections.Immutable" version="1.3.1" />
|
||||
<PackageReference Include="xunit" version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<PrivateAssets>none</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
|
|
Загрузка…
Ссылка в новой задаче