set primary user agent by C# channel

pull/2607/head
Jan Tattermusch 9 years ago
parent 88b8a036ce
commit 766d72b1c0
  1. 20
      src/csharp/Grpc.Core.Tests/ClientServerTest.cs
  2. 25
      src/csharp/Grpc.Core/Channel.cs
  3. 30
      src/csharp/Grpc.Core/ChannelOptions.cs
  4. 1
      src/csharp/Grpc.Core/Grpc.Core.csproj
  5. 4
      src/csharp/Grpc.Core/Server.cs
  6. 2
      src/csharp/Grpc.Core/Version.cs
  7. 15
      src/csharp/Grpc.Core/VersionInfo.cs
  8. 6
      src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
  9. 6
      src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj

@ -33,6 +33,7 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Grpc.Core; using Grpc.Core;
@ -268,12 +269,27 @@ namespace Grpc.Core.Tests
} }
} }
[Test]
public void UserAgentStringPresent()
{
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
string userAgent = Calls.BlockingUnaryCall(internalCall, "RETURN-USER-AGENT", CancellationToken.None);
Assert.IsTrue(userAgent.StartsWith("grpc-csharp/"));
}
private static async Task<string> EchoHandler(string request, ServerCallContext context) private static async Task<string> EchoHandler(string request, ServerCallContext context)
{ {
foreach (Metadata.Entry metadataEntry in context.RequestHeaders) foreach (Metadata.Entry metadataEntry in context.RequestHeaders)
{ {
Console.WriteLine("Echoing header " + metadataEntry.Key + " as trailer"); if (metadataEntry.Key != "user-agent")
context.ResponseTrailers.Add(metadataEntry); {
context.ResponseTrailers.Add(metadataEntry);
}
}
if (request == "RETURN-USER-AGENT")
{
return context.RequestHeaders.Where(entry => entry.Key == "user-agent").Single().Value;
} }
if (request == "THROW") if (request == "THROW")

@ -28,11 +28,14 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion #endregion
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Grpc.Core.Internal; using Grpc.Core.Internal;
namespace Grpc.Core namespace Grpc.Core
@ -44,6 +47,7 @@ namespace Grpc.Core
{ {
readonly GrpcEnvironment environment; readonly GrpcEnvironment environment;
readonly ChannelSafeHandle handle; readonly ChannelSafeHandle handle;
readonly List<ChannelOption> options;
readonly string target; readonly string target;
bool disposed; bool disposed;
@ -57,7 +61,10 @@ namespace Grpc.Core
public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null) public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null)
{ {
this.environment = GrpcEnvironment.GetInstance(); this.environment = GrpcEnvironment.GetInstance();
using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(options)) this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
EnsureUserAgentChannelOption(this.options);
using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options))
{ {
if (credentials != null) if (credentials != null)
{ {
@ -71,7 +78,7 @@ namespace Grpc.Core
this.handle = ChannelSafeHandle.Create(host, nativeChannelArgs); this.handle = ChannelSafeHandle.Create(host, nativeChannelArgs);
} }
} }
this.target = GetOverridenTarget(host, options); this.target = GetOverridenTarget(host, this.options);
} }
/// <summary> /// <summary>
@ -141,6 +148,20 @@ namespace Grpc.Core
} }
} }
private static void EnsureUserAgentChannelOption(List<ChannelOption> options)
{
if (!options.Any((option) => option.Name == ChannelOptions.PrimaryUserAgentString))
{
options.Add(new ChannelOption(ChannelOptions.PrimaryUserAgentString, GetUserAgentString()));
}
}
private static string GetUserAgentString()
{
// TODO(jtattermusch): it would be useful to also provide .NET/mono version.
return string.Format("grpc-csharp/{0}", VersionInfo.CurrentVersion);
}
/// <summary> /// <summary>
/// Look for SslTargetNameOverride option and return its value instead of originalTarget /// Look for SslTargetNameOverride option and return its value instead of originalTarget
/// if found. /// if found.

@ -115,41 +115,49 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Defines names of supported channel options.
/// </summary>
public static class ChannelOptions public static class ChannelOptions
{ {
// Override SSL target check. Only to be used for testing. /// <summary>Override SSL target check. Only to be used for testing.</summary>
public const string SslTargetNameOverride = "grpc.ssl_target_name_override"; public const string SslTargetNameOverride = "grpc.ssl_target_name_override";
// Enable census for tracing and stats collection /// <summary>Enable census for tracing and stats collection</summary>
public const string Census = "grpc.census"; public const string Census = "grpc.census";
// Maximum number of concurrent incoming streams to allow on a http2 connection /// <summary>Maximum number of concurrent incoming streams to allow on a http2 connection</summary>
public const string MaxConcurrentStreams = "grpc.max_concurrent_streams"; public const string MaxConcurrentStreams = "grpc.max_concurrent_streams";
// Maximum message length that the channel can receive /// <summary>Maximum message length that the channel can receive</summary>
public const string MaxMessageLength = "grpc.max_message_length"; public const string MaxMessageLength = "grpc.max_message_length";
// Initial sequence number for http2 transports /// <summary>Initial sequence number for http2 transports</summary>
public const string Http2InitialSequenceNumber = "grpc.http2.initial_sequence_number"; public const string Http2InitialSequenceNumber = "grpc.http2.initial_sequence_number";
/// <summary>Primary user agent: goes at the start of the user-agent metadata</summary>
public const string PrimaryUserAgentString = "grpc.primary_user_agent";
/// <summary> Secondary user agent: goes at the end of the user-agent metadata</summary>
public const string SecondaryUserAgentString = "grpc.secondary_user_agent";
/// <summary> /// <summary>
/// Creates native object for a collection of channel options. /// Creates native object for a collection of channel options.
/// </summary> /// </summary>
/// <returns>The native channel arguments.</returns> /// <returns>The native channel arguments.</returns>
internal static ChannelArgsSafeHandle CreateChannelArgs(IEnumerable<ChannelOption> options) internal static ChannelArgsSafeHandle CreateChannelArgs(List<ChannelOption> options)
{ {
if (options == null) if (options == null || options.Count == 0)
{ {
return ChannelArgsSafeHandle.CreateNull(); return ChannelArgsSafeHandle.CreateNull();
} }
var optionList = new List<ChannelOption>(options); // It's better to do defensive copy
ChannelArgsSafeHandle nativeArgs = null; ChannelArgsSafeHandle nativeArgs = null;
try try
{ {
nativeArgs = ChannelArgsSafeHandle.Create(optionList.Count); nativeArgs = ChannelArgsSafeHandle.Create(options.Count);
for (int i = 0; i < optionList.Count; i++) for (int i = 0; i < options.Count; i++)
{ {
var option = optionList[i]; var option = options[i];
if (option.Type == ChannelOption.OptionType.Integer) if (option.Type == ChannelOption.OptionType.Integer)
{ {
nativeArgs.SetInteger(i, option.Name, option.IntValue); nativeArgs.SetInteger(i, option.Name, option.IntValue);

@ -102,6 +102,7 @@
<Compile Include="Internal\BatchContextSafeHandle.cs" /> <Compile Include="Internal\BatchContextSafeHandle.cs" />
<Compile Include="ChannelOptions.cs" /> <Compile Include="ChannelOptions.cs" />
<Compile Include="AsyncUnaryCall.cs" /> <Compile Include="AsyncUnaryCall.cs" />
<Compile Include="VersionInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Grpc.Core.nuspec" /> <None Include="Grpc.Core.nuspec" />

@ -53,6 +53,7 @@ namespace Grpc.Core
public const int PickUnusedPort = 0; public const int PickUnusedPort = 0;
readonly GrpcEnvironment environment; readonly GrpcEnvironment environment;
readonly List<ChannelOption> options;
readonly ServerSafeHandle handle; readonly ServerSafeHandle handle;
readonly object myLock = new object(); readonly object myLock = new object();
@ -69,7 +70,8 @@ namespace Grpc.Core
public Server(IEnumerable<ChannelOption> options = null) public Server(IEnumerable<ChannelOption> options = null)
{ {
this.environment = GrpcEnvironment.GetInstance(); this.environment = GrpcEnvironment.GetInstance();
using (var channelArgs = ChannelOptions.CreateChannelArgs(options)) this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
using (var channelArgs = ChannelOptions.CreateChannelArgs(this.options))
{ {
this.handle = ServerSafeHandle.NewServer(environment.CompletionQueue, channelArgs); this.handle = ServerSafeHandle.NewServer(environment.CompletionQueue, channelArgs);
} }

@ -2,4 +2,4 @@ using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
// The current version of gRPC C#. // The current version of gRPC C#.
[assembly: AssemblyVersion("0.6.0.*")] [assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentVersion + ".*")]

@ -0,0 +1,15 @@
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Grpc.Core
{
public static class VersionInfo
{
/// <summary>
/// Current version of gRPC
/// </summary>
public const string CurrentVersion = "0.6.0";
}
}

@ -3,8 +3,6 @@
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform> <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{3D166931-BA2D-416E-95A3-D36E8F6E90B9}</ProjectGuid> <ProjectGuid>{3D166931-BA2D-416E-95A3-D36E8F6E90B9}</ProjectGuid>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RootNamespace>Grpc.IntegrationTesting.Client</RootNamespace> <RootNamespace>Grpc.IntegrationTesting.Client</RootNamespace>
@ -48,6 +46,10 @@
<Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project> <Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project>
<Name>Grpc.IntegrationTesting</Name> <Name>Grpc.IntegrationTesting</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
<Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
<Name>Grpc.Core</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config" />

@ -3,8 +3,6 @@
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform> <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A654F3B8-E859-4E6A-B30D-227527DBEF0D}</ProjectGuid> <ProjectGuid>{A654F3B8-E859-4E6A-B30D-227527DBEF0D}</ProjectGuid>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RootNamespace>Grpc.IntegrationTesting.Server</RootNamespace> <RootNamespace>Grpc.IntegrationTesting.Server</RootNamespace>
@ -48,6 +46,10 @@
<Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project> <Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project>
<Name>Grpc.IntegrationTesting</Name> <Name>Grpc.IntegrationTesting</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
<Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
<Name>Grpc.Core</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config" />

Loading…
Cancel
Save