Skip to content

Commit

Permalink
caching ParameterInfo of method and remove StreamReader,avoid Concat …
Browse files Browse the repository at this point in the history
…and ToArray
  • Loading branch information
itn3000 committed Apr 4, 2018
1 parent ff21d75 commit 028fb45
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 24 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,4 @@ paket-files/
# JetBrains Rider
.idea/
*.sln.iml
**/BenchmarkDotNet.Artifacts/
2 changes: 1 addition & 1 deletion src/SoapCore.Benchmark.Shared/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace SoapCore.Benchmark
public class EchoBench
{
// 0 measures overhead of creating host
[Params(0, 100)]
[Params(100)]
public int LoopNum;
static string EchoContent = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
Expand Down
32 changes: 32 additions & 0 deletions src/SoapCore/OperationDescription.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
using System.Reflection;
using System.ServiceModel;
using System.Xml;
using System.Xml.Serialization;
using System.Linq;

namespace SoapCore
{
public class SoapMethodParameterInfo
{
public ParameterInfo Parameter { get; private set; }
public string Name { get; private set; }
public string Namespace { get; private set; }
public SoapMethodParameterInfo(ParameterInfo parameter, string name, string ns)
{
Parameter = parameter;
Name = name;
Namespace = ns;
}
}
public class OperationDescription
{
public ContractDescription Contract { get; private set; }
Expand All @@ -11,6 +26,9 @@ public class OperationDescription
public string Name { get; private set; }
public MethodInfo DispatchMethod { get; private set; }
public bool IsOneWay { get; private set; }
public SoapMethodParameterInfo[] NormalParameters { get; private set; }
public SoapMethodParameterInfo[] OutParameters { get;private set;}
public string ReturnName {get;private set;}

public OperationDescription(ContractDescription contract, MethodInfo operationMethod, OperationContractAttribute contractAttribute)
{
Expand All @@ -20,6 +38,20 @@ public OperationDescription(ContractDescription contract, MethodInfo operationMe
IsOneWay = contractAttribute.IsOneWay;
ReplyAction = contractAttribute.ReplyAction;
DispatchMethod = operationMethod;
NormalParameters = operationMethod.GetParameters().Where(x => !x.IsOut && !x.ParameterType.IsByRef)
.Select(info => CreateParameterInfo(info, contract)).ToArray();
OutParameters = operationMethod.GetParameters().Where(x => x.IsOut || x.ParameterType.IsByRef)
.Select(info => CreateParameterInfo(info, contract)).ToArray();
ReturnName = operationMethod.ReturnParameter.GetCustomAttribute<MessageParameterAttribute>()?.Name ?? Name + "Result";
}
static SoapMethodParameterInfo CreateParameterInfo(ParameterInfo info, ContractDescription contract)
{
var elementAttribute = info.GetCustomAttribute<XmlElementAttribute>();
var parameterName = !string.IsNullOrEmpty(elementAttribute?.ElementName)
? elementAttribute.ElementName
: info.GetCustomAttribute<MessageParameterAttribute>()?.Name ?? info.Name;
var parameterNs = elementAttribute?.Namespace ?? contract.Namespace;
return new SoapMethodParameterInfo(info, parameterName, parameterNs);
}
}
}
43 changes: 20 additions & 23 deletions src/SoapCore/SoapEndpointMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,10 @@ private async Task<Message> ProcessOperation(HttpContext httpContext, IServicePr
Message responseMessage;

//Reload the body to ensure we have the full message
using (var reader = new StreamReader(httpContext.Request.Body))
{
var body = await reader.ReadToEndAsync();
var requestData = Encoding.UTF8.GetBytes(body);
httpContext.Request.Body = new MemoryStream(requestData);
}
var mstm = new MemoryStream((int)httpContext.Request.ContentLength.GetValueOrDefault(1024));
await httpContext.Request.Body.CopyToAsync(mstm).ConfigureAwait(false);
mstm.Seek(0, SeekOrigin.Begin);
httpContext.Request.Body = mstm;

//Return metadata if no request
if (httpContext.Request.Body.Length == 0)
Expand Down Expand Up @@ -195,7 +193,8 @@ private async Task<Message> ProcessOperation(HttpContext httpContext, IServicePr
// Get operation arguments from message
Dictionary<string, object> outArgs = new Dictionary<string, object>();
var arguments = GetRequestArguments(requestMessage, reader, operation, ref outArgs);
var allArgs = arguments.Concat(outArgs.Values).ToArray();
// avoid Concat() and ToArray() cost when no out args(this may be heavy operation)
var allArgs = outArgs.Count != 0 ? arguments.Concat(outArgs.Values).ToArray() : arguments;

// Invoke Operation method
var responseObject = operation.DispatchMethod.Invoke(serviceInstance, allArgs);
Expand All @@ -220,7 +219,7 @@ private async Task<Message> ProcessOperation(HttpContext httpContext, IServicePr
}

// Create response message
var resultName = operation.DispatchMethod.ReturnParameter.GetCustomAttribute<MessageParameterAttribute>()?.Name ?? operation.Name + "Result";
var resultName = operation.ReturnName;
var bodyWriter = new ServiceBodyWriter(_serializer, operation.Contract.Namespace, operation.Name + "Response", resultName, responseObject, resultOutDictionary);
responseMessage = Message.CreateMessage(_messageEncoder.MessageVersion, null, bodyWriter);
responseMessage = new CustomMessage(responseMessage);
Expand All @@ -243,31 +242,30 @@ private async Task<Message> ProcessOperation(HttpContext httpContext, IServicePr
return responseMessage;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private object[] GetRequestArguments(Message requestMessage, System.Xml.XmlDictionaryReader xmlReader, OperationDescription operation, ref Dictionary<string, object> outArgs)
{
var parameters = operation.DispatchMethod.GetParameters().Where(x => !x.IsOut && !x.ParameterType.IsByRef).ToArray();
var arguments = new List<object>();
var parameters = operation.NormalParameters;
// avoid reallocation
var arguments = new List<object>(parameters.Length + operation.OutParameters.Length);

// Find the element for the operation's data
xmlReader.ReadStartElement(operation.Name, operation.Contract.Namespace);

for (int i = 0; i < parameters.Length; i++)
{
var elementAttribute = parameters[i].GetCustomAttribute<XmlElementAttribute>();
var parameterName = !string.IsNullOrEmpty(elementAttribute?.ElementName)
? elementAttribute.ElementName
: parameters[i].GetCustomAttribute<MessageParameterAttribute>()?.Name ?? parameters[i].Name;
var parameterNs = elementAttribute?.Namespace ?? operation.Contract.Namespace;
var parameterName = parameters[i].Name;
var parameterNs = parameters[i].Namespace;

if (xmlReader.IsStartElement(parameterName, parameterNs))
{
xmlReader.MoveToStartElement(parameterName, parameterNs);

if (xmlReader.IsStartElement(parameterName, parameterNs))
{
var elementType = parameters[i].ParameterType.GetElementType();
if (elementType == null || parameters[i].ParameterType.IsArray)
elementType = parameters[i].ParameterType;
var elementType = parameters[i].Parameter.ParameterType.GetElementType();
if (elementType == null || parameters[i].Parameter.ParameterType.IsArray)
elementType = parameters[i].Parameter.ParameterType;

switch (_serializer)
{
Expand All @@ -294,16 +292,15 @@ private object[] GetRequestArguments(Message requestMessage, System.Xml.XmlDicti
}
}

var outParams = operation.DispatchMethod.GetParameters().Where(x => x.IsOut || x.ParameterType.IsByRef).ToArray();
foreach (var parameterInfo in outParams)
foreach (var parameterInfo in operation.OutParameters)
{
if (parameterInfo.ParameterType.Name == "Guid&")
if (parameterInfo.Parameter.ParameterType.Name == "Guid&")
outArgs[parameterInfo.Name] = Guid.Empty;
else if (parameterInfo.ParameterType.Name == "String&" || parameterInfo.ParameterType.GetElementType().IsArray)
else if (parameterInfo.Parameter.ParameterType.Name == "String&" || parameterInfo.Parameter.ParameterType.GetElementType().IsArray)
outArgs[parameterInfo.Name] = null;
else
{
var type = parameterInfo.ParameterType.GetElementType();
var type = parameterInfo.Parameter.ParameterType.GetElementType();
outArgs[parameterInfo.Name] = Activator.CreateInstance(type);
}
}
Expand Down

0 comments on commit 028fb45

Please sign in to comment.