reading of metadata
diff --git a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
index 861cbbe..bfd88a0 100644
--- a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
@@ -47,6 +47,9 @@
         static extern BatchContextSafeHandle grpcsharp_batch_context_create();
 
         [DllImport("grpc_csharp_ext.dll")]
+        static extern IntPtr grpcsharp_batch_context_receive_initial_metadata(BatchContextSafeHandle ctx);
+
+        [DllImport("grpc_csharp_ext.dll")]
         static extern IntPtr grpcsharp_batch_context_recv_message_length(BatchContextSafeHandle ctx);
 
         [DllImport("grpc_csharp_ext.dll")]
@@ -59,12 +62,18 @@
         static extern IntPtr grpcsharp_batch_context_recv_status_on_client_details(BatchContextSafeHandle ctx);  // returns const char*
 
         [DllImport("grpc_csharp_ext.dll")]
+        static extern IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata(BatchContextSafeHandle ctx);
+
+        [DllImport("grpc_csharp_ext.dll")]
         static extern CallSafeHandle grpcsharp_batch_context_server_rpc_new_call(BatchContextSafeHandle ctx);
 
         [DllImport("grpc_csharp_ext.dll")]
         static extern IntPtr grpcsharp_batch_context_server_rpc_new_method(BatchContextSafeHandle ctx);  // returns const char*
 
         [DllImport("grpc_csharp_ext.dll")]
+        static extern IntPtr grpcsharp_batch_context_server_rpc_new_request_metadata(BatchContextSafeHandle ctx);
+
+        [DllImport("grpc_csharp_ext.dll")]
         static extern int grpcsharp_batch_context_recv_close_on_server_cancelled(BatchContextSafeHandle ctx);
 
         [DllImport("grpc_csharp_ext.dll")]
@@ -87,13 +96,24 @@
             }
         }
 
+        public Metadata GetReceivedInitialMetadata()
+        {
+            IntPtr metadataArrayPtr = grpcsharp_batch_context_receive_initial_metadata(this);
+            return MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr);
+        }
+
         public Status GetReceivedStatus()
         {
-            // TODO: can the native method return string directly?
             string details = Marshal.PtrToStringAnsi(grpcsharp_batch_context_recv_status_on_client_details(this));
             return new Status(grpcsharp_batch_context_recv_status_on_client_status(this), details);
         }
 
+        public Metadata GetReceivedStatusTrailingMetadata()
+        {
+            IntPtr metadataArrayPtr = grpcsharp_batch_context_recv_status_on_client_trailing_metadata(this);
+            return MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr);
+        }
+
         public byte[] GetReceivedMessage()
         {
             IntPtr len = grpcsharp_batch_context_recv_message_length(this);
@@ -116,6 +136,12 @@
             return Marshal.PtrToStringAnsi(grpcsharp_batch_context_server_rpc_new_method(this));
         }
 
+        public Metadata GetServerRpcNewRequestMetadata()
+        {
+            IntPtr metadataArrayPtr = grpcsharp_batch_context_server_rpc_new_request_metadata(this);
+            return MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr);
+        }
+
         public bool GetReceivedCloseOnServerCancelled()
         {
             return grpcsharp_batch_context_recv_close_on_server_cancelled(this) != 0;
diff --git a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
index 80aa7f5..e17eb89 100644
--- a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
@@ -34,6 +34,8 @@
 
 namespace Grpc.Core.Internal
 {
+    
+
     /// <summary>
     /// grpc_metadata_array from <grpc/grpc.h>
     /// </summary>
@@ -46,12 +48,18 @@
         static extern void grpcsharp_metadata_array_add(MetadataArraySafeHandle array, string key, byte[] value, UIntPtr valueLength);
 
         [DllImport("grpc_csharp_ext.dll")]
+        static extern UIntPtr grpcsharp_metadata_array_count(IntPtr metadataArray);
+
+        [DllImport("grpc_csharp_ext.dll")]
+        static extern MetadataEntryStruct grpcsharp_metadata_array_get(IntPtr metadataArray, UIntPtr index);
+
+        [DllImport("grpc_csharp_ext.dll")]
         static extern void grpcsharp_metadata_array_destroy_full(IntPtr array);
 
         private MetadataArraySafeHandle()
         {
         }
-
+            
         public static MetadataArraySafeHandle Create(Metadata metadata)
         {
             // TODO(jtattermusch): we might wanna check that the metadata is readonly 
@@ -63,10 +71,53 @@
             return metadataArray;
         }
 
+        /// <summary>
+        /// Reads metadata from pointer to grpc_metadata_array
+        /// </summary>
+        public static Metadata ReadMetadataFromPtrUnsafe(IntPtr metadataArray)
+        {
+            if (metadataArray == IntPtr.Zero)
+            {
+                return null;
+            }
+
+            ulong count = grpcsharp_metadata_array_count(metadataArray).ToUInt64();
+
+            var metadata = new Metadata();
+            for (ulong index = 0; index < count; index ++)
+            {
+                var rawEntry = grpcsharp_metadata_array_get(metadataArray, new UIntPtr(index));
+                string key = Marshal.PtrToStringAnsi(rawEntry.key);
+                var bytes = new byte[rawEntry.valueLength.ToUInt64()];
+                Marshal.Copy(rawEntry.value, bytes, 0, bytes.Length);
+                metadata.Add(new Metadata.Entry(key, bytes));
+            }
+            return metadata;
+        }
+
+        internal IntPtr Handle
+        {
+            get
+            {
+                return handle;
+            }
+        }
+
         protected override bool ReleaseHandle()
         {
             grpcsharp_metadata_array_destroy_full(handle);
             return true;
         }
+
+        /// <summary>
+        /// gprc_metadata from grpc/grpc.h
+        /// </summary>
+        [StructLayout(LayoutKind.Sequential)]
+        private struct MetadataEntryStruct
+        {
+            public IntPtr key;  // const char*
+            public IntPtr value;  // const char*
+            public UIntPtr valueLength;
+        }
     }
 }
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 7dd1959..d8996ae 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -167,6 +167,17 @@
   array->count++;
 }
 
+GPR_EXPORT gpr_intptr GPR_CALLTYPE
+grpcsharp_metadata_array_count(grpc_metadata_array *array) {
+  return (gpr_intptr) array->count;
+}
+
+GPR_EXPORT const grpc_metadata *GPR_CALLTYPE
+grpcsharp_metadata_array_get(grpc_metadata_array *array, size_t index) {
+  GPR_ASSERT(index < array->count);
+  return array->metadata[index];
+}
+
 /* Move contents of metadata array */
 void grpcsharp_metadata_array_move(grpc_metadata_array *dest,
                                    grpc_metadata_array *src) {
@@ -218,6 +229,12 @@
   gpr_free(ctx);
 }
 
+GPR_EXPORT const grpc_metadata_array *GPR_CALLTYPE
+grpcsharp_batch_context_receive_initial_metadata(
+    const grpcsharp_batch_context *ctx) {
+  return &(ctx->recv_initial_metadata);
+}
+
 GPR_EXPORT gpr_intptr GPR_CALLTYPE grpcsharp_batch_context_recv_message_length(
     const grpcsharp_batch_context *ctx) {
   if (!ctx->recv_message) {
@@ -260,6 +277,12 @@
   return ctx->recv_status_on_client.status_details;
 }
 
+GPR_EXPORT const grpc_metadata_array *GPR_CALLTYPE
+grpcsharp_batch_context_recv_status_on_client_trailing_metadata(
+    const grpcsharp_batch_context *ctx) {
+  return &(ctx->recv_status_on_client.trailing_metadata);
+}
+
 GPR_EXPORT grpc_call *GPR_CALLTYPE grpcsharp_batch_context_server_rpc_new_call(
     const grpcsharp_batch_context *ctx) {
   return ctx->server_rpc_new.call;
@@ -271,6 +294,12 @@
   return ctx->server_rpc_new.call_details.method;
 }
 
+GPR_EXPORT const grpc_metadata_array *GPR_CALLTYPE
+grpcsharp_batch_context_server_rpc_new_request_metadata(
+    const grpcsharp_batch_context *ctx) {
+  return &(ctx->server_rpc_new.request_metadata);
+}
+
 GPR_EXPORT gpr_int32 GPR_CALLTYPE
 grpcsharp_batch_context_recv_close_on_server_cancelled(
     const grpcsharp_batch_context *ctx) {