diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index efd39e8ac502a6c469ba0df5234166e411d001cb..9ef30b817df2273ff46bbe2818490c392308e834 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -246,6 +246,8 @@ void GenerateStaticMethodField(Printer* out, const MethodDescriptor *method) {
   out->Indent();
   out->Print("$methodtype$,\n", "methodtype",
              GetCSharpMethodType(GetMethodType(method)));
+  out->Print("$servicenamefield$,\n", "servicenamefield",
+               GetServiceNameFieldName());
   out->Print("\"$methodname$\",\n", "methodname", method->name());
   out->Print("$requestmarshaller$,\n", "requestmarshaller",
              GetMarshallerFieldName(method->input_type()));
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index d289ded6bd1254e2f7bc0d008e1aee4689de071d..9e7acab7edf19ecd04409b8632cda956f669d0e3 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -50,19 +50,22 @@ namespace Grpc.Core.Tests
 
         static readonly Method<string, string> EchoMethod = new Method<string, string>(
             MethodType.Unary,
-            "/tests.Test/Echo",
+            "tests.Test",
+            "Echo",
             Marshallers.StringMarshaller,
             Marshallers.StringMarshaller);
 
         static readonly Method<string, string> ConcatAndEchoMethod = new Method<string, string>(
             MethodType.ClientStreaming,
-            "/tests.Test/ConcatAndEcho",
+            "tests.Test",
+            "ConcatAndEcho",
             Marshallers.StringMarshaller,
             Marshallers.StringMarshaller);
 
         static readonly Method<string, string> NonexistentMethod = new Method<string, string>(
             MethodType.Unary,
-            "/tests.Test/NonexistentMethod",
+            "tests.Test",
+            "NonexistentMethod",
             Marshallers.StringMarshaller,
             Marshallers.StringMarshaller);
 
@@ -102,14 +105,14 @@ namespace Grpc.Core.Tests
         [Test]
         public void UnaryCall()
         {
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext());
             Assert.AreEqual("ABC", Calls.BlockingUnaryCall(internalCall, "ABC"));
         }
 
         [Test]
         public void UnaryCall_ServerHandlerThrows()
         {
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext());
             try
             {
                 Calls.BlockingUnaryCall(internalCall, "THROW");
@@ -124,7 +127,7 @@ namespace Grpc.Core.Tests
         [Test]
         public void UnaryCall_ServerHandlerThrowsRpcException()
         {
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext());
             try
             {
                 Calls.BlockingUnaryCall(internalCall, "THROW_UNAUTHENTICATED");
@@ -139,7 +142,7 @@ namespace Grpc.Core.Tests
         [Test]
         public void UnaryCall_ServerHandlerSetsStatus()
         {
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext());
             try
             {
                 Calls.BlockingUnaryCall(internalCall, "SET_UNAUTHENTICATED");
@@ -154,7 +157,7 @@ namespace Grpc.Core.Tests
         [Test]
         public async Task AsyncUnaryCall()
         {
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext());
             var result = await Calls.AsyncUnaryCall(internalCall, "ABC");
             Assert.AreEqual("ABC", result);
         }
@@ -162,7 +165,7 @@ namespace Grpc.Core.Tests
         [Test]
         public async Task AsyncUnaryCall_ServerHandlerThrows()
         {
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext());
             try
             {
                 await Calls.AsyncUnaryCall(internalCall, "THROW");
@@ -177,7 +180,7 @@ namespace Grpc.Core.Tests
         [Test]
         public async Task ClientStreamingCall()
         {
-            var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, ConcatAndEchoMethod, new CallContext());
             var call = Calls.AsyncClientStreamingCall(internalCall);
 
             await call.RequestStream.WriteAll(new string[] { "A", "B", "C" });
@@ -188,7 +191,7 @@ namespace Grpc.Core.Tests
         public async Task ClientStreamingCall_CancelAfterBegin()
         {
             var cts = new CancellationTokenSource();
-            var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, new CallContext(cancellationToken: cts.Token));
+            var internalCall = new Call<string, string>(channel, ConcatAndEchoMethod, new CallContext(cancellationToken: cts.Token));
             var call = Calls.AsyncClientStreamingCall(internalCall);
 
             // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
@@ -213,7 +216,7 @@ namespace Grpc.Core.Tests
                 new Metadata.Entry("ascii-header", "abcdefg"),
                 new Metadata.Entry("binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff }),
             };
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext(headers: headers));
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext(headers: headers));
             var call = Calls.AsyncUnaryCall(internalCall, "ABC");
 
             Assert.AreEqual("ABC", call.ResponseAsync.Result);
@@ -234,14 +237,14 @@ namespace Grpc.Core.Tests
         {
             channel.Dispose();
 
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext());
             Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(internalCall, "ABC"));
         }
 
         [Test]
         public void UnaryCallPerformance()
         {
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext());
             BenchmarkUtil.RunBenchmark(100, 100,
                                        () => { Calls.BlockingUnaryCall(internalCall, "ABC"); });
         }
@@ -249,7 +252,7 @@ namespace Grpc.Core.Tests
         [Test]
         public void UnknownMethodHandler()
         {
-            var internalCall = new Call<string, string>(ServiceName, NonexistentMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, NonexistentMethod, new CallContext());
             try
             {
                 Calls.BlockingUnaryCall(internalCall, "ABC");
@@ -264,7 +267,7 @@ namespace Grpc.Core.Tests
         [Test]
         public void UserAgentStringPresent()
         {
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext());
             string userAgent = Calls.BlockingUnaryCall(internalCall, "RETURN-USER-AGENT");
             Assert.IsTrue(userAgent.StartsWith("grpc-csharp/"));
         }
@@ -272,7 +275,7 @@ namespace Grpc.Core.Tests
         [Test]
         public void PeerInfoPresent()
         {
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext());
             string peer = Calls.BlockingUnaryCall(internalCall, "RETURN-PEER");
             Assert.IsTrue(peer.Contains(Host));
         }
@@ -285,7 +288,7 @@ namespace Grpc.Core.Tests
 
             var stateChangedTask = channel.WaitForStateChangedAsync(channel.State);
 
-            var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, EchoMethod, new CallContext());
             await Calls.AsyncUnaryCall(internalCall, "abc");
 
             await stateChangedTask;
diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
index f90a46368cb95552750c2f877756c5c3608304c6..e5fb2e54042c8a1172b6d83058de71747e9f66c5 100644
--- a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
@@ -53,7 +53,8 @@ namespace Grpc.Core.Tests
 
         static readonly Method<string, string> TestMethod = new Method<string, string>(
             MethodType.Unary,
-            "/tests.Test/Test",
+            "tests.Test",
+            "Test",
             Marshallers.StringMarshaller,
             Marshallers.StringMarshaller);
 
@@ -98,11 +99,11 @@ namespace Grpc.Core.Tests
         public void InfiniteDeadline()
         {
             // no deadline specified, check server sees infinite deadline
-            var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, new CallContext());
+            var internalCall = new Call<string, string>(channel, TestMethod, new CallContext());
             Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(internalCall, "RETURN_DEADLINE"));
 
             // DateTime.MaxValue deadline specified, check server sees infinite deadline
-            var internalCall2 = new Call<string, string>(ServiceName, TestMethod, channel, new CallContext());
+            var internalCall2 = new Call<string, string>(channel, TestMethod, new CallContext());
             Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(internalCall2, "RETURN_DEADLINE"));
         }
 
@@ -112,7 +113,7 @@ namespace Grpc.Core.Tests
             var remainingTimeClient = TimeSpan.FromDays(7);
             var deadline = DateTime.UtcNow + remainingTimeClient;
             Thread.Sleep(1000);
-            var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, new CallContext(deadline: deadline));
+            var internalCall = new Call<string, string>(channel, TestMethod, new CallContext(deadline: deadline));
 
             var serverDeadlineTicksString = Calls.BlockingUnaryCall(internalCall, "RETURN_DEADLINE");
             var serverDeadline = new DateTime(long.Parse(serverDeadlineTicksString), DateTimeKind.Utc);
@@ -126,7 +127,7 @@ namespace Grpc.Core.Tests
         [Test]
         public void DeadlineInThePast()
         {
-            var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, new CallContext(deadline: DateTime.MinValue));
+            var internalCall = new Call<string, string>(channel, TestMethod, new CallContext(deadline: DateTime.MinValue));
 
             try
             {
@@ -144,7 +145,7 @@ namespace Grpc.Core.Tests
         public void DeadlineExceededStatusOnTimeout()
         {
             var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5));
-            var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, new CallContext(deadline: deadline));
+            var internalCall = new Call<string, string>(channel, TestMethod, new CallContext(deadline: deadline));
 
             try
             {
@@ -162,7 +163,7 @@ namespace Grpc.Core.Tests
         public void ServerReceivesCancellationOnTimeout()
         {
             var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5));
-            var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, new CallContext(deadline: deadline));
+            var internalCall = new Call<string, string>(channel, TestMethod, new CallContext(deadline: deadline));
 
             try
             {
diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs
index 77d36191c3ee5e169ecf098a843ef0ee57ccd887..cc047ac9f8fb86e6676e7dca0b442344a4cf98d4 100644
--- a/src/csharp/Grpc.Core/Method.cs
+++ b/src/csharp/Grpc.Core/Method.cs
@@ -53,16 +53,20 @@ namespace Grpc.Core
     public class Method<TRequest, TResponse>
     {
         readonly MethodType type;
+        readonly string serviceName;
         readonly string name;
         readonly Marshaller<TRequest> requestMarshaller;
         readonly Marshaller<TResponse> responseMarshaller;
+        readonly string fullName;
 
-        public Method(MethodType type, string name, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller)
+        public Method(MethodType type, string serviceName, string name, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller)
         {
             this.type = type;
-            this.name = name;
-            this.requestMarshaller = requestMarshaller;
-            this.responseMarshaller = responseMarshaller;
+            this.serviceName = Preconditions.CheckNotNull(serviceName);
+            this.name = Preconditions.CheckNotNull(name);
+            this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller);
+            this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller);
+            this.fullName = GetFullName(serviceName);
         }
 
         public MethodType Type
@@ -72,6 +76,14 @@ namespace Grpc.Core
                 return this.type;
             }
         }
+            
+        public string ServiceName
+        {
+            get
+            {
+                return this.serviceName;
+            }
+        }
 
         public string Name
         {
@@ -97,6 +109,14 @@ namespace Grpc.Core
             }
         }
 
+        public string FullName
+        {
+            get
+            {
+                return this.fullName;
+            }
+        }
+
         /// <summary>
         /// Gets full name of the method including the service name.
         /// </summary>